“为什么我的上下文越长,答案反而越离谱?”
如果你也在深夜对着 128k 窗口的 GPT-4 怀疑人生,这篇文章就是写给正在抠头的你。


故事从一次“奖励黑客”调研开始

上周,老板甩给我一个看似人畜无害的需求:
“整理一下 RLHF 里所有奖励黑客(reward hacking)的玩法,明天分享。”
我反手把 200 页论文塞进 Claude,结果——

  • 前半段总结得头头是道;
  • 后半段开始胡编“比特币挖矿能缓解奖励黑客”;
  • Token 账单 25k,信用卡先哭了。

这就是 Drew Breunig 说的 Context Rot

当上下文像衣柜一样塞爆,模型找不到那件“正确答案”T 恤,只能随手抓一条“幻觉”内裤套头上。


Context 为什么会“腐烂”?4 种典型死法

死法 现场目击
Context Poisoning 早期检索到一篇错误博客,后面每轮回答都引用它,越错越自信。
Context Distraction 历史对话里 80% 是寒暄,模型把“你好”当成核心线索。
Context Confusion 同时塞入 GitHub 代码、维基百科、小红书段子,模型被迫“端水”。
Context Clash 两篇文章对“RLHF”定义打架,模型直接精神分裂。

6 个招式,手把手把上下文瘦成一道闪电

下面所有代码都跑在 how_to_fix_your_context 这个官方仓库里,每一步都能复现
我用的是 Python 3.11 + uv,整个环境 30 秒就能搭好:

# 1. 一把梭克隆
git clone https://github.com/langchain-ai/how_to_fix_your_context
cd how_to_fix_your_context

# 2. uv 瞬建虚拟环境
uv venv && source .venv/bin/activate  # Windows 用 .venv\Scripts\activate

# 3. 依赖一次性装完
uv pip install -r requirements.txt

# 4. 把钥匙塞兜里
export OPENAI_API_KEY="sk-xxx"
export ANTHROPIC_API_KEY="sk-ant-xxx"

招式 ① RAG:别全文背诵,只带“小抄”进场

核心思想:先查再答,让模型只读“与问题强相关”的段落。
LangGraph 打法

  • 把 Lilian Weng 的 14 篇 RL 博文切成 512 token 的小块;
  • 用 OpenAI text-embedding-3-small 做向量;
  • Claude-3.5 Sonnet 当“阅卷老师”,先让用户澄清范围,再决定检索几轮。

结果:同样“奖励黑客”问题,Token 从 25k 降到 15k,幻觉率目测减半。
RAG 流程
图:RAG 节点图——澄清 → 检索 → 生成,三轮对话内解决。


招式 ② Tool Loadout:工具箱只带“今天用得上的扳手”

痛点:一次把 200 个数学函数全塞 system prompt,模型直接“选择困难”。
解法语义剪枝。把每个函数说明也 embedding 了,用户问“阶乘”只给乘、阶乘、伽马 3-5 个最相关工具。
代码 3 行搞定动态绑定

relevant_tools = vector_store.similarity_search(query, k=5)
graph.update_state({"tools": [tool_registry[t.id] for t in relevant_tools]})

好处

  • 工具描述不打架,调用准确率↑;
  • 每次 prompt 省 500-800 token,长线对话更明显。

招式 ③ Context Quarantine:让“数学宅”与“搜索狂”分居

场景:既要算积分,又要搜最新 ArXiv。
做法:Supervisor 节点当“项目经理”,把任务丢给只装计算器的 Math Agent 或只装浏览器的 Research Agent,两 agent 彼此不见面
LangGraph 的 Supervisor 架构代码像写 DAG 一样爽:

supervisor = Supervisor(agents=[math_agent, research_agent])
supervisor.add_edge("math_agent", END)   # 算完就收工
supervisor.add_edge("research_agent", END)

收益

  • 单 agent 上下文<4k,永远专注;
  • 再也不会把“∫x dx”算成“x 专利号 2025SB250”。

招式 ④ Context Pruning:让“小模型”当“编辑”,先砍废稿

流程

  1. 用 GPT-4o-mini 当“实习编辑”,把召回的 20k 文档先过一遍;
  2. 只保留和“奖励黑客”相关的句子,生成 3k “精华补丁”;
  3. 再送主模型深加工。

实测:同样回答质量,25k → 11k,成本直接腰斩。
提示词核心就一句人话:

“你是严谨编辑,请删除与‘奖励黑客’无关的段落,保留技术细节,输出 Markdown。”


招式 ⑤ Context Summarization:如果全是干货,就“脱水”而非丢弃

与 Pruning 的区别:

  • Pruning 是“扔菜叶”;
  • Summarization 是“把三碗浓汤熬成一碗”。

做法:把召回的 5 篇长文先用 GPT-4o-mini 压缩成 50-70% 长度,保留所有公式、引用,再去生成。
适合“每段都有用”的场景,比如法律、医疗。
Token 再省 30-40%,且关键数字零丢失。


招式 ⑥ Context Offloading:把“记忆”搬到硬盘,别全塞在脑子里

两种“外挂”

  1. Session Scratchpad:当前线程的“草稿纸”,随用随擦。

    def write_note(note: str) -> str:
        state.scratchpad += f"- {note}\n"
        return "已记录"
    
  2. Persistent Memory:跨线程的“笔记本”,存在 InMemoryStore 里,下次重启还能读。
    做 7×24 研究 agent 时,把“今日计划”“结论”写进去,第二天接着写,而不是把昨天 20k 记录再读一遍。

效果

  • 上下文长度恒定,跟对话轮数无关
  • 支持“多用户+多话题”隔离,命名空间一把钥匙开一把锁。

如何把这 6 招串成一套“组合拳”?

Step-by-Step 指南(How-To 风格,可直接抄):

  1. 先用 RAG 召回 → 拿到 20k 候选文档。
  2. 判断相关度

    • 若 <30% 可用 → Pruning 直接扔掉杂音;
    • 若大部分可用但啰嗦 → Summarization 脱水。
  3. 看任务类型

    • 需要算东西 → Quarantine 把计算代理单拎;
    • 需要查实时信息 → Tool Loadout 只给搜索工具。
  4. 全程用 Offloading 把中间结论写“草稿纸”,末尾再一次性读盘,生成最终报告。

一句话顺序
RAG → (Pruning|Summarization) → Quarantine → Tool Loadout → Offloading → Final Answer。


常见问题解答(FAQ)

Q1. 我只有 OpenAI key,能跑完所有 notebook 吗?
A:除了 Claude 节点需 Anthropic,其余全部可 OpenAI 平替。把 ChatAnthropic 换成 ChatOpenAI(model="gpt-4o") 即可。

Q2. 向量库必须用 Pinecone 这种云服务吗?
A:仓库默认 Chroma 内存版,零配置,10 万段文本秒内建成。上生产再考虑 Pinecone / Weaviate。

Q3. Pruning 和 Summarization 会不会丢失关键信息?
A:作者用“奖励黑客”问答对做了 100 次人工评测,事实召回率 96% vs baseline 94%,可放心食用。建议上线前做自己的 golden set 回归。

Q4. 我想在 Node 里加自定义逻辑,但不会写 LangGraph?
A:记住三句话——“节点纯函数,状态是可变字典,边写条件函数”。官方可视化 print(graph.get_graph().draw_mermaid()) 一键生成流程图,对着图 Debug 比 print 爽。


写在最后:上下文不是越大越好,而是“刚刚好”才最好

Karpathy 说,“Context Engineering 是新的 Prompt Engineering。”
当 128k、1M token 窗口成为营销口号,真正的工程师却在练减法

  • 减掉噪音,让信号更尖锐
  • 减掉幻觉,让事实更锋利
  • 减掉账单,让老板更开心

把这 6 招装进工具箱,下次再遇到“越长越离谱”的上下文,你会像外科医生一样下刀,而不是像仓鼠一样囤纸

现在,轮到你把仓库克隆下来,第一次运行就把 25k token 砍到 11k,然后回来告诉我:

“原来大模型不是失忆,是我没给它戴降噪耳机。”