mcpField
M
memory-persistence

memory-persistence

github.com/itallstartedwithaideaAgent 工作流4492 次安装28 周前更新
代码仓库

关于 memory-persistence

memory-persistence 是一项让 AI Agent 在不同会话间保留上下文的 Agent Skills™ 技能。它会提取事实并总结会话,再检索相关记忆以支持后续工作。

主要功能

  1. 01会话结束时提取实体
  2. 02总结对话内容
  3. 03按相关性检索记忆
  4. 04实体、会话和模式记忆
  5. 05使用 Cloudflare KV 持久存储

适用场景

  1. 01在多个会话间保留用户偏好
  2. 02复用以往项目或账户背景
  3. 03延续需要持续一致的决策
  4. 04生成会话摘要以供审计

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/itallstartedwithaidea/agent-skills --skill memory-persistence

安装后在 Claude Code 中输入/memory-persistence确认已加载。

详细介绍

记忆持久化

属于 Agent Skills™,由 googleadsagent.ai™ 提供

描述

记忆持久化使 AI Agent 能够跨会话保留知识,将无状态的推理调用转变为有状态、持续改进的系统。如果没有持久化,每个新会话都会从零开始——Agent 必须重新学习用户偏好、重新发现代码库模式,并重复犯已经纠正过的错误。记忆持久化通过实现钩子,在会话结束时保存关键上下文,并在会话开始时重新加载,从而营造出记忆连续不断的效果。

这项技能基于为 googleadsagent.ai™ 上的 Buddy™ 提供支持的生产级记忆系统构建,该系统使用 Cloudflare KV 作为持久化记忆存储。每次对话结束后,Buddy™ 都会提取实体(广告系列、指标、用户偏好、做出的决策),总结会话,并按用户和会话为索引存储结果。在下一次对话中,系统会检索最相关的记忆并注入上下文,使 Buddy™ 能够引用先前的分析、尊重用户表达的偏好,并在以往决策的基础上继续推进。

记忆系统以三个粒度运行:实体级记忆(如“用户偏好保守的出价策略”等单条事实)、会话级记忆(经过总结的对话)和模式级记忆(如“此账号总是在品牌关键词上超支”等反复出现的行为)。每种粒度适用于不同的检索模式,并有不同的存储和时效性要求。

适用场景

  • 用户会跨多个会话与 Agent 互动,并期望保持连贯
  • Agent 做出的决策需要长期保持一致(偏好、约定)
  • 领域知识会随会话累积,不应丢失
  • 希望避免反复解释代码库结构或项目背景
  • Agent 需要跨时间跟踪不断变化的实体(账号、广告系列、指标)
  • 需要总结会话,以便进行审计或满足合规要求

工作原理

graph TD
    A[Session Start] --> B[Memory Retrieval]
    B --> C[Context Assembly]
    C --> D[Agent Execution]
    D --> E[Session End Trigger]
    E --> F[Entity Extraction]
    F --> G[Session Summarization]
    G --> H[Memory Indexing]
    H --> I[KV Store Write]
    
    B --> J[KV Store Read]
    J --> K{Match Found?}
    K -->|Yes| L[Relevance Ranking]
    L --> M[Top-K Selection]
    M --> C
    K -->|No| C

在会话开始时,记忆检索系统会查询 KV 存储,获取与当前用户和任务相关的记忆。检索到的记忆会按相关性和时效性排序,并将排名靠前的 K 条注入 Agent 的上下文。在会话期间,Agent 正常运行。在会话结束时(由钩子或显式保存触发),实体提取器会从对话中识别关键事实、决策和偏好。会话总结器会生成精简摘要。实体和摘要都会编入索引并写入 KV 存储,以供将来检索。

实现

记忆存储接口(Cloudflare KV):

interface Memory {
  id: string;
  userId: string;
  type: "entity" | "session_summary" | "pattern";
  content: string;
  metadata: {
    sessionId: string;
    timestamp: number;
    importance: number;
    tags: string[];
  };
}

class MemoryStore {
  constructor(private kv: KVNamespace) {}

  async save(memory: Memory): Promise<void> {
    const key = `memory:${memory.userId}:${memory.type}:${memory.id}`;
    await this.kv.put(key, JSON.stringify(memory), {
      metadata: { importance: memory.metadata.importance, timestamp: memory.metadata.timestamp },
      expirationTtl: 60 * 60 * 24 * 90,
    });

    const indexKey = `index:${memory.userId}:${memory.type}`;
    const existing = await this.kv.get<string[]>(indexKey, "json") || [];
    existing.push(memory.id);
    await this.kv.put(indexKey, JSON.stringify(existing));
  }

  async retrieve(userId: string, type: string, limit = 10): Promise<Memory[]> {
    const indexKey = `index:${userId}:${type}`;
    const ids = await this.kv.get<string[]>(indexKey, "json") || [];

    const memories: Memory[] = [];
    for (const id of ids.slice(-limit * 2)) {
      const key = `memory:${userId}:${type}:${id}`;
      const mem = await this.kv.get<Memory>(key, "json");
      if (mem) memories.push(mem);
    }

    return memories
      .sort((a, b) => b.metadata.importance * 0.6 + b.metadata.timestamp * 0.4
        - (a.metadata.importance * 0.6 + a.metadata.timestamp * 0.4))
      .slice(0, limit);
  }
}

会话结束钩子(实体提取):

ENTITY_EXTRACTION_PROMPT = """Analyze the following conversation and extract key entities.

Categories:
- DECISIONS: Choices made, strategies adopted, preferences stated
- METRICS: Specific numbers, KPIs, performance data mentioned
- PREFERENCES: User preferences for communication style, analysis depth, risk tolerance
- FACTS: Key facts about the account, project, or domain

Conversation:
{conversation}

Respond with JSON:
{{"entities": [{{"category": "...", "content": "...", "importance": 0.0-1.0}}]}}"""

async def extract_and_persist(conversation: list[dict], user_id: str, session_id: str):
    prompt = ENTITY_EXTRACTION_PROMPT.format(
        conversation=format_conversation(conversation[-20:])
    )
    result = await model.generate(prompt, temperature=0.0)
    entities = json.loads(result)["entities"]

    store = MemoryStore(kv_namespace)
    for entity in entities:
        memory = Memory(
            id=f"{session_id}_{hash(entity['content'])[:8]}",
            user_id=user_id,
            type="entity",
            content=entity["content"],
            metadata={
                "session_id": session_id,
                "timestamp": int(time.time()),
                "importance": entity["importance"],
                "tags": [entity["category"]],
            },
        )
        await store.save(memory)

    summary = await summarize_session(conversation)
    await store.save(Memory(
        id=session_id,
        user_id=user_id,
        type="session_summary",
        content=summary,
        metadata={"session_id": session_id, "timestamp": int(time.time()), "importance": 0.7, "tags": ["summary"]},
    ))

记忆增强的会话开始:

async def build_memory_context(user_id: str, current_task: str) -> str:
    store = MemoryStore(kv_namespace)

    entities = await store.retrieve(user_id, "entity", limit=15)
    summaries = await store.retrieve(user_id, "session_summary", limit=5)

    context_parts = []
    if entities:
        context_parts.append("<prior_knowledge>")
        for entity in entities:
            tag = entity.metadata["tags"][0] if entity.metadata["tags"] else "fact"
            context_parts.append(f"[{tag.upper()}] {entity.content}")
        context_parts.append("</prior_knowledge>")

    if summaries:
        context_parts.append("<recent_sessions>")
        for s in summaries:
            context_parts.append(f"- {s.content}")
        context_parts.append("</recent_sessions>")

    return "\n".join(context_parts)

最佳实践

  1. 在会话结束时提取实体,而不是在会话期间提取——实时提取会打断 Agent 的流程;在会话结束时批量提取,成本更低,而且能利用完整的对话上下文提高准确性。
  2. 按重要性 × 时效性排序——并非所有记忆都同等重要;对于实体记忆,提高重要性(对用户至关重要的决策)的权重;对于会话摘要,提高时效性的权重。
  3. 积极设置 TTL——超过 90 天的记忆很少仍有参考价值;让它们自动过期,以便控制存储规模并加快检索速度。
  4. 限制记忆注入的 token 数量——检索到的记忆占用的上下文窗口不应超过 10%;占用更多会分散对当前任务的注意力。
  5. 使用模型进行提取——基于正则表达式的实体提取很脆弱;使用快速模型(Haiku 级别)进行提取,将主模型留给实际任务。
  6. 为记忆架构添加版本号——随着提取提示词不断演进,旧架构中的记忆可能不兼容;添加版本字段以便迁移。
  7. 测试记忆的相关性——定期检查检索到的记忆是否确实能改善任务完成效果;不相关的记忆会浪费上下文预算。

平台兼容性

功能Claude CodeCursorCodexGemini CLI
会话钩子✅ 停止钩子✅ 扩展⚠️ 自定义⚠️ 自定义
KV 存储✅ 任意 KV/文件✅ 任意 KV/文件✅ 任意 KV/文件✅ 任意 KV/文件
上下文注入✅ CLAUDE.md✅ 规则/技能✅ 指令✅ 系统提示词
实体提取✅ 完整支持✅ 完整支持✅ 完整支持✅ 完整支持
自动保存触发器✅ 钩子✅ 事件⚠️ 手动⚠️ 手动

相关技能

  • 实体记忆管理 - 构建于持久化层之上的细粒度实体级记忆
  • 持续学习 - 持久化的会话数据支持跨会话模式挖掘和技能推导
  • Token 优化 - 记忆注入必须遵守上下文窗口预算,避免分散 Agent 的注意力
  • 质量得分优化 - 跨会话持久化 QS 跟踪,可用于分析历史趋势

关键词

记忆持久化、会话记忆、实体提取、cloudflare-kv、会话摘要、记忆检索、跨会话上下文、记忆索引、知识持久化、Agent 技能


© 2026 googleadsagent.ai™ | Agent Skills™ | MIT License

评论

支持 Markdown