跳转到内容

上下文太长,Pi 会留下什么

任务开始时,用户要求修改一个配置文件。Agent 随后读取两份长日志,又执行了几条诊断命令。

第三次请求模型时,如果把全部历史原样发送,可能超过上下文窗口;如果只保留最后几条工具输出,最初的修改目标又会消失。

Session 里保存的内容,和本次模型请求实际看到的内容,不是一份东西。

理解 Pi 的上下文处理,可以分开看三份数据:

  1. Session 记录
    保存历史、分支、模型变化和 compaction 条目。

  2. Loop 工作消息
    当前运行处理的 AgentMessage[],可以包含产品自定义消息。

  3. Provider Context
    一次模型调用实际收到的 system prompt、messages 与 tools。

transformContext 在每轮模型调用前处理工作消息,convertToLlm 再把它们转换成 Provider 接受的格式。相关接口位于 packages/agent/src/types.ts,调用位置在 agent-loop.ts

同一份 Session 在不同 turn 可以投影出不同大小的模型输入。摘要、移除旧工具输出、注入最新工作区状态,都发生在这一步。

简单删除最旧消息会破坏几类关系:

  • user 任务被删掉,后面的回答失去目标;
  • tool call 留下了,配对的 tool result 被删掉;
  • 文件证据被移除,摘要仍然引用它;
  • 截断点落在一次多工具调用中间。

Pi 的 compaction 会结合 Provider usage、尾部消息估算、预留 token 和安全切点生成摘要。查看固定版本的 compaction 实现

摘要随后作为新的 Session entry 追加,不会悄悄覆盖原历史。查看 Session 如何投影压缩后的上下文

当前产品层的 AgentSession 已经包含自动压缩。新的 AgentHarness 提供手动 compact(),自动触发仍在待办列表里。查看 AgentHarness 的进度说明

my-pi-agentkeepRecentContext(maxUnits) 会保留最初任务和最近一组消息,并在发生裁剪时写入 context_compacted 事件。它不调用模型生成摘要,这样结果完全确定。

运行实验:

Terminal window
cd agent-harness-lab
npm run lab -- 05

预期输出:

{
"terminal": "completed",
"compactions": 1,
"modelInputSizes": [1, 3, 3]
}

三次模型调用的输入长度没有一直增长,第三次请求前发生了一次显式变换。Trace 同时记录了这次变化,调试时可以回答“为什么模型突然看不到某段旧结果”。

这个 Lab 使用确定性字符预算,不是准确 tokenizer,也没有处理图片和复杂工具批次。它只验证一件事:送往模型的 Context 是从历史计算出来的视图,不等于完整历史。

Coding Agent 的摘要如果只写“我们讨论了若干文件并接近完成”,恢复价值很低。更稳的做法是额外保存结构化 evidence:

current_goal
files_read
files_changed
last_test_result
unresolved_items
active_tool_policy

这些字段不替代自然语言摘要,但能防止“换了一个工具名就丢失文件轨迹”一类脆弱实现。

Provider Context 只服务下一次请求。进程关闭后能否回来,要看 Session 是否持久化,也要看运行中的队列和副作用有没有留下记录。下一章处理这两个问题。