ContextEngine 与五种记忆
上下文窗口满了怎么办:处理器链卸载大结果、压缩历史,超窗口时补救一次;跨会话的东西交给长期记忆。
依据 agent-core 0.1.20 · develop@fbe6a0d9(2026-11-13)核实
两个不同的问题
智能体要"记住东西",其实是两个问题:
| 问题 | 时间尺度 | 负责的模块 |
|---|---|---|
| 这一次对话太长,塞不进模型窗口 | 一个会话之内 | ContextEngine(上下文引擎) |
| 下次再来,还记得这个客户的偏好 | 跨会话 | 长期记忆 LongTermMemory |
上下文引擎:一条处理器链
ContextEngine 给每个会话建上下文,并在消息写入、模型调用前跑一串处理器(processor)来控制窗口大小。内置的处理器分两类:
| 类别 | 处理器 | 思路 |
|---|---|---|
| 卸载 | MessageOffloader、MessageSummaryOffloader、工具结果预算类 | 把大的旧消息换成"开头一小段 + 省略标记",原文另存,需要时再取回 |
| 压缩 | DialogueCompressor、RoundLevelCompressor、CurrentRoundCompressor、MicroCompactProcessor、FullCompactProcessor | 用摘要等方式压缩对话历史 |
在 ReActAgentConfig 上按名字配置处理器:
config.configure_context_processors([
("MessageOffloader", MessageOffloaderConfig(
tokens_threshold=20000, # 累计超过就触发(默认值)
large_message_threshold=1000, # 多大算"大消息"
trim_size=100, # 卸载后保留开头多少
offload_message_type=["tool"], # 只动工具结果(默认)
protected_tool_names=["read_file"], # 这些工具的结果永不卸载(默认)
keep_last_round=True, # 正在进行的这一轮不动(默认)
)),
])
示意代码,参数名和默认值取自 MessageOffloaderConfig;本站没有运行它。
两个容易误解的点:
keep_last_round保护的是"最后一次完整答复之后"的全部消息,也就是当前这张询单的所有工具结果。被卸载的只会是之前已经答完的轮次。- 保护名单是给"必须原文保留"的工具用的。 把大结果工具放进去,卸载器就无事可做。
超窗口之后:只补救一次
即使配了处理器,模型仍可能以"上下文超长"拒绝请求。ReActAgent 在 Rail 的重试用尽后,会请上下文引擎做一次补救:
- 看错误文本是不是上下文超长(源码里列了一组常见说法,比如 "context length"、"prompt is too long")
- 如果已经流式输出过内容,放弃(重试会重复推送)
- 主动压缩一次;确实压缩了才重试,否则保留原异常
长期记忆:五种类型
跨会话的记忆由 LongTermMemory 管理(进程内单例),按记忆空间(scope)隔离。记忆单元的类型枚举是:
| 类型 | 枚举值 | 直观理解 |
|---|---|---|
| 用户画像 | USER_PROFILE | 这个人是谁、有什么偏好 |
| 语义记忆 | SEMANTIC_MEMORY | 事实性知识 |
| 情景记忆 | EPISODIC_MEMORY | 发生过的具体事情 |
| 变量 | VARIABLE | 结构化的键值 |
| 摘要 | SUMMARY | 历史对话的摘要 |
常用入口:add_messages 写入对话、search_user_mem 检索用户记忆、search_user_history_summary 检索历史摘要、get_variables / update_variables 读写变量。智能体侧用 ReActAgentConfig.configure_mem_scope(...) 指定记忆空间。
openJiuwen 还有独立的 agent-memory 仓库,园区地图上留了"规划中"的地块,等它的内容核实后再上线。本关只讲 agent-core 里的记忆接口。
动手:别让窗口撑爆
小结
- 会话内的窗口问题交给
ContextEngine的处理器链:先卸载大的旧工具结果,再考虑压缩。 - 超窗口后的补救只有一次,而且流式输出开始后不补救,别把它当主要手段。
- 跨会话的记忆用
LongTermMemory,五种类型对应画像、知识、经历、变量和摘要。
源码出处
- agent-core/openjiuwen/core/context_engine/context_engine.py:28
class ContextEngine上下文引擎 - agent-core/openjiuwen/core/context_engine/processor/offloader/message_offloader.py:22
class MessageOffloaderConfig卸载器的阈值与保护规则 - agent-core/openjiuwen/core/context_engine/processor/offloader/message_offloader.py:206
def _get_offload_rangekeep_last_round 保护到哪里 - agent-core/openjiuwen/core/context_engine/context_engine.py:426
async def recover_from_model_exception超窗口后的一次补救 - agent-core/openjiuwen/core/memory/manage/mem_model/memory_unit.py:9
class MemoryType记忆类型枚举 - agent-core/openjiuwen/core/memory/long_term_memory.py:69
class LongTermMemory长期记忆入口 - agent-core/openjiuwen/core/memory/long_term_memory.py:965
async def search_user_mem检索用户记忆
链接指向固定提交,仓库后续更新不影响这里的行号。
过关测验
1. MessageOffloader 默认会卸载哪种消息?
2. keep_last_round=True 时,哪些消息一定不会被卸载?
3. 流式输出已经推送了几个字,模型才报上下文超长。框架会怎么做?