Chuyển đến nội dung
25/30Chương 25 trên 30

Điều phối multi-agent: Năm pattern và khi nào một agent thắng

Cùng một hóa đơn được xử lý bốn cách: orchestrator tốn 1,66 lần single agent nhưng cho cùng kết luận.

Trên trang này

Chương 24 kết thúc bằng một câu hỏi mà chính nó đã tạo ra: khi một sub-agent sai, chính xác thì agent cha được nhìn vào cái gì?

Chương này trả lời bằng một hóa đơn. Một nhiệm vụ — khách hàng tranh chấp hóa đơn và muốn nhận phản hồi — được giải bốn cách, tất cả đều chạy Chương 23 harness với cùng provider được kịch bản hóa, tất cả đều đếm cùng token bằng cùng encoder, tất cả đều được tính giá theo mức Chương 16 đọc vào ngày 6 tháng 9 năm 2026.

cách sắp xếplượt gọi modelinput tokensoutputchi phíwall clockkết luận
prompt chaining4900165$0.0037801,648 mssai
một agent, bốn công cụ52,697179$0.0075422,224 msđúng
các phần chạy song song92,910324$0.0097082,165 msđúng
orchestrator-workers123,628438$0.0125125,090 msđúng, và không chứng minh được

Đọc hàng đầu và hàng cuối cùng nhau: giữa chúng là mọi cuộc tranh luận mà ngành này hiện đang có. Cách sắp xếp rẻ nhất cũng nhanh nhất và tạo ra một câu trả lời tự tin, sai, có thể gửi đi. Cách đắt nhất trả lời đúng, tốn tiền gấp 3,3 lần và thời gian gấp 3,1 lần, rồi kết thúc bằng cách trích lại kết luận của một worker mà nó không có cách nào kiểm chứng.

Hàng mà không ai đưa vào các bảng này là hàng thứ hai: một agent với bốn công cụ đạt cùng kết luận như orchestrator với 60 % chi phí và 44 % wall clock. Đó không phải là thiên kiến thích sự đơn giản. Đó là một phép đo, và phần còn lại của chương này nói về khi nào điều đó không còn đúng.

Hiện chi tiết

Chương này cần gì từ các chương trước.

  • Chương 18 cho hợp đồng công cụ: một schema model thấy, một endpoint nó không bao giờ thấy. Cả một agent nằm gọn sau giao diện đó, và đó là toàn bộ multi-agent.
  • Chương 22 cho hai định nghĩa đã công bố về "agent" nhưng không đồng thuận, và cho phép tính rằng một chuỗi prompt là N lượt gọi.
  • Chương 23 cho vòng lặp, năm lối thoát, trạng thái chạy và trace. Mọi cách sắp xếp bên dưới đều là file đó, được gọi theo cách khác.
  • Chương 24 cho chi phí của một cửa sổ và những gì rơi ra khỏi nó. Một sub-agent là chiến lược thứ tư trong bốn chiến lược của nó, và là chiến lược duy nhất là một agent thứ hai chứ không phải một policy.

Không có tensor. Mọi thứ ở đây là TypeScript, trừ hai phép đo chạy với một model cục bộ thật.

Một công ty Bồ Đào Nha viết email về hóa đơn FT-2026-0918. Email nói VAT có vẻ sai và đính kèm hóa đơn: net EUR 248.00, VAT tính 21 %, EUR 52.08, tổng EUR 300.08.

Các dữ kiện cần để trả lời nằm ở ba nơi, và chỉ một trong số đó nằm trong email:

ở đâunội dung nói gì
hóa đơn đính kèmngười bán ở Tây Ban Nha, VAT áp dụng 21 %, EUR 52.08
hồ sơ đơn hàngngười mua đăng ký ở Bồ Đào Nha, có mã VAT hợp lệ, business-to-business
bảng thuếthuế suất nội địa Tây Ban Nha 21 %; business-to-business nội khối EU với mã hợp lệ, reverse charge, 0 %

Ghép cả ba lại thì hóa đơn sai: áp dụng reverse charge, VAT lẽ ra phải bằng không, cần phát hành credit note EUR 52.08. Chỉ nhìn vào hóa đơn thì nó hoàn hảo về số học — 248.00 cộng 52.08 bằng 300.08 — và bạn sẽ nói vậy.

Email đúng là có nói "chúng tôi là một công ty Bồ Đào Nha". Đó là một lời khai, không phải hồ sơ, và không hệ thống billing nào phát hành credit note dựa trên một lời khai. Cái bẫy không phải mẹo: đó là hình dạng bình thường của công việc kinh doanh, nơi quyết định cần một dữ kiện mà không ai nghĩ phải lấy.

Mọi thứ ở trên chạy với một provider được kịch bản hóa theo phong cách Chương 23, với đúng một quy tắc:

Một câu trả lời chỉ được dùng dữ kiện có trong prompt của nó.

"Model" yêu cầu từng công cụ mà nó có, mỗi công cụ một lần, theo thứ tự catalogue, rồi áp dụng một quy tắc cố định lên văn bản nó nhìn thấy. Không có gì được kịch bản riêng theo từng cách sắp xếp, nên các khác biệt trong bảng mở đầu không phải tuyên bố về trí thông minh của model: chúng là định tuyến thông tin, được đo. Một model thật sẽ thêm các lỗi riêng của nó lên trên; nó không loại bỏ những lỗi này.

Năm tên bên dưới là của Anthropic, từ Building effective agents, nơi bộ từ vựng này ổn định.1 Không ý tưởng nào trong năm ý tưởng là mới, và nói nhà nào đặt tên cho cái gì — và ý tưởng nào cũ hơn — là một nửa giá trị của việc biết chúng.

patterns.tsTS
/* 1. Prompt chaining: a fixed pipeline. The control flow is yours. */
export async function chain(steps: Step[], first: string) {
  let carry = first, all = first;
  for (const s of steps) {
    const r = await step(s.role, s.system, s.accumulate ? all : carry);   
    carry = r.text;
    all = `${all}\n${r.text}`;
  }
  return carry;
}

/* 2. Routing: one cheap call picks the branch. The fallback is not a model. */
export async function route<T>(input: string, classify: Classifier,
                               routes: Record<string, Branch<T>>, fallback: Branch<T>) {
  let label: string | undefined;
  try { label = await classify(input); } catch { label = undefined; }
  return ((label && routes[label]) || fallback)(input);                    
}

/* 3. Parallelisation. The pattern IS this line. */
export const parallel = <T>(workers: Branch<T>[], input: string) =>
  Promise.all(workers.map((w) => w(input)));                              

/* 4. Orchestrator-workers: an agent behind a tool. Chapter 18's interface, unchanged. */
export function agentTool(o: WorkerSpec): Tool {
  return {
    name: o.name, description: o.description, readOnly: true,
    parameters: { type: "object", properties: { question: { type: "string" } } },
    async run(args: { question: string }) {
      const child = newRun(o.system, args.question);          // its own window
      await runTracked(child, o.tools, o.usage);              // its own limits
      const conclusion = child.output ?? "no result";
      if (!o.carryFindings) return conclusion;                             
      return `${conclusion}\nFINDINGS ${evidence(child)}`;                 
    },
  };
}

/* 5. Evaluator-optimiser: make, judge, remake. Rounds are calls. */
export async function refine(make: Make, judge: Judge, maxRounds: number) {
  let draft = "", feedback: string | undefined;
  for (let r = 1; r <= maxRounds; r++) {
    draft = (await make(feedback)).text;
    const j = await judge(draft);
    if (j.ok) return { draft, rounds: r };
    feedback = j.note;
  }
  return { draft, rounds: maxRounds };
}

Đó là toàn bộ bộ công cụ: năm hàm, không framework, và bản song song chỉ là một dòng — đó chính là lý do viết nó ra thay vì vẽ. Giờ xét từng cái, với nguồn gốc, giá của nó, và trường hợp nó sai.

Prompt chaining "phân rã một nhiệm vụ thành một chuỗi bước, trong đó mỗi lượt gọi LLM xử lý output của lượt trước".1 Ý tưởng này có trước language model: nó là một pipeline, với đánh đổi của pipeline — rõ ràng đổi lấy luồng điều khiển được cố định trước khi dữ liệu đến.

Bốn bước cho nhiệm vụ của chúng ta: trích xuất các trường hóa đơn, kiểm tra số học, quyết định khoản nợ, viết phản hồi. Ở đây nó thất bại theo hai cách khác nhau, và điều đó dạy nhiều hơn việc chỉ thất bại một lần.

TEXT
--- relay: each step sees only the previous step's output
extract: FIELDS invoice_id=FT-2026-0918 net=248.00 vat_rate_applied=21 vat_amount=52.08 ...
check:   ARITHMETIC ok 248.00+52.08=300.08
decide:  VERDICT=unknown reason=no_invoice_in_context
draft:   "we are looking into invoice FT-2026-0918 and will come back to you."

--- accumulating: each step sees the email and everything produced so far
extract: FIELDS invoice_id=FT-2026-0918 net=248.00 vat_rate_applied=21 ...
check:   ARITHMETIC ok 248.00+52.08=300.08
decide:  VERDICT=invoice_correct reason=net_248.00_plus_21pct_vat_52.08_equals_300.08
draft:   "we have checked FT-2026-0918 and it is correct... Nothing is owed back."

Chuỗi relay tốn $0.001940 và làm mất các trường hóa đơn giữa bước hai và bước ba, vì bước ba chỉ được đưa một câu về số học và không gì khác. Nó tạo ra một tin nhắn chờ xử lý: vô dụng, và vô dụng một cách thấy rõ.

Chuỗi tích lũy — hàng trong bảng mở đầu — tốn $0.003780, tức đắt hơn 95 % cho bốn lượt gọi giống hệt, vì giờ mỗi bước mang theo mọi thứ trước nó. Nó tạo ra output nguy hiểm. Trôi chảy, trích dẫn phép tính của mình, đúng trên mọi con số nó nhắc tới, và nói với khách hàng rằng không nợ gì trong khi đang nợ EUR 52.08.

Khác biệt giữa hai cái là một toán tử ternary. Một chain mang ít dữ liệu hơn tạo ra câu trả lời rõ ràng là thiếu; một chain mang mọi thứ tạo ra câu trả lời tự tin nhưng sai — và chỉ loại thứ hai được gửi đi.

Cả hai đều không phải thất bại thật sự. Thất bại thật sự là pipeline đã quyết định, trước khi đọc bất cứ thứ gì, rằng nhiệm vụ này gồm bốn bước trên nội dung của một email. Trong cấu trúc đó không có chỗ nào để nói "quốc gia đăng ký không nằm trong email này; đi lấy nó". Chaining đúng khi phân rã đã biết trước và ổn định. Ở đây nó là một phỏng đoán, và phỏng đoán đó đã được ship.

Routing, cái lâu đời nhất, và plan B không ai viết

Liên kết đến mục: Routing, cái lâu đời nhất, và plan B không ai viết

Routing "phân loại một input và hướng nó tới một tác vụ theo sau chuyên biệt".1 Tên gọi thì mới; cơ chế là dispatcher, cũ hơn gần như mọi thứ khác trong cuốn này. Điều mới là classifier có thể là một model — và chính điều đó làm nó thất bại theo những cách mà một switch chưa từng thất bại.

route.tsTS
const answer = await route(email,
  (q) => classifyWithSmallModel(q),          // cheap model, one call
  { billing: billingAgent, tax: taxAgent, dunning: dunningAgent },
  taxAgent,                                  // deterministic, chosen in advance
);

Có hai điều về đối số cuối cùng đó. Nó không phải xử lý lỗi; nó là pattern. Router dựa trên model có một failure mode mà dispatcher không có: nó có thể trả về một nhãn không tồn tại, timeout, hoặc — trường hợp đắt đỏ — trả về một nhãn sai nhưng nghe hợp lý mà không có tín hiệu nào cho biết nó sai. Cả ba đều phải rơi vào đâu đó, và nơi đó không thể là một lượt gọi model khác, vì bạn đã ở nhánh nơi các lượt gọi model thất bại.

Điều thứ hai là prompt của chính router không miễn phí. Để chọn một model, router cần một catalogue các model để chọn, và mỗi mục trong đó là input mà router phải trả tiền trước khi nó đọc câu hỏi của người dùng. Ở mức giá input mà khóa học này dùng để định giá, một catalogue khoảng 3,800 token đã tốn ngang toàn bộ lượt chạy agent năm-call trong bảng mở đầu. Trên thực tế, lượt routing chạy trên một model rẻ, đó là toàn bộ lý do routing tự hoàn vốn; nhưng phép tính đáng được làm theo hướng đó thay vì giả định. Routing sai chính xác khi tác vụ được route rẻ hơn quyết định routing.

Parallelisation: các phần, và voting, tức self-consistency

Liên kết đến mục: Parallelisation: các phần, và voting, tức self-consistency

Anthropic chia mục này làm hai: sectioning — "chia một nhiệm vụ thành các subtasks độc lập chạy song song" — và voting — "chạy cùng một nhiệm vụ nhiều lần để nhận output đa dạng".1 Chúng dùng chung một sơ đồ và gần như không có gì khác chung.

Sectioning là thắng lợi rẻ, và là dòng từ patterns.ts: ba specialist — billing, tax, policy — mỗi người có cửa sổ và công cụ riêng, trên cùng email, với một lượt gọi tổng hợp ở cuối. Cùng một công việc, sắp xếp theo hai cách:

lượt gọi modelinputoutputchi phíwall clock
ba worker, lần lượt từng người92,910324$0.0097083,894 ms
cùng ba worker đó, Promise.all92,910324$0.0097082,165 ms

Giống nhau từng token, nhanh hơn 1,8 lần. Đó là lý do pattern này xứng đáng có tên riêng: nó là pattern duy nhất trong năm cái cải thiện được một thứ mà không tốn gì thêm. Điểm mắc là các phần phải thật sự độc lập — đưa cho phần B một dữ kiện do phần A tạo ra và Promise.all sẽ chạy cả hai trên một trạng thái chưa tồn tại. Vòng lặp for che giấu bug đó; bản một dòng phơi nó ra.

Voting là một loài khác đội cùng bức tranh. Chạy cùng câu hỏi k lần rồi lấy đa số là self-consistency, được Wang và cộng sự công bố vào tháng 3 năm 2022 như một chiến lược decoding, gần ba năm trước khi có ai gọi nó là một pattern orchestration. Tóm tắt của bài báo rất chính xác về cơ chế — "đầu tiên lấy mẫu một tập đa dạng các đường suy luận thay vì chỉ lấy đường greedy, rồi chọn câu trả lời nhất quán nhất bằng cách marginalizing out các đường suy luận đã lấy mẫu" — và về mức tăng: +17.9 điểm trên GSM8K.2

Từ đó có hai hệ quả mà bức tranh che khuất. Thứ nhất, voting đòi hỏi sampling của Chương 17: ở temperature bằng không, mọi mẫu k đều là cùng một mẫu, và đa số là một câu trả lời được trả tiền k lần. Thứ hai, nó chỉ hiệu quả ở nơi đa số có ý nghĩa — với phản hồi hóa đơn ở trên thì không có gì để đếm, vì năm bản nháp là năm câu khác nhau. Voting dành cho tác vụ có câu trả lời ngắn, có thể so sánh, đúng như các benchmark của Wang và gần như không có gì mà một agent hướng khách hàng làm.

Đo ở đây trên 20 bài toán lời văn ba bước có đáp án được tính chứ không phải được phán xét, với model cục bộ của Chương 23 suy luận từng bước:

lượt gọi modelinputoutputchi phí cho 20 bàiđúngkhoảng 95 %
một chain greedy201,3302,649$0.0344489/2026–66 %
đa số của 5, temperature 0.81006,65013,245$0.1722409/2026–66 %

Gấp năm lần lượt gọi, gấp năm lần token, đúng gấp năm lần hóa đơn, và không thêm một câu trả lời đúng nào. Voting là một ván cược, không phải một cải tiến, và lượt chạy này đã thua.

Hai lưu ý, trước khi ai đó trích câu đó như một phản bác Wang. Hai mươi thử nghiệm không thể phân biệt 45 % với 60 % — khoảng này rộng bằng chính tuyên bố, tức kỷ luật của Chương 4 áp lên kết quả của chính tôi. Và các mức tăng đã công bố đến từ các model lớn hơn nhiều bậc, nơi các đường suy luận đa dạng mà voting marginalises over thật sự đa dạng. Điều chuyển giao không phải con số: đó là hệ số nhân là chính xác và biết trước, còn mức tăng thì không.

Orchestrator-workers, và summary không phải là gì

Liên kết đến mục: Orchestrator-workers, và summary không phải là gì

Trong workflow orchestrator-workers, "một LLM trung tâm phân rã tác vụ một cách động, ủy quyền cho các worker LLM, và tổng hợp kết quả của chúng", và khác biệt so với sectioning là "subtasks không được định nghĩa trước, mà do orchestrator xác định".1 Nguồn gốc ở đây hoàn toàn không đến từ language model: đây là master-worker, và phiên bản nơi các worker ghi phát hiện vào một không gian chung để controller đọc là kiến trúc blackboard, từ nghiên cứu speech understanding thập niên 1970. Điều mới vào năm 2026 là controller là một model và vì thế việc phân rã có thể được quyết định theo từng input — vừa là linh hoạt, vừa là chi phí, trong một câu.

Nó tốn 12 lượt gọi model so với 5 của single agent, và đạt cùng kết luận. Rồi nó làm một điều đáng nhìn kỹ:

TEXT
orchestrator final: VERDICT=credit_note_due amount=52.08 source=worker_unverified
                  | PO_MISMATCH=yes source=worker_unverified
single agent:       VERDICT=credit_note_due amount=52.08 reason=reverse_charge_should_have_applied
                  | PO_MISMATCH=yes invoice_says=PO-4417 order_says=PO-4471

Cả hai đều đúng. Chỉ một cái biết vì sao. Tax worker có hóa đơn, đơn hàng và bảng thuế trong cửa sổ riêng, đi đến kết luận, và cũng nhận thấy — không ai yêu cầu — rằng số purchase order trên hóa đơn không khớp với đơn hàng. Rồi nó trả về một summary. Orchestrator có thể lặp lại cả hai phát biểu và không kiểm tra được phát biểu nào, vì bằng chứng nằm lại trong một cửa sổ mà nó chưa từng thấy. Đó là câu hỏi kết thúc Chương 24, đã có câu trả lời: agent cha được nhìn vào bất cứ thứ gì agent con chọn ghi xuống.

Cách sửa là một flag, và nó có giá:

worker trả về gìorchestrator input tokenschi phíagent cha có thể làm gì
kết luận của nó3,628$0.012512lặp lại nó
kết luận và bằng chứng của nó4,065$0.013554suy ra lại, và bất đồng

Nhiều hơn mười hai phần trăm input tokens, thêm 8.3 % tiền, và cụm source=worker_unverified biến mất khỏi câu trả lời. Đó là đánh đổi trong mọi multi-agent system và gần như không bao giờ được nói rõ: cửa sổ sạch của agent con đáng có, khả năng audit của agent cha đáng trả tiền, và bạn không thể có cả hai miễn phí.

Vậy khi nào orchestrator-workers sai? Ở đây, trên tác vụ này. Nó mua một câu trả lời đúng mà một agent với cùng bốn công cụ cũng đạt được, với chi phí gấp 1.66 lần và wall clock gấp 2.3 lần, đồng thời làm câu trả lời đó khó bảo vệ hơn. Chính hướng dẫn của Anthropic cũng nói vậy trước khi các pattern bắt đầu: tìm "giải pháp đơn giản nhất có thể, và chỉ tăng độ phức tạp khi cần", vì "agentic systems thường đánh đổi latency và chi phí để có hiệu năng tác vụ tốt hơn".1 Các bảng trên là câu đó với con số bên dưới.

Evaluator-optimiser, và vị giám khảo tự viết đề thi

Liên kết đến mục: Evaluator-optimiser, và vị giám khảo tự viết đề thi

Một lượt gọi tạo ra, một lượt khác đánh giá, và vòng lặp lặp lại cho đến khi đánh giá đạt.1 Các tiền thân đã công bố là Self-Refine — cùng một model làm "generator, refiner, and feedback provider", báo cáo cải thiện tuyệt đối khoảng 20 điểm trung bình trên bảy tác vụ3 — và Reflexion, lưu critique trong một bộ đệm episodic qua các lần thử và báo cáo 91 % pass@1 trên HumanEval trong khi baseline đạt 80 %.4

Mô hình chi phí là đơn giản nhất trong năm cái: hai lượt gọi mỗi vòng, và số vòng không thuộc về bạn. Ba vòng refinement trên một tác vụ vốn tốn một lượt gọi là sáu lượt gọi, nên sàn của pattern là 6× và trần là bất kỳ cap nào bạn đặt — điều này làm lối thoát theo ngân sách của Chương 23 trở thành bắt buộc chứ không chỉ gọn gàng.

Trần thì tinh tế hơn, và đo được. Trên cùng 20 bài toán, model cục bộ trả lời đúng 9. Sau đó nó được cho xem từng câu trả lời đó và được hỏi liệu câu trả lời có đúng không — không cho biết đó là câu trả lời của chính nó, để loại bỏ nhiễu xu nịnh và chỉ còn năng lực:

câu trả lời của chính modelnó nói "có"nó nói "không"
9 câu đúng90
11 câu sai38

Đó là một giám khảo tốt hơn tiêu đề mục gợi ý, và nói vậy chính là điểm của việc đo thay vì khẳng định: nó không chặn câu đúng nào và bắt được 8 trong 11 lỗi. Như một bộ lọc, nó đáng giá các lượt gọi.

Như một quy tắc dừng, tức thứ mà vòng lặp evaluator-optimiser thật sự dùng, ba phê duyệt đó là toàn bộ câu chuyện: chúng kết thúc vòng lặp với một câu trả lời sai trong tay, và không số vòng bổ sung nào chạm được tới chúng. Một vòng refinement không thể trở nên đúng hơn giám khảo của nó. Mua thêm vòng là mua thêm các lần thử nhắm vào lỗi mà giám khảo nhìn thấy, với giá đầy đủ, và hoàn toàn không có gì trước các lỗi nó không thấy.

Vì vậy quy tắc là: một evaluator chỉ xứng đáng với lượt gọi của nó khi nó có thứ mà generator không có. Một compiler, một test suite, một schema validator, một model khác, một con người. Kết quả của chính Self-Refine được đo theo human preference và metric tác vụ, không bao giờ theo ý kiến của model về chính nó. Nếu lợi thế duy nhất của evaluator là một prompt khác, bạn đang trả gấp đôi để mua sự đồng thuận. Chương 29 xây dựng phiên bản có lợi thế thật: một golden set với đáp án được viết sẵn từ trước.

Năm cái trên là hình dạng cho code của bạn. Bên dưới chúng có một họ thứ hai thường được liệt kê cùng và không nên như vậy: ReAct, Reflexion, plan-and-execute và tree of thoughts là reasoning loops, và chi phí của chúng nằm ở request.

Chương 12 nói về reasoning bên trong model, thứ bạn trả bằng output tokens trong một lượt gọi. Đây là loại còn lại. Khác biệt quan trọng khi hóa đơn đến: một chain of thought dài hơn làm một lượt gọi đắt hơn, còn reasoning loop biến một tác vụ thành nhiều lượt gọi, mỗi lượt lại gửi lại mọi thứ trước nó — độ bậc hai mà Chương 23 đã đo trong bảng runaway.

loopsố lượt gọi, mỗi tác vụcác lượt gọi thêm mua được gì
ReActmột lượt mỗi bước, cho đến khi dừngmodel phản ứng với những gì công cụ trả về5
plan-and-executemột lượt để lập kế hoạch, rồi một lượt mỗi bướckế hoạch được cố định trước khi bước đầu chạy6
Reflexionsố lần thử × (act + reflect)critique sống sang lần thử tiếp theo4
tree of thoughtsbranching factor × depth, cộng một lượt đánh giá mỗi nodesearch, có backtracking7

Bài báo tree-of-thoughts công bố bảng chi phí của chính nó, điều hiếm hơn mức nên có. Trên Game of 24 với GPT-4: input/output prompting best-of-100 giải được 33 % với $0.13 mỗi case, chain of thought best-of-100 giải được 49 % với $0.47, và tree of thoughts giải được 74 % với $0.74, với ghi chú của tác giả rằng nó "có thể cần số generated tokens nhiều hơn CoT 5-100 lần".7

Giá gần sáu lần phương pháp rẻ cho tỷ lệ thành công hơn gấp đôi một chút. Đó có phải món hời hay không phụ thuộc vào một case thất bại khiến bạn tốn gì — câu hỏi cần đặt ra trước khi áp dụng bất kỳ cái nào trong bốn cái này.

Khóa học này không reimplement chúng. Cả bốn đều có reference implementations do chính tác giả viết, bằng Python, và giá trị của chúng là nguồn gốc chứ không phải bản dịch: ysymyth/ReAct, noahshinn/reflexion, princeton-nlp/tree-of-thought-llmAGI-Edgerunners/Plan-and-Solve-Prompting. Hãy đọc các prompts trong những repository đó; prompts chính là các bài báo.

Hai topology, và một trong số đó không quay lại

Liên kết đến mục: Hai topology, và một trong số đó không quay lại

Giờ là multi-agent đúng nghĩa, nơi phần lớn nhầm lẫn sống. Có hai cách để một agent lôi agent khác vào, chúng không phải biến thể, và khác biệt nằm ở ai còn nắm quyền sau đó.

Agent như một công cụ. Agent cha gọi nó, nhận câu trả lời, rồi tiếp tục. Đó là giao diện công cụ của Chương 18 với cả một agent phía sau, và agent cha không bao giờ mất quyền kiểm soát. Đây là điều orchestrator ở trên làm.

Handoff. Agent cha chuyển cuộc hội thoại đi và không nhận lại. Hướng dẫn của OpenAI là phát biểu công khai rõ nhất: handoffs là "một chuyển giao một chiều cho phép một agent ủy quyền cho agent khác... Nếu một agent gọi một hàm handoff, chúng tôi lập tức bắt đầu thực thi trên agent mới được handoff tới, đồng thời cũng chuyển trạng thái hội thoại mới nhất."8

Một cảnh báo về từ vựng, vì điều này liên tục làm mọi người vấp: "handoff" là từ của một SDK, không phải một chuẩn. Đó là thuật ngữ từ OpenAI Agents SDK và hướng dẫn đó, nơi cũng đặt tên hai cách sắp xếp là "manager" và "decentralized" và ghi rằng trong manager pattern "các cạnh biểu thị tool calls, còn trong decentralized pattern, các cạnh biểu thị handoffs".8 Trong không gian này một chuẩn mở — A2A, ở phiên bản 1.0.0, thuộc bản quyền của Linux Foundation, có lịch sử phát hành được version hóa và danh sách documented breaking changes, với nguyên tắc được nêu là opaque execution: agents "cộng tác dựa trên năng lực đã khai báo và thông tin trao đổi, mà không cần chia sẻ suy nghĩ nội bộ, kế hoạch hay implementation công cụ của chúng".9 Đó không phải một handoff, và phép so sánh thuộc về Chương 26. Điều quan trọng ở đây là một trong hai từ là API của một library, còn từ kia là một specification có governance.

Sự phân biệt là một cấu trúc dữ liệu, không phải sơ đồ:

graph.tsTS
export type EdgeKind = "tool" | "handoff";
export interface AgentEdge { from: string; to: string; kind: EdgeKind }
export interface AgentGraph { root: string; agents: Record<string, AgentSpec>; edges: AgentEdge[] }

/** One agent may not be both a tool of X and a handoff target of X. */
export function conflicts(g: AgentGraph): AgentEdge[] {
  const seen = new Map<string, EdgeKind>();
  const bad: AgentEdge[] = [];
  for (const e of g.edges) {
    const key = `${e.from}->${e.to}`;
    const other = seen.get(key);
    if (other && other !== e.kind) bad.push(e);                            
    else seen.set(key, e.kind);
  }
  return bad;
}

/** Every agent reachable from the root, and at what depth. */
export function reachable(g: AgentGraph): Map<string, number> {
  const depth = new Map([[g.root, 0]]);
  const queue = [g.root];
  while (queue.length) {
    const id = queue.shift()!;
    for (const e of g.edges.filter((x) => x.from === id)) {
      if (depth.has(e.to)) continue;
      depth.set(e.to, depth.get(id)! + 1);
      queue.push(e.to);
    }
  }
  return depth;
}

Hai mươi dòng, hai bug mà nếu không bạn sẽ tìm thấy trong production. reachable tìm agent mà không ai tới được — đã cấu hình, đã trả tiền, chưa bao giờ được gọi. conflicts từ chối cạnh vừa thuộc cả hai loại cùng lúc, nghe có vẻ soi mói cho đến khi bạn đọc thành tiếng: agent cha vừa giữ quyền kiểm soát vừa trao nó đi. Chạy nó trên một hệ năm agent có một orphan và một double edge:

TEXT
reachable: lead@0 billing@1 tax@1 dunning@1
orphans:   ghost
conflicts: lead->tax

Giờ là phép đo mà mục này tồn tại vì nó, và là phép đo duy nhất trong chương chạy với model thật thay vì model kịch bản.

Một khách hàng nêu một ràng buộc trong tin nhắn đầu tiên — tài khoản của chúng tôi đăng ký ở Bồ Đào Nha, không phải Tây Ban Nha; mọi thứ liên quan đến thuế phải dùng Bồ Đào Nha — trò chuyện về chuyện khác, rồi hỏi một câu mà billing phải trả lời. Case được chuyển giao. Hai mươi bốn thử nghiệm, mỗi lần một quốc gia và công ty khác nhau, bốn payload chuyển giao, và agent nhận sau đó được hỏi một câu: tài khoản của khách hàng này đăng ký ở quốc gia nào?

thứ được chuyểnpayload trung bìnhràng buộc có trong đóspecialist nhớ lại đượckhoảng 95 %
toàn bộ cuộc hội thoại173 tokens24/2420/24 — 83 %64–93 %
summary do agent gửi viết62 tokens1/240/24 — 0 %0–14 %
chỉ tin nhắn người dùng cuối cùng61 tokens0/240/24 — 0 %0–14 %
một typed record69 tokens24/2424/24 — 100 %86–100 %

Hàng thứ ba là một control và hành xử như control: dữ kiện không có ở đó, nên không thể nhớ lại. Ba hàng còn lại là phát hiện.

Transcript đầy đủ là 173 tokens và hoạt động 83 % số lần, bốn lần thất bại của nó là chủ đề của Chương 24 chứ không phải chương này. Typed record là 69 tokens — nhiều hơn summary bảy token — và lần nào cũng hoạt động, vì ràng buộc nằm trong một field có tên thay vì một câu.

Và summary là hàng cần nhìn chằm chằm. Nó thất bại 24 trên 24 lần, và lý do không phải người đọc bỏ sót. Ràng buộc chỉ xuất hiện trong 1 trong 24 summary. Agent nhận không bất cẩn; nó được đưa một văn bản không chứa câu trả lời. Summary là một phép nén mà bạn không viết, được tạo bởi một model có cửa sổ bạn không thấy, tối ưu để đọc như một summary — và "khách hàng nói hồ sơ của chúng ta đang ghi sai quốc gia" chính xác là kiểu mệnh đề mà summariser bỏ đi như nhiễu thủ tục.

Một giới hạn trung thực cho con số đó: summariser là model nửa tỷ parameter và model lớn hơn sẽ giữ lại nhiều hơn. Điều không cải thiện theo kích thước là hình dạng của rủi ro — agent gửi quyết định, theo từng handoff, theo từng cách diễn đạt, một cách không quan sát được, dữ kiện nào sống sót. Typed record hoàn toàn không phụ thuộc vào phán đoán đó, đó là lý do nó thắng theo cấu trúc chứ không phải theo trí thông minh. Bất cứ thứ gì phải sống sót qua một lần chuyển giao nên là field, không phải sentence.

Lập luận tương tự áp dụng theo chiều ngược lại, với topology agent-as-tool, và bảng trước đó đã định giá rồi: thứ trở về từ một worker cũng là một summary, và trả thêm 8.3 % để nhận bằng chứng kèm theo là cùng cách sửa nhìn từ phía agent cha.

Ba sự thật kết thúc, tất cả từ các bảng bên trên.

Một multi-agent system nhân số lượt gọi, và các lượt gọi có chi phí bậc hai theo context. Orchestrator thực hiện 12 lượt gọi model trong khi một agent thực hiện 5, và mỗi lượt mang transcript đang lớn dần của riêng nó — 3,628 input tokens so với 2,697, một khoảng cách sẽ rộng ra theo độ dài tác vụ.

Mọi ranh giới là một kênh mất mát. Hai agent nghĩa là một summary. Bốn agent trong một chain nghĩa là ba summary, chồng lên nhau, mỗi summary do một model viết và tối ưu cho thứ khác với quyết định của bạn.

Single agent tìm thấy thứ không ai yêu cầu. Lỗi không khớp purchase-order xuất hiện vì một cửa sổ cùng lúc chứa hóa đơn và đơn hàng. Chia công việc cho các specialist cũng chia luôn khả năng nhận ra hai dữ kiện mâu thuẫn.

Không điều nào trong đó phản bác các framework multi-agent đã công bố, vốn đáng đọc như nguồn gốc thay vì qua tutorial.10 Nó lập luận rằng agent thứ hai phải tự chứng minh vị trí của mình.

Vì vậy, một bài kiểm tra chứ không phải một sở thích. Thêm agent thứ hai khi ít nhất một điều sau đúng: sub-task cần một cửa sổ sạch mà agent cha không được kế thừa (Chương 24); các sub-task thật sự độc lập và wall clock quan trọng, tức mức 1.8× ở trên; sub-task cần quyền khác hoặc một model khác, điều mà Chương 30 biến thành một lập luận bảo mật; hoặc sub-task thuộc về người khác, nơi một protocol thật bắt đầu quan trọng. Nếu câu trả lời là "để mỗi agent có prompt rõ hơn", hãy cho một agent prompt rõ hơn. Nó miễn phí.

Giờ bạn có thể gọi tên năm pattern, định giá chúng với nhau trên một tác vụ, phân biệt orchestrator với sectioner và tool call với handoff, và bảo vệ single agent bằng một bảng thay vì sở thích.

Mọi cách sắp xếp ở đây cùng chia sẻ một tiện lợi sẽ không sống sót khi chạm vào bất cứ thứ gì thật: tất cả công cụ đều thuộc về chúng ta. Hóa đơn, đơn hàng, bảng thuế, các worker phía sau orchestrator — cùng repository, cùng deploy, cùng type, cùng con người.

Giờ đặt một trong số chúng ở phía bên kia ranh giới công ty. Bảng thuế thuộc về một vendor kế toán, hồ sơ đơn hàng thuộc về một hệ thống kho, và không bên nào đã đọc giao diện Tool của bạn. Bạn cần một cách để một model bạn không viết có thể discover, describe và call một capability do người khác vận hành — với authentication (là nửa của Chương 27), versioning, và bảo đảm rằng server không thể đọc phần còn lại của cuộc hội thoại của bạn. Đó là một vấn đề protocol, nó có một specification với normative schema, và gần như mọi thứ được index về nó mô tả một revision không còn tồn tại.

Chương 26 đọc specification đó thay vì tóm tắt nó, và bắt đầu bằng cách gõ JSON-RPC vào terminal bằng tay.


Mọi chi phí và số token ở trên đến từ provider được kịch bản hóa mô tả trong mục thứ hai, trên Node 22 qua loopback interface, đếm bằng encoding o200k_base và định giá theo mức Chương 16 đọc vào ngày 6 tháng 9 năm 2026 — $2.00 mỗi triệu input tokens và $12.00 mỗi triệu output. Các số wall-clock đến từ cùng lượt chạy với latency của provider đặt là 400 ms mỗi lượt gọi và công cụ là 50 ms, nên chúng đo cách sắp xếp chứ không đo provider nào. Hai phép đo với model thật — bảng handoff và bảng voting-and-judging — dùng Qwen/Qwen2.5-0.5B-Instruct ở float32 trên CPU sau một endpoint cùng hình dạng, greedy trừ nơi có nêu temperature, với các khoảng được tính bằng phương pháp Wilson từ Chương 4. Không request nào trong chương này đi tới endpoint trả phí, và không con số nào trong đó là ước tính.

  1. Anthropic, Building effective agents, 19 tháng 12 năm 2024, anthropic.com/engineering/building-effective-agents, đọc ngày 7 tháng 9 năm 2026. Nguồn của năm tên workflow dùng ở trên và của mọi cụm từ trích từ đó — prompt chaining, routing, parallelisation với các biến thể sectioning và voting, orchestrator-workers, evaluator-optimiser — cũng như khuyến nghị tìm "giải pháp đơn giản nhất có thể, và chỉ tăng độ phức tạp khi cần" và quan sát rằng "agentic systems thường đánh đổi latency và chi phí để có hiệu năng tác vụ tốt hơn". Chương 22 và 23 trích định nghĩa agent của tài liệu này. 2 3 4 5 6 7

  2. Wang, X., Wei, J., Schuurmans, D., Le, Q., Chi, E., Narang, S., Chowdhery, A. và Zhou, D. Self-Consistency Improves Chain of Thought Reasoning in Language Models. arXiv:2203.11171 (tháng 3 năm 2022). Nguồn gốc của voting pattern, được mô tả ở đó như một chiến lược decoding chứ không phải một kiến trúc: lấy mẫu các đường suy luận đa dạng, rồi "chọn câu trả lời nhất quán nhất bằng cách marginalizing out các đường suy luận đã lấy mẫu", với mức tăng được báo cáo +17.9 trên GSM8K, +11.0 trên SVAMP, +12.2 trên AQuA, +6.4 trên StrategyQA và +3.9 trên ARC-challenge.

  3. Madaan, A. và cộng sự. Self-Refine: Iterative Refinement with Self-Feedback. arXiv:2303.17651 (2023). Vòng lặp evaluator-optimiser với một model trong cả ba vai trò — "generator, refiner, and feedback provider" — cải thiện "trung bình ~20% tuyệt đối về hiệu năng tác vụ" trên bảy tác vụ, được đo bằng human preference và metric tự động thay vì bằng phán quyết của chính model.

  4. Shinn, N., Cassano, F., Berman, E., Gopinath, A., Narasimhan, K. và Yao, S. Reflexion: Language Agents with Verbal Reinforcement Learning. arXiv:2303.11366 (2023). Thêm một episodic memory của self-critiques qua các lần thử — "reinforce language agents không bằng cách cập nhật weights, mà thông qua linguistic feedback" — báo cáo 91 % pass@1 trên HumanEval so với 80 % của baseline GPT-4. Lưu ý yêu cầu mà kết quả của nó phụ thuộc vào: một tín hiệu thật từ môi trường, chẳng hạn test fail, thay vì ý kiến của model về chính nó. 2

  5. Yao, S., Zhao, J., Yu, D., Du, N., Shafran, I., Narasimhan, K. và Cao, Y. ReAct: Synergizing Reasoning and Acting in Language Models. arXiv:2210.03629 (2022). Reasoning traces và actions đan xen; Chương 23 đã xây vòng lặp này. Trích ở đây vì hình dạng chi phí chứ không phải kết quả: một lượt gọi model mỗi bước, với toàn bộ transcript được gửi lại mỗi lần.

  6. Wang, L., Xu, W., Lan, Y., Hu, Z., Lan, Y., Lee, R. K.-W. và Lim, E.-P. Plan-and-Solve Prompting: Improving Zero-Shot Chain-of-Thought Reasoning by Large Language Models. arXiv:2305.04091 (2023). "Đầu tiên, lập một kế hoạch để chia toàn bộ tác vụ thành các subtasks nhỏ hơn, rồi thực hiện các subtasks theo kế hoạch" — hình dạng plan-then-execute, và nguồn của đánh đổi mà chương này quan tâm: kế hoạch được cố định trước khi quan sát đầu tiên đến, tức prompt chaining với phân rã do một model viết thay vì do bạn viết.

  7. Yao, S., Yu, D., Zhao, J., Shafran, I., Griffiths, T. L., Cao, Y. và Narasimhan, K. Tree of Thoughts: Deliberate Problem Solving with Large Language Models. arXiv:2305.10601 (2023). Search trên các "thoughts" trung gian với self-evaluation và backtracking; 74 % trên Game of 24 so với 4 % của chain-of-thought prompting. Các số chi phí trích ở trên là của chính bài báo, từ Appendix B.3, Table 7: mỗi case, input/output prompting best-of-100 ở $0.13 cho 33 %, chain of thought best-of-100 ở $0.47 cho 49 %, và tree of thoughts ở $0.74 cho 74 %, với ghi chú của tác giả rằng ToT "có thể cần generated tokens nhiều hơn CoT 5-100 lần". 2

  8. OpenAI, A practical guide to building agents (PDF), đọc ngày 7 tháng 9 năm 2026. Phân tách manager-versus-decentralised, framing dạng graph được trích ở trên ("trong manager pattern, các cạnh biểu thị tool calls còn trong decentralized pattern, các cạnh biểu thị handoffs"), và định nghĩa handoff là "một chuyển giao một chiều... chúng tôi lập tức bắt đầu thực thi trên agent mới được handoff tới, đồng thời cũng chuyển trạng thái hội thoại mới nhất". Lưu ý điều mệnh đề cuối cùng chốt lại: trong SDK này, trạng thái hội thoại có đi theo, đó là một quyết định thiết kế của library này chứ không phải thuộc tính của handoffs nói chung. 2

  9. Agent2Agent (A2A) Protocol Specification, phiên bản phát hành mới nhất 1.0.0, a2a-protocol.org/latest/specification/, đọc ngày 7 tháng 9 năm 2026; bản quyền Linux Foundation, Apache-2.0. Trích ở trên: một "open standard được thiết kế để tạo điều kiện cho communication và interoperability giữa các AI agent systems độc lập, có thể opaque", và nguyên tắc opaque execution — agents "cộng tác dựa trên năng lực đã khai báo và thông tin trao đổi, mà không cần chia sẻ suy nghĩ nội bộ, kế hoạch hay tool implementations của chúng". Trang này có release history (0.1.0, 0.2.6, 0.3.0, 1.0.0), một appendix về breaking changes, và một appendix về quan hệ của nó với MCP. Chương 26 thực hiện phép so sánh đó.

  10. Các framework multi-agent mà chương này không dạy, dành cho độc giả muốn nguồn gốc thay vì tutorial: Wu, Q. và cộng sự, AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation, arXiv:2308.08155 (2023), nơi agents là "customizable, conversable" và chính conversation là programming model; Hong, S. và cộng sự, MetaGPT: Meta Programming for a Multi-Agent Collaborative Framework, arXiv:2308.00352 (2023), mã hóa standard operating procedures vào role prompts và nói rõ rằng "solutions to more complex tasks are complicated through logic inconsistencies due to cascading hallucinations caused by naively chaining LLMs" — chain tự tin nhưng sai được đo ở đầu chương này, được nêu tên ngay trong abstract; và Park, J. S. và cộng sự, Generative Agents: Interactive Simulacra of Human Behavior, arXiv:2304.03442 (2023), hai mươi lăm agents với memory, reflection và planning, câu trả lời đã công bố lớn nhất cho "điều gì xảy ra nếu bạn cứ thêm agents".

Sẵn sàng để LIA chọn giúp bạn chưa?

Xây dựng cùng mọi mô hình AI ở một nơi — bắt đầu miễn phí ngay hôm nay.