Skip to content

MemoryAgent 架构说明

本文描述 MemoryAgent 的模块分层、数据流与关键决策,面向工程维护与架构理解。

定位与职责

MemoryAgent 是 VTuber 链路的编排器,职责是将 AgentCore 的 token 流接入 TTS / Live2D pipeline。

不做

  • LLM 调用(委托给 AgentCore)
  • 工具调用(委托给 AgentCore + ToolManager)
  • Prompt 拼装(委托给 AgentCore → PromptBuilder)
  • Vision 摘要(委托给 AgentCore → VisionSummarizer)

只做

  • AgentCore.run_turn() 消费 token 流
  • 断句 → 表情/动作提取 → TTS 过滤 → 显示处理
  • 维护 MemoryStore(对话消息列表 + 本地历史持久化)

MemoryStore 只管对话消息列表与本地历史,不负责 mem0 记忆的读写。mem0 的读写由 MemoryPlugin(hook 插件)承担,两者职责不同。

模块分层

MemoryAgent (agent.py)                ← 编排器
├── AgentCore (core.py)               ← 共享核心(tool / vision / prompt / LLM)
│   ├── AsyncLLM.stream_with_tools()  ← 统一流式 tool calling
│   ├── VisionSummarizer              ← 图片摘要
│   ├── PromptBuilder                 ← UserPromptBlock 拼装
│   └── ConversationStorage           ← MemoryStoreAdapter(写回由 MemoryAgent 接管)
├── MemoryStore (memory_store.py)     ← memory / history / interrupt
├── MessageFactory (message_factory.py) ← 消息解析与构造
└── Transformers 管线 (transformers.py)
    sentence_divider → actions_extractor → tts_filter → display_processor

AgentCore.write_back = False

MemoryAgent 初始化时将 core.write_back 设为 False,由 MemoryAgent 自身统一负责写回 MemoryStore。这样 assistant message 的写入时机与 TTS 流程对齐,避免双写。

数据流

📥 BatchInput(用户输入:文本 + 可选图片)

✉️ MessageFactory.build_user_message_from_batch()

💬 AgentCore.run_turn(user_text, user_images)
    ─────────────────────────────────────────
    │  [vision 预处理] VisionSummarizer
    │  [prompt 拼装]   PromptBuilder

    │  chat_llm.stream_with_tools(messages, tools=schema)
    │  loop:
    │    text delta → yield str
    │    tool_call  → yield [🔧 name] → execute → continue
    │    stop       → break
    ─────────────────────────────────────────
    ↓ yield str tokens
🔄 Transformers 管线
    sentence_divider      # 按标点断句
      → actions_extractor # 提取 [emotion]/[sound] 等动作标签
      → tts_filter        # 过滤 [think]/[🔧 ...] 等不朗读内容
      → display_processor # 处理显示文本(think 折叠等)

📤 yield SentenceOutput
    ├── display_text  # 字幕 / 弹幕
    ├── tts_text      # 送 TTS 朗读的文本(已过滤标签)
    └── actions       # Live2D 动作 / 表情 / 音效

💾 MemoryStore.add_message()  # 写回 user + assistant message

关键设计决策

工具状态标签不朗读

AgentCore 在执行工具前 yield [🔧 tool_name] 标签。tts_filter 依据 ignore_brackets 配置过滤掉方括号内容(或通过 tag 机制识别),保证 TTS 不读出工具状态,但字幕仍可展示。

Vision 决策

chat_supports_vision(来自 lab.toml[agent.chat_model])决定图片处理方式:

chat_supports_visionrequire_detailed行为
Falseany必须生成 vision 摘要,纯文本喂 chat
TrueFalse图片直接喂 chat,不生成摘要
TrueTrue图片喂 chat + 同步生成逐图摘要(双保险)

History 不存 base64

MemoryStore 写回时只存文本内容,不保留图片 base64,避免 memory 文件膨胀。

Tool 图与用户图隔离

  • 工具回调图:标签 tool1,来源 source="tool"
  • 用户上传图:标签 p1/p2/...,来源 source="upload"

两类图片在 vision 摘要和 prompt 注入时分开处理,不混用标签。

扩展点

  • 多工具截图:在 ToolManager 侧收集多张 tool 图,给出 tool1/tool2... 标签(目前默认单张)
  • 支持 http(s) 图片:在 MessageFactory.extract_text_and_data_images 扩展
  • 自定义断句segment_method 支持 pysbd / 自定义标点规则
  • 中断方式interrupt_method=system(注入 system message)或 user(注入 user message)

记忆读写

mem0 记忆的读写不在 MemoryAgent 里,而在 MemoryPlugin(hook 插件)里:

  • on_before_turn → POST /memory/search,结果注入本轮 memory_context
  • on_after_turn → POST /memory/add,fire-and-forget,写入 mem0 + 触发 graph pipeline

agent_id 来自 Profile 的 [plugins.memory] agent_id,这是记忆归属的唯一来源。elaina 和 congyin 各写各的,但共存于同一个 Neo4j 图中。

魔女の实验室