什么自查询?为什么在 RAG 中需要自查询?
- 标签:AI、大模型、RAG
🏛 业务架构师
自查询(Self-Query)是让 LLM 先从用户的自然语言提问中抽取结构化过滤条件,再连同语义向量一起检索。比如"查一下华东区上季度的投诉处理规范",模型自动拆出 区域=华东、时间=2026Q3、类型=投诉处理 的元数据过滤,再对"处理规范"做语义检索。
为什么需要:很多检索意图的根本不是"语义相似",而是"条件筛选"——纯向量检索处理不了"只要今年生效的""只要我部门可见的"这类硬约束,结果就是召回一堆过期文档、越权文档,业务上直接表现为答错版本、泄露权限。自查询把"模糊意图"翻译成"精确过滤器+语义查询"的组合,是让 RAG 具备业务语义的关键一步。
落地要点:元数据质量是前提——入库时必须打好时间、部门、密级、版本标签,否则模型想抽也没得抽。我的经验是:凡是知识有时效性、组织有权限墙的企业场景(法务、HR、制度文档),自查询属于第一优先级的能力,成本只是一次轻量 LLM 调用,收益却直接体现在合规和准确率上。
🏗 系统架构师
自查询(Self-Querying)是让 LLM 从自然语言 query 中抽取结构化过滤条件 + 语义查询两部分,先过滤再检索。典型例子:"2024 年发布的关于退款政策的 PDF 文档"→ 元数据过滤 year=2024, type=pdf + 语义查询"退款政策"。
为什么需要:纯向量检索是"语义黑盒",无法表达硬性约束。有两种坏方案:把元数据全塞进文本一起嵌入(信号被稀释,过滤不准);检索后再用 Python 过滤(post-filter,Top-K 里可能全是不满足条件的,导致空结果)。自查询实现 pre-filter:先用元数据砍掉 99% 的候选,再在子集上做 ANN——这是检索系统"索引裁剪"的经典思想,既准又快。
架构实现要点:
- 每个文档入库时结构化元数据必须齐(来源、时间、部门、权限、类型),这是自查询能用的前提,schema 设计要在建库早期定好;
- 过滤条件抽取用 LLM + JSON Schema 约束输出,失败降级为无过滤检索;
- 向量库要支持标量字段索引(Milvus/ES 都可以),否则过滤退化为全扫。
成本:多一次 LLM 调用(小模型,300ms 级),换来召回精度大幅提升,权限场景这是必选项而非优化项。
💻 全栈开发专家
自查询(Self-Query)是让 LLM 在检索前把自然语言拆成「语义查询 + 结构化过滤条件」。为什么需要?因为很多检索意图一半是语义、一半是元数据条件,纯向量检索处理不了后者。
例:「查一下 2023 年之后发布的关于平安重疾险的条款」会拆成:
json
{ "query": "平安重疾险 条款",
"filter": { "operator": "gt", "field": "publish_year", "value": 2023 } }LangChain 里的标准用法:
python
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.chains.query_constructor.schema import AttributeInfo
attrs = [AttributeInfo(name="publish_year", type="integer", description="发布年份"),
AttributeInfo(name="dept", type="string", description="所属部门")]
retriever = SelfQueryRetriever.from_llm(llm, vectorstore, "内部制度文档", attrs)工程细节与坑:一,元数据字段的 description 一定要写清楚枚举值和格式,LLM 拆错大多因为字段描述含糊,我们为此专门维护了一份字段字典;二,要开启结构化输出(JSON mode)保证 filter 是合法表达式,解析失败要有降级——退回无过滤的纯向量检索;三,日期类条件让 LLM 相对时间转绝对时间(「去年」→ 具体年份),否则过滤会错。这一招对多租户隔离特别有用,权限条件直接拼进 filter。