本页目录
Lesson 04 — 工具返回值工程:控源胜于止损
本课目标:把窗口最大的租客(工具结果)在进门前整形——截断/分页/引用三板斧,铁律是「省略必须显式」:任何整形产物只要内容少于原文,标记必须注明略了多少、原文多长、怎么拿全文。静默掐尾会让模型把半篇当全篇引用——比溢出更隐蔽的失败。
1. 教学反转:你在 L02 学的压缩,其实是最后手段
账本证据(L00/L01):工具结果占越限窗口 95%、占 RA 集成窗口 75%。据此排治理顺序:
控源(本课) 工具结果进门前整形 无损(原文在源头/文件里)、便宜(纯代码)
↓ 还不够再
外置(L05/L06) 过程关进子窗口、工作集落盘
↓ 还不够再
止损(L02 压缩) 已进窗口的历史有纪律地收房 有损、要花摘要钱、递归失真
一条 3,400 token 的检索结果,进门前整形成 600(纯字符操作),比进来之后再花一次 LLM 调用把它压掉,便宜且无损。压缩处理的应该只是「真正回不去的对话过程」。
2. 三板斧
| 板斧 | 做什么 | 窗口占用(S17 实测) | 适用 |
|---|---|---|---|
截断 shape_result |
预算内头部 + 显式省略标记 | 3,406 → 600 tok | 默认路径:多数结果只需要开头 |
分页 paginate |
offset/limit 取片,页边界双标记 | 412 tok/页 | agent 主动深读:翻页权在它手里 |
引用 reference |
全文无损落盘,窗口只进指针+头部 | 48 tok | 超长材料/日后要回看(L06 前奏) |
三个设计细节:
- 标记也占预算:
shape_result返回值总 token ≤ max_tokens(标记不是免费的,测试锁死); - 分页无缝:
next_offset续读与上页正好衔接,无缺口无重叠(测试逐字节验证); - 翻页是 agent 的决策:harness 不猜「它要不要看更多」,只把 next_offset 递到它手里——把猜测变成决策,是给 agent 的 API 与给人的 API 的共同美德。
3. 省略必须显式:谎报案例
demo Part 3 的现场:一篇「前 1/4 说推荐、结尾反转成不推荐」的调研文档——
- 无标记截断(L00 A3 的做法):窗口只见「……推荐进入下一阶段。(验证细节)」,没有任何迹象表明后面还有内容——「推荐」以最终结论的面目进了窗口。模型引用它不是幻觉,是被喂了半篇冒充的全篇;
- 显式标记(同样预算):尾部多一行
[⚠️ 已截断:省略 959 字(原文共 1114 字);续读 offset=155]——模型知道这是节选、知道还有多少、知道怎么拿全文;翻到末页即见反转。
这条铁律与 L02「压缩必须留审计」是同一条诚实纪律的两个现场,与课程十「没能看到 ≠ 没有变化」同宗:任何信息损失都必须显式、可见、可追溯。测试 test_every_omission_has_marker 按验收条款逐条锁死:凡内容变少,标记必在。
4. 错误也是返回值
40 行 traceback 在窗口里是 162 token 的纯租金——agent 不需要知道异常发生在第 88 行,它需要知道下一步怎么办。shape_error 的格式:⛔ 现象:细节;建议:动作(12 token)。这是 agent-ops L03 结构化降级在返回值维度的延伸:错误信息是给调用方(agent)的接口,不是给人的日志。同理,返回值 schema 该「结论在前、细节可选」——给 agent 的 API 设计与给人的同构。
5. 流派对比:肥工具结果的四种处理
| 流派 | 思路 | 取舍 |
|---|---|---|
| 全文直给 | 相信窗口装得下 | v4 现状:账本 75-95% 的租金就是它交的 |
| 固定截断无标记 | text[:N] |
免费;静默失忆最危险——谎报案例的凶器(L00 A3) |
| 显式省略 + 按需分页 | 标记三要素 + 翻页权给 agent | 本课选择:诚实、可深读;代价是 agent 要多一次决策 |
| 检索式返回 | 结果内 RAG:只回 query 命中段 | 精准省窗;但「命中」由检索质量决定——漏检即静默丢失,需与显式标记结合(练习 2) |
业界锚点:Anthropic 的 writing effective tools 系列(工具返回值分页/过滤/截断是一等设计题);Manus(文件即上下文:全文落盘、窗口留路径——本课引用板斧的完整形态);Claude Code 的 Read/Grep 工具(head_limit、offset/limit 分页、超长截断提示——你每天看到的 [省略 N 行] 就是这条铁律的产品化)。
6. 跑起来
cd harness-lessons/04_tool_shaping
python code.py # 教学反转 → 三板斧对比表 → 谎报案例 → 错误工程
7. 落地清单
| 文件 | 改动 |
|---|---|
src/research_assistant/tool_shaping.py |
新增:shape_result(截断+显式标记,预算含标记)/ paginate(无缝翻页)/ reference(无损外置+指针)/ shape_error(可行动短错误) |
src/research_assistant/nodes.py |
researcher 在开关下对检索结果过 shape_result(纯截断无文件副作用;关态 prompt 逐字节不变) |
src/research_assistant/config.py |
enable_tool_shaping(默认 off)、tool_result_max_tokens=600 |
tests/test_tool_shaping.py |
新增 14 测试(省略必显式逐条版/预算含标记/分页无缝/引用无损/错误格式/researcher 三态) |
验收
cd portfolio-projects/research-assistant
python -m pytest tests/test_tool_shaping.py -q # 14 passed
python -m pytest -q # 401 passed(387 + 14)
cd ../../harness-lessons/04_tool_shaping && python code.py
8. 本课在两条主线上的位置
窗口经济:整形是「砍租金」——账本指认的最大租客在进门前瘦身,省略的每一字都明码标价(标记也占预算)。外置化:引用板斧是外置化的先声——全文无损落盘、窗口只留 48 token 的指针;L06 把落盘位置正规化成工作区。
🎯 面试话术
「窗口治理先控源后止损:账本显示工具结果占 75-95%,所以先整形再谈压缩。三板斧是截断、分页、引用——截断的铁律是省略必须显式:标记注明略了多少、原文多长、怎么拿全文,而且标记本身计入预算。为什么较真这个?我做过谎报实验:一篇结尾反转结论的文档被无标记截断后,『推荐』以最终结论的面目进了窗口——模型引用它不是幻觉,是被喂了半篇冒充的全篇。另外错误也是返回值:40 行堆栈是 162 token 的租金,可行动短错误 12 token——agent 要的不是第 88 行,是下一步怎么办。」