Dayward AI
Week 3 · D15About 6 hours

A Tour of Multi-Agent Patterns (Router/Supervisor, Planner-Executor, Critic, Swarm, Blackboard) and When Not to Use Them; Getting Started With LangGraph

Get acquainted with the common patterns for multi-agent systems, get clear on when a single agent is enough and when you actually need multiple agents, and build your first three-node graph with LangGraph.

Today's goals 0/3

Sign in to tick these off and save your progress.

Today's Goals

  1. Describe what kind of collaboration structure each of Router/Supervisor, Planner-Executor, Critic, Swarm, and Blackboard is
  2. Judge whether a business scenario should use a single agent or multiple agents, and explain why
  3. Build a three-node graph with LangGraph.js and run it successfully once

Yesterday closed on a note: one agent's production form is complete, and support has to triage, check stock, draft a refund proposal, and have the proposal reviewed — one agent cannot do it all. Week three begins by learning every shape of that division of labor, and then learning to refuse most of them.

Plain-Language Walkthrough

A one-person workshop, and an org chart

A company at the very start is one person: pitching clients, writing proposals, delivering, invoicing. That state is extremely efficient because there is no communication cost at all — every piece of information is in one head. Only when the business outgrows one person does hiring start, and with it roles, processes, and an org chart.

But you have surely seen the other kind of company: eight roles created for work three people could finish, three sign-offs for every decision, and nobody accountable for the outcome in the end. Hiring sometimes solves a problem and sometimes only converts one person's confusion into three people's communication cost. That sentence is the ground color of everything today.

First, what "one person cannot keep up" looks like in practice. Up to W2 our e-commerce support agent looks like this: one system prompt demanding both that it "check refund rules strictly and not promise lightly" and that it "sound warm and try to retain the customer"; twelve tools attached, of which query_order and query_refund are easy to confuse from the names alone; and a user asking "can I return this order" requires the model to recognize intent, pick the right tool, obey the refund rules, and still sound human.

The result is predictable: the prompt grows longer and every rule added dilutes another's weight; the tool-misselection rate rises with tool count; and worst, you cannot localize a problem — the answer is wrong and you do not know whether intent was misread, the wrong tool was chosen, or the rules were overridden by the "retain the customer" line. The whole prompt is a black box you can only rewrite and retest wholesale.

Multi-agent, at bottom, cuts that black box into pieces so each piece has its own responsibility, its own prompt, and its own failure mode. There are five classic shapes:

  • Router / Supervisor: one node decides who should take this case and hands it to the matching subagent, one at a time. Suits tasks that need one expert at a time and whose difficulty is deciding whom to ask. This is the most used one, and tomorrow (D16) is entirely about it.
  • Planner-Executor: one node splits a large task into several mutually independent smaller ones, several executors finish them in parallel, and somebody assembles the results into one deliverable. Suits tasks that must be split into several pieces with no ordering between them.
  • Critic: the executor's output goes to a reviewer, is bounced back if it fails and released if it passes. Suits tasks where the output's correctness has a definite criterion and redoing it is cheaper than shipping it wrong. Planner-Executor and Critic usually come together, and D17 assembles them into one chain.
  • Swarm: no central node, and whoever holds the baton decides who gets it next. Suits exploratory tasks where the global order cannot be stated in advance. The cost is that you do not know in advance how many steps it will take, so neither cost nor latency has a ceiling.
  • Blackboard: participants do not know each other exists and only see one shared state: whoever spots something on the board they can handle carries on writing. Suits situations where participants come and go often and you do not want to edit orchestration logic for each one.

Memorizing those five names is pointless. What transfers is this: the difference between patterns is not the name, it is the shape of the graph. Watch four things and the five separate themselves — is there a branch (one of three at runtime), a fan-out (handed to several at once), a join (several outputs merged), and a back edge (can be bounced for a redo).

patterns.js
// Edges come in two kinds: always is unconditional (all taken), choice is conditional
// (only one taken at runtime). Counting them separately is what reveals the fundamental
// difference between "hand it to three people at once" and "pick one of three".
const critic = {
  name: 'Critic',
  edges: [
    { from: 'START', to: 'executor', kind: 'always' },
    { from: 'executor', to: 'critic', kind: 'always' },
    { from: 'critic', to: 'executor', kind: 'choice' }, // back edge: bounce for a redo
    { from: 'critic', to: 'END', kind: 'choice' },
  ],
}
 
function analyzeShape(pattern) {
  // START naturally has one outgoing edge and END naturally takes many incoming ones;
  // without excluding them all five patterns look identical
  const tally = (pick, kind, skip) => {
    const acc = new Map()
    for (const e of pattern.edges) {
      if (e.kind !== kind || pick(e) === skip) continue
      acc.set(pick(e), (acc.get(pick(e)) ?? 0) + 1)
    }
    return [...acc.values()].some((n) => n > 1)
  }
  return {
    branch: tally((e) => e.from, 'choice', 'START'),
    fanOut: tally((e) => e.from, 'always', 'START'),
    join: tally((e) => e.to, 'always', 'END'),
  }
}

Run it and you see: Router has only a branch, Planner-Executor is a fan-out plus a join, Critic is a branch plus a back edge. Interestingly Critic and Swarm produce the same four booleans — not a failure of the criteria, but their difference lying in who decides the back edge: Critic has a fixed reviewer node deciding whether to bounce, and Swarm has whoever holds the baton deciding who gets it next. Where shape cannot separate them, the criterion needs a sentence of plain language.

You can now translate any multi-agent paper's architecture diagram into those four booleans. But the genuinely hard question is unanswered: should the requirement in front of you be split at all?

Cold water first: three criteria, and split only if one hits

Put the costs on the table, because most people never price them before deciding.

Latency multiplies. A single agent answers in one or two model calls; add a Supervisor and there is one routing call; add Critic's review loop and one failure adds two more. A two-second answer becomes six, and a user's patience with a support bot is about three.

Cost grows linearly with call count. Using this course's price list (openai/gpt-4o-mini at 0.15 dollars per million input tokens and 0.60 per million output), one conversation of a thousand tokens in and a thousand out is about 0.00075 dollars. Split into routing plus execution plus review, each step re-injects the current state into its context, so token usage is roughly triple and so is cost. At a hundred thousand daily actives and ten rounds each, a day goes from 750 dollars to 2,250. That is the number to run in your head before splitting.

Debugging difficulty grows with state dimensions. When a single agent errs you read one transcript; with multiple agents you have to answer whether routing was right, whether each subagent received the right state, and whether merging overwrote anything. Which is why D21 is entirely about observability — a multi-agent system with no tracing is basically guesswork when something breaks.

So the criteria are strict. Three of them, and split if any one hits; if none hits, do not split:

  1. The single agent's system prompt contains mutually exclusive behavioural demands. For instance both "check refund rules strictly" and "warmly retain the customer." Those two are not hard to write, they are impossible to optimize simultaneously — turning one up necessarily turns the other down. Splitting here converts one unsolvable weighting problem into two individually solvable ones.
  2. The tool count exceeds what the model can reliably choose among. This course takes eight as the warning line: not the model's hard limit, but the empirical point where misselection starts rising visibly. Note that past the line the first response should be merging tools and tightening descriptions (fold query_order and query_refund into one tool with a type parameter), and splitting agents is the second.
  3. Some step needs its own failure and retry semantics. If "compose an outbound email" fails it should retry only that step rather than restarting the whole round. Independent failure semantics deserve an independent execution unit — the same reasoning as W2's one message, one run.
decide.js
const TOOL_LIMIT = 8 // not the model's hard limit, the empirical point where misselection rises
 
function shouldSplit(s) {
  const reasons = []
  if (s.conflictingRules) reasons.push('the prompt holds mutually exclusive demands one persona cannot satisfy')
  if (s.toolCount > TOOL_LIMIT) reasons.push(`${s.toolCount} tools, past the warning line, so misselection will rise`)
  if (s.needsOwnRetry) reasons.push('one step needs its own failure and retry semantics rather than restarting the round')
  if (reasons.length > 0) return { split: true, reasons }
  // The default answer is "do not split" rather than "it depends" - that is what makes
  // this an actionable criterion
  return { split: false, reasons: ['none of the three criteria hit: splitting only makes it slower, dearer, and harder to debug'] }
}

Nodes, edges, state: what you would write without a framework

Suppose a criterion hits and you decide to split. Without any framework, how would you write it? Most likely a while loop with a chain of if statements deciding which step comes next, passing one big object between them.

By the third branch you hit three things. One, how does state merge? Two steps both write into the result, so is it overwrite or append? You will hand-write merge logic in every branch, and by the fifth you will get one wrong. Two, how do you know where you are? The intermediate process lives in local variables and errors leave only print statements. Three, how do you resume from the middle? A crashed process restarts from the top and the money spent on model calls is wasted.

LangGraph reduces those three to three concepts:

  • Node: an ordinary function. It reads the full state and returns a delta object containing only what this step changed. Never mutate the state in place inside a node — that bypasses the merge rules.
  • Edge: a connection between nodes. Unconditional edges hard-wire order, and conditional edges decide the next step at runtime (tomorrow's Supervisor rests on them).
  • State: a field table where each field is an independent channel carrying a merge rule (a reducer). Accumulating fields append; overwriting fields take the last write.

The third is the most-skipped and most valuable: merge rules are declared on the field rather than written in the node. Which means adding a node requires no thought about how to merge with anybody else's writes; the field knows. D17's parallel executors writing one field rest entirely on this.

graph.js
import { Annotation, StateGraph, START, END } from '@langchain/langgraph'
 
// State: one channel per field, each carrying its merge rule. D16 to D18 copy this as-is
const AgentAnnotation = Annotation.Root({
  messages: Annotation({ reducer: (a, b) => a.concat(b), default: () => [] }),
  workspace: Annotation({ reducer: (a, b) => a.concat(b), default: () => [] }),
  degraded: Annotation({ reducer: (_old, next) => next, default: () => false }),
})
 
// Nodes: read the full state, return a delta containing only changed fields
const intake = (state) => ({ workspace: [{ id: 't-1', goal: lastText(state), status: 'pending' }] })
const handle = async (state) => {
  const task = state.workspace.at(-1)
  const reply = await callModel(task.goal)
  return { workspace: [{ ...task, result: reply, status: 'done' }] }
}
const respond = (state) => {
  const done = state.workspace.filter((t) => t.status === 'done')
  return { messages: [{ role: 'assistant', content: done.map((t) => t.result).join('\n') }] }
}
 
// Edges: today's three are a hard-wired straight line that never changes at runtime.
// Letting the model decide an edge is tomorrow's subject
export const graph = new StateGraph(AgentAnnotation)
  .addNode('intake', intake)
  .addNode('handle', handle)
  .addNode('respond', respond)
  .addEdge(START, 'intake')
  .addEdge('intake', 'handle')
  .addEdge('handle', 'respond')
  .addEdge('respond', END)
  .compile()

Graph execution: how state flows between nodes

Run that graph and what LangGraph does internally is three steps, repeated: pick the nodes due this round, hand the whole current state to one, and merge the delta it returns field by field according to each channel's rule. That is all. Every bit of complexity hides inside "which node is due" and "how to merge," and those two questions are handed to edges and channels respectively.

The key is that you must be able to see the process. invoke gives you only the final state and loses the middle; debugging a graph requires stream with the streaming mode set to updates, which emits an object of node name to that step's delta as each node finishes — and that delta is precisely what the node wrote. Today's lab prints something like:

TextText
intake   wrote [workspace] t-1:pending
handle   wrote [workspace] t-1:done
respond  wrote [messages, degraded] assistant: order SO20260901 has shipped... | degraded=false

Three lines beat a pile of breakpoints. Almost every multi-agent bug is "some field was written badly at some step by somebody," and those three lines say who. Note in passing that the route field never appears — it is tomorrow's Supervisor's territory, and on today's straight line nobody needs to decide who takes the case.

One trap deserves its own paragraph: never mutate state in place inside a node. Writing state.workspace.push(task) looks like it works and actually bypasses the channel's merge rule — you will not notice single-threaded, and by D17 with several executors writing one field in parallel, each side's pushes overwrite each other, in the "wrong one run in ten" way. The correct form is always returning a fresh delta.

What usually forces the upgrade from one agent to many

Back to the org-chart analogy. A company goes from one person to a team not because the founder read a management book but because it hit a concrete wall. Multi-agent is the same, and the real triggers are few and you meet them in order:

The first signal is prompts starting to fight each other. You add "be strict about refunds" and satisfaction drops; you revert it and refund losses rise. That is criterion one and the cleanest split point — split along mutually exclusive demands and every agent's prompt halves in length.

The second signal is a tool list so long you look things up yourself. Merge first, split second, and the order matters (criterion two).

The third signal is a step whose failure needs separate handling. Composing outbound copy, calling a write with side effects, an action needing human review — those are naturally independent execution units (criterion three).

The fourth signal is wanting to swap the model for one step. Triage, a short judgment, takes a cheap small model, while drafting a refund proposal takes a large one. A single agent cannot swap models per step and multiple agents naturally can — the only scenario where multi-agent saves money, worth remembering as an interview highlight.

The fifth signal is insufficient evaluation granularity. A single agent can only be scored as a whole: good or not. Split, and you can score triage accuracy and proposal compliance separately, and therefore know which piece to fix. D21 turns that into a golden set plus tracing.

In passing, week one's Pi SDK and this week's LangGraph are not substitutes but differently positioned — the full selection criteria close out D21 and are not expanded today.

Source Reading

Hands-On Lab

🧪 D15 lab: a three-node LangGraph

Code location: labs/agent-30days/day-15-langgraph-intro

Acceptance criteria:

  1. All four self-checks under MOCK=1 SELFTEST=1 pnpm start pass with exit code 0 (starter/ as-is fails all four, each naming its exercise).
  2. Check 1: the five patterns are classified in order as branch, fan-out plus join, branch plus back edge, branch plus back edge, and fan-out plus join plus back edge, with five ASCII structure diagrams in the terminal and conditional edges drawn dashed.
  3. Check 2: four scenarios judged correctly — the read-only order-lookup assistant judged not to split, and the other three each hitting one criterion and judged to split, printing which criterion hit.
  4. Check 3: the three-node graph runs, exactly one workspace item is done, the last message is from the assistant and carries the order number, and a shipping question and a refund question produce different replies.
  5. Check 4: it can print the three steps from intake to handle to respond with which fields each wrote, and the route field is never written.

Today has no infrastructure dependencies, so this lab has no docker-compose.yml: graph execution, state merging, and per-node tracing all happen in-process. The only network egress is the model call, and under MOCK=1 it returns an offline reply that varies with the input — shipping, refund, and invoice questions get three different answers, so even offline you can tell the state was genuinely computed rather than a fixed string printed. src/shared/state.ts is this week's foundation and D16 to D18 copy it as-is, so today only fills in the fields. If you get stuck, read the README's common-traps section first.

  1. Run MOCK=1 SELFTEST=1 pnpm start as-is first; the wording of those four failures is your to-do list.
  2. Exercise 1, the pattern diagrams: compute the branch, fan-out, and join booleans (the back edge is already written), taking check 1 from five straight lines to five distinct shapes.
  3. Exercise 2, whether to split: implement shouldSplit against the three criteria, replacing the default "just split it," taking check 2 from three correct to four.
  4. Exercise 3, add handle to the graph and connect its edges, taking check 3's workspace from nothing completed to one completed with the order number in the reply.
  5. Exercise 4, replace invoke with stream in updates mode and record each step's delta, so check 4 prints the complete three-step path.

Interview Questions

Today's four questions are in the bank below, weighted toward comparing patterns and the single-versus-multiple-agent trade-off, with the last specifically about when not to split — the question in this week most easily answered as a sermon. Expand a question and read the analysis before the key points; practicing the derivation beats memorizing the answer. Each is tagged for the China-domestic or overseas market so you can prioritize by where you are applying.

Checklist and Tomorrow

  • Describe what kind of collaboration structure each of Router/Supervisor, Planner-Executor, Critic, Swarm, and Blackboard is
  • Judge whether a business scenario should use a single agent or multiple agents, and explain why
  • Build a three-node graph with LangGraph.js and run it successfully once
  • Separate the five patterns using branch, fan-out, join, and back edge, and say which two cannot be separated and why
  • Recite the three splitting criteria, and compute roughly how much latency and cost rise after splitting
  • All 5 acceptance criteria of the lab pass (all four self-checks green)
  • Answer at least 3 of the 4 interview questions without looking at the key points

Tomorrow (D16) covers the Supervisor's dynamic routing. Why first? Because today's graph contains one obvious fiction: all three edges are hard-wired, and intake is always followed by the same handle. A real support request's first job is deciding who should take it — order lookup, refund drafting, or plain chat — and only the model can decide that edge at runtime. Tomorrow turns that decision into a structured output, and answers a more pressing question along the way: why you must not have the model emit a sentence of natural language and parse it with a regular expression.

Interview questions

  • What are the common multi-agent collaboration patterns, and what shape of task suits each?常见的多 Agent 协作模式有哪些?分别适合什么形状的任务?
    Common in ChinaCommon overseasBasic#multi-agent#orchestration#architecture

    How to reason about it · think before answering

    1. This looks like a giveaway but it separates people who memorized names from people who have split a system. Listing five names is a bare pass; the interviewer wants the axis you use to tell them apart, because an axis means you can classify an architecture you have never seen.
    2. Offer a reusable axis: the difference is not the name, it is the shape of the graph. Four questions suffice — is there a branch (pick one at runtime), a fan-out (hand it to several at once), a join (merge several outputs), a back edge (send it back for rework).
    3. Then place each one: Router/Supervisor is branch only, one specialist per turn, the hard part is deciding who; Planner-Executor is fan-out plus join, for work that splits into independent pieces; Critic is branch plus back edge, for output with a clear pass/fail test where redoing is cheaper than shipping; Swarm is also branch plus back edge, but the next hop is chosen by whoever holds the baton; Blackboard is fan-out plus join plus back edge, participants unaware of each other, reacting only to shared state.
    4. Point out yourself that Critic and Swarm score identically on all four, and that the real difference is who decides the back edge — a fixed reviewer node versus the current agent. Volunteering where your own criterion breaks down scores better than reciting one more pattern name, because it proves you have used the axis rather than invented it on the spot.
    5. Attach a cost to each: Router adds one routing call of latency; Planner-Executor's parallelism creates write conflicts so fields need merge rules; Critic loops need a hard retry cap or nothing ever ships; Swarm has no upfront bound on steps so cost and latency are hard to cap; Blackboard has the hardest termination condition and tends to either stall or re-trigger.
    6. Expect: which do you use most in production? Say Router/Supervisor, because its failure mode is the easiest to read — check the recorded routing reason — and because it is the one pattern that can save money, by routing simple intents to a cheaper model.

    分析过程 · 先想清楚再作答

    1. 这题看似送分,其实在筛「背过名词」和「拆过系统」。只报五个名字最多拿及格分,面试官真正想听的是你用什么维度把它们区分开——有维度说明你能给没见过的架构归类,没维度说明你只是读过一篇综述。
    2. 给一个可复用的维度:模式的差别不在名字,在图的形状。盯四件事就够——有没有分叉(运行时三选一)、有没有扇出(同时交给多个人)、有没有汇合(多份产出合到一起)、有没有回边(可以打回重做)。
    3. 然后逐个落位:Router/Supervisor 只有分叉,一次只找一个专家,难点在判断该找谁;Planner-Executor 是扇出加汇合,适合一件事拆成几件、几件之间没有先后;Critic 是分叉加回边,适合对错有明确判据、且重做比发出去便宜的产出;Swarm 也是分叉加回边,但下一棒交给谁由当前这位自己决定;Blackboard 是扇出加汇合加回边,参与者互相不知道对方存在,只认公共状态。
    4. 主动指出 Critic 和 Swarm 的四个特征一模一样,区别落在「回边由谁决定」——Critic 是固定的评审节点在判,Swarm 是当前这位自己判。**主动承认自己的判据在哪里失效,比多背一个模式名更能加分**,因为它证明你真的用过这套维度而不是刚编出来。
    5. 每种模式还要配一句代价,这是区分度所在:Router 多一次路由调用的延迟;Planner-Executor 的并行会带来状态写冲突,字段必须配合并规则;Critic 的回路必须有次数上限,否则永远出不了稿;Swarm 事先不知道会走多少步,成本和延迟都难封顶;Blackboard 的终止条件最难写,容易谁都不接活或者反复触发。
    6. 可以预期的追问:生产上你最常用哪个?答 Router/Supervisor,理由是它的失败模式最好理解——路由判错了看一眼路由理由就知道,而且它是唯一一个能顺便省钱的模式,简单意图可以路由到便宜的小模型。

    Key points

    • Give the axis before the names: branch, fan-out, join and back edge separate all five patterns
    • Router/Supervisor is branch only — one specialist per turn, the hard part is choosing who
    • Planner-Executor is fan-out plus join — split into independent subtasks, then merge into one deliverable
    • Critic is branch plus back edge — for output with a clear pass/fail test, and it needs a hard retry cap
    • Swarm scores the same as Critic; the difference is who decides the back edge. Blackboard decouples via shared state and has the hardest termination condition
    • Pair each with a cost: extra call latency, parallel write conflicts, infinite review loops, unbounded step count, fuzzy termination

    答题要点

    • 先给维度再给名字:分叉、扇出、汇合、回边四个特征就能把五种模式分开
    • Router/Supervisor 只有分叉,一次只找一个专家,难点是判断该找谁
    • Planner-Executor 是扇出加汇合,适合拆成几件互不依赖的小任务再合成一份交付
    • Critic 是分叉加回边,适合对错有明确判据、重做比发出去便宜的产出,必须配打回次数上限
    • Swarm 与 Critic 的四个特征相同,区别在回边由谁决定;Blackboard 靠公共状态解耦,终止条件最难写
    • 每种模式配一句代价:多一次调用的延迟、并行的写冲突、回路的死循环、步数不封顶、终止条件难定
  • In LangGraph, what roles do nodes, edges and state play? If you had no framework, how would you implement it yourself?LangGraph 里节点、边、状态分别扮演什么角色?如果不用框架,你自己会怎么实现?
    Common in ChinaCommon overseasIntermediate#langgraph#orchestration#state-management

    How to reason about it · think before answering

    1. The hinge is the second half. Defining the three concepts only proves you read the docs; explaining what hurts without a framework proves you know what it buys you. The general move for this family of questions is: describe your hand-rolled version first, then name what the framework collapsed.
    2. Hand-rolled version: a loop, a chain of conditionals picking the next step, and one big object carrying data between steps. By the third branch you hit three walls — when two steps write the same field, is it overwrite or append, and you hand-write that merge in every branch; intermediate state lives in local variables so debugging means print statements; a crash restarts from zero and the model calls you already paid for are wasted.
    3. Then map them: a node is an ordinary function that reads the whole state and returns a delta containing only what it changed; edges connect nodes, unconditional ones fix the order and conditional ones decide at runtime; state is a table of fields where each field is its own channel carrying a merge rule.
    4. Dwell on the third, which is the most skipped and most valuable point: the merge rule is declared on the field, not written inside the node. Adding a node therefore requires no thought about how to combine with other writers, and parallel writes to one field behave deterministically instead of depending on who returns first.
    5. Add two concrete traps to show you have actually run this: mutating state in place inside a node bypasses the merge rule — invisible single-threaded, an intermittent overwrite once things run in parallel; and adding a node without wiring an edge raises no error at all, it simply never executes, which only per-node tracing reveals.
    6. Expect: so why not just write it yourself? Because the three primitives are genuinely light — a few dozen lines. What the framework actually sells is checkpointing and recovery, parallel execution, and per-step observability, all of which cost far more to build than the primitives. Mention too that there is no official LangGraph for Java or Swift, so in those languages you do hand-roll exactly these three.

    分析过程 · 先想清楚再作答

    1. 题眼在后半句。只答三个概念的定义,面试官会认为你读过文档;能说出「不用框架会难受在哪」,才证明你知道框架替你解决了什么。这类题的通用解法是:先讲自己手写的版本,再讲框架把哪几处收敛了。
    2. 先给手写版:一个循环,里面一串条件判断决定下一步走哪,中间用一个大对象在各步之间传数据。写到第三个分支就会撞上三件事——两步都往同一个字段写,是覆盖还是追加,你要在每个分支里手写一遍合并逻辑;中间过程全在局部变量里,出错只能靠打印;进程一挂就从头重来,已经花掉的模型调用钱白付。
    3. 然后一一对上:节点是一个普通函数,读全量状态、返回只含改动字段的增量;边是节点之间的连接,无条件边写死顺序,条件边在运行时决定去哪;状态是一张字段表,每个字段是一条独立通道,通道上挂着合并规则。
    4. 重点讲第三条,因为它是最容易被略过、也最值钱的一条:**合并规则是声明在字段上的,不是写在节点里的**。这意味着新增节点时不需要考虑「我该怎么和别人的写入合并」,字段自己知道;也意味着并行写同一个字段时行为是确定的,而不是取决于谁先返回。
    5. 配两个具体的坑,证明你真跑过:一是在节点里原地修改状态(比如直接往数组里 push)会绕过合并规则,单线程时察觉不到,并行时变成偶发覆盖;二是加了节点没连边不会报错,表现只是那个节点永远不执行,只能靠逐节点追踪发现。
    6. 可以预期的追问:那你为什么不直接自己写?答:三要素本身很轻,核心逻辑几十行就能手写出来——框架真正值钱的是检查点与恢复、并行执行、以及每一步的可观测,这三样自己写的成本远高于三要素本身。顺带说明 Java 和 Swift 没有官方 LangGraph,真要在这两门语言里做,就是把这三要素手写一遍。

    Key points

    • A node is a plain function: read the full state, return a delta of changed fields only, never mutate in place
    • Edges set execution order: unconditional edges are fixed, conditional edges decide the next hop at runtime — that is what a supervisor uses
    • State is a table of fields, each field a channel carrying a merge rule declared on the field rather than inside nodes
    • Without a framework you hit three walls: hand-written merges in every branch, no visibility into intermediate steps, and full restart after a crash
    • Two real traps: in-place mutation bypasses the merge rule and causes intermittent overwrites under parallelism; an unwired node raises no error, it just never runs
    • What the framework really sells is checkpoint recovery, parallel execution and per-step observability — not the three primitives themselves

    答题要点

    • 节点是普通函数:读全量状态,返回只含改动字段的增量,不在节点里原地改状态
    • 边决定执行顺序:无条件边写死,条件边在运行时决定下一步去哪(Supervisor 就靠它)
    • 状态是一张字段表,每个字段一条通道,通道上挂合并规则——规则声明在字段上而不是写在节点里
    • 不用框架会撞三堵墙:合并逻辑在每个分支手写一遍、中间过程只能靠打印、进程挂了从头重来
    • 两个真实的坑:原地改状态绕过合并规则(并行时偶发覆盖)、加了节点没连边不报错只是永不执行
    • 框架真正值钱的不是这三要素,而是检查点恢复、并行执行和逐步可观测
  • What signals typically trigger the move from a single agent to a multi-agent system, and what does the upgrade cost you?从单 Agent 升级到多 Agent,通常是被什么信号触发的?升级之后系统会多付出什么?
    Common in ChinaCommon overseasIntermediate#multi-agent#cost#architecture

    How to reason about it · think before answering

    1. This question tests whether business pain forced the split or a blog post did. Answering the business got complex is a non-answer; the interviewer wants observable signals — what symptom made you act.
    2. Give five, in the order they usually appear: prompts start fighting each other (add one rule, another metric drops); the tool list grows until you need the docs yourself; one step's failure needs isolated handling instead of redoing the whole turn; you want a different model for one specific step; and evaluation granularity is too coarse to say more than good or bad.
    3. Expand on the fourth, the counter-intuitive one: multi-agent is usually more expensive, but per-step model selection is the one case where it saves money — a short triage decision on a cheap small model, a drafting step on a larger one. A single agent cannot swap models per step. This lands well in interviews.
    4. Then volunteer the costs, or the answer reads as evangelism: latency multiplies by step count (two seconds becomes six, while user patience is about three); cost grows linearly with calls because every step re-sends the current state as context, typically three times; and debugging cost grows with state dimensions, since a failure now requires checking routing, each sub-agent's input state, and whether merges overwrote each other.
    5. Add the reverse check to show you are not splitting reflexively: too many tools should first prompt consolidation and tighter descriptions, with splitting as the second response; poor quality should first prompt tuning the single-agent version to its best, which then becomes the baseline the multi-agent version is measured against.
    6. Expect: how do you prove the split helped? Keep the single-agent version as a baseline and A/B both against the same golden set, comparing accuracy alongside per-conversation cost and latency. People who cannot name a baseline usually cannot explain why they split either.

    分析过程 · 先想清楚再作答

    1. 这题考的是「你是被业务逼着拆的,还是照着博客拆的」。答「业务变复杂了」等于没答,面试官要的是**可观测的信号**:什么现象出现时你才动手。
    2. 给五个按出现顺序排的信号:一是提示词开始互相打架(加一条规则,另一个指标就掉);二是工具列表长到自己都要查文档;三是某一步的失败需要单独处理,不该整轮重来;四是想给某一步单独换模型;五是评估颗粒度不够,只能整体打分好或不好。
    3. 第四个信号要展开讲,它是唯一一个反常识的:多 Agent 通常更贵,但按步换模型是它唯一能省钱的场景——分诊这种短判断走便宜的小模型,拟方案走大模型。单 Agent 做不到按步换模型。这一条在面试里是明显的亮点。
    4. 然后主动给代价,不给代价的回答会被当成布道:延迟按步数乘倍数(原来两秒变六秒,而用户耐心大约三秒);成本按调用次数线性涨,因为每一步都要把当前状态重新塞进上下文,典型是三倍;调试难度按状态维度涨,出错要同时回答路由对不对、每个子 Agent 拿到的状态对不对、合并有没有互相覆盖。
    5. 再补一句反向判断,证明你不是无脑拆:工具太多的第一反应应该是合并工具、收敛描述,拆 Agent 是第二反应;质量差的第一反应应该是把单 Agent 版本调到最好,那个版本还会成为多 Agent 的对照基线。
    6. 可以预期的追问:拆完怎么证明比原来好?答:留住单 Agent 版本当基线,用同一批标准样本集跑 A/B,比准确率也比每次对话的成本与延迟。说不出对照基线的人,通常也说不清自己为什么拆。

    Key points

    • Five observable signals: prompts fighting each other, a tool list you must look up, one step needing isolated retries, wanting a different model per step, and evaluation too coarse to act on
    • Per-step model selection is the only case where multi-agent saves money: small model for triage, larger model for drafting — impossible in a single agent
    • Cost one: latency multiplies with step count, two seconds becomes six, while patience for a support bot is about three
    • Cost two: spend grows linearly with calls since every step re-sends state as context, typically three times the original
    • Cost three: debugging cost grows with state dimensions, so multi-agent and tracing have to ship together
    • Reverse check: consolidate tools before splitting, and tune the single agent to its best first — that version becomes your baseline

    答题要点

    • 五个可观测信号:提示词互相打架、工具多到要查文档、某一步需要独立重试、想按步换模型、评估颗粒度不够
    • 按步换模型是多 Agent 唯一能省钱的场景:短判断走小模型、拟方案走大模型,单 Agent 做不到
    • 代价一:延迟按步数乘倍数,两秒变六秒,而用户对客服机器人的耐心大约三秒
    • 代价二:成本线性涨,每一步都要把状态重新塞进上下文,典型是原来的三倍
    • 代价三:调试难度按状态维度涨,所以多 Agent 和链路追踪必须一起上
    • 反向判断:工具多先合并再拆分,质量差先把单 Agent 调到最好——那个版本还是多 Agent 的对照基线
  • When should you not introduce a multi-agent system? Give operational criteria, not it depends.什么情况下不应该引入多 Agent 系统?请给出可操作的判据,而不是「视情况而定」。
    Common in ChinaCommon overseasDeep dive#multi-agent#architecture#trade-offs

    How to reason about it · think before answering

    1. This is the highest-signal question in the set because it is asked in reverse. Most candidates keep selling how powerful multi-agent is, while the interviewer is looking for someone who will say no — on a real team, blocking one unnecessary architecture upgrade is worth more than implementing three patterns.
    2. Lead with the default: do not split. Then give three criteria, any one of which justifies splitting — the system prompt contains mutually exclusive behavioural requirements (strictly enforce refund rules while also warmly retaining the customer; these are not hard to write, they are impossible to optimize together); the tool count exceeds what the model picks reliably (roughly eight as a rule of thumb, and the first response to crossing it is consolidating tools, not splitting agents); or one step needs its own failure and retry semantics. None of the three, and a single agent with a few tools is enough.
    3. Then name the most common bad split: treating a prompt problem as an architecture problem. Quality is poor, so we split into three agents — but nine times out of ten poor quality comes from vague prompts, tool descriptions that interfere with each other, or irrelevant history in the context. All three survive the split and are now harder to find. Splitting fixes conflicting responsibilities, not weak capability.
    4. Add two scenarios that clearly should not split: latency-sensitive interactions, where each extra hop is another model round trip and voice or realtime completion becomes unusable; and read-only lookup flows, where a support assistant with three or four tools gains no accuracy from splitting and simply triples the bill.
    5. Then offer an executable verification path, which earns points: keep the single-agent version as a baseline for any split and A/B both against the same golden set, comparing accuracy, per-conversation cost and latency together. An architecture upgrade with no baseline is a refactor with no evidence.
    6. Expect: what if your manager insists on multi-agent? Frame it as a reversible experiment — make the one cut you are most confident in (usually the conflicting-rules criterion), keep the baseline, and bring data in two weeks. That answer shows technical judgment and a way to disagree without stonewalling.

    分析过程 · 先想清楚再作答

    1. 这是本组最有区分度的题,因为它反着问。绝大多数候选人会顺着「多 Agent 很强大」讲下去,而面试官问这题正是想找那个会说不的人——**在真实团队里,拦住一次不必要的架构升级,价值高于实现三个模式**。
    2. 先给结论式的默认值:默认答案是不拆。然后给三条判据,命中任意一条才拆——一是单个 Agent 的系统提示词里出现了互斥的行为要求(既要严格核对退款规则又要热情挽留,这两条不是难写,是不可能同时最优);二是工具数量超过模型能稳定选对的规模(经验线大约八个,超线的第一反应是合并工具而不是拆 Agent);三是某一步需要独立的失败与重试语义。三条都不命中,单 Agent 加几个工具就够。
    3. 接着点名最常见的错拆:把提示词问题当成架构问题。「回答质量不好,所以拆成三个 Agent」——质量差有九成来自提示词含糊、工具描述互相干扰、上下文塞了无关历史,这三样拆完一样存在,只是分散到三个地方更难查。**拆 Agent 解决的是职责冲突,不是能力不足。**
    4. 再补两类明确不该拆的场景:一是低延迟要求的场景,多一跳就多一次模型往返,对语音或实时补全这类交互直接不可用;二是只读的简单查询链路,三五个工具的客服助手拆了只是把一次调用变成三次,准确率不会涨、账单会涨。
    5. 然后给一条可执行的验证路径,这是加分项:任何拆分都先留住单 Agent 版本当对照基线,用同一批标准样本集跑 A/B,同时比准确率、每次对话成本和延迟。**拿不出对照基线的架构升级,等于没有证据的重构。**
    6. 可以预期的追问:那如果老板就是要求上多 Agent 呢?答:那就把它当成一个可回退的实验来做——先按判据拆最有把握的那一刀(通常是互斥规则那一条),保留基线,两周后拿数据说话。这个回答同时展示了技术判断和沟通方式,比硬顶或硬上都好。

    Key points

    • Default to not splitting; split only if one of three criteria holds: mutually exclusive prompt requirements, tool count past the roughly-eight warning line, or a step needing its own failure and retry semantics
    • Too many tools should first trigger tool consolidation and tighter descriptions; splitting agents is the second response
    • The most common bad split is treating a prompt problem as an architecture problem — vague prompts, interfering tool descriptions and irrelevant history all survive the split
    • Clear do-not-split cases: latency-sensitive interactions where every hop adds a model round trip, and read-only lookup flows where accuracy does not move but the bill does
    • Always keep the single-agent version as a baseline and compare accuracy, cost and latency on the same golden set
    • Say the costs out loud: latency multiplies with steps, spend roughly triples, and debugging now spans routing plus state merging

    答题要点

    • 默认答案是不拆;三条判据命中任意一条才拆:提示词有互斥要求、工具超过约八个的告警线、某一步需要独立的失败与重试语义
    • 工具太多的第一反应是合并工具与收敛描述,拆 Agent 是第二反应
    • 最常见的错拆是把提示词问题当架构问题——质量差多半来自提示词含糊、工具描述干扰、上下文塞了无关历史,拆完这三样照旧存在
    • 明确不该拆:低延迟交互(每多一跳就多一次模型往返)、只读的简单查询链路(准确率不涨、账单涨)
    • 任何拆分都要留单 Agent 版本当对照基线,用同一批标准样本集比准确率、成本和延迟
    • 代价要说出口:延迟按步数乘倍数、成本约三倍、调试要同时排查路由与状态合并

Comments