1. Agentic RAG 原理
Agentic RAG(Agent-based Retrieval-Augmented Generation)是指在传统的 RAG(Retrieval-Augmented Generation)框架中引入了 Agent(智能体)作为核心组件的变体。在标准的 RAG 系统中,主要是通过检索相关文档或信息来增强生成模型的能力,而 Agentic RAG 则通过集成一个智能体,帮助系统在搜索和生成过程中进行更智能的决策和交互。
具体来说:它将 AI 代理合并到 RAG 管道中,以编排其组件并执行简单信息检索和生成之外的其他操作,以克服非代理管道的限制。代理 RAG 最常见的是指在检索组件中使用代理。通过使用可访问不同检索器工具的检索代理而变得代理,例如:
- 矢量搜索引擎(也称为查询引擎),通过矢量索引执行矢量搜索(如典型的 RAG 管道)
- Web search 网页搜索
- 任何以编程方式访问软件的 API,例如电子邮件或聊天程序
这里我们用 Agentic RAG 去整合 Web 搜索和传统的 RAG。首先 构建传统 RAG 的Agent节点:
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain.tools import tool
llm = ChatOpenAI(model_name="gpt-4o-mini", temperature=0.1)
@tool
def vec_kg(question:str):
"""
个人知识库,存储AI Agent项目概念的解读
"""
prompt = PromptTemplate(
template="""你是一名问答任务的助手。
请使用以下检索到的上下文来回答问题。如果你不知道答案,就直接说你不知道。
最多使用5句话,并保持答案简洁:
Question: {question}
Context: {context}
Answer:
""",
input_variables=["question", "document"],
)
# 构建传统的RAG Chain
rag_chain = prompt | llm | StrOutputParser()
# 构建检索器
retriever = vectorstore.as_retriever(search_kwargs={"k": 1})
# 执行检索
docs = retriever.invoke("question")
generation = rag_chain.invoke({"context": docs, "question": question})
return generation
tools = [fetch_real_time_info, vec_kg]
model = llm.bind_tools(tools)
tools
[StructuredTool(name='fetch_real_time_info', description='Get real-time Internet information', args_schema=<class '__main__.SearchQuery'>, func=<function fetch_real_time_info at 0x15cb50ae0>),
StructuredTool(name='vec_kg', description='个人知识库,存储AI Agent项目概念的解读', args_schema=<class 'langchain_core.utils.pydantic.vec_kg'>, func=<function vec_kg at 0x15d79df80>)]
import json
from langchain_core.messages import ToolMessage, SystemMessage, HumanMessage
from langchain_core.runnables import RunnableConfig
tools_by_name = {tool.name: tool for tool in tools}
# 定义工具节点
def tool_node(state: AgentState):
outputs = []
for tool_call in state["messages"][-1].tool_calls:
tool_result = tools_by_name[tool_call["name"]].invoke(tool_call["args"])
outputs.append(
ToolMessage(
content=json.dumps(tool_result),
name=tool_call["name"],
tool_call_id=tool_call["id"],
)
)
return {"messages": outputs}
# 定义问答模型
def call_model(
state: AgentState,
):
system_prompt = SystemMessage(
"您是一位乐于助人的AI助手,请尽力回复用户的查询!"
)
response = model.invoke([system_prompt] + state["messages"])
return {"messages": [response]}
# 定义路由节点
def should_continue(state: AgentState):
messages = state["messages"]
last_message = messages[-1]
if not last_message.tool_calls:
return "end"
else:
return "continue"
from langgraph.graph import StateGraph, END
# 定义一个图结构
workflow = StateGraph(AgentState)
# 在图结构中添加节点
workflow.add_node("agent", call_model)
workflow.add_node("tools", tool_node)
# 设置启动点是 agent
workflow.set_entry_point("agent")
# 添加路由边
workflow.add_conditional_edges(
"agent",
should_continue,
{
"continue": "tools",
"end": END,
},
)
# 添加返回边
workflow.add_edge("tools", "agent")
# 编译图
graph = workflow.compile()
from IPython.display import Image, display
display(Image(graph.get_graph().draw_mermaid_png()))
# 定义问答的流
def print_stream(stream):
for s in stream:
message = s["messages"][-1]
if isinstance(message, tuple):
print(message)
else:
message.pretty_print()
inputs = {"messages": [("user", "OpenAI 最近在互联网上有什么新闻?注意,请使用中文回复。")]}
print_stream(graph.stream(inputs, stream_mode="values"))
================================[1m Human Message [0m=================================
OpenAI 最近在互联网上有什么新闻?注意,请使用中文回复。
==================================[1m Ai Message [0m==================================
Tool Calls:
fetch_real_time_info (call_10hLZlqE6FQ66C7o9p0BfgDn)
Call ID: call_10hLZlqE6FQ66C7o9p0BfgDn
Args:
query: OpenAI 新闻
=================================[1m Tool Message [0m=================================
Name: fetch_real_time_info
"[{\"title\": \"OpenAI News\", \"link\": \"https://openai.com/news/\", \"snippet\": \"Introducing OpenAI o3 and o4-mini, Release Apr 16, 2025, API GPT-4.1, Art 16.9, Introducing GPT-4.1 in the API, Product Apr 14, 2025.\", \"sitelinks\": [{\"title\": \"Company\", \"link\": \"https://openai.com/news/company-announcements/\"}, {\"title\": \"Research\", \"link\": \"https://openai.com/news/research/\"}], \"position\": 1}]"
==================================[1m Ai Message [0m==================================
最近,OpenAI 发布了一些新消息,包括推出 OpenAI o3 和 o4-mini,以及在 API 中引入 GPT-4.1。具体信息可以访问 [OpenAI 新闻页面](https://openai.com/news/)。如果你对公司的公告或研究感兴趣,可以查看以下链接:
- [公司公告](https://openai.com/news/company-announcements/)
- [研究动态](https://openai.com/news/research/)
inputs = {"messages": [("user", "请检索我的知识库并总结一下什么是 百小灵, 注意,请使用中文回复。")]}
print_stream(graph.stream(inputs, stream_mode="values"))
================================[1m Human Message [0m=================================
请检索我的知识库并总结一下什么是 百小灵, 注意,请使用中文回复。
==================================[1m Ai Message [0m==================================
Tool Calls:
vec_kg (call_H0qK1LrDo00h1uvM1tWw2Lx7)
Call ID: call_H0qK1LrDo00h1uvM1tWw2Lx7
Args:
question: 百小灵
=================================[1m Tool Message [0m=================================
Name: vec_kg
"\u767e\u5c0f\u7075\u662f\u4e00\u4e2aAI\u52a9\u624b\uff0c\u80fd\u591f\u56de\u7b54\u7528\u6237\u7684\u5404\u79cd\u95ee\u9898\u3002\u5b83\u53ef\u4ee5\u5904\u7406\u8bed\u97f3\u3001\u56fe\u7247\u548c\u9644\u4ef6\u63d0\u95ee\uff0c\u5e76\u81f4\u529b\u4e8e\u4fdd\u62a4\u7528\u6237\u9690\u79c1\u3002\u8be5\u52a9\u624b\u7684\u5177\u4f53\u7814\u53d1\u516c\u53f8\u548c\u4e0a\u7ebf\u65f6\u95f4\u5728\u63d0\u4f9b\u7684\u4e0a\u4e0b\u6587\u4e2d\u6ca1\u6709\u660e\u786e\u8bf4\u660e\u3002"
==================================[1m Ai Message [0m==================================
百小灵是一个AI助手,能够回答用户的各种问题。它可以处理语音、图片和附件提问,并致力于保护用户隐私。该助手的具体研发公司和上线时间在提供的资料中并没有明确说明。
当然,也会存在一些问题,比如:推理模型仅做步骤拆解,但不会触发访问web检索或者RAG的操作,如下所示:
inputs = {"messages": [("user", "请检索我的知识库,并实时联网检索,结合两部分的信息帮我总结:什么是 百小灵。注意:请使用中文回答我")]}
print_stream(graph.stream(inputs, stream_mode="values"))
================================[1m Human Message [0m=================================
请检索我的知识库,并实时联网检索,结合两部分的信息帮我总结:什么是 百小灵。注意:请使用中文回答我
==================================[1m Ai Message [0m==================================
Tool Calls:
vec_kg (call_opPVIwKbLmBC4iZqPe9fof1T)
Call ID: call_opPVIwKbLmBC4iZqPe9fof1T
Args:
question: 什么是百小灵
fetch_real_time_info (call_YWFEHv2giZ2XSfwCznTpPIl4)
Call ID: call_YWFEHv2giZ2XSfwCznTpPIl4
Args:
query: 百小灵
=================================[1m Tool Message [0m=================================
Name: fetch_real_time_info
"[{\"title\": \"https://ying.baichuan-ai.com/chat?from=home\", \"link\": \"https://ying.baichuan-ai.com/chat?from=home\", \"snippet\": \"No information is available for this page. \u00b7 Learn why\", \"position\": 1}, {\"title\": \"\u767e\u53d8\u5c0f\u7075 \u7684\u4e3b\u9875- \u6296\u97f3\", \"link\": \"https://www.douyin.com/user/MS4wLjABAAAAJ4B8d_pkbJ1HdnI669kwWAKMuissXDqa5RZMsu1U2hH2e1Ygs_TstyzTu6BeC-nq\", \"snippet\": \"\u767e\u53d8\u5c0f\u7075 \uff1a\u662f\u591a\u53d8\u7684\u5c0f\u7075 \u4fdd\u6301\u5bf9\u751f\u6d3b\u7684\u7231\u548c\u70ed\u6795\u628a\u6bcf\u4e00\u5929\u6d3b\u7684\u70ed\u6c14\u817e\u817e\uff01 \u7b49\u4e00\u675f\u5149\u7167\u4eae\u6211\u7684\u4e16\u754c\uff01\u3002\u767e\u53d8\u5c0f\u7075 \u5165\u9a7b\u6296\u97f3\uff0cTA\u7684\u6296\u97f3\u53f7\u662fXling1688\uff0c\u5df2\u67091000\u4e2a\u7c89\u4e1d\uff0c\u6536\u83b7\u4e867279\u4e2a ...\", \"position\": 2}, {\"title\": \"\u53e4\u5c0f\u7075_\u767e\u5ea6\u767e\u79d1\", \"link\": \"https://baike.baidu.hk/item/%E5%8F%A4%E5%B0%8F%E9%9D%88/19910830\", \"snippet\": \"\u53e4\u5c0f\u7075\uff0c\u5973\uff0c\u5c0f\u8bf4\u300a\u60ca\u609a\u4e50\u56ed\u300b[1] \u4e2d\u7684\u4eba\u7269\u3002\u5728\u6e38\u620f\u4e2d\u7684\u6635\u79f0\u4e3a\u60b2\u7075\u7b11\u9aa8\uff0c\u793e\u56e2\u201c\u5730\u72f1\u524d\u7ebf\u201d\u56e2\u5458\u3002\u7237\u7237\u662f\u53e4\u5c18\uff08\u732b\u7237\uff09\uff0c\u7236\u4eb2\u662f\u53e4\u51ca\uff0c\u6bcd\u4eb2\u662f\u5361\u95e8.\u83ab\u83b1\u8bfa\uff0c\u81ea\u79f0\u201c\u8d85\u7ea7\u7f8e\u5c11\u5973\u201d\uff0c\u5e73\u65e5\u91cc\u53e4 ...\", \"position\": 3}]"
==================================[1m Ai Message [0m==================================
百小灵是一种人工智能助手,能够回答用户的各种问题。它可以处理语音、图片和附件提问,并致力于保护用户隐私。百小灵的功能包括提供营销文案和社交媒体内容的建议。
根据实时信息,百小灵似乎与一个名为“百变小灵”的项目有关,后者是一个多变的智能助手,旨在为用户提供生活中的各种帮助和建议。
总结来说,百小灵是一个智能助手,旨在通过多种方式(如语音和图像)与用户互动,提供信息和建议,同时注重用户隐私保护。
或者产生幻觉,直接说自己无法访问知识库。如下所示:
inputs = {"messages": [("user", "请检索我的知识库,帮我总结一下什么是 百小灵, 注意,请使用中文回复。")]}
print_stream(graph.stream(inputs, stream_mode="values"))
================================[1m Human Message [0m=================================
请检索我的知识库,帮我总结一下什么是 百小灵, 注意,请使用中文回复。
==================================[1m Ai Message [0m==================================
Tool Calls:
vec_kg (call_9qkzgUSQVzbrODsygE1u38M5)
Call ID: call_9qkzgUSQVzbrODsygE1u38M5
Args:
question: 百小灵
=================================[1m Tool Message [0m=================================
Name: vec_kg
"\u767e\u5c0f\u7075\u662f\u4e00\u79cd\u4eba\u5de5\u667a\u80fd\u52a9\u624b\uff0c\u80fd\u591f\u56de\u7b54\u7528\u6237\u7684\u5404\u79cd\u95ee\u9898\u3002\u5b83\u53ef\u4ee5\u5904\u7406\u8bed\u97f3\u3001\u56fe\u7247\u548c\u9644\u4ef6\u63d0\u95ee\uff0c\u5e76\u4e14\u4f1a\u4fdd\u62a4\u7528\u6237\u9690\u79c1\u3002\u8be5\u52a9\u624b\u7684\u5177\u4f53\u7814\u53d1\u516c\u53f8\u548c\u4e0a\u7ebf\u65f6\u95f4\u5728\u63d0\u4f9b\u7684\u4e0a\u4e0b\u6587\u4e2d\u6ca1\u6709\u660e\u786e\u8bf4\u660e\u3002"
==================================[1m Ai Message [0m==================================
百小灵是一种人工智能助手,能够回答用户的各种问题。它可以处理语音、图片和附件提问,并且会保护用户的隐私。该助手的具体研发公司和上线时间在提供的资料中并没有明确说明。
以上存在的问题使我们在做AI Agent 开发过程中基本都会遇到的情况,同时也是根据实际业务做特定优化的主要工作。