长任务越聊越贵、越聊越笨?用三层记忆把上下文成本降下来
长任务越聊越贵、越聊越笨?用三层记忆把上下文成本降下来
你以为把全部聊天记录塞给模型最保险,实际可能是在花更多的钱,让模型从一堆过期要求里猜哪条才有效。
这种问题在连续修改代码、撰写研究报告、运营数据分析等长任务中尤其明显:前几轮模型反应很快,到了几十轮以后,输入越来越长、响应逐渐变慢,甚至开始遗忘刚刚更新的要求。
假设每轮都重复发送 30,000 Token,连续调用 50 轮,仅输入侧就会累计:
方案 A:每轮携带 30,000 Token × 50 轮 = 1,500,000 输入 Token
方案 B:每轮携带 3,000 Token × 50 轮 = 150,000 输入 Token
完整计算可以写成:
总输入 Token ≈ Σ(第 i 轮携带的历史上下文 + 当前输入)
这只是为了便于理解的示例。实际费用还取决于模型定价、缓存策略、检索回填长度以及输出量。
问题的关键也不只是“Token 太多”。
上下文越长,不等于记忆越可靠。无关信息会稀释注意力,旧要求可能与新要求冲突,模型还要在大量历史中判断“现在到底听谁的”。真正可用的方案,不是粗暴删除历史,而是把记忆拆成三层:
1. 滚动摘要
2. 结构化状态表
3. 可追溯原文索引
目标不是把 Prompt 压到最短,而是做到三个词:低成本、可恢复、可审计。
为什么只做摘要,仍然可能把任务做坏
先看一个贯穿全文的可复现案例。
我们让 AI 在 30 轮内迭代一个 Python 数据分析工具,要求:
- 使用 Python 3.11
- 运行内存低于 512 MB
- 不得修改原始 CSV
- 输出字段必须兼容旧版本
- 所有关键决策可以追溯
任务中又出现了三次需求变化:
- 第 3 轮:输出 CSV
- 第 12 轮:改为同时输出 CSV 和 JSON
- 第 19 轮:JSON 字段名必须兼容 v2 接口
如果只让模型不断改写一段自然语言摘要,它很可能最终得到这样的内容:
工具需要输出 CSV 和 JSON,并注意兼容性与数据安全。
看起来没有错,实际上最关键的内容已经被磨平了:
- “数据安全”不等于“不得修改原始 CSV”
- “注意兼容性”没有说明必须兼容
v2 - 没有记录第 19 轮覆盖了哪条旧要求
- 无法找到原始指令进行核对
一旦后续代码直接覆盖源文件,或者继续使用旧版 JSON 字段,任务就会验收失败。
摘要擅长帮助模型理解大局,却不适合充当事实数据库。
这正是三层记忆存在的原因:不是简单删掉历史,而是给历史分级。
三层记忆分别保存什么
第一层:滚动摘要,回答“我们一路做了什么”
滚动摘要用于快速恢复任务语境,通常包括:
- 任务背景
- 当前阶段
- 已完成工作
- 阶段性结论
- 下一步计划
- 尚未解决的问题
它应该是一份不断重写的“项目简报”,而不是在末尾无限追加的新日记。
摘要内容还应明确区分:
- 事实:已经确认的信息
- 决定:已经生效的选择
- 推测:尚未验证的判断
否则,一句“可能是内存占用导致失败”,经过多轮压缩后,很容易变成“失败原因是内存不足”。这就是典型的摘要漂移。
第二层:结构化状态表,回答“现在准确处于什么状态”
状态表是当前任务的权威状态,适合使用 JSON、YAML 或数据库字段保存。
{
"task_id": "analytics_tool_001",
"goal": "完成可运行的数据分析工具",
"status": "implementation",
"constraints": {
"python_version": "3.11",
"memory_limit_mb": 512,
"modify_source_csv": false
},
"deliverables": ["CSV", "JSON"],
"interface_version": "v2",
"completed": [
"确定输入格式",
"完成数据清洗模块"
],
"open_issues": [
{
"id": "issue_07",
"description": "JSON 时间字段格式尚未确认",
"status": "pending",
"source_message_id": "msg_019"
}
],
"latest_instruction_id": "msg_019",
"state_version": 8
}
这里有三个字段尤其重要。
source_message_id:指向要求的原始出处,避免模型凭印象解释。state_version:标记状态版本,便于检测并发覆盖与错误更新。- 明确的数据类型:
false、512、["CSV", "JSON"]比自然语言更不容易产生歧义。
为了保存需求覆盖关系,还可以单独记录:
{
"current_requirement": "JSON 字段必须兼容 v2 接口",
"supersedes": "msg_012",
"source_message_id": "msg_019"
}
这样系统知道第 19 轮是当前有效要求,而不是把第 3、12、19 轮的指令混在一起。
配图 1:三层记忆架构图
当前请求 → 读取滚动摘要与状态表 → 检索相关原文 → 组装 Prompt → 调用模型 → 更新状态、原文与摘要。
第三层:原文索引,回答“这项结论从哪里来”
原文索引不必把全部内容重复放进 Prompt,只需要保存定位信息与检索标签。
{
"document_id": "conversation_001",
"message_id": "msg_019",
"timestamp": "2025-03-08T10:30:00+08:00",
"type": "requirement_change",
"tags": ["json", "interface-v2", "output-format"],
"summary": "用户要求 JSON 字段兼容 v2 接口",
"storage_path": "messages/conversation_001/msg_019.json",
"content_hash": "sha256:..."
}
其中的 summary 只负责帮助检索。真正引用或执行前,系统应回到 storage_path 对应的原始内容进行核对。
content_hash 则可以帮助判断原文是否被意外修改。
三层记忆的关系可以概括为:
- 摘要回答:我们一路做了什么?
- 状态表回答:现在准确处于什么状态?
- 原文索引回答:结论从哪里来,能否找回原话?
哪些内容绝对不能做有损压缩
“不能压缩”不代表每轮都要发送完整原文,而是必须在权威存储中逐字、逐字段保留,需要时精确回填。
以下七类内容尤其危险。
1. 硬约束与验收标准
预算上限、截止日期、输出格式、禁止事项、性能指标和合规要求。
2. 关键参数与唯一标识
金额、日期、版本号、订单号、文件路径、接口字段、数据库主键和模型参数。
3. 最新有效指令与覆盖关系
用户修改了什么要求,哪条新指令替代了哪条旧指令。
4. 代码、配置与错误现场
完整报错、堆栈、日志、配置文件和复现步骤,不能只写成“程序运行失败”。
5. 证据与引用原文
合同条款、政策内容、论文结论、客户原话及出处,不能依赖模型二次转述。
6. 不可逆操作信息
付款、删除、发布、生产环境变更的对象、范围、权限和确认记录。
7. 尚未解决的分歧与不确定性
不能把“可能”“待确认”“存在争议”压缩成确定事实。
一个非常实用的判断方法是:
如果某个细节被改错后,会导致任务无法验收、无法追责、无法复现,或者造成不可逆损失,就不能只保留自然语言摘要。
例如,把“不得修改原始 CSV”压缩为“注意数据安全”,看起来只少了几个字,实际上丢失的是一个可以直接判断真假的硬约束。
配图 2:错误案例截图
左侧展示原始要求“不得修改原始 CSV”,右侧展示摘要“注意数据安全”,下方标出模型随后使用覆盖写入模式。截图需隐藏 API Key、用户隐私和真实业务数据。
从零搭建一套可运行的分层记忆流程
每轮请求开始前,系统只需要完成四件事:
1. 读取当前状态表
2. 附上短摘要
3. 根据本轮目标检索相关原文
4. 将三者与当前请求组装成 Prompt
伪代码如下:
def build_context(task, user_message):
state = load_current_state(task.id)
summary = load_rolling_summary(task.id)
query = create_retrieval_query(
current_goal=state["goal"],
open_issues=state["open_issues"],
user_message=user_message
)
source_chunks = retrieve_source_text(
task_id=task.id,
query=query,
top_k=5
)
return {
"summary": summary,
"authoritative_state": state,
"retrieved_sources": source_chunks,
"current_user_message": user_message
}
模型返回结果后,不要让它自行把所有历史重新揉成一段话,而应分别更新三层记忆:
response = call_model(build_context(task, user_message))
append_raw_message(user_message, response)
state_patch = extract_state_patch(response)
validate_state_patch(state_patch)
update_state(state_patch)
if should_refresh_summary():
rewrite_summary_from_state_and_recent_messages()
这里最重要的一条工程原则是:
不要允许模型自由改写整个状态表,最好只让它提交 Patch,再由程序验证并更新。
例如,模型可以提交:
{
"deliverables": ["CSV", "JSON"],
"interface_version": "v2",
"latest_instruction_id": "msg_019"
}
程序随后检查:
deliverables是否为数组interface_version是否属于允许的枚举latest_instruction_id对应的消息是否存在- 当前
state_version是否仍是预期版本 - 修改是否触碰不可变字段
摘要生成器只能读取状态,不能绕过校验直接覆盖权威数据。
小白版:先用三个文件跑起来
不要一开始就部署复杂 Agent 平台或向量数据库。最简单的目录结构已经足够验证方案:
memory/
├── state.json
├── summary.md
├── source_index.jsonl
└── messages/
├── msg_001.json
├── msg_002.json
└── msg_019.json
检索初期甚至可以只使用关键词、消息类型和标签,不必马上引入向量搜索。
进阶版:加入检索、版本与自动校验
任务规模扩大后,再逐步增加:
- 数据库状态表
- 关键词与向量混合检索
- 乐观锁或版本号校验
- 原文哈希验证
- 状态变更日志
- 自动化 Schema 校验
- 状态回滚机制
配图 3:状态表前后对比截图
展示第 12 轮前后的deliverables变化,以及第 19 轮新增的interface_version、supersedes和source_message_id。
配图 4:调试日志截图
标出本轮实际发送的摘要长度、状态字段、检索到的消息 ID 和原文片段。所有内部地址与敏感字段应脱敏。
想验证分层记忆到底能节省多少 Token,可以把完整历史、仅摘要、三层记忆三套 Prompt 分别跑一遍,记录每轮输入量与约束遗漏情况。需要接入模型进行连续调用时,可前往 api.884819.xyz 查看 API 接入方式,并将示例中的模型调用部分替换为自己的接口配置。
怎么判断是真省钱,而不是“省 Token、丢任务”
只看输入长度,很容易得出错误结论。
如果一种方案减少了 Token,却导致版本号频繁出错、硬约束遗漏、最终任务无法验收,那么它不是优化,只是把成本从模型调用转移到了返工。
可以对同一项长任务运行三组测试:
- A 组:每轮发送完整历史
- B 组:只发送滚动摘要
- C 组:摘要、状态表与原文索引
分别观察第 5、20、50 轮,或按实际任务记录第 10、30、50 轮的数据。
建议至少统计:
- 累计输入 Token
- 单轮平均延迟
- 关键约束遗漏次数
- 数字与版本号错误次数
- 原文引用准确率
- 最终任务验收通过率
四种常见方案的特点如下:
| 方案 | 输入成本 | 精确信息保留 | 可追溯性 | 实现难度 | |---|---:|---:|---:|---:| | 完整历史 | 高 | 中高 | 高 | 低 | | 仅滚动摘要 | 低 | 低 | 低 | 低 | | 摘要 + 状态表 | 中低 | 高 | 中 | 中 | | 摘要 + 状态表 + 原文索引 | 中低 | 高 | 高 | 中高 |配图 5:上下文长度曲线图
横轴为对话轮数,纵轴为单轮输入 Token。完整历史随轮数近似线性增长,分层记忆保持在相对稳定区间,仅在需要核对证据时短暂上升。
注意,这张表描述的是方案特征,不代表任何任务都能得到相同幅度的节省。最终结果必须通过自己的任务、模型与检索策略实测。
今天就能执行的三步清单
如果你准备把分层记忆加入现有项目,正确顺序不是先搭向量数据库,而是:
1. 列出不可压缩字段
找出硬约束、数字、版本、唯一标识、证据与不可逆操作信息。
2. 建立权威状态表
用固定 Schema 保存当前有效状态,并记录版本与来源。
3. 最后增加摘要和原文检索
摘要负责恢复语境,索引负责按需找回证据。
最佳实践从来不是“永远不发送原文”,而是:
默认发送最小必要状态,需要时精确找回原文。
不要先相信任何“上下文可节省 90%”的结论,最可靠的方法是用自己的任务做 A/B 测试。复制本文的状态表与 Prompt 组装代码,通过 api.884819.xyz 接入模型,跑满 20~50 轮,再比较真实成本、召回率和最终验收结果。
8848AI 注册只需用户名和密码,无需邮箱验证;平台内置 AI 对话功能,注册后可直接使用。国产模型如 Deepseek、千问等完全免费,没有月租、没有订阅,其他模型按量付费。新用户注册即送体验token。
分层记忆解决了“该保存什么、该取回什么”,但还有一个更棘手的问题:检索出来的内容彼此冲突时,模型应该相信最新消息、状态表,还是原始文档?
下一篇,我们将拆解长任务中的记忆冲突处理与版本控制,并给出“新指令覆盖旧指令、事实不可被摘要覆盖、状态更新必须可回滚”的完整实现。
本文由8848AI原创,转载请注明出处。关注8848AI,带你从零开始学AI。#AI教程 #上下文管理 #Agent记忆 #Prompt工程 #人工智能 #Token优化 #8848AI