# dsh-web-search-openai [English](README.md) | 中文 这是一个独立的 DeepSeek Harness bundle:保留稳定的 `web_search` 工具,只把搜索后端替换为 OpenAI Responses 原生 Web Search 提供方。提供方发送 `tools: [{ "type": "web_search" }]`,把 `url_citation` 注解转换成 DSH `WebSearchResult.sources`,并公开稳定提供方 id `openai-responses`。 随包 patch 已配置为 `https://llmapi.imedloop.com/v1/responses`、模型 `gpt-5.6-sol` 和凭据引用 `GPT_API_KEY`。该端点必须实现 Responses 原生 Web Search;只支持普通 Responses 文本生成或 Function Calling(函数调用)并不够。参见 [OpenAI 官方 Web Search 指南](https://developers.openai.com/api/docs/guides/tools-web-search)。 ## 安装 在 DSH Web UI 的插件输入框中只粘贴: ```text github:Alberssssss/dsh-web-search-openai ``` 在终端中执行: ```sh dsh plugin --profile web add github:Alberssssss/dsh-web-search-openai ``` 本地开发时,改为构建并安装当前 checkout: ```sh pnpm install pnpm run build dsh plugin --profile web add /cfs/zzkj/home/lth/dsh-web-search-openai ``` 需要锁定已审查版本时,可以指定 commit: ```text github:Alberssssss/dsh-web-search-openai# ``` 重启 `web` profile Host,刷新浏览器连接并创建新会话。仅刷新页面不会重新加载 Cordis 插件,已有会话会保留创建时的组合。 ## 运行时流程 ```text 模型调用 DSH web_search -> ctx.web 选择 openai-responses -> 提供方解析 GPT_API_KEY -> 使用原生 web_search POST /v1/responses -> 要求响应包含 web_search_call 和 URL 引用 -> 把答案文本和引用转换为 WebSearchResult -> 现有 DSH 工具 UI、事件日志和来源展示保持不变 ``` 如果 HTTP 成功响应不含 `web_search_call` 或可用的 HTTP(S) `url_citation`,提供方会拒绝该响应。它绝不会从模型正文中提取 URL。重复引用 URL 会被去重,来源提供标题时会予以保留,最终 `maxResults` 截断由共享 DSH web 服务执行。 ## 与 `dsh-pharma-product-facts` 的关系 本 bundle 只负责发现 URL。它不会替换对话主模型,不会强制模型调用 `web_search`,不会抓取引用页面正文,也不会验证医药主张。配套 pharma bundle 可以通过稳定的 DSH `web_search` 工具消费搜索结果,再独立抓取并核验 CDE/NMPA 证据,最后生成答案: ```text pharma-product-facts -> DSH web_search -> openai-responses -> 候选官方 URL -> pharma 来源核验 -> 最终答案 ``` 两个 bundle 都可以独立运行。`dsh-pharma-product-facts` 可以搭配任何可用的 DSH 搜索提供方;安装配套插件的命令是: ```sh dsh plugin --profile web add github:Alberssssss/dsh-pharma-product-facts-plugin ``` ## 配置 该 bundle 拥有两个 patch 操作:插入提供方配置项,并替换已有 `web` 配置项的 `searchProvider`。profile 层可以覆盖任一配置项: ```yaml - id: web name: '@deepseek-ai/dsh-web' config: searchProvider: openai-responses - id: web-search-openai name: dsh-web-search-openai config: apiKeyEnv: GPT_API_KEY baseURL: https://llmapi.imedloop.com/v1 model: gpt-5.6-sol maxOutputTokens: 4096 ``` | 配置键 | 默认值 | 含义 | |---|---|---| | `apiKey` | 省略 | 字面量密钥;优先使用 `apiKeyEnv`,避免配置包含密钥。 | | `apiKeyEnv` | `GPT_API_KEY` | 每次搜索都通过 `ctx.credentials` 解析的凭据引用;该服务不存在时回退到启动环境。 | | `baseURL` | `https://api.openai.com/v1` | Responses API 基础地址;随后追加 `/responses`。随包 bundle 明确覆盖为 imedloop 代理。 | | `model` | 必填 | 支持 Responses 原生 Web Search 的模型。随包 bundle 选择 `gpt-5.6-sol`。 | | `maxOutputTokens` | `4096` | 辅助 Responses 请求的正整数输出上限。imedloop 路由可能在输出带引用正文前消耗超过 1024 个推理 token。 | 密钥按请求解析,因此在 DSH 凭据存储中替换 `GPT_API_KEY` 后,下一次搜索即可使用新值,无需重新构建该包。如果存在发起请求的 DSH agent(智能体),确切的无密钥请求体会以 `web/openai-search-llm-request` 追加;请求头和凭据绝不会进入日志。 ## 安全与失败 - 携带凭据的请求设置 `redirect: "error"`;3xx 响应会在访问其 `Location` 前被拒绝。 - 调用方取消会覆盖凭据解析、网络请求和响应解析,并以 `WEB_ABORTED` 返回。 - 缺少凭据返回 `WEB_PROVIDER_CREDENTIAL_MISSING`;网络、HTTP、响应体错误、缺少搜索调用或缺少引用均返回 `WEB_PROVIDER_ERROR`。 - 只有 HTTP(S) URL 引用会进入 `sources`;格式错误和本地协议会被丢弃。 - 提供方响应仍然是外部模型输出。`pharma-product-facts` 等消费方仍须抓取并验证所引用的第一方来源,不能把摘要或答案直接视为证据。 ## 模型体验 ### 辅助 Responses 请求 #### 模型看到的内容 一个独立 Responses 模型会收到 `Search the web for the following query and cite the sources you use:\n` 以及原生 `web_search` 工具声明。该辅助请求不属于对话模型的上下文。 #### token 影响 每次搜索都会产生一个独立 Responses 模型请求;`maxOutputTokens` 限制其生成输出。原生 Web Search 用量和计费取决于所配置端点及账户。 #### KV Cache 影响 搜索请求与对话请求缓存相互独立。指令与工具声明保持稳定,查询内容每次调用都会变化。 ## 已知限制与延期工作 - 当前使用的 Responses API 没有公开本包可用的通用结果数量控制;DSH 会在转换引用后强制执行 `maxResults`。 - URL 引用注解提供 URL 和标题,但没有可移植的来源摘要,因此 `snippet` 留空。 - 该包不添加 fetch 提供方,只修改 `web_search`,来源抓取仍由现有消费方工作流负责。 - 原生搜索可能引用无法抽取正文的动态渲染页面。需要原始来源正文的消费方必须找到可直接抓取的文档,否则报告证据缺口。 - 代理可能接受 Responses 文本生成,却拒绝原生 Web Search。提供方会明确失败,不会降级成无引用正文。 ## 开发 ```sh pnpm run typecheck pnpm run test:coverage pnpm run build pnpm run pack:check ``` Git 安装使用已提交的 `lib/` 文件,不执行安装期生命周期脚本。