如何构建一个查询分析系统:从基础到应用
引言
在现代信息处理领域,查询分析系统变得越来越重要。无论是在搜索引擎优化、客户服务聊天机器人,还是在数据检索中,理解和解析用户查询都能极大地提高系统的效率和准确性。在本文中,我们将会介绍如何构建一个基本的查询分析系统,展示在直接使用用户查询时可能出现的问题,并演示如何利用查询分析来解决这些问题。
主要内容
依赖安装
首先,我们需要安装一些依赖库:
# %pip install -qU langchain langchain-community langchain-openai youtube-transcript-api pytube langchain-chroma
设置环境变量
我们会使用OpenAI的API,在使用之前需设置API密钥:
import getpass
import os
os.environ["OPENAI_API_KEY"] = getpass.getpass()
加载文档
接下来,我们使用 YoutubeLoader 来加载LangChain YouTube视频的转录内容:
from langchain_community.document_loaders import YoutubeLoader
urls = [
"https://www.youtube.com/watch?v=HAn9vnJy6S4",
"https://www.youtube.com/watch?v=dA1cHGACXCo",
# 更多URL...
]
docs = []
for url in urls:
docs.extend(YoutubeLoader.from_youtube_url(url, add_video_info=True).load())
增加额外的元数据
我们为每个文档增加发布年份的元数据:
import datetime
for doc in docs:
doc.metadata["publish_year"] = int(
datetime.datetime.strptime(
doc.metadata["publish_date"], "%Y-%m-%d %H:%M:%S"
).strftime("%Y")
)
索引文档
为了检索文档,我们需要创建一个索引,我们会使用向量存储来索引文档,并首先对它们进行分块,以便检索更精确:
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(chunk_size=2000)
chunked_docs = text_splitter.split_documents(docs)
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_documents(
chunked_docs,
embeddings,
)
无查询分析的检索
直接对用户问题进行相似性搜索:
search_results = vectorstore.similarity_search("how do I build a RAG agent")
print(search_results[0].metadata["title"])
print(search_results[0].page_content[:500])
查询分析的引入
我们可以使用查询分析来改进检索结果。可以定义查询架构,并使用函数调用模型将用户问题转换为结构化查询:
from typing import Optional
from langchain_core.pydantic_v1 import BaseModel, Field
class Search(BaseModel):
query: str = Field(..., description="Similarity search query applied to video transcripts.")
publish_year: Optional[int] = Field(None, description="Year video was published")
转换用户问题为结构化查询
使用OpenAI的工具调用API来转换用户问题:
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI
system = """You are an expert at converting user questions into database queries. \
You have access to a database of tutorial videos about a software library for building LLM-powered applications. \
Given a question, return a list of database queries optimized to retrieve the most relevant results.
If there are acronyms or words you are not familiar with, do not try to rephrase them."""
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
使用查询分析进行检索
使用生成的查询进行检索:
from typing import List
from langchain_core.documents import Document
def retrieval(search: Search) -> List[Document]:
if search.publish_year is not None:
_filter = {"publish_year": {"$eq": search.publish_year}}
else:
_filter = None
return vectorstore.similarity_search(search.query, filter=_filter)
retrieval_chain = query_analyzer | retrieval
results = retrieval_chain.invoke("RAG tutorial published in 2023")
[(doc.metadata["title"], doc.metadata["publish_date"]) for doc in results]
常见问题和解决方案
-
查询生成不准确
- 可能原因:模型输入不准确或者模型理解能力有限。
- 解决方案:调整输入提示,提供更多上下文信息或者尝试不同的模型。
-
检索结果不符合预期
- 可能原因:向量存储索引不准确。
- 解决方案:重新训练或优化向量存储索引的生成方法。
总结和进一步学习资源
通过本文的示例,我们展示了如何通过查询分析改进检索系统的性能。查询分析不仅能提高搜索结果的准确性,还能提供更丰富的用户体验。
进一步学习资源
参考资料
结束语:如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---