多加几步、加分支,能覆盖所有情况吗?
本课一问:第 1 课的流程在两个任务上失败了,原因各不相同。那就每遇到一类失败,给流程加一步、加一条分支——这样补下去,能覆盖所有情况吗?
这一课先不碰:把决定权交给模型要付什么代价(第 3 课);模型「会决定下一步」这个能力从哪来(岔路 B1);那个循环具体怎么写、什么时候停(A1)。
从已有出发
第 1 课拆出两层失败:parse_date 缺的是运行时才出现的信息(第二处 bug 的报错要等第一处修好才有),slugify 败给了程序自己的写回规则。补法也写好了:测试没过就带着新报错再调一次模型(由退出码决定);回复格式不对就拒绝写回。两处都还是代码在决定下一步。
贯穿任务不变:修好 test_parse_date。这一课第一次拿出 agent 轨的录制——同一个任务,模型自己决定每一步走出来的路。
先自己设计:每遇到一类失败,就加一条路
「加一条路」有现成的工具箱。Anthropic 把常见的 workflow 归成五种模式,每种配一张架构图;把它们和 agent 放在一起,按「这条边由谁决定」上色:
拓扑取自 Anthropic《Building effective agents》(2024-12-19;2026-09-26 核对原文仍在,页首加了「工具生态已变」的说明)的 workflow 与 agent 架构图,边色是本课按「这条边由谁决定」标的;「何时用」是对原文的转述。有录制的两格用本课项目 T2(Qwen3-8B-MLX-4bit,seed 1)现算。
试三件事:① 点 Evaluator-optimizer:第 1 课那条「没过就再来」的回边就是它,只是评估者换成了测试的退出码——评估者是代码时,回边是灰的;② 点 Routing 和 Orchestrator-workers:这两种 workflow 里已经有橙色边(模型选岔口、模型定子任务),分野不是一道墙;③ 点 Agent,选 parse_date 按 ▶ 走一遍:这是 T2 录下来的真实 8 轮,每一轮高亮它走的那条边。
照这个思路,把第 1 课的流程补成:跑测试 → 发报错与源文件 → 覆写 → 重跑,没过就带着新报错再来,最多 3 次;回复没有 FILE: 就不写回。下一次遇到新的失败(比如要先读另一个文件、要装一个依赖),再加一条分支。问题是:要加到什么时候?下面把 agent 轨真实走出来的路一条条摆出来。
- ① 朴素方案
- ② 它在哪失败
- ③ 改进方案
同一个任务、同一个模型、同一套 harness 配置(v2 提示词、思考开、不设上限或 30 轮——都没到),只有 seed 不同:A1 录的 seed 1 / 2 / 3,加上 T2 又录的一次 seed 1。
跑测试 → 收集源文件 → 调模型 → 覆写 → 重跑(5 步,全由代码决定)。数据:本课项目的真实运行(agent-traces.json 的 A1 录制 + agent-t2-workflow.json 的 T2 录制;Qwen3-8B-MLX-4bit,2026-09-26)。节点只记工具名(同名工具的参数可能不同);被截断、被丢弃的轮次没有调用,不占节点。树与三个计数都在浏览器里现算。
分支要在设计时写出来,可这些路是在运行时长出来的:模型读了上一步的输出,才决定下一步看哪、改哪。第 6 轮那次 edit_file 改的是 month = MONTHS.index(name.lower()) 这一行——写流程的人事先不知道会有这一步,因为指向它的报错要等第 4 轮的修改生效、第 5 轮重跑之后才出现。
「没过就再来」的回边能把这次失败再送回模型,但它只决定转不转;每一轮看什么、改哪里、要不要先跑一下测试,仍然得有人决定。与其把这些都预先写成分支,不如让模型在每一轮自己决定:给它几样工具(读文件、跑命令、改文件),循环直到它不再调工具。这就是 agent——A1 会把这个循环一行行写出来。
datetime.date(2024, 2, 5) != datetime.date(2024, 3, 5)。 试三件事:① 先猜一个数,再一次次点「加入下一次运行」:第 2 次加进来时树就分叉了;② 点 pd-v2-unlimited-s2 这枚芯片,看它从哪一个节点开始和别人走不同的路;③ 注意第 1 次和第 4 次运行都是 seed 1、配置只差一个两次都没用上的轮数上限,却也不在同一个叶子上——为什么,第 3 课回答。
改进:把「下一步」交给模型,并把它放回光谱上
agent 并不是 workflow 的反面。smolagents 的文档把「agent」直接定义成模型输出控制程序流程的程序,并且写明 agency 是连续的光谱、不是 0 或 1 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条定义性的分类,不是实验结论;六档表与代码骨架逐字取自原文。 出处smolagents · Introduction to agentic systems(2026-09-26 核对) ↗需联网 ;OpenAI 的入门指南也把「集成了模型、但不让模型控制流程执行」的应用排除在 agent 之外 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条官方定义,p.4「What is an agent?」。 出处OpenAI · A practical guide to building agents(2025-04) ↗需联网 。把同一个修 bug 任务按六档画出来:
process_llm_output(llm_response)if llm_decision(): path_a() else: path_b()run_function(llm_chosen_tool, llm_chosen_args)while llm_should_continue(): execute_next_step()if llm_trigger(): execute_agent()def custom_tool(args): ... 六档与代码骨架逐字取自 smolagents 文档《Introduction to agentic systems》(Apache-2.0;2026-09-26 核对),原文写明 agency 是连续的光谱、不是 0 或 1。控制流图是本课把同一个任务画成六档的结构示意,不含任何数字;第 0 档与第 3 档对应本课项目真实录制的两条轨道。
把滑杆推到 ★★☆ Multi-step Agent,注意图里第一次出现了指回自己的边:模型 → 执行工具 → 回到模型。骨架里那个橙色的 llm_should_continue(),就是图里两条橙边的来源——转不转、往哪转,都由模型的输出决定。再往右两档,是 A7 的子 agent 和 A2 岔路里的 Code Mode。
光谱还解释了一个常见的困惑:Anthropic 的 routing、orchestrator-workers 明明有模型在做决定,为什么还叫 workflow?因为模型只在预先画好的岔口里选一条(routing),或者只决定这一轮派几个工人(orchestrator-workers);路的形状仍是设计时写好的。到 Multi-step Agent 这一档,连「还要不要继续、下一步是哪条」都交了出去。所谓分野,是光谱上的一个位置,不是两个互不相通的类别 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条「分野」本身满票核实(Anthropic 原文);「应当当作光谱来讲」是调研给出的教学要求,批评二分法的 Medium / Towards AI 原文未单独核查,这里的依据改用 smolagents 文档与 Karpathy 演讲。 出处smolagents · Introduction to agentic systems ↗需联网 。
极小真数字:要预先写出几个判断
把运行的工具序列插进一棵前缀树:共同的开头合并,下一步不一样的地方分叉。一个节点有几个出口(几种不同的下一步,算上「停」),代码要复现它就得写几减一个判断。同一配置重跑的 4 次运行:
其中最能说明问题的是 T2 那一次的第 5 → 6 轮。第 5 轮它重跑了测试,输出里第一次出现:
AssertionError: datetime.date(2024, 2, 5) != datetime.date(2024, 3, 5)
第 6 轮它就去改 month = MONTHS.index(name.lower()),补上 + 1。这条边的依据,在第 4 轮之前的任何时刻都不存在。
常见误解一:「agent 和 workflow 是二选一。」 上面的光谱里,routing 与 orchestrator-workers 这两种 workflow 已经有模型决定的边;smolagents 分了六档,Karpathy 把它叫作滑杆。真正要回答的是「把哪几条边交给模型」,而不是「用不用 agent」。
常见误解二:「有 while 循环就是 agent。」 第 1 课那条「测试没过就再来,最多 3 次」的回边也是循环,可转不转由退出码决定、每一轮做什么也写死了——它仍在第 0 档。判断的标准是谁决定下一步,不是代码里有没有循环。
🔍 路径不同,都是因为「需要」不同吗?
不全是。分叉有两种来源:一种是看了输出才知道(第 5 → 6 轮那种,报错指向了第二处);另一种是采样的随机性——同一个模型、同一份上下文,先 list_dir 还是先读测试文件,本来就可能不一样。前一种是 agent 的价值,后一种是它的代价。更让人意外的是,连 seed 相同、配置相同的两次运行也会分叉:第 3 课的孪生运行会找到那几个不一样的 token。
证据三问
| 问 | 本课的回答 |
|---|---|
| ① 它解决什么问题? | 当下一步取决于运行时的输出、路没法事先写死时,让路在运行时长出来 |
| ② 为什么可能有效? | 每一轮模型都以最新的环境反馈(测试输出、文件内容)为条件决定下一步,分支条件不必事先写出 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条官方对 agent 的描述:每一步从环境拿 ground truth 评估进展(调研 3-0 满票)。「因此更适合开放式问题」是官方建议,不是实验结论。 出处Anthropic · Building effective agents ↗需联网 |
| ③ 实验上呢? | 同一配置重跑:4 次运行 4 条路;T2 的 4 个任务 4 条;parse_date 第二处的修改依据在第 5 轮才出现 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条项目实测:单一模型(Qwen3-8B 4bit)、一个主任务、每种设置一次。说明路径会在运行时长出来,不估计有多少种。本课项目没有录制「带重试的 workflow」,它在这些任务上能走多远,现在没有数字。 出处本课项目 T2 与 A1 录制(实验课) ↗ |
演进地图:你在这里
- 解决了只调一次模型,每一步都写在代码里:可预期、好测、便宜。卡在T2 workflow 轨 2 / 4 通过。parse_date 只改了报错指到的那一行,重跑才露出第二处(
datetime.date(2024, 2, 5) != datetime.date(2024, 3, 5));slugify 的回复只有函数片段,兜底规则把 130 字符的片段当整份文件写回(原文件 365 字符),丢了import re。 - 第一代 加步骤、加分支:五种 workflow 模式 prompt chaining · routing · parallelization · orchestrator-workers · evaluator-optimizer 你在这里解决了每一类失败补一条预先写好的路径:测试没过就带着新报错再来一次(评估者是测试的退出码)、回复格式不对就拒绝写回。卡在分支要在设计时写出来,可真实路径是在运行时长出来的:T2 agent 轨 4 个任务走出 4 条不同的工具序列;同一配置重跑 4 次 parse_date(seed 1 / 2 / 3 / 1),走出 4 条。
- 解决了边在运行时长出来:T2 agent 轨 3 / 4 通过,包括 workflow 没修好的 parse_date 与 slugify。卡在代价:workflow 已经能解决的任务上 token word_freq ×5.3、leap_year ×4.5,其中 word_freq 的 agent 反而没修好;同配置、同 seed 重跑,2 / 4 个任务在中途分叉。
- 解决了录制前写下三条标准并逐个预测,录制后对照:预测对 3 / 4。卡在预测错的 slugify 不是任务本身需要 agent,而是 workflow 自己的写回规则出了错(回复没有
FILE:标记时的兜底)。每条轨道每个任务只跑 1 次:只能当例子,不能当比率。 - 解决了编排形状固定的部分(并行审查、逐条验证、断点续跑)写进脚本;模型只决定「要不要调这个 workflow、传什么参数」。卡在同一个仓库里两种说法并存:README
:11与:41说 agency 来自训练、不是编排;:239说编排形状固定就写进代码。界线画在哪,没有实验回答。 - 解决了同一个循环,识别出代码工作区后注入编码说明(约 577 token,Qwen3 tokenizer 计)与工作区快照;focus 模式才会收窄工具集与技能索引。卡在判定靠文件标记:本课任务仓单独拷出来(README.md、dateparse.py、test_dateparse.py,没有 .git)在默认 auto 下被判成 general;放在项目目录里原地跑,却因为往上 3 层有个
requirements.txt被判成 coding。姿态在会话开始解析一次,中途不变。
一句话
先停在这里:记住光谱上那条「第一次指回自己的边」:转不转、往哪转,由模型的输出决定。
再深一层:岔路 agency 是训练出来的,还是编排出来的?——模型为什么会「决定下一步」,两种针锋相对的说法,以及同一个仓库里自己的转向。
下一个缺口
把决定权交给模型,代价是什么? → 第 3 课:把「下一步做什么」交给模型,要付什么代价?
agent 轨修好了 workflow 没修好的 parse_date。可路在运行时长出来,也就意味着你事先不知道它会走几步、花多少、每次走得一不一样。
你可能会问
- 「模型凭什么会『决定下一步』?这个能力是训练出来的,还是 harness 编排出来的?」 见岔路 agency 是训练出来的,还是编排出来的?:两种针锋相对的立场、同一个仓库自己的转向,以及本课项目把 harness 从 v1 换成 v2 的一组数字。
- 「routing 和 orchestrator-workers 里模型也在做决定,它们算 agent 吗?」 按 Anthropic 的分法仍是 workflow:路的形状是设计时写好的,模型只在里面选。按 smolagents 的六档,routing 在 ★☆☆,已经不是第 0 档了。两种说法不矛盾,只是切的位置不同。
- 「为什么本课项目不实现 routing 或 orchestrator-workers?」 本课项目只需要两条对照轨道:一条全由代码决定(第 0 档),一条全由模型决定(第 3 档)。中间几档的形态在 A7(子 agent 的派发)和 A2 岔路(Code Mode)里会以别的名字出现。
- 「前缀树里只记工具名,是不是低估了分叉?」 是。同样叫
edit_file,改的是第一处还是第二处、old_string 写了几行,都是不同的决定;把参数算进来,分叉只会更多。组件只记工具名,是为了让树能画得下。