7.RAG系统升级迈向智能体:对话记忆、多轮上下文管理与Router Agent
对话记忆(Conversation memory)
咱们前面做的系统只能实现单论问答,每次都是问—>查—>答这种循环,一旦要是遇到下面的问题:
Q1: What is paper1 about?
Q2: What are its advantages?
由于没有以往的对话记忆,那么系统就会胡言乱语,在上面的问题中,系统根本不知道its是什么,所以就引入到咱们今天的主题了,对话记忆功能。其实这个功能对于调用大模型接口来说,本质上是扩充messages信息,让原来的单一messages:
messages = [
{"role": "user", "content": question}
]
变成下面这个样子,那么系统就可以根据以往的对话信息回答新问题了:
messages = [
{"role": "user", "content": Q1},
{"role": "assistant", "content": A1},
{"role": "user", "content": Q2}
]
开始动手
首先我们需要扩充原来的咱们创建的RAGSystem类,给它的初始化部分增加一个聊天历史字段,用于记录过去的聊天信息,也就是记忆:
def __init__(self, chunks, top_k=5, rerank_k=3):
self.chunks = chunks
self.top_k = top_k
self.rerank_k = rerank_k
self.index = None
self.embeddings = None
self.chat_history = [] # 👈 新增
随后咱们需要修改咱们message的逻辑,过去咱们message可能是这个样子:
messages = [
{"role": "system", "content": "..."},
{"role": "user", "content": context + question}
]
咱们需要改ask函数的逻辑,使得messages可以被加入历史信息,并且将当前对话信息存起来。
def ask(self, question):
retrieved = self.retrieve(question, k=self.top_k)
texts = [c["text"] for c in retrieved]
sorted_indices = self.rerank(question, texts)
best_chunks = [retrieved[i] for i in sorted_indices[:self.rerank_k]]
context = ""
for c in best_chunks:
context += f"[Source: {c['source']}]\n{c['text']}\n\n"
# ==== 前面的逻辑不变 =====
# ===== 构造messages =====
messages = [
{
"role": "system",
"content": "You are a helpful assistant. Answer based on context and conversation history."
}
]
# 👇 加历史对话
messages.extend(self.chat_history)
# 👇 当前问题
messages.append({
"role": "user",
"content": f"{context}\n\nQuestion: {question}"
})
response = client.chat.completions.create(
model="deepseek-chat",
messages=messages
)
answer = response.choices[0].message.content
# ===== 更新历史 =====
self.chat_history.append({
"role": "user",
"content": question
})
self.chat_history.append({
"role": "assistant",
"content": answer
})
return answer
改造完了之后,又有新的坑出现了! 现在的系统随着你用量的增加,慢慢的你的记忆会越来越多,久了token会爆,所以咱们需要对记忆施加一些限制。首先需要在类内定义一个限制记忆长度的方法,在实现上保留最近的几段对话:
def trim_history(self, max_turns=3):
if len(self.chat_history) > max_turns * 2:
self.chat_history = self.chat_history[-max_turns*2:]
随后在ask的结尾加上self.trim_history(),那么就可以限制记忆的长度了。最后的最后,在FastAPI中增加一个记忆清空功能,那么就实现了咱们今天的对话记忆功能了。
@app.post("/clear")
def clear_memory():
rag.chat_history = []
return {"message": "memory cleared"}
迈向智能体:Router Agent
在迈向智能体之前,我感觉有必要说说智能体是什么?智能体跟平时用的大语言模型有点差别,可以说他是“有手有脚”有执行能力的大语言模型,咱们平时用到的大语言模型只能回答你一些文字问题,但是不能具体帮你做一些具体的事。智能体就是给这些大语言模型安装上一些工具tools,这样大语言模型就能根据你的任务,选择合适的工具完成你的任务。
说到这里不得不提一嘴模型上下文协议(Model Context Protocol,MCP),它是由Anthropic推出的开源协议,旨在实现大语言模型与外部数据源和工具的集成,用来在大模型和数据源之间建立安全双向的连接。该协议通过相同的协议同时处理本地资源(例如数据库、文件、服务等)和远程资源(例如Slack或GitHub等API)。
当然,上面这一度事百度给的比较官方的定义,也听起来不像人话,实际上MCP协议可以理解成大模型调用API的接口,现在随着智能体的发展,很多公司都在对外暴露自己的MCP服务接口,帮助建立智能体生态。
咱们现在写的这个RAG功能,其实也可以在某种程度上可以看作是一种MCP,因为它本质上也是给大模型的一个工具。
Router Agent
前面说了很多,其实说到核心的东西,让大模型选择合适的工具,本质上还是定义一个路由,让模型在面对你提出的问题时,它能知道经过哪个路由去选择合适的工具去完成你的任务。工作流程如下:
用户问题 → 判断 → 调用工具 → 得到结果 → 再回答
知道工作流程,那么我们可以开始后面的代码实现了,首先我们我我们的写的RAG变成一个工具,这需要在RAGSystem类里面定义一个函数:
def rag_tool(self, query):
return self.ask(query)
决策函数(路由的核心)
下面我们就可以实现我们智能体的一个核心组件了,决策函数,通过这个函数,智能体可以确定自己选择什么工具完成任务:
def decide_tool(query):
prompt = f"""
You are an AI assistant.
Decide whether the following question needs document retrieval.
Question:
{query}
Answer ONLY:
- "RAG" if it needs document-based answer
- "LLM" if it can be answered directly
"""
response = client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content.strip()
服务ask改为询问智能体
咱们现在是通过智能体回答问题,所以响应的ask需要进行一定的修改,这里就有工具选择的逻辑需要处理了,通过决策函数确定问题是由RAG工具回答,还是经由大语言模型回答:
def ask_with_agent(self, question):
decision = decide_tool(question)
print("🧠 Decision:", decision)
if "RAG" in decision:
print("📚 Using RAG...")
return self.ask(question)
else:
print("💬 Using LLM...")
response = client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": question}
]
)
return response.choices[0].message.content
最后修改FastAPI调用函数,我们的智能体的雏形就基本实现了:
@app.post("/ask")
def ask_question(req: QueryRequest):
answer = rag.ask_with_agent(req.question)
return {
"question": req.question,
"answer": answer
}
如果这篇文章对你有帮助,可以点个赞~
完整代码地址:https://github.com/1186141415/A-Paper-Rag-Agent
更多推荐


所有评论(0)