如何构建一个查询分析系统:从基础到应用

70 阅读3分钟

如何构建一个查询分析系统:从基础到应用

引言

在现代信息处理领域,查询分析系统变得越来越重要。无论是在搜索引擎优化、客户服务聊天机器人,还是在数据检索中,理解和解析用户查询都能极大地提高系统的效率和准确性。在本文中,我们将会介绍如何构建一个基本的查询分析系统,展示在直接使用用户查询时可能出现的问题,并演示如何利用查询分析来解决这些问题。

主要内容

依赖安装

首先,我们需要安装一些依赖库:

# %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]

常见问题和解决方案

  1. 查询生成不准确

    • 可能原因:模型输入不准确或者模型理解能力有限。
    • 解决方案:调整输入提示,提供更多上下文信息或者尝试不同的模型。
  2. 检索结果不符合预期

    • 可能原因:向量存储索引不准确。
    • 解决方案:重新训练或优化向量存储索引的生成方法。

总结和进一步学习资源

通过本文的示例,我们展示了如何通过查询分析改进检索系统的性能。查询分析不仅能提高搜索结果的准确性,还能提供更丰富的用户体验。

进一步学习资源

参考资料

  1. LangChain YouTube
  2. OpenAI API
  3. Chroma Documentation

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

---END---