代码语言

知识点思维导图

31 个知识节点

项目实战(03) - 项目:个人 Agent 工作台

读完后,你应能完成以下任务:

  • 绘制“项目实战(03) - 项目:个人 Agent 工作台 / 编排的本质:声明步骤 + 声明依赖”的关键对象与数据流,解释“关键是 {"from_step": 0, "field": "tasks"} 这种引用型参数。”,并用源码位置、日志或 Trace 标注证据。
  • 为“项目实战(03) - 项目:个人 Agent 工作台 / fan-out:对一个列表里每一项都做同一件事”设计正常与异常输入,验证“它的工程要点是:其中任何一项失败或被拦,整个步骤要能停下来,而不是闷头跑完——demo 里只读权限的用户跑到这一步就被拦在第一项上了。”,输出首个偏差位置与回归测试结果。
  • 实现“项目实战(03) - 项目:个人 Agent 工作台 / 写操作让整个工作流暂停,不是跳过”的最小代码或配置,检验“它可以是 done(跑完)、paused(停在某步等确认)、blocked(被权限拦死)。”,输出命令、结果与 Diff,并说明不适用边界。

一、个人 Agent 工作台的真实应用场景

早上九点,你对工作台说一句:"帮我整理今天的任务,给延期的建提醒,再写个日报草稿。"

这一句话背后是一串动作:

  1. 查出今天所有任务。
  2. 从里面挑出延期的。
  3. 给每个延期任务建一条提醒。
  4. 把"几项任务、几项延期、建了几条提醒"汇总成日报。

前面 44-46 三个项目都是"一问一答"——用户问一句,助手答一句,顶多调一个工具。但这个需求不是一问一答,它是一条有先后、有依赖的流水线:第 2 步要用第 1 步的结果,第 4 步要用前三步的结果,第 3 步还是个写操作得卡确认。

把这种多步任务自动跑起来,就是"工作台"和"聊天助手"的分水岭。这一篇讲怎么做编排。

二、编排的本质:声明步骤 + 声明依赖

很多人以为多步 Agent 很玄乎。其实编排的核心就两件事:把目标拆成有序步骤说清每步的参数从哪来

关键是 {"from_step": 0, "field": "tasks"} 这种引用型参数。它不是一个值,是一句话:"我的这个参数,等第 0 步跑完,去它的输出里取 tasks 字段。"编排器执行到这一步时,再把引用替换成真实数据:

步骤之间靠 results 列表传递数据,依赖关系靠 from_step 声明。这就是工作流引擎最朴素的样子。真实项目里 LangGraph、各种 workflow 框架做的也是这件事,只是封装更厚。

三、fan-out:对一个列表里每一项都做同一件事

第 3 步有个特殊形态:延期任务有好几个,要给"每一个"都建提醒。这叫 fan-out(扇出)——拿上一步的列表,逐项调用同一个工具:

fan-out 在 Agent 编排里很常见:"把这批文件都总结一遍""给这些客户都发通知"。它的工程要点是:其中任何一项失败或被拦,整个步骤要能停下来,而不是闷头跑完——demo 里只读权限的用户跑到这一步就被拦在第一项上了。

四、写操作让整个工作流暂停,不是跳过

单次问答里,写操作没确认就返回"待确认"完事。工作流里不一样——写操作在流水线中间,它没确认,整条流水线得停在这里

[0] 查任务      → 完成
[1] 筛延期      → 完成
[2] 建提醒(写)  → 没确认 → 整个工作流 paused,返回"待确认 2 项"
[3] 写日报      → 还没轮到,不执行

工作流有了"中间状态"。它可以是 done(跑完)、paused(停在某步等确认)、blocked(被权限拦死)。paused 是最能体现编排价值的状态:用户确认后,工作流能从暂停点继续,而不是从头再来。demo 场景 1 暂停、场景 2 确认后跑通,就是这条路径。

五、工程上真正会踩的坑

  • 步骤依赖写死成顺序,不显式声明:以为"反正按顺序跑"就行,结果改了步骤顺序数据就错位。依赖要显式声明(from_step),不能靠隐式假设。
  • fan-out 不处理部分失败:10 个里第 3 个失败了,前 2 个已经执行、后 7 个还没跑,状态一团乱。要明确策略:是全停、还是跳过失败项继续、还是回滚。
  • 暂停状态不持久化:工作流 paused 了,进程一重启状态全丢,用户得从头再来。中间状态要落盘,才能真正"恢复"。
  • 写操作确认做成一步一弹窗:一个工作流里三个写操作,弹三次确认,用户烦死。要么批量确认("这 2 条提醒都建吗"),要么开始前一次性预览所有写操作。
  • trace 只记成功不记失败:被 blocked 的步骤不写 trace,出了问题不知道卡在哪。成功、暂停、拦截都要进 trace。

六、一句话面试答法

多步 Agent 工作流和单次工具调用有什么区别? 单次调用是一问一答,工作流是一串有依赖的步骤。编排的核心是声明每一步调什么工具、参数从哪来——后面步骤通过引用前面步骤的输出来传数据。工程上要处理三种状态:跑完、被权限拦死、以及碰到写操作时暂停等确认。我会把暂停状态持久化,确认后从断点恢复而不是从头重跑,每一步无论成功失败都进 trace,保证整个任务可观察、可恢复。

七、动手实践:47 个人 Agent 工作台

把多个工具、多个步骤编排成一个能自动推进的工作流。一个目标"整理今天的任务、给延期项建提醒、写日报"被拆成 4 步,步骤之间有依赖(后一步用前一步的产出),写操作会让整个工作流暂停等确认。

7.1 在线运行

零依赖,纯标准库。

7.2 预期输出

未确认运行:
读取今天任务 已完成
识别延期项 已完成
暂停:创建提醒 是写操作,需要确认
状态=paused next=2

从检查点确认后恢复:
创建提醒 已完成
生成日报 已完成
状态=done trace=['tasks:done', 'late:done', 'reminders:paused:confirmation required', 'reminders:done', 'report:done']

只读身份运行:
读取今天任务 已完成
识别延期项 已完成
拦截:创建提醒 缺少 write:reminders
状态=blocked outputs=['late', 'tasks']

三种状态各看一次:写操作前 paused 等确认、确认后 done、没权限 blocked。这就是工作流编排和单次问答的区别——它有中间状态,能暂停、能恢复、能被拦在半路。

7.3 代码对应文章的哪些点

概念 在 main.py 哪里
把目标拆成多步计划 plan
步骤间依赖(后一步用前一步产出) Workbench._resolve_argsfrom_step
对列表逐项调用(给每个延期任务建提醒) executefan_out 分支
写操作暂停等确认 execute 返回 paused
权限不足拦截 _run_tool 的权限校验
全程可观察 self.trace

7.4 动手改

  • plan 里加一个新目标(比如"查订单 + 发通知"),体会编排就是"声明步骤 + 声明依赖"。
  • paused 状态存盘,下次启动时从暂停点恢复,体验"任务可恢复"。
  • 给某一步故意引用一个不存在的 from_step,看编排器怎么报错。

7.5 可运行源码:项目:个人 Agent 工作台

main.py

八、总结

  • 编排的本质:声明步骤 + 声明依赖:关键是 {"from_step": 0, "field": "tasks"} 这种引用型参数。
  • fan-out:对一个列表里每一项都做同一件事:它的工程要点是:其中任何一项失败或被拦,整个步骤要能停下来,而不是闷头跑完——demo 里只读权限的用户跑到这一步就被拦在第一项上了。
  • 写操作让整个工作流暂停,不是跳过:它可以是 done(跑完)、paused(停在某步等确认)、blocked(被权限拦死)。
  • 工程上真正会踩的坑:依赖要显式声明(from_step),不能靠隐式假设。
  • 一句话面试答法:单次调用是一问一答,工作流是一串有依赖的步骤。

学完自测

选择所有正确答案;提交后逐项核对判断依据。

1在“项目:个人 Agent 工作台”中,需要同时满足“个人 Agent 工作台的真实应用场景”与“编排的本质:声明步骤 + 声明依赖”。给定正文约束“"帮我整理今天的任务,给延期的建提醒,再写个日报草稿。”,哪些判断保持了原有处理机制?多选
2“项目:个人 Agent 工作台”出现偏差:“在“项目:个人 Agent 工作台 / fan-out:对一个列表里每一项都做同一件事”中,即使不满足“其中任何一项失败或被拦,整个步骤要能停下来,而不是闷头跑完——demo 里只读权限的用户跑到这一步就被拦在第一项上了”,结果与副作用仍会保持不变。”已成为实际行为。围绕“fan-out:对一个列表里每一项都做同一件事”与“写操作让整个工作流暂停,不是跳过”,哪些判断能定位被改变的职责或边界?多选
3评审“项目:个人 Agent 工作台”方案时,验收条件包含“多步 Agent 工作流和单次工具调用有什么区别? 单次调用是一问一答,工作流是一串有依赖的步骤。”。关于“一句话面试答法”与“动手实践:47 个人 Agent 工作台”的哪些决策符合正文机制?多选