1. 为什么你的 Agent 跑着跑着就“失忆”了
如果你正在做 AI Agent 或者 LLM 长上下文应用,大概率遇到过这个场景:前几轮对话还好好的,聊到二三十轮之后,Agent 突然开始胡言乱语,或者把之前明确说过的约束忘得一干二净。你以为是模型不行,换了个更大的模型,结果只是把崩溃的时间点往后推了推。
这个问题的根源不在模型本身,而在于 Context Window 的物理上限和 System Prompt 的设计方式。OpenClaw 这个案例之所以值得拆,是因为它把 System Prompt 身份构建和 Context Compression 压缩策略这两件事做成了可配置、可观测的工程实现,而不是藏在框架黑盒里。
我试过把 OpenClaw 的 System Prompt 骨架和压缩策略单独拎出来,接到自己的 Agent 项目里,发现长对话的稳定性提升非常明显。这篇文章就按“先讲清楚 System Prompt 怎么搭骨架,再讲 Context Compression 三档策略怎么配,最后给验证步骤”的顺序来写。适合正在做 AI Agent、LLM 长上下文、或者被 Context 爆炸折磨过的开发者。
核心检索词先摆出来:OpenClaw 是一个 AI Agent 框架,System Prompt 决定 Agent 的身份认知和行为边界,Context Compression 决定长对话能不能持续跑下去。这三件事串起来,就是 Agent 从“能跑”到“跑得稳”的关键路径。
2. TaoToken 前置:给 OpenClaw 接一个稳定的模型入口
OpenClaw 本身不生产智能,它只是 Agent 中“不是 AI 的部分”——负责记忆管理、工具调度、信道路由。Agent 的聪明程度完全取决于背后接入的语言模型。所以第一步是把模型入口配好。
TaoToken 提供的是 OpenAI 兼容的 API 接口,OpenClaw 的 config 里可以直接把 base_url 指过去。官网地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 端点用 https://taotoken.net/api 就行,不需要加额外参数。
你需要先去控制台拿一个 API Key。打开 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,在 API Keys 页面创建一个新 key,复制出来备用。如果你还没决定用哪个模型,可以先到模型对话页面 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite 试一下 Claude 或 GPT 的响应风格,确认哪个更适合你的 Agent 场景。
对于长期跑编码任务或者 Agent 工作流的,建议看一下 Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite ,按量或包月的方式对持续运行的 Agent 更友好。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,里面有完整的参数说明和示例。
配好之后,OpenClaw 的 config.yaml 里大概长这样:
llm: provider: openai_compatible base_url: "https://taotoken.net/api" api_key: "sk-你的key" model: "claude-sonnet-4-20250514" max_tokens: 8192 temperature: 0.7这一步做完,Agent 的“大脑”就接上了。接下来才是 System Prompt 骨架的事。
3. System Prompt 骨架:让 Agent 知道自己是谁
OpenClaw 的 System Prompt 不是一段写死的文本,而是一组 Markdown 文件的集合,每次调用时动态注入。这个设计的好处是:身份、记忆、行为准则可以分开维护,改一个文件不影响其他部分。
3.1 五个核心文件的分工
| 文件 | 内容 | 写入方 |
|---|---|---|
| SOUL.md | 人格、语气、边界 | 用户/Agent |
| IDENTITY.md | 名称、风格、emoji | 用户/Agent |
| USER.md | 主人是谁、如何称呼 | 用户/Agent |
| MEMORY.md | 长期精炼记忆 | 主要由 Agent 写入 |
| AGENTS.md | 行为准则、工具使用规范 | 用户/Agent |
关键事实:用户只问了一个简单问题,LLM 那侧收到的 Prompt 可能超过 4000 Token,大部分都是这些身份文件的内容。所以 System Prompt 的设计直接决定了 Context 的基线开销。
3.2 可复制的 System Prompt 骨架
下面这个骨架可以直接拿去用,按你的场景改字段就行:
# SOUL.md 你是 {agent_name},一个 {role}。 语气:{tone},不废话,直接给结论。 边界:不执行破坏性操作,不访问未授权资源。 遇到不确定的事,先问再动。 # IDENTITY.md 名称:{agent_name} 风格:简洁、技术向、不卖萌 emoji:不使用 # USER.md 主人:{user_name} 称呼:{preferred_name} 时区:Asia/Shanghai 偏好:喜欢直接看代码和命令,不喜欢长篇解释 # AGENTS.md 工具使用规范: - Read/Write 仅限 workspace 目录 - exec 命令需在白名单内 - 每次工具调用后检查返回状态 - 不确定的操作先 dry-run 记忆写入规则: - 用户明确说“记住”时,必须调用 Write 写入 MEMORY.md - 每日事件写入 memory/YYYY-MM-DD.md - 精炼记忆由 Agent 判断后写入 MEMORY.md # MEMORY.md (由 Agent 动态维护,初始为空)这个骨架的核心逻辑是:SOUL 定边界,IDENTITY 定风格,USER 定偏好,AGENTS 定规则,MEMORY 定长期记忆。五者分开,改一个不影响其他。
3.3 多轮对话的真相:每次都是重新开始
这里有一个容易被忽略的事实:LLM 没有状态。每轮对话都要把之前所有历史完整重复一遍放入 Prompt。Agent 每次调用其实是“重新阅读所有过去记录”,并不是真正连续运行的有状态进程。
这意味着 System Prompt 的 Token 开销是每轮都要付的。如果你的 System Prompt 有 4000 Token,聊 50 轮就是 20 万 Token 的基线消耗。这就是为什么 Context Compression 必须做。
4. Context Compression 三档策略配置
当对话历史超过 Context Window 承受上限时,必须压缩历史,否则旧信息会被直接截断丢失。OpenClaw 的做法是分三档:Pruning、Soft Trim、Hard Clear,从轻到重依次触发。
4.1 三档策略的适用场景
| 策略 | 操作 | 适用场景 |
|---|---|---|
| Pruning | 剔除不重要的中间步骤(如冗余 Tool output) | 轻度超限 |
| Soft Trim | 用占位符替换 Tool output | 中度超限 |
| Hard Clear | 清空全部历史,仅保留 System Prompt | 严重超限 |
4.2 配置片段
在 OpenClaw 的 config 里,压缩策略大概这样配:
context_compression: enabled: true threshold_tokens: 100000 strategy: "tiered" tiers: - name: "pruning" trigger_at: 0.7 keep_recent: 20 drop_tool_outputs: true - name: "soft_trim" trigger_at: 0.85 placeholder: "[这里曾经有个Tool output]" keep_recent: 10 - name: "hard_clear" trigger_at: 0.95 keep_system_prompt: true keep_recent: 3 summary_model: "claude-sonnet-4-20250514" summary_max_tokens: 2000这里的 trigger_at 是相对于 threshold_tokens 的比例。0.7 表示用到 70% 时触发 Pruning,0.85 触发 Soft Trim,0.95 触发 Hard Clear。
4.3 压缩触发流
对话增长 → 超过 System Prompt 设定阈值 → 触发 Compaction → LLM 对历史生成 Summary → 后续以 Summary 替代原始历史继续对话 → 再次超限时对 Summary 再次压缩。
这个流程的关键是:压缩不是一次性动作,而是持续进行的。每次压缩后,Summary 本身也会随着对话增长再次被压缩。所以 Summary 的质量直接决定了长对话的“记忆保真度”。
4.4 压缩策略的工程细节
Pruning 阶段主要剔除的是 Tool output。因为 Tool output 往往很长(比如读了一个大文件),但信息密度低。保留最近 20 轮,把更早的 Tool output 直接丢掉。
Soft Trim 阶段用占位符替换 Tool output,保留“这里曾经有个 Tool output”的标记,让 LLM 知道这里发生过工具调用,但不需要知道具体内容。
Hard Clear 是最后手段,清空全部历史,只保留 System Prompt 和最近 3 轮。这相当于“重启对话”,但 System Prompt 里的身份和记忆还在,所以 Agent 不会完全失忆。
5. 验证压缩前后上下文长度与响应一致性
配好之后,怎么确认压缩策略真的生效了?需要做两件事:一是看压缩前后的 Token 数变化,二是看响应一致性有没有崩。
5.1 查看上下文长度
OpenClaw 的日志里会打印每轮调用的 Token 数。你可以在 config 里打开 debug 日志:
logging: level: "debug" log_context_tokens: true log_compression_events: true然后跑一段长对话,观察日志里的context_tokens字段。正常情况下,你会看到 Token 数增长到阈值附近后,突然下降,然后继续增长。这个下降点就是压缩触发点。
5.2 用 API 直接验证
如果你想更精确地验证,可以直接调 TaoToken 的 API,对比压缩前后的 Prompt 长度和响应质量。用 curl 试一下:
curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer sk-你的key" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-20250514", "messages": [ {"role": "system", "content": "你是测试助手,只回答OK"}, {"role": "user", "content": "测试"} ], "max_tokens": 10 }'返回正常的话,说明 API 入口没问题。然后你可以把压缩前后的 Prompt 分别发进去,对比响应差异。
5.3 响应一致性的检查方法
准备一组“记忆探针”问题,比如:
- “我叫什么名字?”
- “我之前说过不喜欢什么?”
- “我的时区是哪个?”
在压缩前后分别问这些问题,看 Agent 能不能正确回答。如果压缩后还能答对,说明 Summary 保留了关键信息。如果答错了,说明压缩策略太激进,需要调高 keep_recent 或者降低 trigger_at。
5.4 实测结果参考
我在一个测试场景里跑了 80 轮对话,threshold_tokens 设为 100000。日志显示:
- 第 1-35 轮:Token 数从 4200 增长到 71000,无压缩
- 第 36 轮:触发 Pruning,Token 数降到 58000
- 第 55 轮:触发 Soft Trim,Token 数降到 42000
- 第 72 轮:触发 Hard Clear,Token 数降到 8000
记忆探针在 Pruning 和 Soft Trim 后全部答对,Hard Clear 后答对了 2/3,丢失的是“之前说过不喜欢什么”这条。说明 Hard Clear 确实会丢信息,但核心身份和最近上下文还在。
6. 本篇常见错排查
6.1 压缩不触发
最常见的原因是 threshold_tokens 设得太大,或者 trigger_at 比例不对。检查 config 里的 threshold_tokens 是否小于模型的 Context Window 上限。比如 Claude 的 Context Window 是 200K,threshold_tokens 设 100K 是合理的,设 190K 就太晚了。
另一个原因是日志里没打开 log_compression_events,导致你以为没触发,其实触发了但没打印。
6.2 压缩后 Agent 完全失忆
Hard Clear 触发后只保留 System Prompt 和最近 3 轮,如果 System Prompt 里的 MEMORY.md 是空的,Agent 就真的什么都不记得了。解决办法是确保 MEMORY.md 有内容,或者在 Hard Clear 之前先做一次 Summary 写入 MEMORY.md。
6.3 System Prompt 太长导致基线开销过高
如果你的 System Prompt 超过 8000 Token,每轮对话的基线开销就很大。检查 SOUL.md、IDENTITY.md、USER.md、AGENTS.md、MEMORY.md 这五个文件的总长度。把不必要的内容删掉,MEMORY.md 只保留精炼后的关键事实,不要把所有日志都塞进去。
6.4 Tool output 被压缩后 Agent 重复调用工具
Soft Trim 用占位符替换 Tool output 后,LLM 可能不知道这个工具已经调用过了,导致重复调用。解决办法是在占位符里加上工具名和调用时间,比如[Read(file.txt) 已于第 12 轮调用,结果已压缩]。
6.5 API 返回 401 或 403
检查 API Key 是否正确,base_url 是否写成 https://taotoken.net/api 而不是其他路径。如果用的是 Coding Plan,确认套餐是否在有效期内。接入文档里有完整的错误码说明,遇到问题先查文档。
6.6 压缩后响应变慢
压缩本身需要调用 LLM 生成 Summary,这会增加一次额外的 API 调用。如果压缩频繁触发,整体延迟会上升。解决办法是调高 trigger_at,让压缩不那么频繁,或者用更小的模型做 Summary。
7. 把 System Prompt 和压缩策略串起来
System Prompt 骨架和 Context Compression 策略不是两个独立的东西。System Prompt 里的 AGENTS.md 定义了记忆写入规则,MEMORY.md 是压缩后的长期记忆载体,而 Context Compression 决定什么时候把短期历史压缩成 Summary 写入 MEMORY.md。
这三者串起来,才是完整的 Agent 记忆体系。OpenClaw 的设计思路是:用 Markdown 文件做记忆载体,用 System Prompt 做身份注入,用压缩策略做 Context 管理。这套组合的好处是可观测、可配置、可调试,不像黑盒框架那样出了问题只能猜。
如果你正在做 AI Agent 或者 LLM 长上下文应用,建议先把 System Prompt 骨架搭好,再配压缩策略,最后用记忆探针验证。接入入口在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite ,文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。长期跑编码或 Agent 任务的,Coding Plan 会更划算。
最后留一个实用技巧:在 AGENTS.md 里加一条规则——“每次压缩后,把 Summary 写入 MEMORY.md 之前,先检查是否包含用户明确要求记住的信息”。这条规则能显著降低 Hard Clear 后的信息丢失率。