第5章:记忆与状态管理
想象一下,如果你的朋友每次见面都忘记你是谁,那会是多么糟糕的体验!同样,智能体也需要"记忆"来记住用户、记住对话、记住任务进展。本章将带你掌握智能体的记忆与状态管理技术。
5.1 为什么智能体需要记忆
记忆是智能体变得"聪明"的关键。没有记忆的智能体就像金鱼的7秒记忆,无法提供连贯、个性化的服务。
记忆带来的好处:
- 保持对话连贯 - 智能体记得之前说了什么,不会出现"前言不搭后语"
- 避免重复询问 - 已经问过的问题不需要再问第二遍
- 个性化服务 - 根据用户偏好和历史行为提供定制化回答
- 提升效率 - 不需要每次都从头开始了解上下文
5.2 记忆的类型
智能体的记忆和人类一样,也有不同的类型。我们可以将记忆分为三大类:
┌─────────────────────────────────────────────────────┐
│ 智能体记忆架构 │
├─────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────────┐ │
│ │ 短期记忆 │ │ 长期记忆 │ │
│ │ (对话历史) │ │ (知识库) │ │
│ │ │ │ │ │
│ │ • 当前对话上下文 │ │ • 用户基本信息 │ │
│ │ • 最近的几轮对话 │ │ • 用户偏好设置 │ │
│ │ • 临时变量 │ │ • 历史交互记录 │ │
│ │ │ │ • 重要事实知识 │ │
│ └────────┬────────┘ └──────────┬──────────┘ │
│ │ │ │
│ └────────┬───────────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ 工作记忆 │ │
│ │ │ │
│ │ • 当前任务状态 │ │
│ │ • 中间计算结果 │ │
│ │ • 待办事项 │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────┘
5.2.1 短期记忆(对话历史)
短期记忆就像你的大脑正在处理的信息,随时可用但容量有限。
短期记忆特点:
- 存储当前对话的上下文
- 通常保存最近10-20轮对话
- 会话结束后可能清空
- 直接参与每次AI请求
5.2.2 长期记忆(知识库)
长期记忆就像你的长期知识储备,容量大、持久保存。
长期记忆存储内容举例:
- 用户姓名、职业、兴趣爱好
- 用户之前表达过的偏好("我不喜欢辣"、"我对花生过敏")
- 重要的历史事件("去年我们讨论过这个方案")
- 常用知识库(产品文档、公司制度等)
5.2.3 工作记忆
工作记忆是智能体的"工作台",存放当前任务的临时数据。
工作记忆示例:订餐任务
┌─────────────────────────────────┐
│ 工作记忆区域 │
├─────────────────────────────────┤
│ 任务: 帮用户订外卖 │
│ 状态: 选择餐厅中 │
│ │
│ 已收集信息: │
│ • 用户位置: 朝阳区 │
│ • 预算: 50元以内 │
│ • 口味: 川菜 │
│ • 人数: 2人 │
│ │
│ 待确认: 具体送餐地址 │
│ 待执行: 搜索餐厅 → 展示菜单 │
└─────────────────────────────────┘
5.3 短期记忆的实现
短期记忆的实现最简单:维护一个对话历史列表即可。
// 对话历史结构
const conversationHistory = [
{ role: "user", content: "你好,我想订外卖" },
{ role: "assistant", content: "好的!请问您想吃什么类型的美食?" },
{ role: "user", content: "想吃川菜" },
{ role: "assistant", content: "明白了,川菜很受欢迎呢!请问您几位用餐?" }
];
// 发送请求时带上对话历史
async function sendMessage(userMessage) {
// 1. 添加用户消息到历史
conversationHistory.push({ role: "user", content: userMessage });
// 2. 调用AI,带上完整对话历史
const response = await callAI({
messages: conversationHistory, // ← 关键!带上历史
model: "gpt-4"
});
// 3. 添加AI回复到历史
conversationHistory.push({
role: "assistant",
content: response.content
});
return response;
}
⚠️ 注意事项:
- 对话历史太长会消耗更多Token,增加成本
- 不同模型有最大上下文长度限制(如GPT-4是8K/32K)
- 超出限制时需要压缩或截断历史
5.4 长期记忆的实现
长期记忆需要持久化存储,并且要能快速检索。通常使用向量数据库来实现。
5.4.1 向量数据库原理
向量数据库工作流程:
存储阶段: 检索阶段:
┌──────────┐ ┌──────────┐
│ 文本信息 │ │ 用户提问 │
└────┬─────┘ └────┬─────┘
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ Embedding│ │ Embedding│
│ 编码 │ │ 编码 │
│ (向量化) │ │ (向量化) │
└────┬─────┘ └────┬─────┘
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ 向量数据库│ │ 相似度计算│
│ 存储向量 │◄────────────────│ 召回相关 │
└──────────┘ └──────────┘
│
▼
┌──────────┐
│ 返回相关 │
│ 记忆片段 │
└──────────┘
5.4.2 代码实现示例
// 使用向量数据库(如 Pinecone、Chroma、Milvus)
class LongTermMemory {
constructor(vectorDB) {
this.db = vectorDB;
}
// 存储记忆
async store(memory, metadata = {}) {
// 1. 将文本转换为向量
const vector = await embeddingModel.encode(memory);
// 2. 存入向量数据库
await this.db.upsert({
id: generateId(),
vector: vector,
metadata: {
content: memory,
timestamp: Date.now(),
...metadata
}
});
}
// 检索相关记忆
async retrieve(query, topK = 5) {
// 1. 将查询转为向量
const queryVector = await embeddingModel.encode(query);
// 2. 搜索最相似的向量
const results = await this.db.query({
vector: queryVector,
topK: topK
});
// 3. 返回记忆内容
return results.map(r => r.metadata.content);
}
}
// 使用示例
const memory = new LongTermMemory(vectorDB);
// 存储用户喜好
await memory.store("用户喜欢吃川菜,尤其是麻婆豆腐", {
type: "preference",
category: "food"
});
// 之后检索
const relevantMemories = await memory.retrieve("推荐餐厅");
// 返回:["用户喜欢吃川菜,尤其是麻婆豆腐"]
5.5 记忆的管理策略
记忆不是越多越好,需要合理的管理策略。
5.5.1 记忆摘要(压缩)
当对话历史太长时,可以压缩成摘要。
对话历史压缩示例:
原始对话(100轮):
┌────────────────────────────────────┐
│ 用户: 你好 │
│ AI: 你好!有什么可以帮您的? │
│ 用户: 我想学编程 │
│ AI: 太好了!您想学哪种语言? │
│ ...(中间96轮)... │
│ 用户: Python的列表怎么用 │
│ AI: 列表是Python中... │
└────────────────────────────────────┘
压缩后(摘要 + 最近几轮):
┌────────────────────────────────────┐
│ 【摘要】用户是编程初学者,想学习 │
│ Python编程。已了解基础语法,目前 │
│ 在学习数据结构。 │
│ │
│ 用户: Python的列表怎么用 │
│ AI: 列表是Python中... │
└────────────────────────────────────┘
5.5.2 记忆遗忘(清理)
// 记忆遗忘策略
class MemoryManager {
// 按时间遗忘:清理超过30天的短期记忆
async forgetByTime(maxAgeDays = 30) {
const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1000;
await this.db.deleteWhere({ timestamp: { $lt: cutoff } });
}
// 按重要性遗忘:保留重要记忆,删除次要记忆
async forgetByImportance() {
const memories = await this.db.getAll();
const toDelete = memories.filter(m =>
m.importance < 3 && m.lastAccess < Date.now() - 7 * 24 * 60 * 60 * 1000
);
await this.db.deleteMany(toDelete.map(m => m.id));
}
// 手动标记重要记忆永不删除
async markImportant(memoryId) {
await this.db.update(memoryId, { neverForget: true });
}
}
5.5.3 记忆更新
记忆更新场景:
- 用户改变了偏好("我现在不吃辣了")
- 信息过期("我搬到上海了")
- 纠正错误信息
- 增加新属性("对了,我还有个女儿")
5.6 状态管理
状态管理是智能体的"工作区",存储当前任务的临时数据和执行进度。
智能体状态管理架构:
┌─────────────────────────────────────────────┐
│ 全局状态 (Global State) │
│ • 当前会话ID │
│ • 用户信息 │
│ • 配置参数 │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 任务状态 (Task State) │
│ • 当前执行的任务 │
│ • 任务进度 (0-100%) │
│ • 已完成的步骤 │
│ • 待执行的步骤 │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 上下文状态 (Context State) │
│ • 工具调用结果 │
│ • API返回数据 │
│ • 中间计算结果 │
└─────────────────────────────────────────────┘
5.6.1 状态管理代码示例
class AgentState {
constructor() {
this.state = {
// 用户相关
user: {
id: null,
name: null,
preferences: {}
},
// 当前任务
currentTask: {
id: null,
name: null,
status: 'idle', // idle, running, paused, completed
progress: 0,
currentStep: 0,
totalSteps: 0
},
// 工作上下文
context: {
collectedData: {}, // 已收集的信息
toolResults: [], // 工具调用结果
tempVariables: {} // 临时变量
}
};
}
// 更新任务进度
updateProgress(step, total) {
this.state.currentTask.currentStep = step;
this.state.currentTask.totalSteps = total;
this.state.currentTask.progress = Math.round(step / total * 100);
}
// 存储临时数据
setTempData(key, value) {
this.state.context.tempVariables[key] = value;
}
// 获取临时数据
getTempData(key) {
return this.state.context.tempVariables[key];
}
// 完成任务
completeTask() {
this.state.currentTask.status = 'completed';
this.state.currentTask.progress = 100;
// 清理临时数据
this.state.context.tempVariables = {};
}
}
5.7 实战示例:个人助手
让我们做一个能记住用户喜好的"个人助手"。
5.7.1 完整代码实现
class PersonalAssistant {
constructor() {
this.shortTerm = []; // 短期记忆:对话历史
this.longTerm = new Map(); // 长期记忆:用户偏好
this.workingMemory = {}; // 工作记忆:当前任务
}
// 处理用户消息
async chat(userMessage) {
// 1. 检查是否需要更新长期记忆
await this.extractAndStoreMemory(userMessage);
// 2. 检索相关长期记忆
const relevantMemories = this.findRelevantMemories(userMessage);
// 3. 构建系统提示
const systemPrompt = this.buildSystemPrompt(relevantMemories);
// 4. 调用AI(带上短期记忆)
const messages = [
{ role: "system", content: systemPrompt },
...this.shortTerm.slice(-10), // 最近10轮
{ role: "user", content: userMessage }
];
const response = await callAI(messages);
// 5. 更新短期记忆
this.shortTerm.push({ role: "user", content: userMessage });
this.shortTerm.push({ role: "assistant", content: response });
return response;
}
// 提取并存储记忆
async extractAndStoreMemory(message) {
// 简单规则:检测"我喜欢/我讨厌/我是"等表达
const patterns = [
{ regex: /我喜欢(.+)/, type: 'like' },
{ regex: /我讨厌(.+)/, type: 'dislike' },
{ regex: /我是(.+)/, type: 'identity' },
{ regex: /我(.+)过敏/, type: 'allergy' }
];
for (const pattern of patterns) {
const match = message.match(pattern.regex);
if (match) {
this.longTerm.set(`${pattern.type}:${match[1]}`, {
content: match[1],
type: pattern.type,
timestamp: Date.now()
});
console.log(`💾 已记忆:${pattern.type} - ${match[1]}`);
}
}
}
// 查找相关记忆
findRelevantMemories(query) {
const memories = [];
// 简单关键词匹配(实际可用向量检索)
if (query.includes('推荐') || query.includes('吃')) {
for (const [key, value] of this.longTerm) {
if (value.type === 'like' || value.type === 'dislike') {
memories.push(value);
}
}
}
return memories;
}
// 构建系统提示
buildSystemPrompt(memories) {
let prompt = '你是用户的个人助手。';
if (memories.length > 0) {
prompt += '\n\n关于用户的已知信息:\n';
memories.forEach(m => {
const prefix = {
like: '喜欢',
dislike: '不喜欢',
identity: '身份',
allergy: '过敏'
}[m.type];
prompt += `- 用户${prefix}:${m.content}\n`;
});
}
return prompt;
}
}
5.7.2 运行效果演示
交互示例:
用户: 我喜欢吃川菜
助手: 好的,我记下了!您喜欢川菜。
💾 已记忆:like - 川菜
用户: 我对花生过敏
助手: 了解了,我会记住您对花生过敏,以后推荐食物时会注意避开。
💾 已记忆:allergy - 花生
用户: 推荐个餐厅
助手: 检索记忆:用户喜欢川菜,对花生过敏
基于您的喜好,我推荐以下川菜馆:
1. 蜀香园 - 正宗川菜,有明确过敏原标注
2. 川味轩 - 口碑很好,可定制免花生
需要我帮您查看菜单或预订吗?
用户: 我明天要开会
助手: 好的,请问需要什么时间提醒您?需要我准备会议资料吗?
(此信息属于临时任务,存入工作记忆)
✅ 记忆管理最佳实践:
- 短期记忆保持精简,只保留必要的对话上下文
- 长期记忆使用向量数据库存储,支持语义检索
- 工作记忆及时清理,避免数据堆积
- 定期对长期记忆进行整理和去重
- 给用户查看和删除记忆的权限
本章小结
核心知识点回顾:
- 短期记忆 - 维护对话历史列表,实现对话连贯性
- 长期记忆 - 使用向量数据库存储和检索用户偏好
- 工作记忆 - 存储当前任务的临时状态和进度
- 记忆管理 - 摘要压缩、遗忘清理、更新同步
- 状态管理 - 分层管理全局、任务、上下文状态
下一章,我们将学习如何让智能体进行规划与任务分解,把复杂任务拆解成可执行的小步骤!