OpenAI Agents SDK #27:让 Agent 拥有私有知识库,FileSearchTool 一行代码搞定

本期深拆 FileSearchTool——OpenAI Agents SDK HostedTool 家族第二名成员。文章完整解析 5 个 dataclass 参数(vector_store_ids、max_num_results、include_search_results、ranking_options、filters),重点展开 RankingOptions 的 ranker 版本(default-2024-11-15)、score_threshold 调优逻辑、RRF hybrid_search 权重配置,以及 Filters 的 ComparisonFilter/CompoundFilter 两类过滤结构。同步提供 Vector Store 四步工作流(上传 → 创建 → 绑定 → 调用)完整代码,并对 WebSearchTool / FileSearchTool / HostedMCPTool 三类 HostedTool 做 6 维度选型矩阵对比。中文社区对 FileSearchTool 至今处于原创真空,本期为中文首发深度解读,结尾附 3 条生产级实践建议。

Research Brief

自己搭 RAG,绕不过这几步:选向量数据库、写 embedding 管线、实现检索逻辑、处理结果重排……光是跑通 hello world 就要大半天。
FileSearchTool 把这些全托管了。
你把文件上传到 OpenAI Vector Store,把 Store ID 传给工具,Agent 就能直接在你的私有文档里做语义检索——OpenAI 在服务器端处理分片、embedding、检索和重排,不需要你本地写一行向量逻辑。1

FileSearchTool 是什么

FileSearchTool 是 OpenAI Agents Python SDK 的托管工具(HostedTool),HostedTool 家族第二名成员,排在 WebSearchTool 之后。2
官方 docstring 说得很直白:
"A hosted tool that lets the LLM search through a vector store. Currently only supported with OpenAI models, using the Responses API."
「一个让 LLM 搜索向量存储的托管工具。目前仅支持 OpenAI 模型,使用 Responses API。」
3
三个核心约束:
  • 运行在 OpenAI 服务器:检索执行全程在 OpenAI 基础设施内,开发者不需要实现任何本地检索逻辑
  • 仅支持 OpenAIResponsesModel:不兼容 Chat Completions 后端,换模型时必须注意这一点
  • wire name 固定:工具名称在协议层是 "file_search",SDK 层导入:from agents import FileSearchTool

5 个参数全景

FileSearchTool 是 dataclass,定义在 src/agents/tool.py,共 5 个字段:4
参数类型默认值说明
vector_store_idslist[str]—(必填要搜索的 Vector Store ID 列表
max_num_resultsint | NoneNone返回结果数上限;API 层限制 1-50,不设时由 API 决定(通常 10)
include_search_resultsboolFalse是否在 LLM 输出中包含搜索结果的详细元数据
ranking_optionsRankingOptions | NoneNone排序与相关性调优选项
filtersFilters | NoneNone基于文件属性的过滤条件
最简用法:
from agents import Agent, FileSearchTool

agent = Agent(
    name="knowledge_agent",
    instructions="用户问你问题时,请搜索知识库回答。",
    tools=[
        FileSearchTool(
            vector_store_ids=["vs_abc123"],
            max_num_results=5,
        )
    ],
)
include_search_results=True 是个调试利器——开启后 LLM 的输出里会附带检索命中的原始片段和分数,方便排查「为什么没搜到」或「为什么搜到了错的」。

RankingOptions 与 Filters 深潜

这两个参数的类型来自 openai SDK 包(openai.types.responses.file_search_tool_param)而非 agents SDK 本身——属于跨包类型引用,IDE 自动补全时要注意导入路径。5

RankingOptions

from openai.types.responses.file_search_tool_param import RankingOptions

ranking = RankingOptions(
    ranker="default-2024-11-15",   # 或 "auto"
    score_threshold=0.7,            # 0-1,越高越严格
    hybrid_search={
        "embedding_weight": 0.7,    # 语义匹配权重
        "text_weight": 0.3,         # 关键词匹配权重
    }
)
三个子字段说明:
ranker:排序器版本,两个合法值——"auto"(API 自动选最优)和 "default-2024-11-15"(固定版本,可复现)。注意这里不是 "default-2024-08-21"——SDK 源码确认是 "default-2024-11-15"
score_threshold:相关性得分阈值,范围 0 到 1。调高可以剔除低质量命中,但会减少返回数量。官方建议:「如果你发现文件搜索结果相关性不足,可以调整 ranking_options 来提升响应质量」6——调高 score_threshold 是第一步。
hybrid_search:RRF(Reciprocal Rank Fusion,倒数排名融合)权重配置。embedding_weight 控制语义相似度的权重,text_weight 控制关键词重叠的权重。至少一个大于 0。文档类内容(关键词精确匹配重要)可以调高 text_weight;语义理解类问答偏向调高 embedding_weight

Filters

FiltersComparisonFilterCompoundFilter 的 Union 类型:
from openai.types.responses.file_search_tool_param import ComparisonFilter, CompoundFilter

# 按属性过滤:只搜 region='us' 的文档
single_filter = ComparisonFilter(
    type="eq",
    key="region",
    value="us"
)

# 日期范围过滤:2024 年的文档
date_filter = CompoundFilter(
    type="and",
    filters=[
        ComparisonFilter(type="gte", key="created_at", value=20240101),
        ComparisonFilter(type="lte", key="created_at", value=20241231),
    ]
)

# 按文件名 in-list 过滤
filename_filter = ComparisonFilter(
    type="in",
    property="filename",
    value=["policy_v2.pdf", "handbook.pdf"]
)
ComparisonFilter 支持 8 种比较操作:eqnegtgteltlteinninCompoundFilter 支持 and / or 嵌套,可以组合任意层级的过滤条件。

Vector Store 四步工作流

使用 FileSearchTool 前需要先准备好 Vector Store。完整流程四步:1
from openai import OpenAI

client = OpenAI()

# Step 1:上传文件到 Files API
with open("company_handbook.pdf", "rb") as f:
    uploaded_file = client.files.create(
        file=f,
        purpose="assistants"
    )

# Step 2:创建 Vector Store
vector_store = client.vector_stores.create(
    name="Company Knowledge Base"
)

# Step 3:将文件添加到 Vector Store(自动等待处理完成)
vs_file = client.vector_stores.files.create_and_poll(
    vector_store_id=vector_store.id,
    file_id=uploaded_file.id
)

# Step 4:检查状态
print(vs_file.status)  # completed 则可用
几个需要知道的细节:
处理状态机:文件进入 Vector Store 后经历 pending → processing → completed(或 error)。create_and_poll 会自动轮询等到 completed;如果不用 poll 版本,就需要手动 client.vector_stores.files.list(vector_store_id=...) 检查状态,status == "completed" 才能搜索。
支持格式.pdf.md.txt.docx.html.json.py.ts 等 19 种格式。text/* 类型文件编码须是 utf-8 / utf-16 / ascii。6
定价:所有 Vector Store 总计 ≤1GB 免费,超出 $0.10/GB/天。1
速率限制:每个 vector_store_id 300 请求/分钟,与文件批处理操作共享配额。批量上传大量文件时要控制并发。
绑定到 Agent 只需一行:
tools=[FileSearchTool(vector_store_ids=[vector_store.id])]

HostedTool 三兄弟怎么选

FileSearchToolWebSearchToolHostedMCPTool 同属 HostedTool 家族,三者均运行在 OpenAI 服务器端,均需要 OpenAIResponsesModel,但适用场景完全不同。2
WebSearchToolFileSearchToolHostedMCPTool
数据来源实时公开互联网你的私有 Vector Store远程 MCP 服务器
必填参数无(全默认可用)vector_store_idstool_config(含 server_url)
外部依赖提前创建 Vector Store + 上传文件外部 MCP 服务器在运行
延迟特性网络往返 + 搜索引擎OpenAI 基础设施内检索,低延迟取决于 MCP 服务器位置
适合场景最新信息、实时新闻、公开内容企业知识库、产品文档、RAG外部工具生态、结构化 API
高级功能search_context_size 控制上下文量ranking_options + filters 精准召回defer_loading + ToolSearchTool
三者可以在同一个 Agent 里混用。官方文档示例里就有同时挂 WebSearchTool()FileSearchTool(max_num_results=3, vector_store_ids=[...]) 的写法——互联网 + 私有文档两路信息源同时覆盖。
官方 research_bot 示例目前只用了 WebSearchTool,但 README 把「加入 FileSearchTool 支持」列为第一个建议改进项7:「Retrieval: Add support for fetching relevant information from a vector store. You could use the File Search tool for this.」——这意味着官方自己也认为 FileSearchTool 是 research_bot 的自然延伸。
中文社区现状:微信公众号生态对「文件搜索工具」的搜索结果几乎全部指向 Windows 桌面搜索工具,OpenAI Agents SDK 的 FileSearchTool 完全缺席。知乎有数篇文章涉及 FileSearchTool,但均为官方文档翻译,无独立教程、配置指南或实战案例。8 全中文网络目前处于原创真空状态,本期是中文首发深度解读。

3 条生产级建议

1. max_num_results 控制在 3-5,先跑质量测试再加
默认不设时 API 通常返回 10 条,全部塞进 context 会增加噪声,模型反而容易被低质量命中干扰。建议先从 max_num_results=3 起步:给 Agent 发几条真实问题,用 include_search_results=True 看命中内容,确认质量后再根据场景调大。内容密度高的场景(产品手册、合同文本)可以保持 3-5;需要广覆盖的场景(FAQ、知识库)可以到 8-10。
2. score_threshold 宁高勿低,用 include_search_results 诊断
低阈值(如 0.3)会让大量不相关片段进入 context,高阈值(如 0.8)则可能返回空。推荐做法:先用 include_search_results=True 拿到命中分数分布,找到你的「相关/不相关」分界线,再把 score_threshold 设在该分界线附近。分数分布集中在 0.6 以下说明文档切片质量有问题,需要重新处理文件(换 chunk 大小或清理噪声文档)而不是靠调阈值蒙混。
3. Vector Store 多个,按主题分库而不是一锅炖
vector_store_ids 接受列表,但不等于应该把所有文档塞进一个 Store。按主题分库有两个好处:一是可以对不同 Agent 配不同的知识库(客服 Agent 只能访问产品文档,内部 Agent 才能访问合同库);二是可以在 filters 里按 vector_store_id 范围缩小搜索范围,在多 Store 场景下精准定位。一个实用分法:产品文档一库、操作手册一库、历史记录一库,用 CompoundFilterand 组合文件属性做跨库检索。

下期预告#28 进入 HostedMCPTool——HostedTool 家族第三名成员,让 Agent 直接调用远程 MCP 服务器上的工具,defer_loading + ToolSearchTool 组合怎么玩。

Add more perspectives or context around this content.

  • Sign in to comment.