DeepAgent 实战:从零搭建一个会自己分工的深度调研助手

你以为写 Agent 最难的是 Prompt?其实最难的是怎么让一堆 Agent 不打架、不跑偏、不循环。

一、开场:为什么你需要 DeepAgent

学会 LangChain 和 LangGraph 之后,很多人会经历一个"能力过剩但效率不足"的阶段:

  • 单个 Agent 写起来很快,但一旦业务复杂起来(调研 → 分析 → 起草 → 审阅 → 定稿),一个 Prompt 根本装不下;
  • 多 Agent 协作听起来很美,但状态怎么传?子 Agent 怎么调度?上下文爆炸怎么办?
  • 你开始手动写一堆 Node 拼接,结果发现 80% 的时间都花在"造轮子"上,而不是业务逻辑。

DeepAgent 就是来解决这个问题的。

它是 LangGraph 生态里面向生产落地的高阶封装方案,把复杂 Agent 需要的核心能力------任务规划、长期记忆、子 Agent 调度、上下文压缩------全部打包好了。你可以把它理解为:

  • LangChain:给你一堆 AI 开发积木
  • LangGraph:搭建复杂工作流的底层蓝图
  • DeepAgent:直接给你一栋能住人的房子

跳过重复的底层基建,直接聚焦 Agent 的业务逻辑与能力迭代。

今天我们用一个真实案例------「深度调研助手」------把 DeepAgent 的核心用法讲透。这个助手只需要你给一个主题,它就能自己规划、派调研员、算数据、写报告、找编辑审稿,最后一篇中文调研简报就出来了。


二、先认识一下 DeepAgent 的三大核心能力

在进入代码之前,先搞清楚 DeepAgent 帮你兜住了哪些底。

1. 状态管理(State)

多 Agent 协作最大的坑是什么?状态不一致。

主 Agent 说"我已经调研完了",调研员子 Agent 其实还在写文件;分析师读到的是旧数据;编辑器拿到的是半成品草稿。DeepAgent 通过内建的状态管理把这层脏活接了过去,你只需要关心"每一步产出了什么文件"。

2. 循环路由与持久化执行

复杂 Agent 不是一条直线跑到底,而是"规划 → 执行 → 检查 → 修正"的循环。DeepAgent 帮你处理了循环的边界条件------什么时候该停、什么时候该重试、什么时候该回退。

3. 上下文压缩

子 Agent 之间传信息最怕什么?上下文爆炸 。三个调研员每个返回 5000 token,主 Agent 还没开始写就被淹死了。DeepAgent 的解法很聪明:Agent 之间通过文件传递信息,不依赖对话历史。

这一条看起来简单,但你会在后面代码里反复看到它的威力。


三、架构拆解:一个主 Agent + 三个子 Agent

我们的「深度调研助手」要处理这样一个任务:

调研国家统计局公开的 2023 年省级地区生产总值(GDP)数据:提取 GDP 总量前 6 名省份的具体数值及同比增速,计算六省 GDP 总和、各省占全国 GDP 的比重,并按增速从高到低排名。

这个任务天然适合分工:

角色 职责 关键工具
主 Agent(编排) 规划流程、协调子 Agent、亲自起草报告 write_todos、task、write_file
调研员(researcher) 联网搜集资料,写入 findings 文件 web_search
分析师(analyst) 数值计算、排名、同比对比 eval REPL(沙箱)
编辑(editor) 审阅草稿,返回修改建议 无(纯审阅)

主 Agent 遵循的标准流程是:

复制代码
规划 → 调研 → 分析 → 起草 → 审阅 → 定稿

关键设计原则有三条,值得你抄下来:

  1. 专业的事交给专业的 Agent:主 Agent 不亲自做联网搜索,调研员只负责一个子主题。
  2. 审阅与修订分离:编辑器只给意见,不直接改稿。这样主 Agent 能保持整体思路做针对性修改。
  3. 文件是唯一的共享状态 :所有 Agent 通过 /workspace/sources/ 和 /workspace/reports/ 交换信息。

金句:多 Agent 协作的本质不是"让 AI 聊天",而是"让 AI 通过文件交接工作"。


四、核心代码走读

4.1 主 Agent 的创建:createDeepAgent

先看骨架代码 agent.mjs:

php 复制代码
import { createDeepAgent, FilesystemBackend } from "deepagents"
import { ChatOpenAI } from "@langchain/openai"

const model = new ChatOpenAI({
    model: process.env.MODEL_NAME,
    apiKey: process.env.OPENAI_API_KEY,
    configuration: { baseURL: process.env.OPENAI_BASE_URL },
    temperature: 0,
})

export function createIntelligenceDeskAgent() {
    const backend = new FilesystemBackend({
        rootDir: projectDir,
        virtualMode: true, // 虚拟文件系统,Agent 只能看到 /workspace
    })

    return createDeepAgent({
        model,
        systemPrompt: orchestratorPrompt,
        subagents: [researchSubAgent, analystSubAgent, editorSubAgent],
        memory: [path.join(projectDir, "AGENTS.md")], // 所有子 Agent 可读
        backend,
        skills: ["/skills/"] // 挂载技能目录
    })
}

几个关键参数拆开讲:

  • backend :DeepAgent 的文件读写后端。virtualMode: true 意味着 Agent 感知的是一个虚拟路径 /workspace,实际映射到项目目录。这一层抽象非常重要------Agent 之间的所有协作都建立在文件之上。
  • subagents :注册子 Agent。主 Agent 通过 task 工具按名字调用它们。
  • memory:共享的长期记忆文件,所有子 Agent 都能读到,适合放全局规则。
  • skills:技能目录,本质是给主 Agent 看的"写作指南"(后文细说)。

4.2 调研员子 Agent:约束比能力更重要

调研员是最容易失控的角色------LLM 天生的"探索欲"会让它不停搜索、反复写文件。看看这段 systemPrompt 是怎么给它套上缰绳的:

ini 复制代码
const researchSubAgent = {
    name: "research_sub_agent",
    description: "通过联网搜索调研单一子主题。每次只分配一个子主题; 多个独立子主题可并行启动多个调研员。",
    systemPrompt: dedent`
     你是一名专业调研员,负责调研**一个**分配给你的子主题,并写入**一份**调研结果文件。

     ## 工作流程(严格遵守,禁止空转循环)
     1. **可选**: 用 write_todos 列出最多3条中文执行步骤
     2. 最多调用3次 web_search (硬性上限,绝不超过)
     3. 将搜索结果整体为结构化摘要, 包含关键事实与来源URL。
     4. 调用 write_file **一次**, 保存到任务指定的路径
     5. 用一句话确认已完成,然后**立即停止**

     ## write_todos 使用规则 (若使用)
     - 最多3条,每条 content 必须使用中文
     - 最后一条 todo 必须是[写入 findings 文件]
     ...
    `,
    tools: [webSearch],
}

这套 Prompt 的写法值得你逐句品:

  • "硬性上限,绝不超过" ------ 把数字限制写死,不要给 LLM 留模糊空间。
  • "调用 write_file 一次" ------ 显式约束写文件次数,防止反复覆盖。
  • "用一句话确认已完成,然后立即停止" ------ 给 Agent 一个明确的终止信号。
  • "禁止空转循环" ------ 直接点出最常见的失败模式。

你会发现,约束一个好的子 Agent,比给它更多工具更重要。

4.3 分析师子 Agent:让 LLM 写代码,别让它算数

LLM 不擅长计算,这是常识。但很多团队还是会踩这个坑------让模型"心算"一堆 GDP 加总,结果错得离谱还自信满满。

正确的姿势是:LLM 擅长写代码,让代码去计算。

javascript 复制代码
import { createCodeInterpreterMiddleware } from "@langchain/quickjs"

const analystSubAgent = {
    name: "analyst",
    description: "使用 eval REPL 进行数值计算与结构化数据分析。",
    systemPrompt: dedent`
        你是一名数据分析师,所有计算必须通过 eval REPL 完成 **禁止** 猜测数字。
        1. 从 /workspace/sources/ 读取数据文件
        2. 在 REPL 中编写并运行 JavaScript, 计算综合、均值、排名、增长率等
        3. 将分析结果保存到 /workspace/sources/analysis_*.md
        必须展示计算过程,结论可以从 REPL 输出复现。
    `,
    middleware: [createCodeInterpreterMiddleware()]
}

@langchain/quickjs 提供一个沙箱环境,Agent 在里面写 JS 并执行,不会影响主进程。这个设计非常关键:

  • 安全性:即使 LLM 写出危险的代码,也跑不出沙箱。
  • 可复现性:结论能从 REPL 输出推导出来,而不是模型"感觉"出来的。
  • 零幻觉:数字是算出来的,不是编出来的。

4.4 编辑子 Agent:审阅与修订分离

编辑器最容易犯的错误是"顺手改稿"。看看这个 Prompt 是怎么堵死的:

csharp 复制代码
const editorSubAgent = {
    name: "editor",
    description: "审阅报告草稿的准确性、结构与完整性。",
    systemPrompt: dedent`
      你是一名资深情报编辑,负责**审阅**报告草稿 **不要**亲自改写报告。

      ## 审阅要点
      - 报告是否直接回答了原始问题?
      - 章节结构是否清晰、段落是否充实(而非只有bullet 列表)
      - 是否引用了来源,并在 【参考资料】 章节列出?
      - 是否有遗漏、无依据的断言或缺失的视角?

      ## 输出
      返回简洁的审阅意见和具体、可操作的修改建议。
      **不要**写入报告文件,只提供反馈。
    `
}

为什么要这么设计?

  • 单一职责:编辑专注"挑刺",主 Agent 专注"改稿"。
  • 保持整体思路:如果编辑器直接改稿,可能会打乱主 Agent 的叙事逻辑。
  • 可追溯:修改建议是显式的,主 Agent 可以选择采纳或不采纳。

五、编排的核心:主 Agent 的 System Prompt

主 Agent 是整个系统的大脑,它的 systemPrompt 定义了流程规则、委派规则、文件约定三件事。原文很长,我提炼几个关键片段:

5.1 强制中文输出

markdown 复制代码
## 语言要求
- **所有输出必须使用中文**:对话回复、write_todos 任务列表、文件内容、搜索关键词
- 搜索时优先使用中文关键词;英文专有名词(如 LangGraph、AutoGen)可保留

中文任务用中文搜索,命中率会高很多。这条规则看着小,实际影响很大。

5.2 明确区分"技能"和"子 Agent"

markdown 复制代码
## task 工具(子 Agent 委派)
**仅**以下 subagent_type 合法:researcher、analyst、editor、general-purpose。
- web-research、report-writer 是**技能**(写作指南),**不是**子 Agent,禁止作为 subagent_type 调用
- 报告起草、修订、定稿由**主 Agent 自己**用 write_file / edit_file 完成,不要委派 task

这是踩坑之后的血泪教训------LLM 看到"web-research"这种名字,很容易把它当成子 Agent 去 task 调用。必须在 Prompt 里显式禁止。

5.3 委派的硬性上限

markdown 复制代码
## 委派规则
- 每个调研员只负责一个聚焦的子主题
- **每份报告最多 3 个调研员**------只选最相关的子主题
- 最多并行启动 3 个调研员,已有 3 份 findings 文件后不再新增调研员
- 每份报告只调用编辑一次(草稿完成后)

为什么是 3?这是一个经验值:

  • 太少覆盖不全,太多协调成本爆炸;
  • 并行超过 3 个,主 Agent 的上下文会被 findings 文件淹没;
  • 编辑只调一次,防止"改来改去没完没了"。

六、Skills:给主 Agent 的写作指南

DeepAgent 的 skills 目录挺有意思,它不是可执行代码,而是给主 Agent 看的写作手册 。比如 report-writer/SKILL.MD:

yaml 复制代码
---
name: report-writer
description: 将调研结果整理为结构清晰、专业的中文情报报告
---

# 报告撰写技能

> **注意**: 本技能是主Agent的写作指南,不是子Agent。请主 Agent 亲自用`write_file`
撰写报告,**不要**通过 `task` 工具委派`report-writer`。

## 报告结构
1. **标题** - `# [主题]: 情报简报`
2. **执行摘要** - 3-5 条核心要点
3. **背景** - 主题背景与当前重要性
4. **核心发现** - 按主题组织,而非按来源堆砌
5. **结论** - 直接回答原始问题
6. **参考资料** - 编号列表

这种设计把"写作规范"从 systemPrompt 里剥离出来,单独放文件,好处是:

  • 主 Prompt 更清爽:只放流程,不放细节。
  • 可替换 :换一个 report-writer 就是另一种报告风格。
  • 可组合 :web-research + report-writer 就是一套"调研 + 写作"流程。

金句:Prompt 是瞬时的,Skill 是资产化的。把可复用的写作规范沉淀成文件,才是生产级 Agent 的做法。


七、流式输出与工具追踪(cli.mjs 片段)

cli.mjs 负责把 Agent 的执行过程"可视化"给开发者,核心是这段:

csharp 复制代码
for await (const [namespace, chunk] of await agent.stream(
    { messages: [new HumanMessage(query)] },
    { streamMode: "updates", subgraphs: true, recursionLimit }
)) {
    // ...
}

三个参数值得注意:

  • streamMode: "updates" :每完成一步就推送一次更新,而不是等全部跑完。
  • subgraphs: true:把子 Agent 的执行过程也暴露出来------你能看到"调研员 1 搜索了关键词 A"。
  • recursionLimit: 300:防止 Agent 陷入无限循环,超限直接中止。

配合 FILE_TOOLS 和 EVAL_TOOL 集合,CLI 可以针对不同类型的工具调用给出不同的展示格式:

ini 复制代码
const FILE_TOOLS = new Set([
    "write_file", "edit_file", "read_file",
    "ls", "glob", "grep"
])
const EVAL_TOOL = "eval"

这个模式特别适合调试------当你看到 Agent 反复调用同一个工具时,就知道它的 Prompt 需要加强了。


八、三个关键踩坑点

坑 1:子 Agent 无限循环

症状:调研员不停搜索,同一个关键词搜三遍。

解法:在 systemPrompt 里写死上限,并给一个"停止信号":

markdown 复制代码
2. 最多调用3次 web_search (硬性上限,绝不超过)
5. 用一句话确认已完成,然后**立即停止**,不要再搜索、写文件或更新 todo

坑 2:技能被当成子 Agent

症状 :主 Agent 尝试 task(subagent_type="web-research"),报错找不到。

解法:在 systemPrompt 里显式禁止,同时给"技能"和"子 Agent"起不同风格的名字(技能用 kebab-case,子 Agent 用名词)。

坑 3:上下文爆炸

症状:3 个调研员各返回 5000 token,主 Agent 还没开始写就超限了。

解法 :Agent 之间通过文件传递信息,不依赖对话历史 。子 Agent 只返回一句"已完成",具体内容写进 findings_*.md,主 Agent 按需读取。


九、总结:DeepAgent 到底帮你省了什么

能力 自己实现 DeepAgent
状态管理 手写 State Graph 内建
子 Agent 调度 手动 orchestrate task 工具
文件系统 自己封装 FilesystemBackend
上下文压缩 手动裁剪 内建
技能资产化 没有 skills 目录
沙箱计算 自己搭 quickjs 中间件

回到最初那句话 :DeepAgent 不是替代 LangChain/LangGraph,而是让你跳过重复的底层基建,直接聚焦 Agent 的业务逻辑与能力迭代。

相关推荐
YIAN1 小时前
LangGraph 完全入门指南:从线性工作流到带中断恢复的有状态 Agent 编排
langchain·node.js·agent
李溪白1 小时前
篇八:幻觉控制与可信回答——别让你的 AI 一本正经地胡说八道
agent
sarasuki1 小时前
Agent 是怎么做错误处理的呢?
人工智能·设计模式·agent
Topskys1 小时前
AI Agent 沙箱
agent
jerrywus1 小时前
用了Pi基本就回不去了, 如果你也在用Pi, 强烈推荐安装pi-chrome
agent·claude·cline
小盆女神节奶粉1 小时前
让 Agent 在沙箱里写代码跑代码,产物进 OSS
langchain·agent
武子康2 小时前
两台 A6000,LingBot 应该先验哪条路径?
人工智能·后端·agent
七夜zippoe2 小时前
Agent 编排引擎设计:任务 DAG、条件分支与循环控制
ai·agent·循环控制·条件分支·任务dag
FITA阿泽要努力2 小时前
第 1 周·第 3 讲|工具如何交给模型:工具定义、参数与结构化调用
服务器·数据库·python·agent