← 博客书房

Agent 实战:从 Dify 到 LangGraph·多 Agent 协作:宠物日记工作流

实战30 分钟

多 Agent 协作:宠物日记工作流

实战锚点 · lovelyPet:supervisor 模式实战,给萌宠日记生成做多 Agent 编排。

单 Agent 上下文不够用了怎么办?拆成多个 Agent,各自独立思考,协同完成任务。

什么时候需要多 Agent

先泼冷水:大部分任务单 Agent 就够了。不要为了「多 Agent」而多 Agent。

真正需要多 Agent 的三种信号:

什么时候需要多 Agent 📦 上下文不够 任务需要读 50 个文件 单 Agent 窗口塞不下 → 拆成子 Agent 各读一部分 ⚡ 任务可并行 同时生成文案 + 配图 + 审核 串行太慢 → 并行 Agent 各干各的 🔒 角色需要隔离 写代码的 Agent 不应该 同时做代码审查 → 分开,各自有工具权限

Supervisor 模式:最常用的多 Agent 架构

+ + Supervisor(主 Agent) 接收任务 · 分派 · 汇总结果 任务 A 任务 B 任务 C 子 Agent · 文案生成 独立上下文 · 只有 Write 工具 子 Agent · 配图搜索 独立上下文 · 只有 Read 工具 子 Agent · 内容审核 独立上下文 · 只有 Grep 工具 汇总 → 输出最终结果

碎开来说这个模式的三个核心概念:

Supervisor 不干活,只管人。 它收到「帮我写一篇宠物日记」后,不自己写,而是拆分成子任务分派给子 Agent。它的上下文里不塞具体文件内容,只塞子 Agent 的汇报结果。

子 Agent 有独立的上下文和工具池。 文案 Agent 只有 Write 工具(不能读代码),搜索 Agent 只有 Read/Grep 工具(不能写文件)。隔离意味着安全和不干扰。

汇报是摘要,不是全量。 子 Agent 完成后只返回一段摘要文字给 Supervisor,不返回它的完整消息历史。这就是上下文隔离的价值——Supervisor 的窗口不会被子 Agent 的海量工具调用撑爆。

easy-agent 的实现

easy-agent Step 19 实现了 Sub-Agent,核心就是把「启动一个子 Agent」包装成一个工具:

const agentTool = {
  name: "Agent",
  description: "把子任务委派给一个有独立上下文的子 Agent",
  inputSchema: {
    type: "object",
    properties: {
      prompt: { type: "string" },         // 给子 Agent 的任务描述
      description: { type: "string" },     // 给 Supervisor 看的摘要
      subagent_type: { type: "string" },   // 用哪个子 Agent
    },
    required: ["prompt", "description"],
  },
  async call(input, context) {
    // 1. 找到对应的 Agent 定义(system prompt + 工具池)
    const agent = findAgent(input.subagent_type);

    // 2. 用隔离的消息数组启动子 Agent 的循环
    const result = await runChildAgent({
      agentDefinition: agent,
      prompt: input.prompt,
      availableTools: filterTools(agent),  // 只给允许的工具
    });

    // 3. 返回摘要(不是完整消息历史)
    return { content: result.finalText };
  },
};

Step 21 在此基础上加了 Agent Teams:多个子 Agent 之间可以通过「邮箱文件」互相发消息,实现真正的协作而不只是汇报。

// 每个 teammate 有一个 inbox 文件
// messages 通过文件锁保证并发安全
async function writeToMailbox(recipientName, message, teamName) {
  const inboxPath = getInboxPath(recipientName, teamName);
  const release = await lockfile.lock(inboxPath);
  const messages = await readMailbox(recipientName, teamName);
  messages.push({ ...message, read: false });
  await fs.writeFile(inboxPath, JSON.stringify(messages));
  release();
}

LangGraph 的多 Agent

LangGraph 里用 Supervisor 模式只需要定义图的边:

const graph = new StateGraph(AgentState);

// Supervisor 节点
graph.addNode("supervisor", async (state) => {
  const decision = await supervisorLLM.invoke(state);
  return { next: decision.nextAgent };  // "writer" | "reviewer" | "FINISH"
});

// 子 Agent 节点
graph.addNode("writer", writerAgent);
graph.addNode("reviewer", reviewerAgent);

// 条件边:Supervisor 决定下一个执行的 Agent
graph.addConditionalEdges("supervisor", (state) => state.next, {
  writer: "writer",
  reviewer: "reviewer",
  FINISH: END,
});

// 子 Agent 完成后回到 Supervisor
graph.addEdge("writer", "supervisor");
graph.addEdge("reviewer", "supervisor");
easy-agent 的裸实现LangGraph
Agent 工具 + runChildAgentaddNode + addConditionalEdges
邮箱文件通信共享 State(消息队列)
文件锁保并发框架管理
没有可视化LangSmith 图结构追踪

实战锚点:萌宠圈日记工作流

你的 lovelyPet 项目可以设计这样的多 Agent 流水线:

用户上传宠物照片/视频
       ↓
  Supervisor(判断:需要生成日记)
       ↓
  ┌── 文案 Agent(写日记正文,有 Write 工具)
  ├── 审核 Agent(检查内容合规,只有 Read 工具)
  └── TTS Agent(文字转语音,有 Bash 工具)
       ↓
  Supervisor(汇总,返回给用户)

本章要点

  1. 多 Agent 的三种触发信号:上下文不够、任务可并行、角色需隔离
  2. Supervisor 模式:主 Agent 分派任务、子 Agent 独立执行、摘要汇报
  3. 子 Agent 有独立上下文和工具池——隔离就是安全
  4. 汇报是摘要不是全量——保护 Supervisor 的上下文窗口
  5. easy-agent 的 Agent Teams 用邮箱文件实现 Agent 间通信
  6. LangGraph 用图的节点和条件边表达同样的模式

→ 下一章:Context Engineering