create_history_aware_retriever
是 LangChain 库中的一个函数,位于 langchain.chains.history_aware_retriever
模块。它用于创建一个能够结合对话历史进行语义检索的链(chain),特别适合需要上下文感知的检索增强生成(RAG)场景。该函数通过语言模型(LLM)重构用户查询,结合历史对话上下文生成更精准的查询,从而从向量存储或其他检索器中获取相关文档。
以下是对 create_history_aware_retriever
函数的详细介绍,涵盖其定义、功能、参数、返回值、使用方式、应用场景、优化建议和注意事项。
create_history_aware_retriever
?create_history_aware_retriever
是一个工厂函数,用于构建一个上下文感知的检索链。它通过以下步骤实现:
List[BaseMessage]
格式),理解用户的当前意图。该函数的主要目标是解决传统检索器在多轮对话中缺乏上下文理解的问题。例如,在对话中用户提到“它如何工作?”,没有历史上下文,检索器难以判断“它”指代什么。通过 create_history_aware_retriever
,可以结合历史生成更明确的查询,如“量子计算如何工作?”,从而提高检索精度。
背景:
create_history_aware_retriever
是为此设计的工具。简单比喻:
可以将 create_history_aware_retriever
想象为一个“智能图书管理员”,不仅听懂你当前的提问,还能根据之前的对话记录为你重新组织问题,找到最相关的书籍(文档)。
create_history_aware_retriever
提供了以下主要功能:
VectorStoreRetriever
或自定义检索器。List[BaseMessage]
),维护对话上下文。Runnable
对象,可与其他 LangChain 链(如 ConversationalRetrievalChain
)组合。特点:
以下是 create_history_aware_retriever
的函数签名及参数说明:
from langchain.chains.history_aware_retriever import create_history_aware_retriever
def create_history_aware_retriever(
llm: BaseLanguageModel,
retriever: BaseRetriever,
prompt: BasePromptTemplate | None = None
) -> Runnable
llm: BaseLanguageModel
langchain_core.language_models.BaseLanguageModel
ChatOpenAI
或 ChatAnthropic
。ChatOpenAI(model="gpt-4o", api_key="your-api-key")
retriever: BaseRetriever
langchain_core.retrievers.BaseRetriever
VectorStoreRetriever
(基于向量存储)或 BM25Retriever
(基于关键字)。get_relevant_documents
方法。VectorStoreRetriever(vectorstore=Chroma(...))
prompt: BasePromptTemplate | None
(可选,默认为 None)
langchain_core.prompts.BasePromptTemplate
None
,使用默认提示模板。from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system", "根据以下对话历史和用户输入,生成一个清晰的检索查询:\n历史:{chat_history}\n输入:{input}"),
("human", "生成查询")
])
Runnable
input
和 chat_history
)并返回检索到的文档列表(List[Document]
)。{
"input": str, # 用户当前输入
"chat_history": List[BaseMessage] # 历史对话消息
}
List[Document]
,检索到的相关文档。create_history_aware_retriever
的工作流程如下:
input
)和历史对话(chat_history
)。prompt
(或默认提示)将 chat_history
和 input
格式化为 LLM 的输入。retriever
,调用其 get_relevant_documents
方法。List[Document]
)。内部结构:
RunnableSequence
,包含:
Runnable
用于格式化输入和调用 LLM。Runnable
用于调用检索器。Runnable
类型的,符合 LangChain 的链式工作流。以下是通过代码示例展示 create_history_aware_retriever
的使用方式,涵盖基本用法、与 RAG 链集成、自定义提示和异步调用等场景。
创建一个简单的历史感知检索链:
from langchain.chains.history_aware_retriever import create_history_aware_retriever
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.documents import Document
from langchain_community.vectorstores import Chroma
from langchain_core.messages import HumanMessage, AIMessage
# 创建示例文档
docs = [
Document(page_content="量子计算使用量子比特进行并行计算,速度远超经典计算。"),
Document(page_content="经典计算依赖二进制比特,适用于大多数传统应用。")
]
# 初始化嵌入模型和向量存储
embeddings = OpenAIEmbeddings(api_key="your-api-key")
vectorstore = Chroma.from_documents(docs, embeddings)
retriever = vectorstore.as_retriever()
# 初始化 LLM
llm = ChatOpenAI(model="gpt-4o", api_key="your-api-key")
# 创建默认提示模板
prompt = ChatPromptTemplate.from_messages([
("system", "根据以下对话历史和用户输入,生成一个清晰的检索查询:\n历史:{chat_history}\n输入:{input}"),
("human", "生成查询")
])
# 创建历史感知检索链
history_aware_retriever = create_history_aware_retriever(llm, retriever, prompt)
# 模拟对话历史
chat_history = [
HumanMessage(content="什么是量子计算?"),
AIMessage(content="量子计算使用量子比特进行计算,具有并行处理能力。")
]
# 调用链
input_data = {"input": "它如何工作?", "chat_history": chat_history}
result = history_aware_retriever.invoke(input_data)
print([doc.page_content for doc in result])
输出:
['量子计算使用量子比特进行并行计算,速度远超经典计算。']
说明:
将 history_aware_retriever
与回答生成链结合,构建完整的 RAG 系统:
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.documents import Document
from langchain_community.vectorstores import Chroma
from langchain_core.messages import HumanMessage, AIMessage
# 初始化嵌入模型和向量存储
docs = [
Document(page_content="量子计算使用量子比特进行并行计算,速度远超经典计算。")
]
embeddings = OpenAIEmbeddings(api_key="your-api-key")
vectorstore = Chroma.from_documents(docs, embeddings)
retriever = vectorstore.as_retriever()
# 初始化 LLM
llm = ChatOpenAI(model="gpt-4o", api_key="your-api-key")
# 创建历史感知检索链
prompt_history = ChatPromptTemplate.from_messages([
("system", "根据对话历史和用户输入,生成检索查询:\n历史:{chat_history}\n输入:{input}"),
("human", "生成查询")
])
history_aware_retriever = create_history_aware_retriever(llm, retriever, prompt_history)
# 创建回答生成链
prompt_answer = ChatPromptTemplate.from_messages([
("system", "根据以下文档回答问题:\n{context}\n问题:{input}"),
("human", "{input}")
])
qa_chain = create_stuff_documents_chain(llm, prompt_answer)
# 组合成 RAG 链
rag_chain = create_retrieval_chain(history_aware_retriever, qa_chain)
# 模拟对话历史
chat_history = [
HumanMessage(content="什么是量子计算?"),
AIMessage(content="量子计算使用量子比特进行计算。")
]
# 调用 RAG 链
input_data = {"input": "它如何工作?", "chat_history": chat_history}
result = rag_chain.invoke(input_data)
print(result["answer"])
输出:
量子计算通过量子比特的叠加和纠缠进行并行计算,显著提升处理速度。
说明:
使用自定义提示模板控制查询生成:
from langchain.chains.history_aware_retriever import create_history_aware_retriever
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.documents import Document
from langchain_core.messages import HumanMessage, AIMessage
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
# 初始化向量存储
docs = [
Document(page_content="量子计算基于量子力学原理,利用量子比特。")
]
embeddings = OpenAIEmbeddings(api_key="your-api-key")
vectorstore = FAISS.from_documents(docs, embeddings)
retriever = vectorstore.as_retriever()
# 初始化 LLM
llm = ChatOpenAI(model="gpt-4o", api_key="your-api-key")
# 自定义提示模板
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个检索专家。结合以下历史和输入,生成一个简洁的检索查询(不超过20字):\n历史:{chat_history}\n输入:{input}"),
("human", "生成查询")
])
# 创建检索链
history_aware_retriever = create_history_aware_retriever(llm, retriever, prompt)
# 模拟对话历史
chat_history = [
HumanMessage(content="量子计算是什么?"),
AIMessage(content="量子计算基于量子力学。")
]
# 调用链
input_data = {"input": "它的原理是什么?", "chat_history": chat_history}
result = history_aware_retriever.invoke(input_data)
print([doc.page_content for doc in result])
输出:
['量子计算基于量子力学原理,利用量子比特。']
说明:
使用异步方法处理高并发:
import asyncio
from langchain.chains.history_aware_retriever import create_history_aware_retriever
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.documents import Document
from langchain_community.vectorstores import Chroma
from langchain_core.messages import HumanMessage, AIMessage
# 初始化向量存储
docs = [
Document(page_content="量子计算使用量子比特进行并行计算。")
]
embeddings = OpenAIEmbeddings(api_key="your-api-key")
vectorstore = Chroma.from_documents(docs, embeddings)
retriever = vectorstore.as_retriever()
# 初始化 LLM
llm = ChatOpenAI(model="gpt-4o", api_key="your-api-key")
# 创建提示模板
prompt = ChatPromptTemplate.from_messages([
("system", "根据历史和输入生成检索查询:\n历史:{chat_history}\n输入:{input}")
])
# 创建检索链
history_aware_retriever = create_history_aware_retriever(llm, retriever, prompt)
# 模拟对话历史
chat_history = [
HumanMessage(content="量子计算是什么?"),
AIMessage(content="量子计算使用量子比特。")
]
# 异步调用
async def main():
input_data = {"input": "它如何工作?", "chat_history": chat_history}
result = await history_aware_retriever.ainvoke(input_data)
print([doc.page_content for doc in result])
asyncio.run(main())
输出:
['量子计算使用量子比特进行并行计算。']
说明:
ainvoke
异步调用,适合高并发场景。create_history_aware_retriever
在以下场景中广泛应用:
以下是使用 create_history_aware_retriever
时的优化建议,帮助提高效率和准确性:
prompt = ChatPromptTemplate.from_messages([
("system", "结合历史和输入,生成一个不超过20字的检索查询:\n历史:{chat_history}\n输入:{input}"),
("human", "生成查询")
])
OpenAIEmbeddings
或 SentenceTransformers
)提高检索精度。retriever
的 top_k
或 score_threshold
,控制返回文档数量。retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
BM25Retriever
)和语义检索,增强覆盖率。gpt-4o-mini
)降低成本。temperature
(如 0.3)确保查询生成稳定。llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.3)
from langchain_core.cache import InMemoryCache
llm.cache = InMemoryCache()
ainvoke
或 astream
处理高并发。chat_history
,避免 token 超限。chat_history = chat_history[-10:] # 保留最后10条消息
from langchain.memory import ConversationSummaryMemory
memory = ConversationSummaryMemory(llm=llm)
summary = memory.predict_new_summary(chat_history, "")
from langchain_core.callbacks import BaseCallbackHandler
class QueryCallback(BaseCallbackHandler):
def on_llm_end(self, output, **kwargs):
print(f"生成查询:{output.generations[0][0].text}")
config = {"callbacks": [QueryCallback()]}
from langsmith import Client
config = {"callbacks": [Client(api_key="your-langsmith-key")]}
以下是使用 create_history_aware_retriever
时需要注意的关键点:
llm
支持聊天或生成任务,推荐使用 ChatOpenAI
或 ChatAnthropic
。retriever
的质量,需确保向量存储包含相关文档。ConversationSummaryMemory
压缩历史。input
或 chat_history
中包含敏感信息。if any(char in input_data["input"] for char in ["<", ">", "&"]):
raise ValueError("输入包含不安全字符")
gpt-4o-mini
降低成本。create_history_aware_retriever
与 LangChain 生态中的其他组件紧密集成,以下是主要结合点:
ChatOpenAI
、ChatAnthropic
。llm = ChatOpenAI(model="gpt-4o")
VectorStoreRetriever
、BM25Retriever
等。retriever = vectorstore.as_retriever()
ChatPromptTemplate
自定义查询生成逻辑。prompt = ChatPromptTemplate.from_messages([...])
create_retrieval_chain
或 create_stuff_documents_chain
组合。rag_chain = create_retrieval_chain(history_aware_retriever, qa_chain)
ConversationBufferMemory
或 ConversationSummaryMemory
管理历史。from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory(return_messages=True)
RunnableConfig
配置回调,监控执行。config = {"callbacks": [StdOutCallbackHandler()]}
以下是一个完整的示例,展示如何使用 create_history_aware_retriever
构建一个上下文感知的 RAG 系统:
from langchain.chains.history_aware_retriever import create_history_aware_retriever
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.documents import Document
from langchain_community.vectorstores import Chroma
from langchain_core.messages import HumanMessage, AIMessage
from langchain.memory import ConversationBufferMemory
# 初始化向量存储
docs = [
Document(page_content="量子计算使用量子比特进行并行计算,基于叠加和纠缠原理。"),
Document(page_content="经典计算使用二进制比特,适合传统应用。")
]
embeddings = OpenAIEmbeddings(api_key="your-api-key")
vectorstore = Chroma.from_documents(docs, embeddings)
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
# 初始化 LLM
llm = ChatOpenAI(model="gpt-4o-mini", api_key="your-api-key", temperature=0.3)
# 创建历史感知检索提示
prompt_history = ChatPromptTemplate.from_messages([
("system", "根据对话历史和用户输入,生成一个简洁的检索查询(不超过20字):\n历史:{chat_history}\n输入:{input}"),
("human", "生成查询")
])
# 创建历史感知检索链
history_aware_retriever = create_history_aware_retriever(llm, retriever, prompt_history)
# 创建回答生成提示
prompt_answer = ChatPromptTemplate.from_messages([
("system", "根据以下文档回答问题,保持简洁:\n{context}\n问题:{input}"),
("human", "{input}")
])
qa_chain = create_stuff_documents_chain(llm, prompt_answer)
# 组合 RAG 链
rag_chain = create_retrieval_chain(history_aware_retriever, qa_chain)
# 初始化对话记忆
memory = ConversationBufferMemory(return_messages=True)
# 模拟多轮对话
def chat(query):
chat_history = memory.chat_memory.messages
result = rag_chain.invoke({"input": query, "chat_history": chat_history})
memory.save_context({"input": query}, {"output": result["answer"]})
return result["answer"]
# 第一轮对话
print(chat("什么是量子计算?"))
# 输出:量子计算使用量子比特进行并行计算,基于叠加和纠缠原理。
# 第二轮对话
print(chat("它如何工作?"))
# 输出:量子计算通过量子比特的叠加和纠缠实现并行计算。
说明:
ConversationBufferMemory
管理对话历史。create_history_aware_retriever
是 LangChain 中用于创建上下文感知检索链的函数,结合对话历史生成精准查询。llm
:语言模型,用于查询重构。retriever
:底层检索器,执行文档检索。prompt
:提示模板,控制查询生成(可选)。Runnable
链,输入历史和查询,输出文档列表。