file search 怎样设置检索过滤
来源:17golang原创
时间:2026-10-25 12:13:28 420浏览 收藏
我第一次给知识库加“只查中文资料”的条件时,误以为 file_search 会像数据库的 WHERE 子句一样直接过滤正文。结果是条件看起来写对了,返回内容却仍然混进了不该出现的文件。真正的关键是:过滤对象是 vector store 中文件对象的 attributes,它会先缩小候选文件,再进行语义和关键词检索。
官方地址:https://developers.openai.com/api/docs/guides/tools-file-search
本文只讨论这个文件级边界。示例使用 Python SDK,过滤条件中的值、字段名和组合关系都需要与你上传文件时写入的属性保持一致。
影响面:过滤错一层,召回结果就会变杂
OpenAI 的 file search 建立在 vector store 上。文件被加入后会被切分、嵌入并建立索引;可过滤的是 vector_store.file 关联的属性,而不是把正文当成结构化字段查询。比如给每个文件补上 region、category 和 Unix 时间戳 date,再让 file_search 按这些属性限定候选范围。

时间线:先写属性,再把过滤条件交给工具
我后来把排查拆成两个动作。第一步是在文件进入 vector store 时写入稳定属性;第二步是在 Responses API 的工具配置里使用 filters。属性名不是文件名的自动别名,想按文件名过滤也要显式写入一个自定义属性。
from openai import OpenAI
client = OpenAI()
# 给 vector_store.file 写入可筛选的文件级属性;date 使用 Unix 时间戳。
client.vector_stores.files.create(
vector_store_id="vs_123",
file_id="file_123",
attributes={
"region": "cn",
"category": "guide",
"date": 1761868800,
},
)
这些属性最多 16 个键,键和值都要保持稳定。日期、版本或租户编号最好统一类型,否则后面的 gte、lte 比较会很难排查。
触发条件:单条件能用,组合条件开始失控
单条件最容易确认。比较过滤使用 eq、ne、gt、gte、lt、lte、in 或 nin;多条件则用 and 或 or 包起来。它表达的是“哪些文件可以进入检索”,不是“正文必须出现哪些词”。
from openai import OpenAI
client = OpenAI()
# 先限定区域和日期,再允许两类文档进入候选集。
response = client.responses.create(
model="gpt-6-astra",
input="请找出最近的部署指南,并说明回滚条件。",
tools=[{
"type": "file_search",
"vector_store_ids": ["vs_123"],
"filters": {
"type": "and",
"filters": [
{"type": "eq", "key": "region", "value": "cn"},
{"type": "gte", "key": "date", "value": 1761868800},
{
"type": "or",
"filters": [
{"type": "eq", "key": "category", "value": "guide"},
{"type": "eq", "key": "category", "value": "runbook"},
],
},
],
},
"max_num_results": 10,
}],
)
# 需要排查召回内容时,可在请求中加入 include="file_search_call.results"。
print(response)

根因:看似“过滤不生效”,通常是属性契约不一致
这类问题我最后归成三种。第一,上传时根本没有写属性,查询自然没有可比较的字段。第二,属性键写成了 lang,过滤却使用 language;字段名不一致不会自动猜测。第三,把日期写成字符串,却用数字范围比较,或者把 in 的数组值写成了一个逗号分隔字符串。
另一个容易误判的点是:过滤完成后仍然要做语义检索。如果候选文件本来就很少,问题不一定是 filters 错了,也可能是用户问题与剩余文件内容的相关性不足。官方检索文档还提供了 max_num_results、rewrite_query、score_threshold 等检索参数,它们解决的是召回和排序,不替代属性过滤。
修复动作:把属性契约写成一张小表
| 字段 | 示例值 | 适合的过滤 | 注意点 |
|---|---|---|---|
region | cn | eq | 统一枚举,不混用中文名 |
category | guide | eq/in | 多类别用数组给 in |
date | Unix 时间戳 | gte/lte | 所有文件使用同一类型 |
我会先取一份属性命名表,再把“上传端”和“检索端”放在同一份配置里维护。遇到 0 条结果时,先临时去掉一个条件定位是哪一层收窄过度,然后恢复条件,不要立即改写用户问题。这样才能区分“没有文件符合条件”和“语义检索没有命中”。
防复发:用可观察的请求参数保留排查线索
正式接入时建议固定三件事:属性键使用小写和稳定枚举;日期全部用数字时间戳;需要审查召回内容时,在开发环境把 file_search_call.results 加到 include。结果数量默认最多返回 10 条,当前文档允许通过 max_num_results 调到 50 条以内。不要把 API 密钥、真实用户标识或内部路径写进文章示例。
我对 file search 的结论是:filters 负责“哪些文件有资格被检索”,语义查询负责“这些文件里哪段内容最相关”。前者是文件属性契约,后者是内容相关性;把两层拆开,检索过滤就不会再变成一场盲目调 prompt 的排障。
相关问题
file search 能直接按正文中的关键词过滤吗?
filters 针对文件属性。正文关键词仍由检索过程处理,不能把任意正文片段当成结构化属性键。
为什么设置了 in 还是没有结果?
先确认该属性确实写在每个 vector_store.file 上,再确认 value 是数组,并且数组元素的类型和值与属性完全一致。
组合条件应该用 and 还是 or?
所有条件都必须满足时用 and;允许多个候选值时可在内部使用 or,并注意嵌套结构是否把候选集收得过窄。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
439 收藏
-
241 收藏
-
208 收藏
-
418 收藏
-
313 收藏
-
101 收藏
-
126 收藏
-
418 收藏
-
185 收藏
-
307 收藏
-
250 收藏
-
397 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习