51-自查询检索Self-Querying-大模型自动过滤元数据
文章目录
【51.Python+AI】自查询检索Self-Querying:让大模型自己决定从向量库查什么
📖 文章简介: 本文深入讲解RAG系统中一项高级检索技术——Self-Querying(自查询检索)。传统检索只做语义匹配,而Self-Querying让LLM先理解用户意图、自动提取查询中的结构化过滤条件(时间、类别、作者等元数据),再与语义向量检索联合执行。文中拆解了LangChain的SelfQueryRetriever完整工作流程,包含Mermaid时序图、自定义元数据字段的Schema定义、以及一个"个人知识库"的实战——用户问"2025年的AI论文",自动过滤年份+语义检索。适合想让RAG从"傻搜"升级为"精准查"的开发者。

🎬 个人主页: 源码骑士
❄ 专栏传送门: 《Android开发基础》《python基础课程》
⭐️热衷从源码视角拆解技术底层原理,将复杂架构讲得通俗易懂
🎬 源码骑士的简介:
5年Android Framework系统开发经验,曾主导多项系统级性能优化专项
技术栈覆盖Android系统全链路(Binder/Handler/AMS/WMS/启动流程)及Java后端全家桶(Spring + MyBatis + Redis + Oracle)
累计产出原创技术文章100+篇,文章以流程图为特色,被读者评价为"看一篇胜过啃一周源码"
导入语
你的向量库里存了1000篇论文,有2023年的、2024年的、AI方向的、医学方向的。用户问"找一下2024年关于大模型微调的论文"。你的普通检索器怎么做?——把所有"大模型""微调"语义相关的都召回来,然后用户发现返回的都是2023年的,还得自己翻。
Self-Querying就是解决这个问题的:让LLM自动从用户的问题中提取出结构化查询条件(年份=2024,主题=大模型微调),然后向量库同时做"元数据过滤 + 语义检索"——一步到位返回准确结果。
1 ~> Self-Querying的工作流程
2 ~> LangChain实现
from langchain.chains.query_constructor.base import AttributeInfo
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_chroma import Chroma
# ====== 定义文档的元数据结构 ======
metadata_field_info = [
AttributeInfo(
name="year",
description="文档的发布年份",
type="integer",
),
AttributeInfo(
name="category",
description="文档分类,如'AI'、'医学'、'金融'",
type="string",
),
AttributeInfo(
name="author",
description="文档作者",
type="string",
),
]
document_content_description = "学术论文的标题和摘要"
# ====== 创建向量库 ======
embeddings = OpenAIEmbeddings()
vector_store = Chroma(
embedding_function=embeddings,
persist_directory="./papers_db",
)
# ====== 创建自查询检索器 ======
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
retriever = SelfQueryRetriever.from_llm(
llm=llm,
vectorstore=vector_store,
document_contents=document_content_description,
metadata_field_info=metadata_field_info,
verbose=True, # 打印LLM解析的中间结果
)
# ====== 使用 ======
results = retriever.invoke("找2024年关于大模型微调的AI论文")
# LLM自动解析出:
# query="大模型微调"(语义检索)
# filter="and(eq('year', 2024), eq('category', 'AI'))"(结构化过滤)
for doc in results:
print(f"[{doc.metadata['year']}] {doc.metadata['author']}: {doc.page_content[:100]}")
3 ~> 支持的操作符
Self-Querying支持的比较操作符:
├─ eq:等于 → eq("category", "AI")
├─ ne:不等于 → ne("year", 2023)
├─ gt/gte:大于/大于等于 → gt("rating", 4)
├─ lt/lte:小于/小于等于 → lte("year", 2024)
├─ like:模糊匹配 → like("author", "张")
└─ in/not in:在列表中 → in("category", ["AI", "CS"])
逻辑组合:
├─ and → and(eq("year", 2024), eq("category", "AI"))
└─ or → or(eq("category", "AI"), eq("category", "CS"))
4 ~> 实战:知识库搜索引擎
# 完整示例:公司规章制度知识库
from datetime import datetime
metadata_schema = [
AttributeInfo(name="department", description="适用部门", type="string"),
AttributeInfo(name="effective_date", description="生效日期,格式YYYY-MM-DD", type="string"),
AttributeInfo(name="version", description="版本号", type="integer"),
AttributeInfo(name="status", description="状态:active/archived", type="string"),
]
retriever = SelfQueryRetriever.from_llm(
llm=llm, vectorstore=vector_store,
document_contents="公司规章制度文档",
metadata_field_info=metadata_schema,
search_kwargs={"k": 5},
)
# 用户问:"技术部2025年生效的最新考勤制度"
# LLM自动解析:
# query = "考勤制度"
# filter = and(eq("department", "技术部"), gte("effective_date", "2025-01-01"))
# 结果:精准命中,不会混入其他部门或旧版本
results = retriever.invoke("技术部2025年生效的考勤政策")
思考 && 总结
- Self-Querying = SQL的WHERE子句 + 向量语义检索: 它让向量库从"只能搜大概意思"升级为"可以精确筛选条件"。
- 元数据定义越详细,过滤越精准:
AttributeInfo的description直接影响LLM提取条件的准确率——要写得清晰具体。 - 适合数据有天然分类的场景: 论文(年份/领域)、公司文档(部门/版本)、商品(品类/价格)等都是最佳应用场景。
- 不是所有向量库都支持元数据过滤: Chroma和Milvus支持良好,需确认你的向量库是否支持复杂过滤。
- 查询解析也会消耗Token: 每次检索LLM都会先解析用户意图,注意计入成本。
Self-Querying让RAG从"给你一堆相关内容自己找"变成"直接给你最相关的"。这10行代码的提升,用户体验的改善是质变的。
结尾
各位小伙伴,本文完!源码骑士 — Android Framework & 全栈开发
👀 关注 | ❤️ 点赞 | ⭐ 收藏 | 💬 评论 | 🔄 一键四连!🗡️ 寄语:精准检索从"你想查什么"开始,而不是"我有什么"。
往期回顾:【Python+AI】检索策略进阶 / 【Python+AI】LangChain搭RAG / 【Python+AI】向量数据库选型 / 【Python+AI】JSON Mode / 【Python+AI】Function Calling
更多推荐
所有评论(0)