Bootstrap

使用 LangChain 掌握检索增强生成 (RAG) 的终极指南:5、将自然语言问题转换为结构化查询

5. 查询构建 — Ragatouille

用户用自然语言提出问题并被路由到特定数据源(例如,向量存储、图形数据库等)后,该问题需要被转换为结构化查询,以便从选定的数据源检索信息(例如,文本到SQL、文本到Cypher等)。在本节中,我们将看到如何使用Langchain将自然语言问题转换为结构化查询。

# 导入环境变量扩展
%load_ext dotenv
%dotenv secrets/secrets.env

# 导入所需的库
from langchain_community.document_loaders import YoutubeLoader
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.runnables import RunnablePassthrough

在本节中,我们将看到如何使用自然语言问题构建一个查询,以便根据它们的元数据过滤记录。为此,我们考虑一个用例,即根据视频的元数据过滤YouTube播放列表。首先,我们来了解一下在YouTube视频中可以找到哪些元数据。

# 从YouTube URL加载文档
docs = YoutubeLoader.from_youtube_url(
    "https://www.youtube.com/watch?v=sVcwVQRHIc8", add_video_info=True
).load()

# 打印第一个文档的元数据
docs[0].metadata

输出示例:

{
  'source': 'sVcwVQRHIc8',
  'title': 'Learn RAG From Scratch – Python AI Tutorial from a LangChain Engineer',
  'description': 'Unknown',
  'view_count': 147737,
  'thumbnail_url': 'https://i.ytimg.com/vi/sVcwVQRHIc8/hq720.jpg',
  'publish_date': '2024-04-17 00:00:00',
  'length': 9191,
  'author': 'freeCodeCamp.org'
}

现在,假设我们要基于titlecontentview_countpublish_datelength过滤播放列表。因此,一旦我们向LLM提出问题,它应该返回一个包含上述字段的对象,这些字段用于从播放列表/数据库中选择视频。为此,我们定义了一个Pydantic模型,类似于我们在“路由”部分构建的模型。

# 定义TutorialSearch Pydantic模型
import datetime
from typing import Optional
from langchain_core.pydantic_v1 import BaseModel, Field

class TutorialSearch(BaseModel):
    """在关于LLMs和Langchain的视频数据库/播放列表中进行搜索。"""

    content_search: str = Field(..., description="应用于视频文字的相似性搜索查询。")
    title_search: str = Field(..., description="应用于视频标题的内容搜索查询的替代版本。")
    min_view_count: Optional[int] = Field(None, description="视图计数的最小值过滤器。")
    max_view_count: Optional[int] = Field(None, description="视图计数的最大值过滤器。")
    earliest_publish_date: Optional[datetime.date] = Field(None, description="最早的发布日期过滤器。")
    latest_publish_date: Optional[datetime.date] = Field(None, description="最晚的发布日期过滤器。")
    min_length_sec: Optional[int] = Field(None, description="视频的最小长度(秒)。")
    max_length_sec: Optional[int] = Field(None, description="视频的最大长度(秒)。")

    def pretty_print(self) -> None:
        # 打印非空字段
        for field in self.__fields__:
            if getattr(self, field) is not None and getattr(self, field) != getattr(
                self.__fields__[field], "default", None
            ):
                print(f"{field}: {getattr(self, field)}")

接下来,我们构建一个链,该链接受用户问题和提示,将其提供给LLM,LLM根据定义的Pydantic模型提供答案,并返回答案。

# 定义元数据提示模板
meta_data_prompt = ChatPromptTemplate.from_messages([
    ("system", "你是转换用户问题为数据库查询的专家。"),
    ("user", "{question}")
])

# 初始化GPT-4模型
llm = ChatOpenAI(model='gpt-4', temperature=0)
# 使用with_structured_output()方法初始化结构化输出
structured_llm = llm.with_structured_output(TutorialSearch)

# 创建元数据链
meta_data_chain = (
    {'question': RunnablePassthrough()}
    | meta_data_prompt
    | structured_llm
)

# 调用元数据链并打印结果
query = meta_data_chain.invoke("Build RAG using Langchain videos published before January 2024 with at least 1000 views.")
query.pretty_print()

输出示例:

content_search: Building RAG using Langchain
title_search: RAG Langchain
min_view_count: 1000
latest_publish_date: 2024-01-01

这可以用来过滤数据库的记录,如本文所示。我们将在最后一部分使用文本到Cypher查询构建,以从图形数据库获取信息。

总结

本文介绍了如何使用Langchain将用户用自然语言提出的问题转换为结构化查询,以便从特定数据源检索信息。通过定义Pydantic模型和构建链,我们可以将用户问题转化为数据库查询,从而优化检索最相关结果的过程。

;