AI Agent记忆机制:从无状态对话到持久化认知的架构演进
AI Agent记忆机制:从无状态对话到持久化认知的架构演进

一、当Agent每次都从零开始:无状态交互的工程困境
大模型应用落地过程中,一个反复出现的痛点是:Agent 缺乏持久记忆。用户昨天告诉 AI 自己的技术栈是 Go + K8s,今天再对话时,Agent 又从零开始推荐 Python 方案。在客服、个人助手、代码审查等场景中,这种"金鱼记忆"直接导致用户体验断崖式下跌。
生产环境中,一个企业级代码审查 Agent 需要记住团队编码规范、历史审查偏好和项目架构决策。如果每次审查都重新加载上下文,Token 消耗会指数级增长,响应延迟也会随之恶化。更深层的问题是:没有记忆的 Agent 无法形成"经验积累",它永远是一个只会模式匹配的工具,而不是能持续进化的智能体。
这个问题的本质是——如何在 LLM 固定的上下文窗口限制下,构建一个既能高效检索历史信息、又能按重要性动态裁剪的记忆系统。
二、记忆分层架构:从工作记忆到长期存储的认知模型
借鉴认知科学中的记忆模型,AI Agent 的记忆系统可以划分为三个层次,每层有不同的存储介质、检索策略和生命周期。
graph TB
A[用户输入] --> B[工作记忆 Working Memory]
B --> C[短期记忆 Short-term Memory]
C --> D[长期记忆 Long-term Memory]
B -->|当前对话上下文| E[LLM 上下文窗口]
C -->|近期会话摘要| F[向量数据库]
D -->|结构化知识/偏好| G[关系数据库]
F -->|语义检索| B
G -->|精确查询| B
subgraph 记忆写入流程
H[对话结果] --> I{重要性评估}
I -->|高重要性| J[写入长期记忆]
I -->|中重要性| K[写入短期记忆]
I -->|低重要性| L[丢弃]
J --> G
K --> F
end
工作记忆直接映射到 LLM 的上下文窗口,容量有限但访问速度最快。短期记忆存储近期对话的摘要和关键实体,通过向量检索按语义相关性召回。长期记忆保存用户偏好、领域知识和决策规则,通常以结构化数据存储,支持精确查询。
三者之间的协作逻辑是:每次用户输入到达时,先从短期和长期记忆中检索相关片段,注入工作记忆,再由 LLM 生成响应。生成完成后,对响应内容做重要性评估,决定是否持久化到记忆层。
三、生产级记忆系统实现
3.1 记忆条目与重要性评估
package memory
import (
"context"
"crypto/sha256"
"encoding/hex"
"time"
)
// MemoryType 记忆类型枚举
type MemoryType int
const (
MemoryWorking MemoryType = iota // 工作记忆
MemoryShortTerm // 短期记忆
MemoryLongTerm // 长期记忆
)
// Memory 记忆条目
type Memory struct {
ID string `json:"id"`
Type MemoryType `json:"type"`
Content string `json:"content"` // 记忆内容
Summary string `json:"summary"` // 内容摘要
Embedding []float64 `json:"embedding"` // 向量表示
Importance float64 `json:"importance"` // 重要性评分 0-1
AccessCount int `json:"access_count"`// 被检索次数
Metadata map[string]string `json:"metadata"` // 扩展元数据
CreatedAt time.Time `json:"created_at"`
AccessedAt time.Time `json:"accessed_at"`
ExpiresAt *time.Time `json:"expires_at"` // 过期时间
}
// NewMemory 创建记忆条目
func NewMemory(content string, importance float64) *Memory {
now := time.Now()
hash := sha256.Sum256([]byte(content + now.String()))
return &Memory{
ID: hex.EncodeToString(hash[:16]),
Content: content,
Importance: importance,
CreatedAt: now,
AccessedAt: now,
Metadata: make(map[string]string),
}
}
// ImportanceEvaluator 重要性评估器
type ImportanceEvaluator struct {
llmClient LLMClient
}
// Evaluate 评估记忆内容的重要性
func (e *ImportanceEvaluator) Evaluate(ctx context.Context, content string) (float64, error) {
prompt := `评估以下内容的记忆重要性,返回0到1之间的分数。
评分标准:
- 包含用户偏好、决策规则、关键事实:0.7-1.0
- 包含操作步骤、上下文线索:0.4-0.7
- 闲聊、重复信息、临时状态:0.0-0.4
内容:` + content + `
只返回数字分数:`
score, err := e.llmClient.GetFloat(ctx, prompt)
if err != nil {
// 评估失败时使用基于规则的降级策略
return ruleBasedEvaluate(content), nil
}
return score, nil
}
// ruleBasedEvaluate 基于规则的降级评估
func ruleBasedEvaluate(content string) float64 {
// 简单启发式:包含关键词则提升重要性
highKeywords := []string{"偏好", "决定", "规则", "架构", "技术栈", "禁止", "必须"}
for _, kw := range highKeywords {
if contains(content, kw) {
return 0.75
}
}
return 0.3
}
3.2 向量检索与记忆召回
package memory
import (
"context"
"sort"
)
// VectorStore 向量存储接口
type VectorStore interface {
Upsert(ctx context.Context, id string, embedding []float64, metadata map[string]string) error
Search(ctx context.Context, query []float64, topK int) ([]SearchResult, error)
Delete(ctx context.Context, id string) error
}
// SearchResult 向量检索结果
type SearchResult struct {
ID string `json:"id"`
Score float64 `json:"score"`
Metadata map[string]string `json:"metadata"`
}
// MemoryStore 记忆存储与检索管理器
type MemoryStore struct {
vecStore VectorStore // 向量数据库客户端
embedder Embedder // 文本向量化接口
evaluator *ImportanceEvaluator
maxWorking int // 工作记忆最大条目数
}
// Recall 从记忆中检索相关内容
func (ms *MemoryStore) Recall(ctx context.Context, query string, topK int) ([]*Memory, error) {
// 将查询文本向量化
queryVec, err := ms.embedder.Embed(ctx, query)
if err != nil {
return nil, err
}
// 从向量数据库检索最相似的条目
results, err := ms.vecStore.Search(ctx, queryVec, topK)
if err != nil {
return nil, err
}
var memories []*Memory
for _, r := range results {
mem := &Memory{
ID: r.ID,
Content: r.Metadata["content"],
Summary: r.Metadata["summary"],
Metadata: r.Metadata,
}
memories = append(memories, mem)
}
// 按相关性和重要性综合排序
sort.Slice(memories, func(i, j int) bool {
scoreI := results[i].Score * 0.6
scoreJ := results[j].Score * 0.6
if impI, ok := memories[i].Metadata["importance"]; ok {
scoreI += parseFloat(impI) * 0.4
}
if impJ, ok := memories[j].Metadata["importance"]; ok {
scoreJ += parseFloat(impJ) * 0.4
}
return scoreI > scoreJ
})
return memories, nil
}
// Store 存储新记忆
func (ms *MemoryStore) Store(ctx context.Context, content string) error {
// 评估重要性
importance, err := ms.evaluator.Evaluate(ctx, content)
if err != nil {
return err
}
// 低重要性内容不持久化
if importance < 0.3 {
return nil
}
mem := NewMemory(content, importance)
// 向量化并存储
embedding, err := ms.embedder.Embed(ctx, content)
if err != nil {
return err
}
mem.Embedding = embedding
metadata := map[string]string{
"content": mem.Content,
"importance": formatFloat(mem.Importance),
"created_at": mem.CreatedAt.Format("2006-01-02T15:04:05Z"),
}
return ms.vecStore.Upsert(ctx, mem.ID, embedding, metadata)
}
3.3 上下文窗口管理策略
package memory
import "fmt"
// ContextWindowManager 上下文窗口管理器
type ContextWindowManager struct {
maxTokens int // 最大 Token 数
usedTokens int // 已使用 Token 数
entries []contextEntry // 当前上下文条目
}
type contextEntry struct {
role string // system/user/assistant
content string
tokens int
}
// BuildContext 构建发送给LLM的完整上下文
func (cwm *ContextWindowManager) BuildContext(
systemPrompt string,
recentMessages []Message,
recalledMemories []*Memory,
) []Message {
var messages []Message
// 1. 系统提示词(不可裁剪)
systemTokens := estimateTokens(systemPrompt)
messages = append(messages, Message{Role: "system", Content: systemPrompt})
cwm.usedTokens = systemTokens
// 2. 召回的记忆(按重要性排序,可裁剪)
for _, mem := range recalledMemories {
memText := fmt.Sprintf("[历史记忆] %s", mem.Summary)
memTokens := estimateTokens(memText)
if cwm.usedTokens+memTokens > cwm.maxTokens {
break // 超出窗口则截断
}
messages = append(messages, Message{Role: "system", Content: memText})
cwm.usedTokens += memTokens
}
// 3. 近期对话(从最新往回填充)
remaining := cwm.maxTokens - cwm.usedTokens
var recent []Message
usedRecent := 0
for i := len(recentMessages) - 1; i >= 0; i-- {
msgTokens := estimateTokens(recentMessages[i].Content)
if usedRecent+msgTokens > remaining {
break
}
recent = append([]Message{recentMessages[i]}, recent...)
usedRecent += msgTokens
}
messages = append(messages, recent...)
return messages
}
// estimateTokens 估算文本Token数(中文约1.5字/Token)
func estimateTokens(text string) int {
return int(float64(len([]rune(text))) * 1.5)
}
四、记忆系统的工程权衡与适用边界
记忆系统的引入并非没有代价。首先是存储成本:向量数据库的存储开销远高于关系型数据库,当用户量达到百万级时,记忆条目可能膨胀到数亿条,向量索引的内存占用会非常可观。其次是检索延迟:每次对话都需要执行向量检索和重要性排序,在 P99 延迟敏感的场景中,这个额外开销可能不可接受。
重要性评估的准确性也是一个挑战。基于 LLM 的评估虽然灵活,但每次评估都需要一次模型调用,成本和延迟都很高。基于规则的降级方案虽然快速,但无法处理复杂的语义判断。生产环境中通常采用混合策略:先用规则做粗筛,对规则无法判断的内容再调用 LLM 评估。
记忆遗忘机制容易被忽视。如果不做定期清理,记忆库会持续膨胀,检索质量也会因噪声增加而下降。常见的遗忘策略包括:基于时间的过期淘汰、基于访问频率的衰减、以及基于重要性阈值的定期裁剪。但遗忘本身也有风险——过早遗忘关键信息会导致 Agent 行为退化,而过晚遗忘则浪费存储和检索资源。
五、总结
AI Agent 记忆系统的核心设计围绕三个层次展开:工作记忆负责当前上下文的即时处理,短期记忆通过向量检索召回近期相关信息,长期记忆以结构化方式保存用户偏好和领域知识。工程实现中需要重点关注的权衡包括:存储成本与检索质量的平衡、重要性评估的准确性与延迟的取舍、遗忘策略的激进程度与信息保留的矛盾。记忆系统不是越复杂越好,而是要在实际业务场景中找到"够用且可控"的平衡点,避免过度工程化带来的维护负担。
更多推荐

所有评论(0)