RAG基于用户问题的内容,对其进行分类和路由,然后选择适当的处理方式(2)
示例代码:
import datetime
from typing import Literal, Optional, Tuple
from pydantic import BaseModel, Field
class TutorialSearch(BaseModel):
"""在关于某个软件库的教程视频数据库中进行搜索。"""
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)}")
from langchain_groq import ChatGroq
from langchain_core.prompts import ChatPromptTemplate
system = """你是一名擅长将用户问题转换为结构化数据库查询的专家。
你的任务是根据用户输入生成结构化的搜索查询。
始终返回一个包含以下键的 JSON 对象:
- **content_search**:从查询中提取与内容相关的关键字,**不能为空**,即使用户输入过于宽泛,也要尽量提取最有用的关键词。
- **title_search**:content_search 的简化版本,优化用于匹配标题,**不能为空**,应当为简短但精准的关键词。
- **min_view_count、max_view_count、earliest_publish_date、latest_publish_date、min_length_sec、max_length_sec**:如果用户未明确提供,则使用 `None`。
如果无法确定 `content_search` 和 `title_search`,请合理推测关键词,而不是返回 `null`。
"""
prompt = ChatPromptTemplate.from_messages(
[
("system", system),
("human", "{question}"),
]
)
llm = ChatGroq()
structured_llm = llm.with_structured_output(TutorialSearch)
query_analyzer = prompt | structured_llm
query_analyzer.invoke({"question": "从零开始实现购物网站的建设"}).pretty_print()
这段代码的主要作用是让 LLM(大语言模型)自动把用户的搜索问题转换为结构化的查询条件,从而方便在数据库或向量检索系统中使用。
比如,用户可能随口问:
“后端数据库最新教程”
我们希望 LLM 能自动转换成可用于数据库查询的结构化数据,比如:
{
"content_search": "最新数据库教程",
"title_search": "新数据库",
"earliest_publish_date": null,
"latest_publish_date": null,
"min_view_count": null,
"max_view_count": null,
"min_length_sec": null,
"max_length_sec": null
}
这样,后续代码就可以用这个结构化数据去筛选视频,比如:
- 内容搜索(
content_search
):在视频字幕里查找「最新数据库教程」 - 标题搜索(
title_search
):查找标题中包含「新数据库」的内容 - 发布时间(
earliest_publish_date
和latest_publish_date
):如果用户要求最近的教程,可以加上时间筛选 - 观看次数过滤(
min_view_count
和max_view_count
):可以筛选出最热门的教程 - 时长过滤(
min_length_sec
和max_length_sec
):可以选择短视频还是完整课程
代码作用拆解
第一步:定义结构化搜索格式
from typing import Optional
from pydantic import BaseModel, Field
import datetime
class TutorialSearch(BaseModel):
"""在教程数据库中搜索相关视频"""
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="最长视频时长(秒)")
这部分的作用
- 这里用了
Pydantic
的BaseModel
,它是 Python 里专门用于定义结构化数据格式的工具。 content_search
和title_search
是必填字段(...
表示不能是None
)。- 其他字段都是可选的,比如
min_view_count
之类,默认是None
,只有用户提供了相关信息时才会启用。 - 作用:确保 LLM 生成的搜索查询是标准化的,而不是乱七八糟的字符串。
第二步:让 LLM 自动转换搜索条件
from langchain_core.prompts import ChatPromptTemplate
system = """你是一名擅长将用户问题转换为结构化数据库查询的专家。
你的任务是根据用户输入生成结构化的搜索查询。
始终返回一个包含以下键的 JSON 对象:
- **content_search**:从查询中提取与内容相关的关键字,**不能为空**,即使用户输入过于宽泛,也要尽量提取最有用的关键词。
- **title_search**:content_search 的简化版本,优化用于匹配标题,**不能为空**,应当为简短但精准的关键词。
- **min_view_count、max_view_count、earliest_publish_date、latest_publish_date、min_length_sec、max_length_sec**:如果用户未明确提供,则使用 `None`。
如果无法确定 `content_search` 和 `title_search`,请合理推测关键词,而不是返回 `null`。
"""
prompt = ChatPromptTemplate.from_messages(
[
("system", system), # 设定 LLM 的角色和任务
("human", "{question}"), # 让 LLM 处理用户输入
]
)
这部分的作用
system
变量定义了LLM 的角色,告诉它:“你是一名数据库搜索优化专家。”- 规定 LLM 必须返回 结构化的 JSON 对象,这样可以确保数据格式统一。
- 让 LLM 提取最重要的关键词,而不是简单重复用户的输入。
第三步:调用 LLM 进行函数调用
llm = ChatGroq()
structured_llm = llm.with_structured_output(TutorialSearch)
query_analyzer = prompt | structured_llm
这部分的作用
-
ChatGroq()
- 这里用的是
ChatGroq()
,Groq 是一个运行 LLM(比如 GPT-4)的 API。 - 它就像
OpenAI.ChatCompletion.create()
,但速度更快,适合 RAG(检索增强生成)。
- 这里用的是
-
llm.with_structured_output(TutorialSearch)
- 这一步的作用是:让 LLM 输出的内容严格符合
TutorialSearch
这个结构。 - LLM 不会随便输出自由文本,而是必须返回 JSON 形式的结构化数据。
- 这一步的作用是:让 LLM 输出的内容严格符合
-
query_analyzer = prompt | structured_llm
- 这个
|
符号表示管道(Pipeline),相当于:def query_analyzer(question): prompt_text = generate_prompt(question) response = llm.call(prompt_text) return parse_response_to_TutorialSearch(response)
- 也就是说,把用户输入的
question
传给prompt
,然后让 LLM 生成结构化数据。
- 这个
第四步:执行搜索
query_analyzer.invoke({"question": "后端数据库最新教程"}).pretty_print()
假设 LLM 处理完后返回:
{
"content_search": "最新数据库教程",
"title_search": "新数据库",
"earliest_publish_date": null,
"latest_publish_date": null,
"min_view_count": null,
"max_view_count": null,
"min_length_sec": null,
"max_length_sec": null
}
这时候 pretty_print()
的作用是打印:
content_search: 最新数据库教程
title_search: 新数据库
这样,我们的后端就可以拿 content_search
和 title_search
去检索匹配的视频,并根据其他过滤条件(比如发布时间、观看次数)进一步筛选。
示例 1:用户查询 “Python 高级教程,最好是 2023 年之后的”
LLM 可能返回:
{
"content_search": "Python 高级教程",
"title_search": "Python 进阶",
"earliest_publish_date": "2023-01-01",
"latest_publish_date": null,
"min_view_count": null,
"max_view_count": null,
"min_length_sec": null,
"max_length_sec": null
}
这表示:
- 只搜索 Python 相关的高级教程
- 发布时间必须是 2023 年及之后
- 不限制观看次数和时长
示例 2:用户查询 “Vue.js 快速入门(不要太长)”
LLM 可能返回:
{
"content_search": "Vue.js 快速入门",
"title_search": "Vue.js 教程",
"earliest_publish_date": null,
"latest_publish_date": null,
"min_view_count": null,
"max_view_count": null,
"min_length_sec": null,
"max_length_sec": 600
}
这里 max_length_sec: 600
表示只要 10 分钟以内的短视频。
总结
这段代码的作用是:
✅ 智能分析用户输入,生成结构化查询
✅ 确保数据格式统一,方便后续检索
✅ 结合 LLM 的理解能力,优化查询关键词
这样,我们的后端可以直接用 content_search
和 title_search
进行向量数据库检索,再用其他字段做过滤查询,最终返回最相关的视频! 🚀
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dtcms.com/a/29185.html
如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!