从0打造编码Agent 实验 实验 ≈ 40 分钟 页内实验 ×4
A0 工作流还是 Agent:什么时候需要 agent,什么时候一段代码就够? 实验课

同 4 个任务,workflow 与 agent 双轨真跑:每个任务哪条轨道够用?

双轨真跑
本课项目用本机 Qwen3-8B 把 4 个任务各跑了一遍两条轨道(T2):workflow 修好 2 个,agent 修好 3 个;录制之前写下的预测对了 3 个。这一课先让你自己预测,再把两条轨道逐步摊开,最后把同配置同 seed 的孪生运行和贯穿任务的全部 21 次运行放在一起看:路是怎么在运行时长出来的。
🧪

这一课做什么:把 T2 的全部录制摊开:4 个任务 × 2 条轨道,两条轨道合计 workflow 13,118 token、agent 107,931 token。先自己预测,再逐步看两条轨道各走了哪几步、在哪里赢、在哪里输。所有数字都来自录制,没有一个是手写的。

从已有出发 · 累计数据流 点已学环节看它回答什么
每一轮循环都经过

实验一:先预测,再揭示

项目在录制之前写下了三条判别标准(第 3 课):①修复需要的信息是否全在「报错 + 被测源文件」里;②下一步是否取决于运行时才出现的输出;③改动范围能否预先确定。拿它们(或你自己的标准)逐个判断,每个任务选一条轨道:

实验 · T2 四个任务:先预测哪条轨道够用(Qwen3-8B-MLX-4bit · seed 1 · 2026-09-26)
先预测,再揭示:每个任务哪条轨道够用? 代码决定模型决定

数据:本课项目 T2 双轨录制(agent-t2-workflow.json,2026-09-26;Qwen/Qwen3-8B-MLX-4bit,本机 mlx_lm.server;两条轨道同为 seed 1、同一沙箱;workflow 单次调用 max_tokens 8192,agent 每轮 4096、上限 30 轮)。每条轨道每个任务只跑 1 次:只能当例子,不能当比率。token 与轮数可比;耗时受本机同时运行的其他任务影响,只能粗看。本地模型没有账单,成本以 token 计;按价格换算留到 A8。

🎯

提示(先选完再看):parse_date 的两处 bug 按顺序暴露;slugify 与 word_freq 的规格都写在 docstring 里;leap_year 是补一个函数。揭示之后,找出你和项目都判错的那一个,想想错在「标准」还是错在「workflow 的实现」。

实验二:逐任务双轨对照

实验 · 同一个任务两条轨道并排(workflow 5 步 vs agent N 轮)
同一个任务,两条真实轨道并排 代码决定模型决定

数据:本课项目 T2 双轨录制(agent-t2-workflow.json,2026-09-26;Qwen/Qwen3-8B-MLX-4bit,本机 mlx_lm.server;两条轨道同为 seed 1、同一沙箱;workflow 单次调用 max_tokens 8192,agent 每轮 4096、上限 30 轮)。每条轨道每个任务只跑 1 次:只能当例子,不能当比率。token 与轮数可比;耗时受本机同时运行的其他任务影响,只能粗看。本地模型没有账单,成本以 token 计;按价格换算留到 A8。

🎯

试三件事:① parse_date:workflow 的 ⑤ 重跑露出第二处 bug;agent 在第 5 轮看到同一条报错,第 6 轮去改了它;② slugify:workflow 的 ④ 用兜底规则写回了片段;agent 修好了,但最后几轮全是被截断的思考,停止原因是 length——harness 的验收说通过,模型自己并没说「做完了」;③ word_freq:反过来,workflow 一次就过,agent 在思考里打转。

实验三:孪生运行与换 seed

同配置、同 seed 的两次 agent 运行按轮对齐:

实验 · T2 agent 轨 vs A1 里同配置同 seed 的运行(第一处不同由原始 trace 比对得出)
同配置、同 seed 的两次 agent 运行 · 按轮对齐 代码决定模型决定

数据:本课项目 T2 双轨录制(agent-t2-workflow.json,2026-09-26;Qwen/Qwen3-8B-MLX-4bit,本机 mlx_lm.server;两条轨道同为 seed 1、同一沙箱;workflow 单次调用 max_tokens 8192,agent 每轮 4096、上限 30 轮)。每条轨道每个任务只跑 1 次:只能当例子,不能当比率。token 与轮数可比;耗时受本机同时运行的其他任务影响,只能粗看。本地模型没有账单,成本以 token 计;按价格换算留到 A8。

再从贯穿任务的全部 harness v2 运行里任选一次逐轮回放(它们的配置各不相同,下拉框里的标签写着差别;unlimited 的 s1 / s2 / s3 是只换 seed 的三次):

实验 · 贯穿任务 parse_date 的 harness v2 运行(A1 录制)
逐轮回放:看每一轮模型决定了什么 请求模型回复工具调用工具结果harness 注入

数据:本课项目 miniagent 的真实运行(src/data/project/agent-traces.json,2026-09-26 导出;模型 Qwen/Qwen3-8B-MLX-4bit,本机 mlx_lm.server)。token 数取自服务端 usage;思考截取约 600 字、正文与工具输出约 900 字(保留头尾)。耗时受本机同时运行的其他任务影响,只能粗看;token 与轮数才可比。

实验四:所有路径放在一棵树里

先看 T2 的 4 个不同任务,再看贯穿任务的全部 21 次运行(A1 的 20 次 + T2 的 1 次;配置各不相同,分叉的原因里还混着提示词、权限规则、上下文策略的差别):

算法模拟器 · 前缀树(浏览器现算)· T2 四个任务
路径树 · 真实运行的工具调用序列,一条条插进前缀树 分叉点(下一步在运行时才定)停

T2 agent 轨:4 个不同的任务,同一套配置,各跑 1 次。

对照:workflow 轨每个任务都走同一条、设计时写好的路径 跑测试 → 收集源文件 → 调模型 → 覆写 → 重跑(5 步,全由代码决定)。

数据:本课项目的真实运行(agent-traces.json 的 A1 录制 + agent-t2-workflow.json 的 T2 录制;Qwen3-8B-MLX-4bit,2026-09-26)。节点只记工具名(同名工具的参数可能不同);被截断、被丢弃的轮次没有调用,不占节点。树与三个计数都在浏览器里现算。

算法模拟器 · 前缀树(浏览器现算)· 贯穿任务全部真实运行
路径树 · 真实运行的工具调用序列,一条条插进前缀树 分叉点(下一步在运行时才定)停

贯穿任务 parse_date 的全部真实运行:A1 的 20 次(两版提示词 × 上限、权限、上下文、工具模式、思考开关等不同配置)+ T2 的 1 次。配置不同,路径不同的原因也更多。

对照:workflow 轨每个任务都走同一条、设计时写好的路径 跑测试 → 收集源文件 → 调模型 → 覆写 → 重跑(5 步,全由代码决定)。

数据:本课项目的真实运行(agent-traces.json 的 A1 录制 + agent-t2-workflow.json 的 T2 录制;Qwen3-8B-MLX-4bit,2026-09-26)。节点只记工具名(同名工具的参数可能不同);被截断、被丢弃的轮次没有调用,不占节点。树与三个计数都在浏览器里现算。

🎯

试两件事:① 在 T2 那棵树上,4 个任务的第一步都是 list_dir,从第二步起就各走各的——任务不同,路当然不同;② 在全部运行那棵树上,先猜一个数再点「全部加入」,然后点几枚 ✗ 的芯片,看失败的运行停在树的哪一层。

⚠

别从这些数字读出「workflow 与 agent 谁更好」。单一本地模型(4bit 量化的 8B)、4 个小任务、每条轨道每个任务只跑 1 次 。大纲要的「跨文件」「需要装依赖」两类任务还没建,而它们恰恰最能区分两条轨道。能说明的是:两条轨道各有各的失败方式,判别标准可以先写下来、再用真实运行检验。

自己动手

  1. 在 04-实践项目 里改你的判别标准或 workflow 的写回规则(比如:回复没有 FILE: 标记就拒绝写回),写进 MILESTONES.md 的预测表,先写预测;
  2. 重录 T2(需要本地模型服务;脚本会先确认本机没有别的测速任务在跑):.venv/bin/python scripts/with_server.py scripts/record_t2.py,只录某几个任务就在后面加任务名;
  3. 导出并脱敏:.venv/bin/python scripts/export_batch2.py t2,再运行 知识平台/src/data/precomputed/gen_a00_workflow_agent.py(用项目的 .venv/bin/python,需要 transformers);
  4. 刷新本页:预测卡、双轨对照、孪生运行都会换成你的新数据。验收:.venv/bin/python -m miniagent validate traces/t2-*.jsonl 全部 OK。

演进地图

什么时候需要 agent:每一代都被上一代的某个真数字逼出来
  1. 朴素 单次调用:报错 + 源文件发给模型,要回整份新文件,覆写后重跑 本课项目 workflow.py · 5 步全由代码决定 你在这里
    解决了只调一次模型,每一步都写在代码里:可预期、好测、便宜。
    卡在T2 workflow 轨 2 / 4 通过。parse_date 只改了报错指到的那一行,重跑才露出第二处(datetime.date(2024, 2, 5) != datetime.date(2024, 3, 5));slugify 的回复只有函数片段,兜底规则把 130 字符的片段当整份文件写回(原文件 365 字符),丢了 import re。
  2. 第一代 加步骤、加分支:五种 workflow 模式 prompt chaining · routing · parallelization · orchestrator-workers · evaluator-optimizer
    解决了每一类失败补一条预先写好的路径:测试没过就带着新报错再来一次(评估者是测试的退出码)、回复格式不对就拒绝写回。
    卡在分支要在设计时写出来,可真实路径是在运行时长出来的:T2 agent 轨 4 个任务走出 4 条不同的工具序列;同一配置重跑 4 次 parse_date(seed 1 / 2 / 3 / 1),走出 4 条。
  3. 第二代 把「下一步做什么」交给模型:while + 工具 = agent 本课项目 loop.py(A1 细讲) 你在这里
    解决了边在运行时长出来:T2 agent 轨 3 / 4 通过,包括 workflow 没修好的 parse_date 与 slugify。
    卡在代价:workflow 已经能解决的任务上 token word_freq ×5.3、leap_year ×4.5,其中 word_freq 的 agent 反而没修好;同配置、同 seed 重跑,2 / 4 个任务在中途分叉。
  4. 第三代 先判别再选轨道:能用一段代码就不用 agent 三条判别标准 · 先直接调 API 你在这里
    解决了录制前写下三条标准并逐个预测,录制后对照:预测对 3 / 4。
    卡在预测错的 slugify 不是任务本身需要 agent,而是 workflow 自己的写回规则出了错(回复没有 FILE: 标记时的兜底)。每条轨道每个任务只跑 1 次:只能当例子,不能当比率。
  5. 岔路 混合:把固定编排写成 agent 的一个工具 learn-claude-code s16 Workflow Runtime
    解决了编排形状固定的部分(并行审查、逐条验证、断点续跑)写进脚本;模型只决定「要不要调这个 workflow、传什么参数」。
    卡在同一个仓库里两种说法并存:README :11 与 :41 说 agency 来自训练、不是编排;:239 说编排形状固定就写进代码。界线画在哪,没有实验回答。
  6. 岔路 通用 agent 切换到编码姿态 Hermes coding_context.py
    解决了同一个循环,识别出代码工作区后注入编码说明(约 577 token,Qwen3 tokenizer 计)与工作区快照;focus 模式才会收窄工具集与技能索引。
    卡在判定靠文件标记:本课任务仓单独拷出来(README.md、dateparse.py、test_dateparse.py,没有 .git)在默认 auto 下被判成 general;放在项目目录里原地跑,却因为往上 3 层有个 requirements.txt 被判成 coding。姿态在会话开始解析一次,中途不变。
数字口径:本课项目 T2 双轨录制(Qwen3-8B-MLX-4bit,本机 mlx_lm.server,seed 1,2026-09-26;4 个任务各跑 1 次,只说明现象会发生,不估计比率);孪生运行 = A1 里与 T2 agent 轨配置相同、seed 相同的那次运行;Hermes 一行是 pin 56dc01d9 的原实现在临时目录里实跑的判定。

一句话

📌
先写标准、再跑两条轨道、逐项对照,错在哪里比对了几个更有用。

→ 下一章:A1 循环:模型只会吐文字,它怎么改你的文件?什么时候停?