mm_agent_tutorial

第 5 章 记忆与知识:RAG、多模态检索与状态管理

本章摘要: 只有“当前上下文(Context)”的智能体就像只有“金鱼记忆”的实习生,无论能力多强,都无法胜任长周期、复杂背景的任务。 本章将构建智能体的认知纵深。我们将突破单纯的“文本 RAG”,深入探讨多模态混合检索——即如何让智能体在海量的 PDF、图表、照片和日志中,像人类一样“联想”和“查阅”。同时,我们将引入有限状态机(FSM)来约束大模型的发散性,确保任务流程严丝合缝。 核心概念Multi-modal EmbeddingHybrid SearchQuery RewritingSlot FillingMemory Lifecycle


5.1 记忆架构:从海马体到大脑皮层

如果不进分层设计,随着对话变长,Token 成本将呈指数级增长,而检索准确率却会因“大海捞针”效应而下降。我们需要构建一个仿生的记忆金字塔。

5.1.1 三级记忆模型 (The 3-Level Memory Model)

请参考以下架构图,理解不同层级的存储介质、读写速度与用途:

                  [ 智能体 "大脑" (CPU/GPU) ]
                              ^
                              | (Attention)
+-----------------------------+-----------------------------+
|  L1: 工作记忆 (Working Memory / Hot Context)              |
|  -------------------------------------------------------  |
|  * 介质: LLM Context Window (RAM)                         |
|  * 内容: 系统提示词 + 当前轮次对话 + 工具实时返回结果     |
|  * 策略: FIFO (先进先出), 滑动窗口                        |
|  * 成本: $$$ (每次推理都计费)                             |
+-----------------------------------------------------------+
              ^                           | (写入摘要)
              | (注入)                    v
+-----------------------------------------+-----------------+
|  L2: 情景记忆 (Episodic Memory / Session State)           |
|  -------------------------------------------------------  |
|  * 介质: NoSQL / Redis / JSON                             |
|  * 内容: 对话历史摘要, 用户当前意图, 槽位状态(Slots)      |
|  * 策略: 读写频繁, 随会话结束而归档                       |
+-----------------------------------------+-----------------+
              ^                           | (沉淀/归档)
              | (检索/Recall)             v
+-----------------------------------------+-----------------+
|  L3: 语义记忆 (Semantic Memory / Long-term Knowledge)     |
|  -------------------------------------------------------  |
|  * 介质: Vector DB + 搜索引擎 (ElasticSearch)             |
|  * 内容: 公司文档, 维修手册(PDF), 历史工单库, 知识图谱    |
|  * 策: 静态为主, 周期性更新, 混合检索                   |
+-----------------------------------------------------------+

5.1.2 Rule of Thumb (经验法则)

  1. Context 预算控制:始终假设你只有 8k token 的预算,即使模型支持 128k。精简的 Context 能带来更高的指令遵循能力(Instruction Following)。
  2. L2 是“压缩机”:不要把 50 轮对话原样塞给 L1。每隔 5-10 轮,触发一个后台的小模型(如 GPT-3.5-Turbo 或 Claude-Haiku)对历史进行摘要:“用户之前询问了 X,尝试了方案 A 失败,现在正在尝试方案 B。”
  3. L3 的“真相源”原则:L3 存储的数据必须包含原文引用(Raw Content Ref)。Embedding 只是索引,不是真相。生成答案时必须基于原文,而不是基于向量。

5.2 多模态 RAG:超越文本匹配

在多模态场景下,用户的问题往往是隐晦的。比如用户拍了一张红灯闪烁的照片问:“这怎么修?” 如果你只检索文本“这怎么修”,结果将是灾难性的。

5.2.1 三种多模态索引策略

我们如何把 PDF 中的图文存入数据库?

策略 描述 优点 缺点 适用场景
A. Image-to-Text (Captioning) 用 VLM 把图变成文字描述,存入文本向量库。 兼容现有纯文本 RAG 架构。 丢失细节(颜色深浅、微小划痕、空间关系)。 通用文档检索。
B. Cross-Modal Embedding 使用 CLIP/SigLIP 等模型,将 Text 和 Image 映射到同一向量空间。 支持“以文搜图”和“以图搜图”。 需要专门的向量库支持;难以处理含大量文字的图。 电商搜图、场景匹配。
C. ColPali / Late Interaction 保留图像的 Patch Embedding,与文本 Token 直接进行交互(前沿技术)。 极高的多模态理解力,无需 OCR 中间层。 计算开销大,存储成本高。 复杂图表、技术图纸解析。

5.2.2 查询改写与多路召回 (Query Rewriting & Multi-Route Retrieval)

这是 RAG 成功的关键。用户输入通常是不完整多模态的。

架构流程图

用户输入: [Image: 仪表盘亮灯] + "这个灯亮了,怎么关掉?"
       |
       v
[ 1. 理解与改写 (Rewriter Agent) ]
       |-- 分析图片 --> 识别出物体: "Honda CR-V 2023", 识别文字: "Check Engine"
       |-- 补全指代 --> 将"这个灯"替换为"Engine Warning Light"
       |-- 意图扩展 --> 增加同义词: "Turn off", "Reset", "Troubleshoot"
       |
       v (生成多路 Query)
       |
+------+--------------------------+-------------------------+
| Route A: 关键词检索 (BM25)      | Route B: 向量检索 (Dense) | Route C: 视觉相似度 (Visual)
| "Honda CR-V Check Engine Reset" | Embedding(语义描述)      | Embedding(用户原图)
| (擅长专有名词匹配)               | (擅长概念匹配)            | (擅长外观匹配)
+------+--------------------------+-------------------------+
       |                          |                         |
       v                          v                         v
[ 2. 混合重排序 (Hybrid Rerank) ]
       |-- 统一分数 = w1*BM25 + w2*Vector + w3*Visual
       |-- 剔除相似度 < 0.6 的噪声
       |
       v
[ Top-K 结果注入 Context ]

5.2.3 冲突消解:当图文不一致时

知识库中的文档可能过时,或者图片与文字有冲突。 策略


5.3 状态管理:让 Agent 拥有“定力”

简单的 Chain-of-Thought (CoT) 不足以支撑长流程任务。我们需要有限状态机 (FSM) 来管理任务进度。

5.3.1 状态机模型

以“设备报修”为例,Agent 的行为应由当前 State 决定。

State: [ INITIAL ]
  |-- Event: 用户打招呼 --> Action: 问候, 转 [ CLARIFY_INTENT ]
  |
State: [ CLARIFY_INTENT ]
  |-- Event: 用户说"修电脑" --> Action: 询问设备型号, 转 [ COLLECT_INFO ]
  |-- Event: 用户说"查询进度" --> Action: 调用查询工具, 转 [ CHECK_STATUS ]
  |
State: [ COLLECT_INFO ] (关键: 槽位填充)
  |-- Check: 缺少 Serial_Number? --> Action: 追问序列号
  |-- Check: 缺少 Error_Photo? --> Action: 追问故障截图
  |-- Check: 全部收集完毕? --> Action: 生成工单, 转 [ SUBMIT ]
  |
State: [ SUBMIT ]
  |-- Action: 调用 API 提交, 返回结果, 转 [ END ]

5.3.2 槽位填充 (Slot Filling) 与 Working Memory

COLLECT_INFO 状态下,Agent 的核心目标不是聊天,而是填满 JSON Schema。

System Prompt 示例

“你现在的任务是收集故障信息。你需要填满以下字段:[device_model, error_code, user_location]当前已知:device_model='Printer X'。请询问缺失的字段,不要闲聊。”


5.4 记忆的更新、遗忘与隐私

5.4.1 RAG 的“时间旅行”问题

如果知识库里有 2021 年的手册和 2024 年的手册,Embedding 很接近,Agent 很容易混淆。 解决方案

  1. 元数据过滤 (Metadata Filtering):在检索前,先进行 SQL 过滤 WHERE year = 2024
  2. 时间衰减 (Time Decay):在 Rerank 阶段,给最新的文档加分。Score = Similarity * (1 / (1 + age_in_years))。

5.4.2 隐私清洗 (PII Redaction)

用户上传的图片可能包含人脸、车牌或密码贴纸。


5.5 本章小

  1. 记忆分层是刚需:L1 贵且短,L2 维持会话,L3 存储知识。分工明确,互不越界。
  2. RAG 必须“改写”:用户的原始 Query 往往是垃圾,经过 LLM 改写和扩展后的 Query 才是黄金。
  3. 多模态检索是混合的:结合文本关键词(精确匹配)和视觉向量(模糊匹配),再通过 Rerank 统一。
  4. 状态机约束行为:对于非闲聊型 Agent,显式的 State 和 Slot 定义是稳定性的基石。

5.6 练习题

说明:思考后点击箭头查看参考思路。

基础题 (50%)

Q1: 上下文预算管理

场景:你的 Agent 接入了一个上下文限制为 8k 的模型。系统提示词占用了 1k。此时用户上传了一个 50 页的 PDF(提取文字后约 20k token)并询问全文总结。 问题:你不能直接把全文塞进去。请提出两种低成本的处理策略。

显示提示与答案 * **Hint**: Map-Reduce 思想或 RAG 思想。 * **Answer**: 1. **Map-Reduce (分块摘要)**: * 将 20k token 切分为 5 个 4k 的块。 * 分别让 LLM 对每个块生成 500 字摘要。 * 将 5 个摘要合并(2.5k token),再次输入 LLM 生成最终总结。 2. **Query-Based RAG (如果是特定问题)**: * 如果用户问特定点,切片存入向量库,只检索相关的 Top-5 chunks。 * *注意*:如果是求“全文总结”,RAG 效果通常不好,Map-Reduce 是更优解。

Q2: 槽位填充设计

场景:设计一个“会议室预定助手”。 问题:定义一个 JSON Schema,包含预定所需的必要槽位。并写出一个 System Prompt 的片段,指导 Agent 当用户只说“我要定明天的会”时该怎么做。

显示提示与答案 * **Hint**: 只有日期是不够的,还需要时间、人数、甚至设备需求。 * **Answer**: * **Schema**: ```json { "date": "tomorrow", "start_time": null, "duration": null, "attendee_count": null } ``` * **Prompt**: > "当前状态: [Collecting_Requirements]。已知信息: 日期=明天。缺失信息: 开始时间, 时长, 人数。请礼貌地追问用户具体的开始时间和预计参会人数,以便推荐合适的会议室。"

Q3: 多模态索引选择

场景:你需要建立一个“服装设计灵感库”,设计师会输入“这种波西米亚风格的领口”并上传一张草图,希望找到历史上相似的衣服。 问题:你应该选择 Captioning + Text Search 还是 Visual Embedding Search?为什么?

显示提示与答案 * **Hint**: 语言能描述“风格”,但很难描述具体的“曲线”或“纹理”。 * **Answer**: * **选择**: **Visual Embedding Search (如 CLIP/SigLIP)**。 * **理由**: “波西米亚风格的领口”这种视觉特征很难用简短的文字精准描述(Lossy compression)。直接用图像向量匹配图像向量,能更好地捉形状、纹理和风格上的相似性。Captioning 可能会漏掉“领口微小的褶皱”这种关键细节。

挑战题 (50%)

Q4: RAG 的“小白鼠”陷阱 (Open Question)

场景:你正在做一个医疗建议 Agent。数据库里有一篇医学论文,里面提到了“某种草药在小白鼠身上实验有效,但人类服用有剧毒”。 问题:用户问:“这种草药人能吃吗?”。普通的 RAG 可能会检索到“有效”这个词,导致 Agent 回答“有效”。如何从数据处理检索策略上避免这种致命错误?

显示提示与答案 * **Hint**: 上下文完整性与否定词检测。 * **Answer**: 1. **大块切片 (Larger Context Chunks)**: 避免把“有效”和“小白鼠/剧毒”切分到不同的 chunk 里。确保上下文完整,让 LLM 看到“有效”是有前提条件的。 2. **假设性/否定性问题检测**: 在重排序(Rerank)阶段训练模型识别“禁忌症”或“副作用”相关的语境,提高警示性内容的权重。 3. **引用强制验证**: 强制 Agent 输出引用原文。并在 System Prompt 强调:“如果原文包含实验对象差异(动物 vs 人)或副作用警告,必须作为首要结论展示。”

Q5: 长短期记忆的协同

场景:用户正在组装一台复杂的机器(耗时 3 天)。

显示提示与答案 * **Hint**: 怎么把 L2 的摘要变成 L3 的检索 Query? * **Answer**: 1. **意图识别**: 用户指代“昨天那个零件 A”。 2. **查阅 L2**: Agent 读取 Session Summary(情景记忆),找到 "Day 1: User installed Part A (Model: Gearbox-X1)"。 3. **实体解析**: 将“零件 A”解析为 "Gearbox-X1"。 4. **构建 L3 Query**: 生成检索词 "Gearbox-X1 screw torque specifications"。 5. **RAG 检索**: 在 L3(说明书库)中检索扭矩数据。 6. **生成回答**: "根据记录,您昨天安装的是 Gearbox-X1。根据手册,其螺丝扭矩应为 50Nm。"

5.7 常见陷阱与错误 (Gotchas)

1. 表格崩坏 (The Broken Table)

2. “图片在第几页?” (The Lost Reference)

3. 过度检索 (Retrieval Loop)

4. 脏数据污染 (Garbage In, Garbage Out)