模型看到什么#

“上下文”就是随一次请求发送出去的消息列表。理解它就能解释大多数令人意外的行为:为什么某个轮次被遗忘了、压缩为什么改变了提示词,以及为什么 UI 里的记录会比模型收到的内容更长。

消息角色#

角色

含义

system

应用指令,每次请求都会重新构建。

user

用户文本,或按顺序排列的文本和图像。

assistant

模型的回答、它的推理,以及它请求的所有工具调用。

tool

通过 tool_call_id 与 assistant 调用相关联的结果。

agent

internal continuation;模型提供商会把它当作用户输入。

系统指令每次都会重建#

历史记录扩展恢复的是对话,不是提示词。指令会在每次请求时重新添加,因此修改系统提示词或工具会在下一个轮次生效,不会让过期指令越堆越多。

这也是 extensions=[] 会丢掉对话的原因:没有扩展恢复消息。参见保存并恢复对话。

记录与模型输入#

压缩之后两者会分岔,而两者都有用:

raw log      1  2  3  4  5  6  7  8      what the user saw
             └──── checkpoint ────┘
model input  [checkpoint]  6  7  8        what the model receives
  • 在 UI 中展示原始日志:await storage.list_raw_messages(session_id)。

  • 发送给模型的内容:最新的检查点,加上它之后的原始消息。

检查点会记录它覆盖到的最后一条原始消息,因此恢复从该位置之后开始,已摘要的消息不会被重复发送。

把模型上下文和展示用的历史记录分开#

你可以独立决定持久化哪些内容、回传给模型哪些内容。Message.persist=False 请求持久化订阅者不要存储某条消息,但不会把这条消息从当前请求中隐藏。include_in_messages=False 让某条消息不进入之后恢复的上下文,但不一定把它排除在原始记录之外。应用数据请放在消息属性里,不要把私有的路由信息写进提示词文本。

不要用拼接可见聊天气泡的方式重建模型提供商的上下文。即使 UI 把它们隐藏起来,工具调用和对应的工具结果依然是对话的一部分。恢复出来的上下文必须保留它们的 ID 和结构;持久化扩展会替你处理这种投影。参见保存并恢复对话。

上下文不够用时#

CompactionExtension 会监视请求的大小,一旦超过阈值,就把较早的轮次替换成一条摘要。

  • 最近的轮次会完整保留,包括其中的工具调用和工具结果。

  • 当前轮次绝不会被拆开,所以单个过大的轮次会原样保留。

  • 如果摘要并不比它替换掉的内容更小,那就什么都不改。

用 max_tokens 和 keep_recent_tokens 配置它,并观察 COMPACTION_* 事件。参见压缩而不丢失历史记录。