OpenAI Agents SDK 工程笔记:WebSearchTool 与 FileSearchTool 托管工具边界与生产禁区

千笔-AIWritePaper · https://www.aiwritepaper.com

挂上 WebSearchTool 或 FileSearchTool,并不等于「Agent 会自己做完可靠检索」。它们是 OpenAI 托管 工具:在服务器侧执行网页或向量库检索,再把命中回灌给模型。启用条件绑在 Responses 模型路径上;结果默认进入对话上下文,不自动等于已抽检的终裁事实。租户向量库挂错、截断丢掉反证、空命中仍自信作答,都会在生产里变成静默事故。

本文在 openai-agents 0.23.1 下核对 SDK 类形状,并用离线假检索模拟回灌与抽检(不打真实托管 API)。伪造 URL/题名漂移、空命中自信答、跨租户向量库、超大片段截断、非 Responses 混用,各留日志与 CSV(_w/hosted-search-smoke/)。

图:上排为 WebSearch / FileSearch 与自建检索分工;中部为启用与回灌路径;底部为五条生产禁区。

目标说明

读完你应能独立完成五件事。

  1. 说明 WebSearchTool / FileSearchTool 的托管含义,以及为何文档写明当前主要支持 OpenAI Responses。
  2. 为 FileSearch 显式传入本租户 vector_store_ids,并限制 max_num_results。
  3. 在答案落地前做引用抽检:URL/题名必须能回溯到本轮命中集。
  4. 空命中时拒绝自信结论;截断策略不得静默丢掉关键反证。
  5. 把 5 条失败样本写进禁区表与 CI。

适用与边界

适合:已在 Agents SDK 里挂托管检索,需要分清「谁执行、结果怎么回灌、何处终裁」;多租户共用同一 OpenAI 项目、多个向量库并存。

不讲:tool 循环与超时调参、as_tool、MCP、guardrails、lifecycle、ModelSettings、RunContext、streaming、ModelProvider、LocalShell、needs_approval、tool_use_behavior、SQLiteSession、AgentsException 族(见既有工程笔记)。CodeInterpreterTool / HostedMCPTool 等同族托管工具只作对照,不展开。

失败含义:smoke 用假命中固定抽检与截断行为;真实托管检索的排序、计费与延迟以平台为准。类名与字段来自本机 openai-agents 0.23.1。

机制:启用、回灌、与自建检索分工

工具 执行位置 关键参数 工程含义
WebSearchTool OpenAI 托管 search_context_size、user_location、filters、search_content_types name=web_search;网页命中回灌模型
FileSearchTool OpenAI 托管 必填 vector_store_ids;max_num_results(1-50);include_search_results name=file_search;只搜你挂上的库
自建 @function_tool 检索 你的进程 自定 schema / 审计日志 可强制租户过滤、引用落库、拒绝空答

启用条件可以记成三句。第一,Agent 的 tools 列表挂上上述托管工具。第二,模型路径需走支持托管工具的 OpenAI Responses。第三,FileSearch 的向量库 ID 必须在构造时绑死本租户,禁止运行期从用户输入直接拼进 vector_store_ids。

回灌路径:模型发起 web_search / file_search 调用,托管侧执行后,命中作为工具结果回到 Runner,再进入后续模型上下文。include_search_results=True 时,FileSearch 可把检索细节一并纳入输出侧可见结果,便于你做抽检;它仍然不是「已人工核验」标记。

python 复制代码
from agents import Agent, FileSearchTool, WebSearchTool

agent = Agent(
    name="Assistant",
    tools=[
        WebSearchTool(search_context_size="medium"),
        FileSearchTool(
            vector_store_ids=["vs_tenant_A"],
            max_num_results=3,
            include_search_results=True,
        ),
    ],
)

与自建检索的分工:托管适合广搜与公司向量库的第一跳;终裁引用、跨库权限、合规审计应落在自建工具或应用层闸门。把托管命中直接写进对外答复,等于把平台检索当公证处。

离线 smoke:5 条通过 + 5 条失败

text 复制代码
P1  PASS WebSearchTool 托管名与 Responses 专用声明 -> name=web_search context=medium
P2  PASS FileSearchTool 需 vector_store_ids 且可限制条数 -> name=file_search stores=['vs_tenant_A'] max=3 include=True
P3  PASS 托管工具与自建 function_tool 检索分工探针 -> hosted=OpenAI服务器执行 / custom=本地on_invoke;生产须分审计与租户边界
P4  PASS 引用抽检:题名与 URL 均可回溯到命中集 -> issues=-
P5  PASS 空命中策略:禁止自信作答 -> injected_chars=0 refuse=True
F1  FAIL 把托管命中当终裁:伪造 URL/题名漂移未抽检 -> issues=['title_drift:FORGED: 年度系统综述 2025', 'title_drift:真题名(漂移)']
F2  FAIL 空命中仍自信作答 -> hits=0 answer='根据全面检索,可以确认产品已通过全部合规审计。' blind=True
F3  FAIL 跨租户向量库误挂:FileSearch 命中他户文档 -> agent_store=vs_tenant_A hit_store=vs_tenant_B leaked=True title=B租户薪资制度
F4  FAIL 超大片段静默截断丢掉关键反证 -> truncated=True dropped=['填充段2', '关键反证'] critical_lost=True kept_chars=156
F5  FAIL 与非 Responses 后端混用托管检索(文档约束) -> mixed=True constraint=WebSearchTool/FileSearchTool currently only supported with O...
CSV rows: 10

逐条读法。

  • P1/P2:SDK 类名与属性可用;WebSearch 默认 search_context_size=medium;FileSearch 必须带 vector_store_ids。
  • P3:托管在 OpenAI 侧执行,自建在本地 on_invoke,审计与租户边界策略不同。
  • P4:答案中的 URL 都能在命中集找到,抽检通过。
  • P5:空注入时策略选择拒绝作答,而不是让模型自由发挥。
  • F1:伪造题名与漂移题名进入答案,抽检报 title_drift。
  • F2:零命中仍输出「全面检索...确认」,典型幻觉话术。
  • F3:Agent 绑定 vs_tenant_A,命中却来自 vs_tenant_B 的薪资文档。
  • F4:填充段耗尽预算后截断,关键反证 进入 dropped 且 critical_lost=True。
  • F5:在非 Responses 后端混挂托管检索,触碰文档约束(本条记录混用意图,不发起真实错误请求)。

生产禁区表

编号 禁区 实测证据 替代做法
D1 把托管命中当终裁事实 F1 伪造/漂移题名 答案发布前引用抽检;高风险句人工复核
D2 空命中仍自信作答 F2 命中数为 0 时固定拒答或转人工
D3 跨租户 / 跨库串搜 F3 向量库 ID 来自服务端租户映射,禁止请求方直传
D4 截断静默丢证据 F4 截断必打日志;关键命中优先保留或分页
D5 与非 Responses 能力混用 F5 托管检索仅挂在支持的 Responses 配置上
D6 密钥或项目级权限过宽 (配置审计) 分项目或分向量库 ACL;最小权限

配置对照:四个问题定检索形态

问题 是 否
是否必须走 OpenAI 托管网页/向量检索? 用 WebSearch/FileSearch 自建 function_tool 对接自有搜索
是否多租户? 每租户独立 vector_store,服务端绑定 仍要防 F3
对外答复是否需可追溯引用? 强制抽检 + 落库命中快照 仅内部草稿可放宽
上下文是否紧张? 限 max_num_results / context_size,并监控截断 会走上 F4

最小复现:断言「截断不得丢掉反证」

python 复制代码
kept = search.inject(max_chars=budget, stop_on_truncate=True)
assert "关键反证" not in search.dropped_titles or fail_run()
# 生产里改为:截断则升采样关键命中,或拒绝生成最终答案

把「关键」定义为带 must_keep 标签的命中(合规条款、否证、权限边界)。CI 用假检索固定预算,断言标签命中永不进 dropped。

常见误判

  • 「FileSearch 已经挂了公司库,就不会串租户」:挂错 vector_store_ids 或允许客户端传库 ID 时,F3 立刻出现。
  • 「有链接就等于可引用」:F1 的伪造题名同样能带着链接进入答案。
  • 「context_size=high 更安全」:更大窗口仍可能截断;安全靠保留策略,不靠只调大。
  • 「空结果时让模型凭训练知识补全」:那是把托管检索失败藏进幻觉。

命中快照与抽检字段

对外答复前,建议把本轮托管命中落成一张只读快照,再对答案做字符串级抽检。最小字段如下。

字段 来源 用途
tool web_search / file_search 分工具审计
title 命中题名 防漂移
url 或 file_id 命中定位 防伪造链接
vector_store_id FileSearch 防跨租户
rank / score 若平台返回 截断优先级
must_keep 应用标签 F4 保留策略

抽检规则两条就够硬:答案里出现的每个 URL 必须落在快照;答案里复述的题名若带年份/「系统综述」等强主张词,必须与快照题名逐字一致。F1 的 title_drift 就是第二条红灯。

空命中与截断的产品话术

空命中不要让模型说「根据全面检索」。固定三选一:明确「未检索到可用来源」、改写查询重试一次、转人工。截断时若 must_keep 命中被丢,应阻断最终答案,而不是用剩余填充段生成「看起来完整」的回复。F2 与 F4 在用户侧表现都很像「模型很自信」,根因却是检索层策略缺失。

多租户上线检查清单可以贴在发布页:向量库映射表是否按租户单测;预发环境是否仍指向 vs_demo;日志是否打印 vector_store_id(注意脱敏)。这三项能消掉大半 F3 事故。

验收清单

  • 生产 Agent 仅在 Responses 兼容配置下挂 WebSearch/FileSearch。
  • FileSearch 的 vector_store_ids 来自服务端租户映射。
  • 对外答案有引用抽检:URL/题名 ∈ 本轮命中快照。
  • 空命中拒答;截断打点且关键命中不丢。
  • CI 跑 _w/hosted-search-smoke/smoke.py,P 系列 PASS,F 系列可复现。

自建检索何时必须上

出现下列任一条件,应在托管之外再挂自建检索或网关抽检,而不是只加一个 WebSearch。

  1. 答案进入客户合同、监管报送或对外知识库。
  2. 语料含多租户隔离要求,向量库 ACL 无法单独证明。
  3. 必须保留「谁在何时检索了哪条命中」的审计行。
  4. 需要与内部权限系统联查(单据号、员工号、病例号)。

这四条与 F1至F3 直接对应:托管负责找得到,自建或网关负责证明找对了、找的是本租户、并且可追溯。

当天 30 分钟落地

  1. 5 分钟:列出所有挂了 WebSearch/FileSearch 的 Agent,核对模型后端。
  2. 10 分钟:把向量库 ID 改为服务端映射,禁止请求体直传。
  3. 5 分钟:加上命中快照落盘与答案 URL 抽检。
  4. 5 分钟:空命中与截断告警接入值班看板。
  5. 5 分钟:把 CSV 进仓库,升级 SDK 时复跑。

踩坑

  • 演示环境用共享 vs_demo,上线忘记换成租户库。
  • 只抽检答案里的域名白名单,不核对题名漂移。
  • 为省 token 把命中按长度排序再硬切,短反证被排到后面丢掉。
  • 在 Chat Completions 实验分支误留托管工具,排障时以为是「偶发无结果」。
  • 把 include_search_results 当成已审计标志,跳过人工抽检。

与前序主题的咬合

相邻主题 关系 一句话
AgentsException(10-03 A) 失败出口 本篇管检索结果是否可终裁,不管异常分桶
SQLiteSession(10-02 A) 历史落盘 命中快照可另存,勿只靠会话文本
自建 function_tool 检索 分工 托管做第一跳,自建做租户与审计

把托管检索当「搜索引擎插件」还是「证据管道」,决定你敢不敢把答案交给客户。插件心态会停在能搜到;管道心态会要求快照、抽检、拒答与截断告警四件套齐全。本篇 smoke 的五条失败,对应的都是管道缺段,而不是模型偶发胡言。

上线前用本目录假检索再跑一遍:改 max_chars 应能稳定复现 F4;把 Agent 绑定库改成 vs_tenant_B 应能复现 F3。谁在预发关掉抽检「先看效果」,等于把 F1/F2 的失败样本直接送给客户。值班手册里应写明:检索类事故先查命中快照与 vector_store_id,再查模型温度与提示词。

密钥轮换时同步检查向量库 ACL,避免旧项目密钥仍能读到已迁移租户的库。预发与生产的库 ID 表要分文件,禁止共用一份「临时」配置。

总结

WebSearchTool 与 FileSearchTool 提供的是托管检索与回灌 ,不是公证过的事实库。启用绑在 Responses 路径与正确的向量库 ID 上;生产能不能扛住,取决于引用抽检、空命中策略、租户隔离与截断纪律。把五条失败写进禁区表,升级 SDK 或改检索参数时复跑同一份 smoke。字段名以你安装的 openai-agents 版本为准;若托管工具可选参数有变,先对照官方 Tools 文档与本目录 CSV。

检索抽检清单与禁区表归档可用千笔-AIWritePaper 整理;边界与脚本不依赖产品名。

相关推荐
AIGC大时代2 天前
OpenAI Agents SDK 工程笔记:tool_use_behavior 与 is_enabled 动态工具开关生产禁区
agents sdk·生产禁区·is_enabled
AIGC大时代3 天前
OpenAI Agents SDK 工程笔记:LocalShellTool 与 ApplyPatchTool 执行面边界与生产禁区
agents sdk·生产禁区·localshelltool·applypatchtool
爬点儿啥10 个月前
[Ai Agent] 12 Swarm 与 Agents SDK —— 去中心化的多智能体协作
去中心化·区块链·swarm·langgraph·agents sdk·handoff
缘友一世1 年前
Agents-SDK智能体开发[4]之集成MCP入门
llm·mcp·agents sdk