02.2 — RAG 与长期记忆
定位: Agent 长期记忆的核心实现技术——深入理解 RAG 如何在 Agent 中发挥作用,以及如何将 RAG 与 Agent 深度集成 面试高频度: ⭐⭐⭐⭐⭐ 考查方式: 设计题(为 Agent 设计 RAG 系统)、对比题(RAG vs 微调)、机制题(RAG 检索流程和各组件优化)
一、这是什么?为什么需要它?
是什么
RAG(Retrieval-Augmented Generation,检索增强生成) 是一种在 LLM 生成回答前先从外部知识库检索相关信息的架构模式。在 Agent 中,RAG 是长期记忆的主要实现方式。
为什么需要 RAG?
❌ 没有 RAG 的 Agent(纯 LLM):
知识截止于训练数据
无法访问私有/实时数据
"幻觉"无法被事实纠正
每次都要把全部知识写入 prompt
✅ 有 RAG 的 Agent:
可以访问最新的外部知识
可以查询私有文档/数据库
用检索到的事实约束生成,减少幻觉
只注入相关信息,节省 token核心洞察:RAG 就是给 Agent 装了一个"图书馆"——LLM 不需要记住所有知识,它只需要知道怎么去图书馆查资料。
RAG 在记忆系统中的位置
Agent 记忆层次中的 RAG:
┌─ 短期记忆 ───────────────────┐
│ In-context (messages 数组) │ ← 会话中的"刚刚"
└──────────────────────────────┘
┌─ 长期记忆 ───────────────────┐
│ RAG(向量检索 + 知识库) │ ← 会话间的"记得"
└──────────────────────────────┘
┌─ 模型参数 ───────────────────┐
│ 预训练知识 / 微调 │ ← 模型"天生"知道的
└──────────────────────────────┘二、原理拆解
2.1 RAG 的标准流程
┌──────────────────────────────────────────────────────────┐
│ RAG 核心流程 │
│ │
│ 用户查询 │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ 1. 查询 │ "什么是 ReAct 模式?" │
│ │ Query │ │
│ └────┬─────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ ┌──────────────────┐ │
│ │ 2. 编码 │───→│ 查询向量化 │ │
│ │ Embed │ │ [0.12, 0.87, ...]│ │
│ └────┬─────┘ └──────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ ┌──────────────────┐ │
│ │ 3. 检索 │───→│ 向量相似度搜索 │ │
│ │ Retrieve │ │ 找到 Top-K 匹配 │ │
│ └────┬─────┘ └──────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ ┌──────────────────┐ │
│ │ 4. 增强 │───→│ 将检索结果注入 │ │
│ │ Augment │ │ prompt │ │
│ └────┬─────┘ └──────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ 5. 生成 │ 结合检索内容的回答 │
│ │ Generate │ "ReAct 模式是一种..." │
│ └──────────┘ │
│ │
└──────────────────────────────────────────────────────────┘2.2 RAG 各组件详解
① 文档嵌入(Embedding)
| 组件 | 说明 | 常见方案 |
|---|---|---|
| Embedding Model | 将文本转为向量 | text-embedding-3-small, bge-large |
| 向量维度 | 向量长度,影响精度和存储 | 384/768/1536 维 |
| 分块策略 | 如何切分文档 | 固定大小、语义分块、递归分块 |
| 元数据 | 附带的标量信息 | 来源、时间、类型、权限 |
为什么分块大小很重要?
分块太小 (64 tokens) → 上下文不完整,检索不准确
分块合适 (256-512 tokens) → 语义完整,检索精确
分块太大 (2048+ tokens) → 噪音多,命中率低② 检索策略
| 策略 | 工作原理 | 适用场景 |
|---|---|---|
| 向量检索 | 余弦相似度/欧几里得距离 | 语义搜索,通用场景 |
| 关键词检索 | BM25/TF-IDF | 精确匹配,专有名词 |
| 混合检索 | 向量 + 关键词加权融合 | 最佳实践——兼顾语义和精确 |
| HyDE | 先生成假设文档再检索 | 查询和文档语义差距大时 |
混合检索的权重策略:
最终得分 = α × 向量相似度 + (1-α) × BM25 得分
α = 0.7 → 偏向语义理解
α = 0.3 → 偏向关键词匹配
通常 α=0.5 是安全起点③ 检索结果增强
python
# RAG 中如何将检索结果注入 prompt
def build_rag_prompt(query: str, retrieved_docs: list) -> str:
context = "\n\n---\n\n".join([
f"[来源 {i+1}]: {doc['content']}"
for i, doc in enumerate(retrieved_docs)
])
prompt = f"""基于以下参考资料回答问题。
参考资料:
{context}
问题: {query}
要求:
1. 优先使用参考资料中的信息
2. 如果参考资料不足以回答问题,明确说明
3. 注明信息来源于哪个参考资料"""
return prompt2.3 RAG 在 Agent 中的深度集成
Agent 中的 RAG 比标准 RAG 更复杂,因为 Agent 需要动态决定何时检索、检索什么。
┌─────────────────────────────────────────────────────────┐
│ Agent + RAG 深度集成架构 │
│ │
│ Agent 循环 │
│ ┌────────────┐ │
│ │ 感知 │ │
│ │ 用户问题 │ │
│ └─────┬──────┘ │
│ │ Agent 自主决定是否需要检索 │
│ ▼ │
│ ┌────────────┐ ┌──────────────┐ │
│ │ 思考 │───→│ 需要更多信息? │ │
│ │ 推理 │ │ ┌───┐ ┌──┐ │ │
│ └─────┬──────┘ │ │是│ │否│ │ │
│ │ └──┼───┼──┼──┘ │
│ ▼ │ │ │ │
│ ┌────────────┐ │ │ │ │
│ │ 检索行动 │←──────┘ │ │ │
│ │ search() │ │ │ │
│ └─────┬──────┘ │ │ │
│ │ 文档返回 │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────┐ │
│ │ 观察 │ 融合检索结果继续推理 │
│ │ 分析文档 │ │
│ └────────────┘ │
└─────────────────────────────────────────────────────────┘python
# Agent 自主决定检索的 RAG 实现
class AgentRAG:
def __init__(self, knowledge_base: VectorStore):
self.kb = knowledge_base
def decide_to_retrieve(self, query: str, context: str) -> bool:
"""让 LLM 自主判断是否需要检索"""
prompt = f"""当前任务: {query}
已有上下文: {context}
是否需要搜索知识库来获取更多信息?回答 YES 或 NO。"""
decision = llm.call(prompt)
return "YES" in decision.upper()
def run(self, user_query: str):
messages = [{"role": "user", "content": user_query}]
while True:
# Agent 思考:需要检索吗?
if self.decide_to_retrieve(user_query, str(messages)):
# 执行检索(作为工具调用)
query = llm.call(f"为检索生成搜索查询:{user_query}")
docs = self.kb.similarity_search(query, k=3)
messages.append({
"role": "system",
"content": f"【检索结果】\n{docs}"
})
# LLM 生成回答
response = llm.call(messages)
if response.has_tool_call:
# 执行其他工具...
continue
return response.content2.4 RAG vs 微调
这是面试中的经典对比问题:
| 维度 | RAG | 微调 (Fine-tuning) |
|---|---|---|
| 知识更新 | 即时——只需更新索引 | 慢——需要重新训练 |
| 成本 | 低(检索 + 生成) | 高(训练 + 部署) |
| 幻觉控制 | 好——用外部事实约束 | 差——模型可能"创造" |
| 长尾知识 | 好——可以索引任意知识 | 差——难以覆盖所有 |
| 推理能力 | 保持 LLM 原有能力 | 可能降低(灾难性遗忘) |
| 实时性 | 高——可以搜最新数据 | 低——训练数据截止 |
| 适用场景 | 知识问答、文档分析 | 风格迁移、指令遵循 |
选择指南:
需要访问最新/私有数据 → RAG
需要模型改变行为/风格 → 微调
两者兼顾 → RAG + 微调(最佳实践)三、图解全景
┌──────────────────────────────────────────────────────────┐
│ Agent 中 RAG 的完整工作流程 │
│ │
│ 数据准备阶段 (离线) │
│ ┌─────────┐ ┌────────┐ ┌──────────┐ │
│ │ 文档源 │───→│ 分块 │───→│ 向量化 │ │
│ │ PDF/Wiki │ │ 策略 │ │ Embedding│ │
│ └─────────┘ └────────┘ └─────┬────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ 向量数据库 │ │
│ │ Index │ │
│ └──────────┘ │
│ │
│ 推理阶段 (在线) │
│ ┌─────────┐ ┌────────┐ ┌──────────┐ │
│ │ Agent │───→│ 检索触发│───→│ 查询向量化│ │
│ │ 决策 │ │ 工具调用│ │ │ │
│ └─────────┘ └────────┘ └─────┬────┘ │
│ │ │
│ ┌─────────┐ ┌────────┐ │ │
│ │ LLM生成 │←───│ 注入 │←────────┘ │
│ │ 最终回答│ │ Prompt │ │
│ └─────────┘ └────────┘ │
└──────────────────────────────────────────────────────────┘四、实战验证
4.1 用 LangChain 实现 Agent RAG
python
# 一个完整的 Agent + RAG 示例
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import OpenAIEmbeddings
from langchain.agents import AgentExecutor, create_react_agent
from langchain.tools import Tool
# 1. 准备知识库
embeddings = OpenAIEmbeddings()
vectorstore = Chroma(
persist_directory="./agent_knowledge",
embedding_function=embeddings
)
# 2. 创建检索工具
def search_knowledge(query: str) -> str:
"""从知识库中检索相关信息"""
docs = vectorstore.similarity_search(query, k=3)
return "\n".join([d.page_content for d in docs])
tools = [
Tool(
name="search_knowledge",
func=search_knowledge,
description="搜索知识库获取相关信息"
),
# 其他 Agent 工具...
]
# 3. 创建 ReAct Agent(自动在需要时检索)
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
max_iterations=5
)
# 4. 运行
result = agent_executor.invoke({
"input": "解释 ReAct 模式并给出一个例子"
})
print(result["output"])4.2 RAG 质量评估
bash
# RAG 系统的关键指标
# 1. 检索准确率 (Retrieval Precision)
# 检索到的文档中,真正相关的比例
# 目标: > 80%
# 2. 检索召回率 (Retrieval Recall)
# 所有相关文档中,被检索到的比例
# 目标: > 70%
# 3. 生成准确率 (Generation Accuracy)
# 基于检索结果生成的回答是否正确
# 目标: > 90%
# 4. 端到端延迟
# 检索 + 生成的总耗时
# 目标: < 3s
# 优化的关键是"检索质量"——检索不对,生成一定不对。
# 检索质量 = f(分块策略, 嵌入模型, 检索算法, 重排序)4.3 体验 Agent RAG 的效果
bash
# 对比测试:纯 LLM vs Agent + RAG
# 场景:询问最新的 Python 3.12 特性
# 纯 LLM:
# "Python 3.12 引入了..."
# → 可能准确,可能过时,可能幻觉
# Agent + RAG:
# Agent: "我需要搜索 Python 3.12 的官方文档"
# → search_knowledge("Python 3.12 new features")
# → 从索引的官方文档中检索
# → "根据 Python 3.12 官方文档..."
# → 有来源、更准确、更新五、面试视角
| 追问 | 答案要点 |
|---|---|
| RAG 在 Agent 中扮演什么角色? | 长期记忆的实现技术。为 Agent 提供外部知识访问能力,解决知识截止、幻觉、私有数据访问三大问题 |
| RAG 的核心流程是什么?各组件如何优化? | Query → Embed → Retrieve → Augment → Generate。优化点:分块策略(256-512 tokens)、检索策略(混合检索 BM25+向量)、重排序(reranker) |
| Agent 中 RAG 和标准 RAG 的区别? | 标准 RAG:每次必检索。Agent RAG:Agent 自主决定何时检索、可以多次检索、检索是工具调用之一、结果可以被 Agent 进一步分析再用 |
| RAG 如何解决"检索不准确"的问题? | 多查询扩展(生成多个搜索词)、HyDE(先假设再检索)、重排序(初检+精排)、混合检索(语义+关键词互补) |
| RAG vs 微调,什么场景选哪个? | RAG 适合知识密集、需要更新、长尾知识的场景。微调适合行为改变、风格迁移。最佳实践是 RAG + 微调互补使用 |
| Agent 中 RAG 的挑战是什么? | 检索时机(什么时候该检索)、检索内容(生成好的搜索查询)、结果融合(检索结果多怎么办)、成本(每次检索都有 embedding 和存储成本) |
📚 相关链接
- **记忆分类与架构** — 记忆类型的基础
- **记忆管理与检索** — 记忆的检索和更新策略
- **Agent 架构模式** — Agent 如何调用检索工具
- **RAG 知识库** — RAG 技术的全面深入
- ← 返回 **Agent记忆系统索引**