基于Langchain构建带对话历史与引用的RAG整合问题求助
整合Langchain对话历史与引用提取的RAG实现方案
核心思路
要同时实现对话历史记忆和引用提取,关键是让对话历史参与检索与生成环节,同时通过bind_tools让模型自动从检索文档中提取引用信息。以下是具体实现步骤:
1. 导入依赖库
from langchain_core.chat_history import InMemoryChatMessageHistory from langchain_core.runnables.history import RunnableWithMessageHistory from langchain_core.tools import tool from langchain_openai import ChatOpenAI from langchain.chains import create_retrieval_chain from langchain.chains.combine_documents import create_stuff_documents_chain from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
2. 定义引用提取工具
用@tool装饰器定义工具,让模型可以调用它从检索到的文档中提取来源和关键内容:
@tool def extract_references(documents: list) -> list: """从检索文档中提取引用信息,返回包含来源、关键内容的列表""" references = [] for doc in documents: references.append({ "source": doc.metadata.get("source", "未知来源"), "key_content": doc.page_content[:120] + "..." # 截取核心内容便于展示 }) return references
3. 构建带对话历史的检索生成链
- 先给LLM绑定引用提取工具,让模型具备调用工具的能力
- 构建包含对话历史占位符的Prompt,确保历史对话能传入生成环节
- 组合检索链与对话历史组件:
# 初始化LLM并绑定工具 llm = ChatOpenAI(model="gpt-3.5-turbo") llm_with_tools = llm.bind_tools([extract_references]) # 定义带对话历史的Prompt prompt = ChatPromptTemplate.from_messages([ ("system", "结合对话历史和检索到的文档回答问题,必须调用工具提取引用信息并附在回答末尾。"), MessagesPlaceholder(variable_name="chat_history"), ("user", "{input}"), ("system", "检索文档:{context}") ]) # 创建文档处理链 document_chain = create_stuff_documents_chain(llm_with_tools, prompt) # 替换为你已实现的检索器(比如向量数据库检索器) # retriever = your_vector_store.as_retriever() # 创建基础检索链 retrieval_chain = create_retrieval_chain(retriever, document_chain) # 绑定对话历史管理 session_store = {} def get_session_history(session_id: str) -> InMemoryChatMessageHistory: if session_id not in session_store: session_store[session_id] = InMemoryChatMessageHistory() return session_store[session_id] # 最终整合对话历史的RAG链 final_chain = RunnableWithMessageHistory( retrieval_chain, get_session_history, input_messages_key="input", history_messages_key="chat_history", output_messages_key="answer" )
4. 调用示例
# 第一次提问(初始化对话) first_response = final_chain.invoke( {"input": "RAG的核心优势是什么?"}, config={"configurable": {"session_id": "user_001"}} ) print("回答内容:", first_response["answer"]) print("提取的引用:", first_response["tool_calls"]) # 第二次提问(自动携带对话历史) second_response = final_chain.invoke( {"input": "那它在长文本处理上比传统LLM好在哪里?"}, config={"configurable": {"session_id": "user_001"}} ) print("回答内容:", second_response["answer"]) print("提取的引用:", second_response["tool_calls"])
关键注意事项
- 确保Prompt中的
MessagesPlaceholder变量名与RunnableWithMessageHistory中的history_messages_key一致 - 检索器返回的文档必须包含
metadata字段(如来源、页码),否则引用提取工具无法获取有效来源信息 - 如果需要将引用直接嵌入回答正文,可以修改Prompt指令,让模型把提取的引用自然整合到回答中
内容的提问来源于stack exchange,提问作者PiluSus
相关产品推荐
相关产品推荐

