当前位置: 首页 > news >正文

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_datelatest_publish_date):如果用户要求最近的教程,可以加上时间筛选
  • 观看次数过滤min_view_countmax_view_count):可以筛选出最热门的教程
  • 时长过滤min_length_secmax_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="最长视频时长(秒)")

这部分的作用

  • 这里用了 PydanticBaseModel,它是 Python 里专门用于定义结构化数据格式的工具。
  • content_searchtitle_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

这部分的作用

  1. ChatGroq()

    • 这里用的是 ChatGroq(),Groq 是一个运行 LLM(比如 GPT-4)的 API。
    • 它就像 OpenAI.ChatCompletion.create(),但速度更快,适合 RAG(检索增强生成)。
  2. llm.with_structured_output(TutorialSearch)

    • 这一步的作用是:让 LLM 输出的内容严格符合 TutorialSearch 这个结构
    • LLM 不会随便输出自由文本,而是必须返回 JSON 形式的结构化数据。
  3. 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_searchtitle_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_searchtitle_search 进行向量数据库检索,再用其他字段做过滤查询,最终返回最相关的视频! 🚀

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dtcms.com/a/29185.html

相关文章:

  • 同步异步日志系统-设计模式
  • Zabbix 7.2实操指南:基于OpenEuler系统安装Zabbix 7.2
  • 《数组》学习——区间和
  • 修改MySQL密码
  • 【大模型系列篇】DeepSeek-R1如何通过强化学习有效提升大型语言模型的推理能力?
  • #渗透测试#批量漏洞挖掘#畅捷通T+远程命令执行漏洞
  • Linux自学day23-进程和线程
  • 【Java】代理模式
  • 激光工控机在自动化生产线中有什么关键作用?
  • Java 中创建线程的几种方式
  • [数据结构] Map的使用与注意事项
  • element-plus树形数据与懒加载的实现
  • kettle从入门到精通 第九十二课 ETL之kettle 使用Kettle的Carte对外发布读写接口
  • 设计模式教程:命令模式(Command Pattern)
  • .NET版PDF处理控件Aspose.PDF教程:在 C# 中将 TIFF 文件转换为 PDF
  • hive迁移补数脚本细粒度 表名-分区唯一键
  • C语言基础系列【15】union 共用体
  • Apache Doris 实现毫秒级查询响应
  • 【RabbitMQ业务幂等设计】RabbitMQ消息是幂等的吗?
  • Ubuntu安装PostgreSQL
  • 城市地质安全专题连载⑦ | 加强国土空间规划管控,规避城市地质安全风险
  • 跟着李沐老师学习深度学习(十二)
  • javaSE学习笔记21-线程(thread)-锁(synchronized 与Lock)
  • 从零开始用STM32驱动DRV8301:无人机/机器人电机控制指南
  • 基于图扑 HT 可视化实现智慧地下采矿可视化
  • CentOS更换yum源
  • 安装MySQL9.1.0-winx64.msi的报错解决办法:Database initialization failed。(也适用9.2.0)
  • 基于spring的策略模式
  • 【树莓派Pico设备驱动】-MAX7219驱动8位7段数码管(基于SPI)
  • 微信小程序地图map全方位解析