上下文太长,Pi 会留下什么
任务开始时,用户要求修改一个配置文件。Agent 随后读取两份长日志,又执行了几条诊断命令。
第三次请求模型时,如果把全部历史原样发送,可能超过上下文窗口;如果只保留最后几条工具输出,最初的修改目标又会消失。
Session 里保存的内容,和本次模型请求实际看到的内容,不是一份东西。
一次运行有三份消息
Section titled “一次运行有三份消息”理解 Pi 的上下文处理,可以分开看三份数据:
-
Session 记录
保存历史、分支、模型变化和 compaction 条目。 -
Loop 工作消息
当前运行处理的AgentMessage[],可以包含产品自定义消息。 -
Provider Context
一次模型调用实际收到的 system prompt、messages 与 tools。
transformContext 在每轮模型调用前处理工作消息,convertToLlm 再把它们转换成 Provider 接受的格式。相关接口位于 packages/agent/src/types.ts,调用位置在 agent-loop.ts。
同一份 Session 在不同 turn 可以投影出不同大小的模型输入。摘要、移除旧工具输出、注入最新工作区状态,都发生在这一步。
截断要照顾消息关系
Section titled “截断要照顾消息关系”简单删除最旧消息会破坏几类关系:
- user 任务被删掉,后面的回答失去目标;
- tool call 留下了,配对的 tool result 被删掉;
- 文件证据被移除,摘要仍然引用它;
- 截断点落在一次多工具调用中间。
Pi 的 compaction 会结合 Provider usage、尾部消息估算、预留 token 和安全切点生成摘要。查看固定版本的 compaction 实现。
摘要随后作为新的 Session entry 追加,不会悄悄覆盖原历史。查看 Session 如何投影压缩后的上下文。
当前产品层的 AgentSession 已经包含自动压缩。新的 AgentHarness 提供手动 compact(),自动触发仍在待办列表里。查看 AgentHarness 的进度说明。
先做一个可观察的裁剪
Section titled “先做一个可观察的裁剪”my-pi-agent 的 keepRecentContext(maxUnits) 会保留最初任务和最近一组消息,并在发生裁剪时写入 context_compacted 事件。它不调用模型生成摘要,这样结果完全确定。
运行实验:
cd agent-harness-labnpm run lab -- 05预期输出:
{ "terminal": "completed", "compactions": 1, "modelInputSizes": [1, 3, 3]}三次模型调用的输入长度没有一直增长,第三次请求前发生了一次显式变换。Trace 同时记录了这次变化,调试时可以回答“为什么模型突然看不到某段旧结果”。
这个 Lab 使用确定性字符预算,不是准确 tokenizer,也没有处理图片和复杂工具批次。它只验证一件事:送往模型的 Context 是从历史计算出来的视图,不等于完整历史。
摘要还应该保留什么
Section titled “摘要还应该保留什么”Coding Agent 的摘要如果只写“我们讨论了若干文件并接近完成”,恢复价值很低。更稳的做法是额外保存结构化 evidence:
current_goalfiles_readfiles_changedlast_test_resultunresolved_itemsactive_tool_policy这些字段不替代自然语言摘要,但能防止“换了一个工具名就丢失文件轨迹”一类脆弱实现。
Provider Context 只服务下一次请求。进程关闭后能否回来,要看 Session 是否持久化,也要看运行中的队列和副作用有没有留下记录。下一章处理这两个问题。