Hầu hết mọi người vẫn đang sử dụng Claude Code như một thực tập sinh siêu đắt đỏ.
Họ giao cho nó một nhiệm vụ, chờ một câu trả lời, rồi tự tay quyết định bước tiếp theo.
Nhưng những đội ngũ tận dụng được nhiều sức mạnh nhất từ AI đang xây dựng thứ gần giống với một hệ thống phân tán nhỏ.

Một agent phạm vi vấn đề.
Năm agent rẻ hơn tìm kiếm song song.
Một script quyết định loại bỏ trùng lặp.
Ba agent hoài nghi cố gắng phá vỡ các phát hiện.
Một model cao cấp nhất đưa ra phán quyết cuối cùng.
Đó là kỹ thuật graph (graph engineering).
Trước khi bạn đọc tiếp:
Hãy đánh dấu hướng dẫn này để bạn có thể quay lại các mẫu graph khi bắt đầu xây dựng workflow Claude của riêng mình.
Và theo dõi
@Gyome1_ -
Tôi phân tích Claude Code, các AI agent, và những hệ thống biến một model thành một workflow kỹ thuật đáng tin cậy.
Tôi đã dành hàng tuần để mổ xẻ các kiến trúc agent thực tế, sơ đồ workflow, và các mẫu sản xuất để tái tạo Graph Engineering thành một sổ tay thực hành duy nhất.
Thay vì viết một prompt dài hơn, bạn thiết kế con đường mà thông tin đi qua hệ thống:
tuyến tính → fan-out → reduce → verify → tổng hợp
Mỗi agent trở thành một node với một công việc có giới hạn. Mỗi cạnh (edge) mang dữ liệu có cấu trúc. Router quyết định nhánh nào chạy. Bộ xác minh (verifier) từ chối các đầu ra yếu. Vòng lặp tiếp tục cho đến khi graph không còn tìm thấy gì mới.
Sự thay đổi quan trọng là Claude Code không còn phải hành xử như một trí thông minh duy nhất làm việc qua một danh sách kiểm tra khổng lồ nữa.
Nó có thể tạo mã điều phối, sinh ra một đội tàu các agent chuyên biệt, định tuyến đầu ra của chúng qua các model khác nhau, và lắp ráp kết quả cuối cùng chỉ khi bằng chứng sống sót qua quá trình xác minh.

Các mẫu cơ bản không phải là mới. Các kỹ sư phần mềm đã sử dụng DAG, pipeline, barrier, MapReduce, và các worker phân tán trong nhiều thập kỷ.
Điều đã thay đổi là những gì nằm bên trong mỗi node bây giờ.
Một node có thể tìm kiếm một kho lưu trữ, kiểm toán một quá trình di chuyển, thách thức một quyết định kiến trúc, kiểm tra các lỗi kiểm thử, hoặc tổng hợp năm mươi phát hiện độc lập thành một báo cáo có trích dẫn.
Hướng dẫn này phân tích toàn bộ hệ thống từ agent tuyến tính đơn giản nhất đến diamond graph, router node, bảng xác minh đối nghịch (adversarial verifier panel), vòng lặp hội tụ, phân tầng model, và workflow động được tạo trực tiếp bên trong Claude Code.
Đến cuối bài, bạn sẽ có thể nhìn vào một tác vụ lớn và ngừng hỏi:
"Tôi nên viết prompt gì?"
1. GRAPH ENGINEERING BẮT ĐẦU TỪ HÓA ĐƠN
Graph engineering thường được trình bày như một cách để chạy nhiều agent hơn.
Cách đóng khung đó bỏ lỡ phần đắt đỏ nhất.
Bạn có thể khởi động hai mươi agent Claude chống lại cùng một kho lưu trữ và nhận được hai mươi báo cáo chồng chéo, ngữ cảnh lặp lại, kết luận mâu thuẫn, và một hóa đơn API lớn hơn nhiều.
Một graph hữu ích kiểm soát nơi tính toán diễn ra, model nào xử lý mỗi quyết định, và cách các phát hiện không chắc chắn di chuyển qua workflow.
Hãy tưởng tượng yêu cầu Claude Code chuẩn bị một quá trình di chuyển sản xuất:

Kiểm tra kho lưu trữ, tìm mọi phụ thuộc, đề xuất quá trình di chuyển, xác định rủi ro, xác minh kế hoạch, và viết báo cáo tóm tắt cuối cùng.
Bên trong một prompt, điều này trở thành một quy trình dài và mờ đục. Claude tìm kiếm codebase, lưu trữ các phát hiện trong ngữ cảnh, thiết kế quá trình di chuyển, xem xét kế hoạch của chính nó, và tạo ra báo cáo cuối cùng.
Khi báo cáo thất bại, nguồn gốc của sự thất bại rất khó xác định. Claude có thể đã bỏ lỡ một file, hiểu sai một phụ thuộc, mất một chi tiết trước đó, hoặc chấp nhận một giả định yếu trong quá trình xác minh.
Mọi giai đoạn cũng có thể chạy trên cùng một model đắt đỏ, ngay cả khi các phần của tác vụ liên quan đến việc trích xuất hoặc sắp xếp đơn giản.
Graph engineering mở workflow đó ra và cho mọi quyết định một vị trí có thể nhìn thấy.
Các nhánh kiểm tra chạy cùng lúc vì chúng sử dụng cùng một tác vụ có phạm vi và không phụ thuộc vào đầu ra của nhau.
Các phát hiện của chúng gặp nhau tại một giai đoạn reduce, nơi các bản sao biến mất và bằng chứng được nén thành một tập dữ liệu nhỏ hơn.
Một router sau đó đọc mức độ nghiêm trọng. Các thay đổi thông thường di chuyển qua một đánh giá nhẹ. Các phát hiện rủi ro cao nhận được phân tích sâu hơn từ một số người đánh giá độc lập trước khi đến model cuối cùng.
Kết quả là một workflow nơi độ trễ, chi phí model, kích thước ngữ cảnh, và độ sâu xác minh được kiểm soát thông qua cấu trúc của graph.
Một node nên đưa ra một quyết định
Một node hữu ích có một trách nhiệm có giới hạn.
Tìm mọi cuộc gọi đến API đã lỗi thời. Phân loại mỗi rủi ro di chuyển là thấp, trung bình, hoặc cao. Kiểm tra kế hoạch rollback cho các trường hợp thất bại.
Mỗi node cần một đầu vào rõ ràng, một đầu ra được xác định, và một bề mặt quyết định có giới hạn.
Một node tìm kiếm kho lưu trữ, ước tính tác động kinh doanh, thiết kế sửa lỗi, và viết khuyến nghị vẫn chứa một số giai đoạn ẩn. Việc gỡ lỗi vẫn khó khăn vì lý luận trung gian bị chôn vùi bên trong một lệnh gọi model duy nhất.
Các ranh giới nhỏ hơn tiết lộ nơi bằng chứng đi vào hệ thống và nơi ý nghĩa của nó thay đổi.
Một cạnh nên mang bằng chứng
Một cạnh đại diện cho dữ liệu cần thiết bởi node tiếp theo.
Bộ quét (scanner) có thể trả về một object có thể dự đoán:

1{2 "file": "src/auth/session.ts",3 "lines": [84, 119],4 "dependency": "legacySessionClient",5 "confidence": 0.94,6 "evidence": "Cả hai vị trí gọi đều phụ thuộc vào phương thức refresh đã lỗi thời."7}
Bộ phân loại rủi ro bây giờ nhận được cùng các trường cho mọi phát hiện. Nó có thể từ chối các kết quả không đầy đủ, nhóm các file liên quan, và định tuyến bằng chứng không chắc chắn vào một đánh giá khác.
Schema làm giảm độ lệch diễn giải giữa các node. Các đoạn văn bản tự do buộc mọi agent hạ nguồn phải tái tạo lại ý nghĩa của agent trước đó. Qua nhiều giai đoạn, những mơ hồ nhỏ có thể làm thay đổi kết luận cuối cùng.
Đầu ra có cấu trúc giữ cho bằng chứng ổn định khi nó di chuyển qua graph.
Một số node là mã thông thường
Giả sử tám agent tìm kiếm trả về tám mươi phát hiện.
Workflow cần kết hợp các mảng, loại bỏ các phản hồi trống, xóa trùng lặp, và sắp xếp các mục còn lại.
Các thao tác này có câu trả lời xác định:
1const uniqueFindings = [2 ...new Map(3 results4 .flatMap(batch => batch ?? [])5 .map(item => [`${item.file}:${item.lines.join("-")}`, item])6 ).values()7];
Một phép biến đổi JavaScript xử lý việc này ngay lập tức và tạo ra cùng một đầu ra trong mỗi lần chạy. Gửi cùng một tác vụ cho một model khác làm tăng chi phí token và tạo ra một nơi khác nơi bằng chứng có thể biến mất.
Các node model nên xoay quanh việc tìm kiếm, phân loại, so sánh, đánh giá, và tổng hợp. Mã có thể xử lý xác thực, khử trùng lặp, sắp xếp, các quy tắc định tuyến rõ ràng, và các phép biến đổi có thể dự đoán khác.
Sự phân chia này trở thành nền tảng của graph.
Mọi lệnh gọi model nên tương ứng với một quyết định thực sự đòi hỏi sự phán xét.
2. HÌNH KIM CƯƠNG: CÁCH CÁC GRAPH AGENT THỰC TẾ DI CHUYỂN CÔNG VIỆC
Hầu hết các graph agent nghiêm túc cuối cùng đều có cùng một hình dạng.
Một tác vụ bắt đầu với một phạm vi chung duy nhất, phân chia qua một số worker độc lập, chờ đầu ra của chúng, nén bằng chứng, và chuyển kết quả vào một quyết định cuối cùng.
Hình dạng đó là hình kim cương.

Phía bên trái là fan-out.
Điểm giữa nơi tất cả các nhánh gặp nhau là barrier.
Phía bên phải là fan-in.
Mẫu này xuất hiện ở khắp mọi nơi một khi một tác vụ trở nên quá lớn cho một cửa sổ ngữ cảnh duy nhất.
Một cuộc kiểm toán kho lưu trữ có thể chia theo phân hệ. Một báo cáo thị trường có thể chia theo nguồn. Một tác vụ nghiên cứu có thể chia theo giả thuyết. Một đánh giá di chuyển có thể chia qua việc sử dụng API, thay đổi cơ sở dữ liệu, rủi ro triển khai, và phạm vi kiểm thử.
Mỗi worker nhận được cùng một phạm vi với một nhiệm vụ hẹp hơn.
Graph sau đó chờ cho đến khi đủ bằng chứng hữu ích đã quay trở lại.
Fan-out nên tạo ra công việc độc lập
Một nhánh thuộc về fan-out khi nó có thể bắt đầu từ đầu vào chung và tạo ra một kết quả hữu ích mà không cần đọc đầu ra của một nhánh khác.
Đối với một cuộc kiểm toán bảo mật, sự phân chia có thể trông như thế này:

Claude Code có thể khởi chạy các lệnh gọi này đồng thời với một primitive barrier như parallel()
1const findings = await parallel(2 checks.map(check => async () => {3 return agent({4 task: check.task,5 context: auditScope,6 schema: FINDING_SCHEMA7 });8 })9);
Sự điều phối vẫn nằm trong JavaScript thông thường. Mỗi nhánh nhận được một tác vụ có giới hạn và trả về một object đã được xác thực.
Kết quả đến như một tập hợp các đầu ra có thể được lọc, kiểm tra, và chuyển vào giai đoạn tiếp theo.
Một fan-out lớn vẫn cần một lý do đằng sau mỗi nhánh.
Chia một nhiệm vụ mơ hồ thành mười hai agent gần như giống hệt nhau thường tạo ra các phát hiện lặp lại với cách diễn đạt hơi khác một chút. Sự song song hữu ích đến từ các nguồn, góc nhìn, vùng mã, hoặc giả thuyết khác biệt.
Barrier tạo ra một điểm quyết định
Một barrier tạm dừng giai đoạn tiếp theo cho đến khi các nhánh cần thiết đã hoàn thành.
Sự tạm dừng đó quan trọng vì một số quyết định phụ thuộc vào tập hợp đầy đủ.
Một node xếp hạng không thể xác định lỗ hổng quan trọng nhất trong khi một nửa kho lưu trữ vẫn đang được kiểm tra. Một model tổng hợp không thể viết một kế hoạch di chuyển hoàn chỉnh trong khi đánh giá triển khai vẫn đang chạy.
Tại barrier, graph có cơ hội kiểm tra trạng thái của lần chạy:
1const completed = findings.filter(Boolean);23if (completed.length < MIN_REQUIRED_RESULTS) {4 throw new Error("Insufficient audit coverage");5}
Đây là nơi các thất bại một phần trở nên có thể nhìn thấy.
Một worker có thể hết thời gian, trả về dữ liệu sai định dạng, hoặc không tạo ra phát hiện nào. Lọc các giá trị null giữ cho lần chạy tiếp tục, nhưng các workflow sản xuất thường cần một chính sách rõ ràng hơn:
- có bao nhiêu nhánh thành công là cần thiết;
- nhánh nào là bắt buộc;
- liệu một node thất bại có nên thử lại không;
- liệu kết quả cuối cùng có nên được đánh dấu là không đầy đủ không.
Do đó, barrier là một phần của mô hình độ tin cậy, không chỉ là một cơ chế đồng bộ hóa.
Reduce trước khi bạn tổng hợp
Sau fan-out, graph có thể chứa hàng tá phát hiện chồng chéo.
Gửi tất cả chúng trực tiếp vào một model cao cấp nhất tạo ra một ngữ cảnh lớn, lặp lại cùng một bằng chứng, và làm cho các chi tiết quan trọng khó phân biệt hơn.
Giai đoạn reduce chuẩn bị bằng chứng.
Một số reduction có thể xảy ra trong mã:
1const unique = deduplicateByKey(2 completed.flatMap(result => result.findings),3 finding => `${finding.file}:${finding.line}:${finding.type}`4);
Lớp tiếp theo có thể yêu cầu phán xét:
1const curated = await agent({2 task: `3 Nhóm các phát hiện có liên quan.4 Giữ lại tất cả các tham chiếu file và dòng.5 Xếp hạng mỗi nhóm theo tác động vận hành.6 Trả về bằng chứng mạnh nhất cho mọi kết luận.7 `,8 input: unique,9 schema: CURATED_FINDINGS_SCHEMA10});
Reduction kiểm soát những gì đến được model cuối cùng.
Một reducer tốt loại bỏ sự lặp lại trong khi vẫn giữ bằng chứng. Một reducer quyết liệt có thể nén một số rủi ro khác biệt thành một bản tóm tắt mơ hồ và xóa các chi tiết cần thiết cho việc xác minh.
Mẫu an toàn nhất giữ một liên kết giữa mọi tuyên bố đã được giảm và các mục nguồn của nó.
1{2 "risk": "Phiên làm việc có thể bị lỗi sau khi di chuyển",3 "severity": "cao",4 "sourceFindingIds": ["AUTH-04", "API-11", "TEST-07"],5 "evidence": [6 "Ba dịch vụ gọi phương thức refresh đã lỗi thời",7 "Không có đường dẫn dự phòng",8 "Thiếu phạm vi bao phủ tích hợp"9 ]10}
Bây giờ node tổng hợp nhận được một tập dữ liệu nhỏ hơn mà không mất khả năng truy xuất nguồn gốc.
3. ĐỘ TIN CẬY LÀ MỘT PHẦN CỦA GRAPH
Một graph có thể kết thúc nhanh chóng và vẫn tạo ra một câu trả lời tồi.
Một khi một số agent bắt đầu tìm kiếm, phân loại, và đánh giá cùng một tác vụ, vấn đề chính trở thành kiểm soát.
Hệ thống cần các quy tắc để quyết định phát hiện nào xứng đáng với công việc sâu hơn, đầu ra nào nên bị từ chối, và khi nào workflow đã tìm kiếm đủ.
Định tuyến theo rủi ro
Một node router đọc đầu ra có cấu trúc và chọn nhánh tiếp theo.

Việc phân loại có thể đến từ một model, trong khi bản thân nhánh vẫn rõ ràng trong mã.
1const route =2 finding.severity === "cao"3 ? runFullAudit(finding)4 : runQuickReview(finding);
Điều này giữ cho đánh giá đắt đỏ tập trung xung quanh các phát hiện có tác động đáng kể.
Một router hữu ích dựa vào các trường mà graph có thể kiểm tra: mức độ nghiêm trọng, độ tin cậy, các hệ thống bị ảnh hưởng, mức độ phơi nhiễm tài chính, hoặc sự hiện diện của bằng chứng bị thiếu.
Thêm xác minh độc lập
Một agent đánh giá kết luận của chính nó mang cùng các giả định vào cả hai giai đoạn.
Một graph mạnh hơn gửi các phát hiện quan trọng đến một số người đánh giá với các nhiệm vụ khác nhau.

Các người đánh giá không nên nhận được hướng dẫn để cải thiện câu trả lời ban đầu. Nhiệm vụ của họ là tìm kiếm các lý do khiến nó có thể không đầy đủ hoặc sai.
Graph có thể yêu cầu sự đồng thuận trước khi một phát hiện được chuyển tiếp:
1const accepted = votes.filter(vote => vote.approve).length >= 2;
Cô lập các agent thay đổi mã
Các agent lập trình song song có thể can thiệp lẫn nhau khi chúng chỉnh sửa cùng một thư mục làm việc.
Một agent có thể ghi đè lên một file trong khi một agent khác vẫn đang đọc nó. Các kiểm thử có thể chạy dựa trên một hỗn hợp các thay đổi không liên quan.
Git worktrees cung cấp cho mỗi nhánh bản sao riêng của kho lưu trữ.
1kho lưu trữ chính2 │3 ├→ worktree/auth-fix4 ├→ worktree/db-migration5 └→ worktree/test-repair
Mỗi agent có thể sửa đổi các file và chạy kiểm thử bên trong môi trường của riêng nó. Một node sau đó so sánh các bản vá, kiểm tra xung đột, và chọn những gì nên được hợp nhất.
Điều này biến sự cô lập thành một phần của graph thay vì một bước dọn dẹp thủ công.
Để khám phá hội tụ
Một số tác vụ không thể hoàn thành trong một lần.
Một cuộc kiểm toán kho lưu trữ có thể phát hiện ra một phụ thuộc trỏ đến một gói khác. Gói đó có thể tiết lộ một vị trí gọi khác. Graph cần một cách có kiểm soát để tiếp tục tìm kiếm mà không lặp lại mọi thứ nó đã thấy.
1const seen = new Set();2let dryRounds = 0;34while (dryRounds < 2) {5 const findings = await discoverNext([...seen]);6 const fresh = findings.filter(item => !seen.has(item.id));78 fresh.forEach(item => seen.add(item.id));9 dryRounds = fresh.length === 0 ? dryRounds + 1 : 0;10}
Chi tiết quan trọng là khử trùng lặp dựa trên mọi mục đã thấy trước đó.
Chỉ khử trùng lặp dựa trên các phát hiện đã được xác nhận cho phép các mục bị từ chối hoặc không chắc chắn quay lại ở lần tiếp theo và tiêu thụ cùng một công việc một lần nữa.
Vòng lặp dừng lại sau một số vòng khô, một ngân sách cố định, hoặc một số lần lặp tối đa. Các graph sản xuất thường cần cả ba.
Ghép model với node
Mọi node không cần model mạnh nhất hiện có.
Trích xuất, phân loại cơ bản, và tìm kiếm hẹp thường có thể chạy trên một tầng nhanh hơn. Đánh giá kiến trúc, xác minh đối nghịch, và tổng hợp cuối cùng có thể biện minh cho một model mạnh hơn.

Phân tầng model trở thành một thuộc tính khác của graph.
Ngân sách được xác định bởi bao nhiêu node chạy, vòng lặp lặp lại thường xuyên như thế nào, bao nhiêu ngữ cảnh vượt qua mỗi cạnh, và model nào xử lý mỗi giai đoạn.
Một graph với hai mươi lệnh gọi tìm kiếm rẻ tiền vẫn có thể tốn kém hơn một lệnh gọi mạnh mẽ. Kiến trúc cần một ngân sách token trước khi nó cần một nhánh khác.
Biết khi nào nên ngừng vẽ
Các tác vụ nhỏ hiếm khi cần router, bảng bỏ phiếu, worktree, và vòng lặp hội tụ.
Chi phí graph bao gồm mã điều phối, schema, thử lại, ghi log, lưu trữ trung gian, và nhiều trạng thái thất bại hơn để gỡ lỗi.
Một workflow tuyến tính thường là đủ khi một model có thể giữ ngữ cảnh liên quan, tác vụ có ít nhánh độc lập, và chi phí của một câu trả lời sai là thấp.
Graph engineering trở nên hữu ích khi tác vụ có được công việc song song, các quyết định đắt đỏ, tập bằng chứng lớn, hoặc các yêu cầu xác minh có ý nghĩa.
Workflow hoàn chỉnh cuối cùng có thể trông như thế này:

Giá trị đến từ việc làm cho sự di chuyển của công việc trở nên có thể nhìn thấy.
Mọi node có một trách nhiệm giới hạn. Mọi cạnh mang bằng chứng có cấu trúc. Mọi nhánh có một lý do để tồn tại. Mọi vòng lặp có một điều kiện dừng.
Tại thời điểm đó, Claude Code không còn làm việc thông qua một hướng dẫn dài nữa.
Nó đang thực thi một hệ thống được kỹ thuật hóa.





