AI
人工智能相关文章
Agentic RAG实战指南:构建能自主规划检索策略的AI问答系统
Agentic RAG实战指南:构建能自主规划检索策略的AI问答系统
# Agentic RAG实战指南:构建能自主规划检索策略的AI问答系统
## 摘要
传统RAG是被动的"检索-生成"流水线,无法根据中间结果动态调整检索策略。Agentic RAG将Agent的自主规划能力引入RAG流程,让系统像人类研究员一样,自主决定检索什么、何时检索、如何组合信息。
## 一、RAG进化论:从Naive到Agentic
### 1.1 三代RAG对比
| 维度 | Naive RAG | Adaptive RAG | Agentic RAG |
|-----|-----------|-------------|-------------|
| 检索策略 | 固定Top-K | 查询改写+自适应 | Agent自主规划 |
| 检索轮数 | 单轮 | 1-2轮 | 多轮(自主决定) |
| 工具使用 | 仅向量检索 | 多检索器 | 向量+SQL+API+搜索 |
| 纠错能力 | 无 | 有限 | 自我反思+重检索 |
| 适用场景 | 简单FAQ | 中等复杂度 | 复杂研究型任务 |
### 1.2 Agentic RAG的核心思想
Agentic RAG的关键在于**将检索过程本身变成一个Agent决策问题**:
```
用户问题 → Agent思考("需要什么信息?")
→ 选择工具(向量检索/SQL查询/Web搜索)
→ 获取结果
→ Agent思考("信息是否充分?")
→ 不充分 → 重新检索(换关键词/换工具)
→ 充分 → 综合生成答案
```
## 二、基于LangGraph的Agentic RAG实现
### 2.1 定义状态与工具
```python
from typing import TypedDict, Annotated, Sequence
from langchain_core.messages import BaseMessage
import operator
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], operator.add]
original_question: str
search_history: list[str]
retrieved_docs: list[dict]
reflection_count: int
is_sufficient: bool
# 定义可用工具
from langchain_core.tools import tool
@tool
def vector_search(query: str, top_k: int = 5) -> str:
"""从向量数据库检索相关文档片段"""
from langchain_community.vectorstores import Chroma
vectorstore = Chroma(persist_directory="./chroma_db",
embedding_function=embeddings)
docs = vectorstore.similarity_search(query, k=top_k)
return "\n\n---\n\n".join([d.page_content for d in docs])
@tool
def sql_query(question: str) -> str:
"""将自然语言问题转为SQL查询结构化数据"""
from langchain_community.utilities import SQLDatabase
db = SQLDatabase.from_uri("mysql+pymysql://root:Renjnet@1@59.110.223.195:7889/info")
from langchain.chains import create_sql_query_chain
chain = create_sql_query_chain(llm, db)
sql = chain.invoke({"question": question})
return db.run(sql)
@tool
def web_search(query: str) -> str:
"""搜索互联网获取最新信息"""
from langchain_community.tools.tavily import TavilySearchResults
search = TavilySearchResults(max_results=5)
return search.invoke(query)
tools = [vector_search, sql_query, web_search]
```
### 2.2 构建Agent工作流
```python
from langgraph.graph import StateGraph, END
from langgraph.prebuilt import ToolNode
# Agent节点:决策下一步
def agent_node(state: AgentState):
system_prompt = """你是一个智能研究助手。对于用户的问题,你需要:
1. 分析当前已获取的信息是否足够回答问题
2. 如果不够,选择合适的工具获取更多信息
3. 如果已充分,生成最终答案
可用工具:
- vector_search: 检索内部文档库
- sql_query: 查询结构化数据库
- web_search: 搜索互联网
已检索轮数:{reflection_count}/5
已获取文档数:{retrieved_docs_count}
如果信息充分,直接给出最终答案。"""
messages = state["messages"]
response = llm_with_tools.invoke(
[{"role": "system", "content": system_prompt.format(
reflection_count=state["reflection_count"],
retrieved_docs_count=len(state["retrieved_docs"])
)}] + list(messages)
)
return {"messages": [response]}
# 反思节点:检查答案质量
def reflection_node(state: AgentState):
last_msg = state["messages"][-1]
reflection_prompt = """评估当前信息是否足够回答原始问题。
原始问题:{question}
当前已获取信息摘要:{summary}
信息是否充分?回答 YES 或 NO,并说明缺少什么。"""
response = llm.invoke(reflection_prompt.format(
question=state["original_question"],
summary=str(last_msg.content)[:1000]
))
is_sufficient = "YES" in response.content
return {
"is_sufficient": is_sufficient,
"reflection_count": state["reflection_count"] + 1
}
# 路由决策
def should_continue(state: AgentState):
if state["is_sufficient"] or state["reflection_count"] >= 5:
return "end"
if hasattr(state["messages"][-1], "tool_calls") and state["messages"][-1].tool_calls:
return "tools"
return "agent"
# 构建图
workflow = StateGraph(AgentState)
workflow.add_node("agent", agent_node)
workflow.add_node("tools", ToolNode(tools))
workflow.add_node("reflection", reflection_node)
workflow.set_entry_point("agent")
workflow.add_conditional_edges("agent", should_continue, {
"tools": "tools",
"end": END
})
workflow.add_edge("tools", "reflection")
workflow.add_edge("reflection", "agent")
app = workflow.compile()
```
### 2.3 运行示例
```python
result = app.invoke({
"messages": [{"role": "user", "content": "公司2025年Q4的AI产品营收同比增长多少?主要驱动因素是什么?"}],
"original_question": "公司2025年Q4的AI产品营收同比增长多少?主要驱动因素是什么?",
"search_history": [],
"retrieved_docs": [],
"reflection_count": 0,
"is_sufficient": False
})
print(result["messages"][-1].content)
```
**执行流程示例**:
```
1. Agent → "需要先查数据库获取营收数据" → sql_query
2. Reflection → "有营收数据但缺少增长因素分析" → 不充分
3. Agent → "搜索内部文档了解增长分析" → vector_search
4. Reflection → "有定性分析但缺少市场对比" → 不充分
5. Agent → "搜索行业报告" → web_search
6. Reflection → "信息充分" → YES
7. Agent → 生成最终答案
```
## 三、高级优化技巧
### 3.1 查询分解(Query Decomposition)
对于复杂问题,先分解为子问题再逐个检索:
```python
decompose_prompt = """将以下复杂问题分解为2-5个独立的子问题。
原问题:{question}
输出JSON数组格式:
["子问题1", "子问题2", ...]"""
def decompose_query(question: str) -> list[str]:
response = llm.invoke(decompose_prompt.format(question=question))
return json.loads(response.content)
```
### 3.2 答案融合(Answer Fusion)
多个子问题的答案需要融合去重:
```python
fusion_prompt = """以下是多个子问题的检索结果和答案,请融合为一个完整、连贯的回答。
原始问题:{question}
子答案:
{sub_answers}
要求:
1. 去除重复信息
2. 保留所有关键数据点
3. 逻辑连贯
4. 标注信息来源"""
```
### 3.3 检索策略自适应
```python
def select_strategy(question: str) -> str:
"""根据问题类型自动选择检索策略"""
classify_prompt = """判断以下问题属于哪类:
- factual: 事实型,需要精确数据(适合SQL查询)
- analytical: 分析型,需要综合信息(适合多轮向量检索)
- current: 时效型,需要最新信息(适合Web搜索)
问题:{question}
只输出类型关键词。"""
return llm.invoke(classify_prompt.format(question=question)).content.strip()
```
## 四、生产部署注意事项
1. **限制最大检索轮数**:防止Agent陷入无限循环(建议3-5轮)
2. **Token预算控制**:每轮检索结果截断,避免上下文溢出
3. **缓存策略**:相似问题的中间检索结果可复用
4. **超时机制**:单次查询总耗时不超过30秒
5. **降级方案**:Agent失败时退回传统RAG
## 总结
Agentic RAG将RAG从"被动检索"升级为"主动研究",通过Agent的自主规划能力实现多轮检索、工具组合和自我纠错。虽然增加了系统复杂度,但在需要深度分析的复杂问答场景中,其回答质量远超传统RAG。
---
*本文由北科信息日采集系统自动生成,发布日期:2026-05-05*