> ## Documentation Index
> Fetch the complete documentation index at: https://docs.inputapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 联网搜索与引用

> 使用原生 Responses 搜索工具，保留引用并检查渠道支持边界。

## 三种不同的搜索接入

| 接入 | 实际执行方 | 入口 |
| - | - | - |
| 原生 Responses 内置搜索 | 支持该工具的上游模型服务 | 本页与 [Responses API](/zh/api-reference/responses) |
| 客户端函数工具 | 应用执行搜索服务，再回传工具结果 | [工具调用](/zh/guides/tool-calling) |
| Alpha Search | 部署专用搜索后端 | [Alpha Search](/zh/guides/alpha-search) |

Responses 的 `tools` / `tool_choice` 是可表达的原生字段。上游必须实际支持工具名和模型组合；网关不会替任意模型实现搜索。Chat 的 `web_search_options` 是另一种条件支持的请求结构，不能直接把 Responses 工具对象搬进去。OpenRouter 的 `:online` 后缀、`plugins` 搜索回退和其服务端工具目录不是本网关统一契约。

## 工具选择与返回值

示例要求显式设置 `API_SEARCH_TOOL`。命令展示项目已有专门处理的 `web_search_preview`；若部署确认支持当前上游 `web_search`，可改用该值。两个工具的参数和特性不完全相同，不自动降级或重试。原生字段可转发不等于新工具名在所有渠道具有完整的调用统计与计费语义；新工具接入应由部署方核实。本页不提供价格或免费额度承诺。

`tool_choice: required` 请求使用工具。示例进一步要求至少一个已完成的 `web_search_call` 和一条 URL 引用，否则退出失败；这是示例的验收条件，不表示所有无引用 Responses 响应均为协议错误。不要假定跨协议转换保留内置搜索及其引用，优先确认原生 Responses 路径。

引用位于 `output` 消息中每个 `output_text.annotations` 的 `url_citation`，包含 `url`、`title`、`start_index`、`end_index`。脚本把索引和原始文本块一起保存，不合并后套用旧偏移。界面应保留可点击来源，按上游索引约定处理 Unicode，不直接假定 JavaScript 切片语义。链接不会被脚本访问；URL 和标题仍是外部数据，渲染时转义。

脚本只接受 HTTP(S) 无凭据引用，验证基础索引类型和顺序；不会验证引用页是否支持结论，也不展示私有推理。输出是答案和引用 JSON，可能包含公开网页文字。一次请求、无自动重试；使用本地 fixture 验证解析，真实搜索质量需要独立验收。

实现依据：`relaykit/dto/openai_request.go`、`relay/channel/openai/adaptor.go`、`relay/common/relay_info.go`。参见 [上游搜索文档](https://developers.openai.com/api/docs/guides/tools-web-search)。

## 运行示例

在文档目录运行，使用已获准发送的输入和支持该能力的模型；先阅读 [REST 运行时](/zh/guides/http-runtime)。脚本与 `http-client.mjs` 放在同一目录。

```sh theme={null}
export API_ROOT_URL='https://gateway.example.com'
export API_KEY='YOUR_API_KEY'
export API_MODEL='YOUR_SEARCH_MODEL_ID'
export API_SEARCH_TOOL='web_search_preview'
node examples/web-search.mjs
```

```javascript theme={null}
import { requestJSON } from './http-client.mjs';

try {
  const { API_MODEL, API_SEARCH_TOOL } = process.env;
  if (!API_MODEL?.trim() || !['web_search_preview', 'web_search'].includes(API_SEARCH_TOOL)) {
    throw new Error('Select a model and a supported native search tool.');
  }
  const result = await requestJSON('/v1/responses', {
    model: API_MODEL, store: false,
    input: 'Search the official Node.js website for its release schedule and summarize it with source citations.',
    tools: [{ type: API_SEARCH_TOOL }], tool_choice: 'required',
  });
  if (result.status !== 'completed' || !Array.isArray(result.output)) throw new Error('Incomplete response.');
  let calls = 0;
  const blocks = [];
  for (const item of result.output) {
    if (item?.type === 'reasoning') continue;
    if (item?.type === 'web_search_call') {
      if (item.status !== 'completed') throw new Error('Incomplete search.');
      calls++;
      continue;
    }
    if (item?.type !== 'message' || item.role !== 'assistant' || item.status !== 'completed'
      || !Array.isArray(item.content)) throw new Error('Unexpected output.');
    for (const part of item.content) {
      if (part?.type !== 'output_text' || typeof part.text !== 'string' || !Array.isArray(part.annotations)) {
        throw new Error('Missing text or annotations.');
      }
      const citations = [];
      for (const annotation of part.annotations) {
        if (annotation?.type !== 'url_citation') throw new Error('Unsupported annotation.');
        const { url, title, start_index, end_index } = annotation;
        if (typeof url !== 'string' || typeof title !== 'string' || !title.trim()
          || !Number.isSafeInteger(start_index) || !Number.isSafeInteger(end_index)
          || start_index < 0 || end_index <= start_index) throw new Error('Invalid citation.');
        const link = new URL(url);
        if (!['http:', 'https:'].includes(link.protocol) || link.username || link.password) throw new Error('Invalid citation URL.');
        // Keep provider offsets attached to the original text block; do not fetch links.
        citations.push({ url, title, start_index, end_index });
      }
      blocks.push({ text: part.text, citations });
    }
  }
  if (!calls || !blocks.some((block) => block.text.trim()) || !blocks.some((block) => block.citations.length)) {
    throw new Error('This example requires a completed search and cited text.');
  }
  console.log(JSON.stringify({ search_calls: calls, blocks }));
} catch {
  console.error('Search example failed. Check native tool support, completed search, and citations. No automatic retry.');
  process.exitCode = 1;
}
```

[Read in English](/en/guides/web-search)

## 原生 Gemini 搜索与 URL 上下文

Gemini 使用 `tools[].googleSearch` 和候选中的 grounding 元数据，不使用 Responses web\_search 事件。读取指定 URL 使用独立的 urlContext 工具。见[原生内置工具指南与可运行模式](/zh/guides/gemini-builtins)。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.