实验前提:两套实现共用同一份 prompt(
prompt.ts)、同一个检索后端(tools.ts的 MCP)、同一个裁判(judge.ts)。 唯一的变量是「谁来驱动模型循环」——手写的whilevs LangGraph 的图引擎。
实验设置
- 辩题:具身智能创业公司应该先把钱花在硬件本体上,还是先花在数据闭环上
- 模型:百炼 Token Plan,
qwen3.8-max/qwen3.8-flash - 轮数:2 轮(正式演示用 3 轮,对照实验省成本)
- 执行:
npm run compare -- "辩题"
结果
三轮实验的完整数据
| 轮次 | 状态 | LangGraph 调用 | 手写调用 | token 差异 | 延迟差异 |
|---|---|---|---|---|---|
| 1 | 流程未对齐 | 8 | 10 | +46.1% | −3.4%(手写快) |
| 2 | 改手写版 | 8 | 10 | +90.3% | +64.9%(手写慢) |
| 3 | 流程已对齐 | 6 | 11 | +39.3% | −4.5%(手写快) |
第 3 轮(当前状态,流程对齐后):
| 指标 | LangGraph | 手写 loop | 差异 |
|---|---|---|---|
| 模型调用次数 | 6 | 11 | 手写多 5 次 |
| token 消耗 | 31,518 | 43,890 | 手写多 39.3% |
| 辩手延迟 | 94.2s | 89.9s | 手写快 4.5% |
| 端到端墙钟 | 160.0s | 148.6s | 手写快 7.1% |
| 客套命中率 | 0 / 4 | 0 / 4 | 持平 |
原始数据:runs/compare_*.json
三个结论
1. 唯一稳定的结论:调用次数差 5 次
三轮实验里,只有调用次数的差距是稳定的(8/10 → 8/10 → 6/11)。 token 百分比在 +46% ~ +90% 之间大幅波动,延迟甚至两次反转(快3.4% → 慢64.9% → 快4.5%)。
这说明单次实验的百分比全部在噪声范围内。 而调用次数是整数、可复现的,才是可信信号。
差异来源查清了:LangGraph 那边 createAgent 收敛得更好——
6 次调用完成了「取证 + 4 轮发言」,而手写版用了 11 次。
我的工具描述里写了"建议 2-3 次",反而暗示模型多调几次;
框架那边只说"检索支持本方立场的事实",模型一次就收手。
这个差异是 prompt 措辞造成的,不是 loop 机制造成的。 下次要测公平,得把这个变量也固定住。
2. 延迟差异是噪声,不要拿来当选型理由
手写版快 4.5%(墙钟快 7.1%),但它在多调 5 次的情况下还更快—— 这不符合常理(多 5 次网络往返应该更慢),说明差异来自网络抖动而非机制。
所以"手写比框架快"这个结论不成立。 3~7% 完全被单次请求的波动盖住了。 真要测延迟,得跑 10 次以上取 p50/p95。
3. 辩论质量与 loop 实现无关
三轮实验,裁判评分在正方 19.522.5、反方 18.525.2 之间浮动,
但两版在同一场里的评分始终接近。发言质量也不因实现而异:
- 手写版:陆昭「95% 是筛选后的利用率,不是跨本体可复用率」
- LangGraph 版:沈铭「90% 成功率若只在同一台标定好的机器上成立,换一台关节公差、力控漂移,立刻归零」
质量来自 prompt 和反谄媚机制,不来自 loop 框架。 想提升辩论质量该改 prompt。
方法论教训(这次实验最大的收获)
第一轮我把 46% 的 token 差距诊断成"maxSteps 太宽松 + 上下文裁剪粗糙",
改完差距反而扩大到 90%。数据揭示真相:两版的准备阶段流程压根不一样——
手写版拆成三步 LLM 调用,框架版一次 createAgent 走完。
测出来的差异是流程差异,不是框架差异。
教训:做 A/B 对照时,流程必须先对齐,再谈机制。 否则你测出来的任何数字,都可能只是在测你两边写得不一样而已。
选型结论
本次实验没有得出"谁更快更便宜"的结论,因为变量还没完全控制住。 但得出了两个更重要的判断:
- 对这个场景,框架没有明显性能优势——回合一两次的短流程, 图引擎和自动摘要帮不上什么忙。差异在噪声内
- 手写 loop 的价值不在性能,在可解释性——每一行都知道为什么这么写, 调试时知道去哪看。这是面试里更值钱的东西
| 场景 | 建议 |
|---|---|
| 本项目(同步、短流程、崩了重跑不心疼) | 手写。性能差距不构成理由,可解释性才是 |
| 跨进程/跨天任务 | LangGraph。checkpoint 能力手写要几个月 |
| 中途需要人工审批 | LangGraph。断点续跑是刚需 |
| 要跑百万次的编排 | LangGraph。并发一致性自己扛不住 |
手写 loop 值得投入的地方
不是为了省 token,是这三件事手写之后才真正属于你:
- 上下文裁剪策略可以自己定。框架给的是通用摘要,但我们知道辩论该保什么 (自己的立场 + 对手最近说了什么),可以写针对性更强的策略
- 中间件的边界自己划。反谄媚的锚点注入在
wrapModelCall里做是一行, 在框架里要理解它的钩子生命周期才能放对位置 - 调试时知道去哪看。框架把 loop 藏进图里,出问题时你得先反推图的结构
(见
docs/agent-harness-research.md第二节的源码位置)
下一步要改进的
- 固定工具描述措辞,让两版的调用收敛程度一致,再重测
- 跑 10 次取 p50/p95 延迟,单次的 3~7% 是噪声
- 补单次调用的分位数延迟,排除调用次数干扰
- 测「相同 prompt 重复 5 次」的质量方差,确认评分波动是正常噪声