上下文工程的教科书都讲检索,但真实系统里污染上下文的重灾区有两个:检索回来的片段,和工具执行吐出来的输出。这篇讲两者的裁剪纪律。

RAG:不是检索到就塞进去

Chunk 策略服务于问题形态。 FAQ 类短问答用小 chunk(200–400 token)配高分片段;代码问答要按符号边界切(函数/类完整),宁可 chunk 大也不切断定义;手册类文档按标题层级切,保留层级路径作上下文头。万能 chunk 大小不存在,按查询模式定切法。

片段头部要有路标。 裸片段是上下文毒药:

❌ "…返回 403 表示权限不足,需要检查…"
✅ [OSS 文档/错误码#403] "…返回 403 表示权限不足,需要检查…"

带出处的片段让模型能正确区分"来源不同、说法冲突"的情况,也让回答可溯源。

预算化注入。 给检索设 token 预算(比如总上下文的 25%),按相关度分数装满即止。重排(rerank)值得投入:召回 50 条、精排取 8 条,比召回 8 条直接用,质量通常高一档——粗召回解决"找得到",精排解决"排得对"。

没被引用的片段是负资产。 回顾性统计哪些片段实际被答案引用了,长期不被引用的来源要么质量差要么切法不对。RAG 不是建完就完,引用率是它的核心运营指标。

工具输出:最大的隐形炸弹

Agent 调 kubectl get pods、cat 大文件、ls 巨型目录,输出动辄几千 token,而其中模型需要的可能只有 20 token。不裁剪的后果不只是贵——噪音会稀释真正相关的信息,直接降低后续推理质量。

我的裁剪三板斧,按顺序考虑:

1. 命令层面:让输出天生就小

kubectl get pods -o custom-columns=NAME:.metadata.name,STATUS:.status.phase
jq '.[] | {name, status}' data.json        # 而不是 cat data.json
git log --oneline -20                       # 而不是 git log

2. 通用裁剪:head / tail / 上下文窗口

command | head -100
command | tail -50
command | grep -C 5 "ERROR" | head -80

对已知结构的输出(日志、列表),head+grep 的组合几乎总是正确的第一刀。

3. 结构化提取:最后的手段才是全文

curl -s api | jq '{code: .status, msg: .message}'

原则:工具输出是给模型看的报表,不是给终端看的瀑布流。 包装工具时就把裁剪内建进去——一个设计良好的 Agent 工具,签名里应该有 max_lines / filter 这类参数。

一个真实例子

诊断"服务 503"时,原始做法把 3000 行日志塞进上下文,模型在噪音里打转。裁剪后:

journalctl -u api --since "1h" -p err | head -100

12 行错误日志,根因一眼可见。信息密度比信息量值钱得多。

小结

上下文的守门人不只在检索层,在每个工具调用的出口。纪律一句话:进入上下文的每一行,都要为它占的 token 负责。