Engineering note
记忆、会话与上下文窗口:哪些信息应该留下
这是「Agent 工程实战」的第 13 篇。专题从一个能聊天、能调工具的 .NET Agent 出发,逐步补齐可靠性、安全、测试与发布能力。
本篇要解决的问题: 从会话持久化、并发控制到上下文预算,建立可控的“记忆”。
本章定位:本章讨论 Agent 的记忆从哪里来、什么时候该删、怎样摘要,以及为什么上下文窗口应该被当成预算。
建议阅读方式:先通读原理,再对照当前项目源码,最后完成本章实践。先把进程内消息列表管理好,再引入数据库和长期记忆。过早堆存储技术,往往掩盖不了上下文策略缺失。
本章导读
本章讨论 Agent 的记忆从哪里来、什么时候该删、怎样摘要,以及为什么上下文窗口应该被当成预算。
本章采用“源码观察 → 概念拆解 → 工程改造 → 实践验证”的顺序。示例中的接口和代码骨架用于说明设计方向,真正提交代码时应结合项目当前状态逐步落地。
13.1 当前的记忆是什么
当前 _messages 是进程内列表:程序退出即丢失,且所有消息都不断追加。这适合演示多轮对话,不适合长期使用。
13.2 会话对象
建议将消息列表放入会话:
public sealed class AgentSession
{
public string Id { get; init; } = Guid.NewGuid().ToString("N");
public DateTimeOffset CreatedAt { get; init; } = DateTimeOffset.UtcNow;
public List<Message> Messages { get; } = [];
}
后续可以把会话持久化到 JSON、SQLite 或数据库。
13.3 上下文压缩
上下文窗口有限,不能无限追加。常见策略:
- 保留 system 消息;
- 保留最近若干轮;
- 把旧消息摘要化;
- 工具输出截断并保存原文引用;
- 把稳定用户偏好写入单独的长期记忆。
摘要不是越多越好。必须记录摘要的来源、时间和可能的失真,关键事实应支持重新检索原文。
13.4 本章交付物
- session ID;
- 会话保存与恢复;
- 消息长度统计;
- 摘要策略;
- 工具输出截断策略。
13.5 短期记忆与长期记忆
短期记忆是当前会话中的消息,回答“这轮对话发生了什么”;长期记忆是跨会话保存的用户偏好或事实,回答“以前知道什么”。两者不应混在同一个 _messages 列表里。
例如用户说“我偏好使用中文”,可以保存成一条带来源和时间的偏好记录;但不能把所有历史聊天原文都永久塞进 system message。
13.6 上下文预算
上下文窗口应该被当成一种预算:
system 指令预算
+ 用户问题预算
+ 工具 schema 预算
+ 历史消息预算
+ 工具结果预算
+ 输出预算
<= 模型上下文上限
工具 schema 也会占用上下文。工具数量增加后,不能无限把所有工具都发给模型,可以按任务类型筛选工具。
13.7 工具结果的引用化
读取大型文件时,不要把全部内容放进会话。可以把内容保存到临时 artifact,工具结果只返回摘要、路径、大小和片段:
{
"success": true,
"data": {
"artifactId": "file-123",
"path": "Agent/ModelHandle.cs",
"preview": "前 2000 个字符"
}
}
模型需要更多内容时,再调用带范围的读取工具。这种设计同时改善成本、速度和安全性。
13.8 会话并发
同一会话不能同时被两个请求无序修改。至少要有版本号或锁:
读取 session version = 7
执行一轮
只有 version 仍为 7 才能提交 version = 8
Web 化后,这个问题会从“偶尔显示错乱”变成真实的数据一致性问题。
13.9 练习:实现上下文预算报告
在发送模型请求前统计 system、历史、工具定义和待发送问题的字符数,打印一个脱敏报告。先观察哪部分增长最快,再决定摘要和截断策略。
13.10 本章产出
本章结束时,Agent 应该知道自己记住了什么、忘记了什么、为什么裁剪上下文,以及一次请求占用了多少预算。
单篇实战作业
实践:增加上下文预算报告,分别统计 system、历史、工具 schema 和工具结果占用的字符数。
建议把作业拆成一个独立提交,并在提交说明中写清楚:改动前的行为、改动后的行为、验证命令、尚未解决的风险。先把进程内消息列表管理好,再引入数据库和长期记忆。过早堆存储技术,往往掩盖不了上下文策略缺失。
章节复盘
复盘问题:上下文被裁剪后,模型是否知道自己不知道什么?关键事实能否重新检索原文?
本章的完成标准不是把所有设计一次性做完,而是能把它变成项目中的一个明确边界,并为下一章留下可验证的接口。
下一篇:第 14 篇《日志、指标与可观测性:看见 Agent 到底做了什么》
如果你正在把 Agent 放进真实工作流,建议完成本篇的实战作业后再继续:每一步都应留下可验证的代码、测试或运行记录。