☰
跟着Datawhale打卡·【ai-agent-book:从入门到 Agent 工程实践】学习笔记Task5
2026/10/28 10:22:41 网站建设 项目流程

本期博客学习第十章

https://github.com/bojieli/ai-agent-book/blob/main/chapter10/README.md

第十章的标题是多agent协作,我最近也正好想搭建多gent在钉钉处理我的工作任务,正好借这个机会了解下这种模式有什么利弊,需要我和agent之间怎么协作。

实验10-1 multi-role-transfer 比较角色切换与按需加载技能

这个实验的核心目标是了解多agent任务里,在同一个会话中让agent自己去判断,自动吧任务交给不同的专业角色(skill)去做。实验开头需要先配置环境:

# 从仓库根目录开始:使用共享的第 10 章环境 uv sync --locked --python 3.12 --extra ch10 切换目录前先激活环境: macOS/Linux: source .venv/bin/activate cd chapter10/multi-role-transfer

配置大模型key:

# 配置 key(二选一) export OPENAI_API_KEY=your-openai-api-key # 直接 export export TAVILY_API_KEY=your-tavily-key # research.web_search 必需;无 mock fallback # 或: cp env.example .env 后填写

做到这一步我有点疑惑着三行是什么意思,通过查阅资料了解到这一步主要是配置两个apikey,一个是openai的,一个是tavily的。Tavily 是第三方网页检索服务器。我的方案是实验里的全集任务都要跑并且都是用千问模型不用openai。实验中配了三个skill(coding、writing、research)

那为什么要配置Tavily,不能用模型自带的工具去完成research呢?

一是这个实验这个实验考察的是Agent 架构里,检索是一个独立可插拔的外部工具。二是千问内置搜索是 “模型平台打包在一起” 的黑盒搜索,模型和搜索绑定,不利于观察【工具解耦】这个要点;Tavily 模式:模型 ↔ 检索工具,两层分离,Agent 显式发起工具调用,我们作为开发者角度能看到搜索 query、返回的网页原文片段,可控、可观测;而模型自带联网工具是平台内部封装,看不到搜索中间过程,检索逻辑被平台藏起来了。

跑完这个实验看到了agent之间的分工,我只想说真的太可怜!!!完美适配我当下的卡点,想试着从这个方向做切入点做好自己工作流程的优化!工具之间的每一步交互,思考内容,经过几轮思考,skill之间的分工都非常清晰。

1、先对整体流程有个基础的认知:

这是一套分工式多 Agent(角色移交) 的执行链路,核心机制:所有 Agent 共享同一份对话上下文;每个 Agent 只拥有自己的一套专属工具;只能通过transfer_to_agent把会话交给别的角色,附带移交理由 reason,不能直接调用别的角色的工具。任务被拆成4个环节模型之间自动承接任务,不需要人工干预。

2、通过拆解这段日志详细的学习一下每一个步骤背后的设计思想:

1)traige领取任务:

2)阶段一,拆解复合任务:

(1)大模型以 triage 的系统提示词做身份约束,读取全部用户需求;

(2)triage 内部推理:任务第一步需要互联网实时事实数据,属于 research 的职责;

(3)triage 自身没有web_search工具,不能自己联网;

(4)调用唯一可用工具transfer_to_agent,目标 agent 名称写research,同时输出 reason(移交理由,用于日志可观测);

(5)系统底层动作:把活跃角色切换为 research,完整对话上下文原样传递过去,不截断、不丢失用户三条需求。

3)阶段二,第一次 web_search 调用(query1):

(1)research 读取完整上下文:用户要三年销量,需要拿到精确数字;

(2)research 可用工具二选一:web_search /transfer_to_agent。现在缺少数据,所以选择web_search;

(3)构造第一个搜索 query,作为入参传给工具;

(4)工具函数底层:发起 POST 请求到 Tavily 的搜索 API,带上 query、你的 TAVILY_API_KEY;

(5)Tavily 服务内部:

  • 拿着这个 query 检索互联网,抓取一批匹配网页;
  • 做摘要压缩;
  • 组装 json 返回给我们的程序;

(6)返回结果解读:Tavily 这次搜到的网页里,没有同时集齐 21/22/23 三年准确销量数字,answer 字段直接告知缺少目标数据;

(7)research(千问)读到这个返回结果,推理判断:当前搜索词太宽泛,搜不到精准数据,需要改写 query 再次搜索,不移交。

4)第三阶段,第二次 web_search 调用(query2):

(1)模型反思上一轮搜索失败原因:缺少权威数据源限定词;新能源销量官方发布方是【中国汽车工业协会】;

(2)重构 query,加入权威机构名称,再次调用 web_search;

(3)再次请求 Tavily 接口,独立新一轮全网检索;

(4)这次 Tavily 返回的网页摘要里,拿到了 2022、2023 的两组数据:688.7 万、829.2 万;

(5)模型校验:还差 2021 年的数据,信息不全,不能移交下游,继续搜索。(这一次搜索池和上一次不一样,因为搜索词变了)

5)第四阶段,第三次 web_search 调用(query3):

(1)现在已经有 22、23,缺 21;模型选择拆成单年精准查询;

(2)第三次调用 web_search,新 query 只查 2021 + 中汽协;

(3)Tavily 新一轮检索,返回 2021 数据:352.1 万;

(4)模型校验上下文内收集到的数据:

  • 2021:352.1 万
  • 2022:688.7 万
  • 2023:829.2 万 ✅ 三年数据全部集齐,信息需求满足,停止调用 web_search;

(5)research 内部判断:我的职责是搜集事实数据;数据已经齐了,计算 CAGR 不属于我的能力范围,我没有 calculate 工具;

(6)所以调用 transfer_to_agent,移交给 data_analysis。移交的时候,三年销量数据全部留在共享上下文里,data_analysis 可以直接读到。

6)data_analysis开始干活:

(1)data_analysis 读取上下文:拿到三组销量、用户要求计算 CAGR;

(2)CAGR 公式:CAGR = (期末值 / 期初值) ^ (1/间隔年数) − 1期初 2021,期末 2023,间隔 2 年,所以开 1/2 次方;

(3)选择工具calculate,把数学表达式作为参数传入;

(4)calculate 是本地安全求值工具(不是调用外部 API,本地 Python 求值),返回小数 0.5346,也就是 53.46%;

(5)模型校验:计算完成;data_analysis 只负责定量计算统计,不负责写投资人文稿;没有文字润色、字数统计的工具;

(6)调用 transfer_to_agent,移交 writing,上下文携带原始销量 + CAGR 结果。

7)writing:

(1)writing 读取上下文:拿到全部数据、CAGR、约束条件:面向投资人、≤120 字;

(2)模型生成符合风格的中文总结文案;

(3)用户有硬性字数约束,writing 自带工具count_characters(本地工具,统计文本字符);

(4)传入生成好的文本,执行字数校验,返回 107 字,满足 ≤120 的限制;

如果这里字数超过 120,writing 会改写文本、重新调用 count_characters 反复校验,直到合规;

(5)校验通过,写作任务闭环;writing 角色职责完成,没有后续子任务;

(6)调用 transfer_to_agent,交还控制权给 triage(入口角色,统一对外输出)。

8)活跃角色回到 triage,输出最终回复:triage 不再做推理、不再移交,只把上下文里已经产出好的定稿,整理成友好格式返回给用户。

拆解任务步骤之后,有几个风险点也随之暴露:1、搜索是串行的,这样效率比较慢怎么做优化?2、Tavily给错数字,后面的计算也会出错怎么前置的规避这个问题?3、traige的路由依赖模型对齐,模糊需求是不是容易移交错角色?

自己在网上找了对应的优化方案记录一下:

1、搜索效率优化方案:

1)预生成多候选 query,并行搜索。research 拿到信息需求之后,一次性生成 3~5 条差异化搜索 query(不同关键词、不同权威数据源),并发调用 Tavily,一次性拿到多组检索结果,再做结果融合、去重、筛选有效数据。

2)增加 query 质量提示词,减少重试次数。给 research 角色的系统 prompt 增强约束:要求优先指定权威来源、限定时间范围、精准字段,尽量一次命中目标数据,从源头减少反复试错。 比如强制要求:构造query时带上权威机构名称、年份,尽量一次拿到全部需要指标,避免多次迭代搜索。

3)增加检索缓存层。搭建本地缓存:query + 时间窗口作为 key,短时间内相同搜索词直接返回缓存结果,不用重复调用 Tavily API。适合重复测试、eval 批量跑 case 的场景。

2、强单点依赖,规避水线单点故障风险:

1)多源检索交叉校验。同时调用多个检索源(Tavily + 备选检索服务,比如 bocha、serpapi),拿到多份独立来源的数据。research 增加校验逻辑:对比不同来源的数值,只有多个来源数字一致才采信;数据冲突时标记异常,不直接往下游移交,退回 triage 告警或者重新检索。

2)增加事实校验子步骤 / 校验 Agent。在 research 拿到数据之后、移交数据分析之前,插入校验环节:

  • 校验规则:年份、数值范围、环比 / 同比逻辑是否符合常识;

  • 异常判定:比如销量几千万这种明显不符合常识的离谱数字,识别出来,拒绝向下传递。 我们这次日志里 Tavily 返回的688.7 million本身就是错误(单位写错,应该是万,不是百万),校验环节就可以拦截掉。

3)给下游角色增加告警能力。data_analysis、writing 增加数据合理性自检:如果数值明显异常,不继续输出最终文稿,主动调用 transfer_to_agent 回退到 research 重新核查数据,而不是基于错误数据产出结论。

4)输出溯源标注:最终结果附带数据来源链接,方便人工复核。

3、triage 路由判断依赖模型对齐,模糊需求容易移交错角色:

1)增强 triage 系统提示词 + 明确判定规则。triage 的 system prompt 里写死清晰的判定清单、边界 case。比如只要需要外网实时事实,优先交给 research;明确每个角色的职责边界、禁止范围;分不清的时候,不要强行路由,可以询问用户澄清需求,而不是随便移交。

2)把路由从纯 LLM 判断,改成【LLM 提取特征 + 硬规则兜底】混合路由。先用模型提取需求标签:是否需要联网、是否需要代码执行、是否是纯文本写作、是否需要数学计算; 然后写规则引擎做兜底路由。

3)增加路由评审 Agent。triage 生成移交决策(目标角色 + reason)之后,先交给一个轻量的 reviewer 角色,专门复核路由是否合理; 评审不通过,打回 triage 重新判断。适合高稳定性要求的场景。

4)多轮澄清机制。

当triage 对路由结果置信度低的时候(模型输出置信标记),不强行移交,主动向用户提问,澄清需求:

“你的需求同时包含查数据、写代码,我需要确认优先完成哪一部分?”

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询