# 豆包搜索 Custom 版

本文介绍 `modelverse` 接入的**豆包搜索 Custom 版**联网搜索模型的调用方式与输入输出参数。

联网搜索 API 采用统一入口 `POST /v1/web_search`，通过请求体中的 `model` 字段选择供应商（该字段在转发前被剥离）。其余字段为豆包搜索的**原生参数，原样透传、原样返回，不做归一化**，因此请按本文字段直接对接。

> ⚠️ 豆包搜索字段采用**大驼峰**命名（`Query` / `Count` / `Filter` …），请注意大小写。

## 支持的模型

| 模型                       | 说明                                                                     |
| :------------------------- | :----------------------------------------------------------------------- |
| `doubao-web-search-custom` | 豆包搜索 Custom 版，支持网页 / 图片搜索、正文抽取、时间与站点过滤、Query 改写等能力，适合国内内容搜索场景。 |

## 接口

`https://api.modelverse.cn/v1/web_search`

- **请求方式**：`POST`
- **鉴权**：`Authorization: Bearer <平台 API Key>`
- **响应形式**：**非流式**，一次性返回豆包原生 JSON。

## 请求参数

| 参数                     | 类型   | 是否必选 | 描述                                                                                                     |
| :----------------------- | :----- | :------- | :------------------------------------------------------------------------------------------------------- |
| `model`                  | string | 是       | 固定填 `doubao-web-search-custom`，用于选路，转发前被剥离。                                               |
| `Query`                  | string | 是       | 搜索词，长度 1–100 字符。                                                                                 |
| `SearchType`             | string | 是       | 搜索类型：`web`（网页）/ `image`（图片）。                                                                |
| `Count`                  | int    | 否       | 返回结果数：`web` ≤ 50 / `image` ≤ 5，默认 `10`。                                                         |
| `Filter`                 | object | 否       | 过滤条件，见下方 [Filter 对象](#filter-对象)。                                                            |
| `QueryControl`           | object | 否       | 检索控制，见下方 [QueryControl 对象](#querycontrol-对象)。                                                |
| `ContentFormats`         | string | 否       | 正文返回格式：`text` / `markdown`。                                                                       |
| `Industry`               | string | 否       | 行业垂直搜索：`finance` / `game` / `health` / `gov`。                                                     |

### Filter 对象

| 字段                | 类型         | 是否必选 | 描述                                                                                       |
| :------------------ | :----------- | :------- | :----------------------------------------------------------------------------------------- |
| `NeedContent`       | bool         | 否       | 是否返回网页正文。                                                                          |
| `NeedUrl`           | bool         | 否       | 是否返回结果 URL。                                                                          |
| `Sites`             | list<string> | 否       | 站点白名单，仅返回指定站点的结果。                                                          |
| `BlockHosts`        | list<string> | 否       | 站点黑名单，过滤掉指定站点的结果。                                                          |
| `TimeRange`         | string       | 否       | 时间范围：`OneDay` / `OneWeek` / `OneMonth` / `OneYear`，或日期区间。                       |

### QueryControl 对象

| 字段           | 类型 | 是否必选 | 描述                                       |
| :------------- | :--- | :------- | :----------------------------------------- |
| `QueryRewrite` | bool | 否       | 是否启用 LLM 对 `Query` 进行改写以提升召回。 |

## 请求示例

⚠️ 如果您使用 Windows 系统，建议使用 Postman 或其他 API 调用工具。

### curl

```bash
curl -X POST https://api.modelverse.cn/v1/web_search \
  -H "Authorization: Bearer $MODELVERSE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "doubao-web-search-custom",
    "Query": "最新的北京游玩攻略",
    "SearchType": "web",
    "Count": 10,
    "Filter": {
      "NeedContent": false,
      "NeedUrl": true,
      "TimeRange": "OneYear"
    },
    "QueryControl": {
      "QueryRewrite": true
    },
    "ContentFormats": "markdown"
  }'
```

### python

```python
import os
import requests

resp = requests.post(
    "https://api.modelverse.cn/v1/web_search",
    headers={
        "Authorization": f"Bearer {os.getenv('MODELVERSE_API_KEY')}",
        "Content-Type": "application/json",
    },
    json={
        "model": "doubao-web-search-custom",
        "Query": "最新的北京游玩攻略",
        "SearchType": "web",
        "Count": 10,
        "Filter": {
            "NeedContent": False,
            "NeedUrl": True,
            "TimeRange": "OneYear",
        },
        "QueryControl": {"QueryRewrite": True},
        "ContentFormats": "markdown",
    },
)
data = resp.json()
for item in data.get("Result", {}).get("WebResults", []):
    print(item["Title"], item["Url"])
```

## 响应格式

接口返回 `application/json`，为豆包搜索原生响应结构透传（不归一化）。核心为 `Result` 字段。

### 输出

| 参数                              | 类型   | 描述                                                             |
| :-------------------------------- | :----- | :--------------------------------------------------------------- |
| `ResponseMetadata`                | object | 请求元信息。                                                     |
| `ResponseMetadata.RequestId`      | string | 本次请求的唯一标识，可用于定位与排查问题。                       |
| `ResponseMetadata.Error`          | object | 业务错误信息，成功时 `Code` 为空字符串。                         |
| `ResponseMetadata.Error.Code`     | string | 业务错误码，成功时为空字符串。                                   |
| `ResponseMetadata.Error.Message`  | string | 业务错误描述，成功时为空字符串。                                 |
| `Result`                          | object | 搜索结果。                                                       |
| `Result.ResultCount`              | int    | 返回结果数。                                                     |
| `Result.WebResults`               | array  | 网页结果列表，`SearchType=web` 时返回，元素见下表。              |
| `Result.ImageResults`             | array  | 图片结果列表，`SearchType=image` 时返回。                        |
| `Result.SearchContext`            | object | 搜索上下文，含 `OriginQuery`、`SearchType`。                     |
| `Result.TimeCost`                 | int    | 上游耗时（毫秒）。                                               |
| `Result.LogId`                    | string | 上游日志 ID。                                                    |

**`WebResults[]` 元素字段：**

| 字段        | 类型   | 描述                       |
| :---------- | :----- | :------------------------- |
| `Title`     | string | 网页标题。                 |
| `Url`       | string | 网页地址。                 |
| `Snippet`   | string | 摘要片段。                 |
| `Content`   | string | 网页正文（`Filter.NeedContent=true` 时返回）。 |
| `Position`  | int    | 结果排序位置。             |

### 响应示例

```json
{
  "ResponseMetadata": {
    "RequestId": "...",
    "Error": { "Code": "", "Message": "" }
  },
  "Result": {
    "ResultCount": 10,
    "WebResults": [
      {
        "Title": "...",
        "Url": "https://...",
        "Snippet": "...",
        "Content": "...",
        "Position": 1
      }
    ],
    "ImageResults": [],
    "SearchContext": {
      "OriginQuery": "最新的北京游玩攻略",
      "SearchType": "web"
    },
    "TimeCost": 123,
    "LogId": "..."
  }
}
```

## 成功 / 失败判定

- HTTP `200` **且** `ResponseMetadata.Error.Code` 为空 → **成功**，计 1 次调用。
- HTTP `200` 但 `ResponseMetadata.Error.Code` 非空 → **业务失败，不计费**。
- 上游返回非 `200`（4xx/5xx）→ 网关透传对应错误码，**不计费**。

## 错误响应

当网关侧参数或鉴权错误时，返回标准 JSON 错误响应：

```json
{
  "error": {
    "message": "错误描述信息",
    "type": "invalid_request_error",
    "code": "error_code",
    "param": "<请求 ID，用于反馈或排查错误原因>"
  }
}
```

常见错误场景：

| 场景                                  | 现象                                             |
| :------------------------------------ | :----------------------------------------------- |
| `model` 未知 / 未绑定适配器           | 参数错误，提示 `unsupported web search model`。  |
| API Key 无效 / 无该模型权限           | 鉴权 / 权限错误。                                |
| 缺少必填字段（如 `Query` / `SearchType`） | 由上游返回业务错误，网关判失败不计费。           |

## 注意事项

1. **按次计费**：一次成功搜索计 1 次，按模型单价结算；上游业务失败 / 非 2xx 不计费。
2. **字段大小写**：豆包搜索为大驼峰命名（`Query`/`Count`/`Filter`…），与 OpenAI 风格的小写字段不同，请勿混用。
3. **不归一化**：本接口原样透传请求与响应，不同 `model` 的字段结构不同，请按所选模型对应字段使用。
4. **结果数上限**：`web` 类型 `Count` ≤ 50，`image` 类型 ≤ 5。
5. **Query 长度**：1–100 字符，超长请自行截断。
