Spring AI 2.0 Agent 进阶:Memory、State 与 Context Engineering 常见技术全景

在 Agent 中加入 ChatMemory 只是第一步。真正做长对话和长任务以后,很快会遇到更多问题:聊天太长导致 Token 爆炸,旧消息污染当前任务;服务重启后会话丢失;用户修改前面的消息后,新旧分支互相污染;一个任务执行半小时,中途失败后不知道从哪里继续;长期记忆越来越多,却不知道当前应该取哪几条;Context 明明塞了很多信息,模型还是遗漏最关键的一段。

这一阶段真正需要掌握的,就是围绕这些问题形成的一组 Memory、State 和 Context Engineering 技术。

一、先建立这一阶段的"技术树"

这一阶段可以先记住下面这张图:

bash 复制代码
Agent
 │
 ├── Conversation Memory
 │    ├── Conversation ID / Thread
 │    ├── Sliding Window
 │    ├── Summary Memory
 │    ├── Persistent Memory
 │    └── Long-term Memory
 │
 ├── Task State
 │    ├── State Store
 │    ├── Checkpoint
 │    ├── Resume
 │    ├── Branch
 │    └── State Machine
 │
 └── Context Engineering
      ├── Context Window
      ├── Token Budget
      ├── Context Assembly
      ├── Context Compression
      ├── Memory Retrieval
      ├── Lost in the Middle
      └── Context Pollution

这些术语没有必要一次研究很深。关键是知道它们分别在解决什么问题。

二、Conversation ID、Session、Thread:先把不同对话隔离开

第一个实际问题通常是:

两个用户同时聊天,Memory 怎么知道哪条消息属于谁?

因此会出现:

bash 复制代码
Conversation ID
Session ID
Thread ID

三个词在不同框架里的命名并不完全一致,核心思想都是:给一段连续会话一个唯一标识。

Spring AI 中最直接的是:

bash 复制代码
.advisors(a -> a.param(
    ChatMemory.CONVERSATION_ID,
    conversationId
))

于是:

bash 复制代码
user-A-session-01
→ A用户当前聊天记录

user-B-session-03
→ B用户当前聊天记录

典型 Badcase 是"串会话":A 用户的信息突然进入 B 用户 Context。生产系统中 Conversation ID 还必须和真实用户身份、Tenant、权限体系绑定,不能只依赖前端随便传一个字符串**【必须将ID嵌入至关键的身份验证、权限、信息等内容绑定】**。

三、Sliding Window:聊天越来越长怎么办

用户聊了 300 轮,不可能每一次都把 300 轮重新发给模型。

于是有了:

Sliding Window,滑动窗口。

例如:

bash 复制代码
历史 300 条消息
        ↓
只保留最近 20 条
        ↓
进入当前 Context

Spring AI 的:

bash 复制代码
MessageWindowChatMemory

就是这一思路。

它解决:

bash 复制代码
Token越来越多
成本越来越高
旧内容干扰新问题

但它又会产生新的 Badcase:

用户 50 轮以前说过一个重要条件,现在被窗口删除了。

因此 Sliding Window 后面自然会引出 Summary Memory 和 Long-term Memory。

四、Summary Memory 与 Context Compression:不能保留全文,就压缩

长对话中通常没有必要保留所有原始句子。【尤其是Sliding Window,更需要压缩技术】

例如 50 轮对话可以压缩成:

bash 复制代码
用户正在申请深圳企业补贴。
企业成立于2021年。
已确认满足注册年限要求。
当前正在核验营收条件。

这种思路常见术语包括:

bash 复制代码
Summary Memory
Context Summarization
Context Compression
Compaction

它们的共同目标是:

用更少的 Token 保留对后续任务仍然重要的信息。【删除旧消息后,又怕重要消息丢失。涉及到重要消息(非关键业务数据时),需要想到Summary Memory等压缩技术】

例如:

bash 复制代码
原始历史 20,000 tokens
        ↓
Summary / Compression
        ↓
1,500 tokens

需要注意压缩可能造成信息损失,所以不能把订单金额、身份证号、审批状态等重要业务数据只存在自然语言摘要里。这些内容应该进入明确的 Task State 或数据库。

五、Working Memory、Long-term Memory:长期信息怎么保存

Agent Memory 中还经常出现两个词:

bash 复制代码
Working Memory
Long-term Memory

Working Memory 可以理解为当前任务正在使用的信息,例如最近对话、当前计划、刚刚执行的 Tool Result

Long-term Memory 则指跨较长时间甚至跨会话仍然值得保留的信息。例如:

bash 复制代码
用户长期偏好
历史任务经验
项目长期事实
曾经确认的重要规则

Long-term Memory 很少采用:

bash 复制代码
全部长期记录
→ 全部塞进 Prompt

更合理的是:

bash 复制代码
长期记忆库
    ↓
根据当前问题检索相关 Memory
    ↓
只取少量相关内容
    ↓
加入 Context

于是又会出现一个术语:

Memory Retrieval。

它和 RAG 非常相似,只不过 RAG 检索的是外部知识,Memory Retrieval 检索的是过去保存的用户或任务记忆。

六、Episodic Memory 与 Semantic Memory:长期记忆还会继续分类

进一步看 Agent 论文或框架时,经常出现:

Episodic Memory:事件记忆。

例如:

bash 复制代码
2026-09-10
用户曾经完成一次深圳政策申报,
最终使用材料A、B、C。

它保存的是"过去发生过什么",电视剧的剧情【你做了什么】

Semantic Memory:语义记忆。

例如:

bash 复制代码
用户所在企业属于科技服务行业。
用户偏好中文输出。

它保存的是相对稳定的事实和知识,用户/场景画像【我能通过"你做了什么"来保存重要信息】

还有:

Procedural Memory ,程序性记忆,强调"某类任务应该怎样完成",和现在常见的 Skill 思想比较接近。【你要怎么做】

初学阶段知道三者区别即可,不需要马上实现三套数据库。

七、Persistent Memory 与 TTL:重启以后还要不要记得

默认内存 Memory 会遇到:

bash 复制代码
Spring Boot 重启
       ↓
Memory 消失

因此生产系统需要:

Persistent Memory / Memory Persistence

即把 Memory 保存到:

bash 复制代码
Redis
MySQL
MongoDB
PostgreSQL
...

Spring AI 对应的重要接口就是:

bash 复制代码
ChatMemoryRepository

此外经常还会看到:

TTL(Time To Live):临时会话/任务,刷新后就没有任何问答或记忆记录,大幅减少Token成本

例如:

bash 复制代码
普通临时会话:
7天后自动删除

长期项目会话:
180天

敏感临时任务:
1小时

TTL 解决 Memory 无限增长以及隐私、存储成本等问题。

八、State Store:任务执行状态不能只靠聊天记录

如果 Agent 正在执行:

bash 复制代码
读取文件
→ 分析
→ 搜索
→ 生成报告
→ 导出Word

执行到"搜索"以后程序崩溃,仅保存聊天记录很难准确知道:

bash 复制代码
哪些步骤完成了?
哪些没完成?
生成过哪些文件?
哪些工具已经执行?

这就需要:

State Store。

例如:

bash 复制代码
{
  "taskId": "agent-001",
  "currentStep": "SEARCH",
  "completedSteps": ["READ", "ANALYZE"],
  "artifactId": null,
  "status": "RUNNING"
}

State Store 通常放在 Redis、数据库或工作流引擎里。

这里最重要的认知是:

bash 复制代码
Memory
→ 保存模型需要理解的过去

State Store
→ 保存程序必须准确知道的当前状态

九、Checkpoint 与 Resume:长任务失败后从哪里继续

只要 Agent 开始执行几十秒甚至几十分钟的任务,两个术语会迅速出现:

bash 复制代码
Checkpoint
Resume

Checkpoint 表示在关键节点保存任务快照

例如:

bash 复制代码
Step 1 完成
↓
Checkpoint 1

Step 2 完成
↓
Checkpoint 2

Step 3 失败

系统恢复以后:

bash 复制代码
读取 Checkpoint 2
        ↓
从 Step 3 继续

而不是重新执行:

bash 复制代码
Step 1 → Step 2 → Step 3

这对于收费 API、生成文件、数据库修改等操作非常重要

后面学习真正的 Agent Workflow、LangGraph 或工作流引擎时,会频繁看到 Checkpoint。

十、Branch / Fork:用户修改旧问题怎么办

聊天产品还有一个很实际的问题。

原对话:

bash 复制代码
Q1
 ↓
A1
 ↓
Q2
 ↓
A2

用户突然修改 Q1:

bash 复制代码
Q1'

那么新的合理结构应该是:

bash 复制代码
          Q1
        /    \
      A1      Q1'
      ↓        ↓
     Q2       New A1

这类概念通常称为:

bash 复制代码
Branch
Fork
Conversation Tree

它解决的是多分支会话状态隔离

如果仍然把旧分支 A1、Q2 放进新分支 Context,就会形成典型的:

Context Pollution,上下文污染。

十一、Context Window 与 Token Budget:模型能看到多少东西

LLM 都有 Context Window。

它表示一次调用能够接受的上下文总量,包括:

bash 复制代码
System Prompt
Chat History
RAG Documents
Tool Result
Task State
User Query
Output空间

所以 Agent 工程里会出现:

Token Budget。

例如整个窗口允许:

bash 复制代码
128K tokens

应用可能人为分配:

bash 复制代码
System Prompt        5K
Memory              15K
RAG                  20K
Tool Result           8K
当前任务              5K
预留模型输出          8K

这并不是固定公式,而是一种资源管理思想。

因此 Context Management 的真正问题不是:

"还能不能继续塞?"

而是:

"有限 Context 中哪些信息最值得保留?"

十二、Lost in the Middle:放进 Context 也不代表模型一定用得到

还有一个很重要的术语:

Lost in the Middle。

研究发现,长 Context 中的信息如果被埋在中间位置,模型有时更容易忽略它。

例如:

bash 复制代码
重要规则
     ↓
50页无关资料
     ↓
另一条重要规则

即使 Context Window 没有超限,模型也可能遗漏第一条规则

因此 Context Engineering 会进行:

bash 复制代码
Rerank
重要内容前置
去除重复
Context Compression
分阶段调用

这和前面 RAG 学到的 Rerank 实际上开始联系起来。

十三、Context Pollution 与 Stale Context:旧信息可能比没有信息更危险

Agent 还有两种很典型的问题。

Context Pollution:无关信息污染当前推理。

例如之前讨论过广东政策,现在切换到海南政策,广东资料仍然大量存在 Context 中。

Stale Context:过期上下文。

例如 Memory 中记录:

bash 复制代码
2025年政策:
补贴最高100万

而 RAG 已经找到:

bash 复制代码
2026年最新政策:
最高80万

如果系统没有处理版本和时间优先级,模型可能使用旧 Memory。

因此工程中常见:

bash 复制代码
Freshness
Version
Timestamp
Source Priority
Memory Invalidation

Memory Invalidation 指某些事实已经失效时,需要删除或标记旧 Memory。

十四、用 Badcase 快速选择技术

这一阶段真正需要记住的是下面这张表:

出现的问题 首先想到的技术
用户说"第二条",模型不知道指什么 Conversation Memory
不同用户聊天串了 Conversation ID / Isolation
聊天太长、Token太多 Sliding Window
删除旧消息以后又忘记重要信息 Summary Memory
跨会话还需要记住用户事实 Long-term Memory
长期 Memory 太多 Memory Retrieval
重启以后聊天消失 Persistent Memory
临时 Memory 永远不删除 TTL
不知道任务执行到哪一步 State Store
长任务失败需要继续 Checkpoint / Resume
修改旧消息后上下文混乱 Branch / Fork
Context 太长 Token Budget / Compression
信息明明存在但模型没使用 Lost in the Middle
旧任务信息影响新任务 Context Pollution
过去信息已经失效 Stale Context / Invalidation

到这里,这一阶段就基本够用了。

面试如果被问"Agent 的 Memory 怎么设计",回答也不应只停留在 MessageChatMemoryAdvisor。更完整的回答可以是:

我会先区分会话 Memory 和 Task State。短期聊天可以通过 Conversation ID 和 Sliding Window 管理,长会话需要 Summary 或 Context Compression;跨会话的重要事实进入 Long-term Memory,并按当前问题做 Memory Retrieval。长任务的确定状态单独放 State Store,通过 Checkpoint 支持恢复。同时需要控制 Token Budget、Context Pollution、Stale Context 和多用户隔离,避免把所有历史消息简单塞进 Prompt。

**【不同场景的技术工程能力-恢复能力-实际成本控制与多租户问题】**这已经是一个比较完整、同时仍属于中等难度的 Agent 工程回答。

下一阶段进入 Tool Calling 与 Action 时,也应该继续采用完全相同的学习方式:不再反复解释"Tool 是什么",而是直接学习这一阶段的技术树------Tool Schema、Tool Registry、Tool Selection、Dynamic Tool Discovery、Structured Parameters、Validation、Retry、Timeout、Fallback、Idempotency、Human-in-the-loop、Termination Condition、Tool Error Handling、Parallel Tool Calls、Native Tool / MCP Tool 等常见术语,以及分别在什么 Badcase 下使用。这样推进速度会快很多。

相关推荐
拖孩1 小时前
这个小程序是 AI 帮我写的,可它里面一个 AI 功能都没有
前端·后端·微信小程序
leeyi2 小时前
Agent 要用 API key,但明文一次都不能进模型——Secret Runtime 落地实录(第110篇)
后端·aigc·agent
GreenTea2 小时前
发布 3 天登顶 HN:不生成一个字的模型 Jev,我把它的源码和黑料都扒了一遍
前端·后端·算法
JoyT2 小时前
Spring AI 2.0 RAG 工程优化:从 Chunking、混合检索到 Rerank
后端
她的男孩2 小时前
做了"异步导出",用户点了还是卡 3 分钟:扒完 4223 行源码,@Async 压根没生效
人工智能·后端·程序员
wno7043 小时前
Spring Security添加图形验证码
java·后端·spring
ewbok3 小时前
Springboot整合mqtt实现软硬件通信
后端
CRZZX3 小时前
阶段 0.3:为 AI Agent 建立输入、工具、限流与前端渲染安全边界
后端
鱼弦3 小时前
实时性能力的边界:大模型能否胜任毫秒级响应的交互?
后端