统一模型接入与用量管理 立即注册
蓝天
原站参考文档

以下为胜算云公开资料。文中的原站账号、地址、定价和专有服务不属于蓝天;蓝天可用模型以当前 sub2api 配置为准。接入蓝天请先查看 快速开始。

查看原文

模型联网接口

用同一把胜算云 Key 调用联网搜索、网页抓取和当前时间工具。支持直接调用搜索 / 抓取接口,也支持在 Chat、Responses、Messages 请求中声明内置工具,由平台执行并继续模型作答。客户端配置步骤见独立指南《在 Agent 中使用内置模型联网接口》。

BASE URLhttps://router.shengsuanyun.com/api
认证方式Authorization: Bearer YOUR_API_KEY

端点列表

内置服务端工具Chat / Responses / Messages更新于 2026-11-05

内置服务端工具:搜索、抓取与当前时间

在 Chat、Responses 或 Messages 模型请求的 tools 中声明工具后,模型按需发起调用,胜算云执行工具并让模型继续回答。三种协议使用相同的胜算云工具类型;请求 JSON 的准确名称如下。

工具 声明类型 用途
web-search · 联网搜索 ssy:web_search 搜索网页,返回来源、标题和摘要供模型作答
web-fetch · 网页抓取 ssy:web_fetch 读取指定网页的标题与正文
datetime · 当前时间 ssy:datetime 获取指定时区的当前时间、Unix 时间戳与 UTC 偏移

直接调用 /v1/tools/search、/v1/tools/fetch 时,由客户端安排搜索、抓取及后续模型请求;使用下方内置工具声明时,由平台完成工具执行与模型续答。两种接入方式均可使用胜算云 API Key。

在客户端中使用,请看独立指南:在 Agent 中使用内置模型联网接口 →,包含 DSH、Claude Code、Cherry Studio 的配置步骤与截图。

API 开发者接入参考

本文面向使用 SSY API 的客户端开发者,覆盖 ssy:web_search、ssy:web_fetch 和 ssy:datetime。根据 2026-11-05 发布说明,生产入口已验证三种协议的流式与非流式工具调用、历史恢复、跨 Gateway 续聊,以及搜索供应商切换。

生产 API 前缀:https://router.shengsuanyun.com/api/v1;测试环境为 https://test-router.shengsuanyun.com/api/v1。示例模型与网络:

协议 请求路径 发布验证模型
Chat /chat/completions deepseek/deepseek-v4-pro
Responses /responses deepseek/deepseek-v4-pro
Messages /messages anthropic/claude-haiku-4.5

这组模型的示例都传 network:"global"。密钥从环境变量 SSY_API_KEY 读取,不写入代码或分享的请求记录。

1. 声明工具并发送请求

三种协议都可以使用以下工具声明,可按需选择一个或多个:

{"tools":[
  {"type":"ssy:web_search","parameters":{"engine":"bocha","max_results":3,"max_uses":1}},
  {"type":"ssy:web_fetch","parameters":{"engine":"deepseek","max_content_tokens":2000,"max_uses":1}},
  {"type":"ssy:datetime","parameters":{"timezone":"Asia/Shanghai","max_uses":1}}
],"ssy_tool_contexts":[]}

工具的可选设置放在声明的 parameters 中。模型需要时发起调用,由平台执行并继续模型生成,客户端无需执行这些内置工具。统一建议从首轮传 ssy_tool_contexts:[],以便取得 Fetch、datetime 及 Chat/Responses 搜索的精确历史恢复载体;Messages 成功搜索也可能直接使用结果卡片内的载体。

下面只使用 Python 标准库。修改 protocol 选择接口格式,修改 tool_kind 选择工具,即可发送对应的非流式请求:

import json
import os
import urllib.request

protocol = "chat"  # "chat" / "responses" / "messages"
tool_kind = "web_search"  # "web_search" / "web_fetch" / "datetime"
base = os.environ.get("SSY_BASE_URL", "https://router.shengsuanyun.com/api/v1").rstrip("/")
paths = {"chat": "/chat/completions", "responses": "/responses", "messages": "/messages"}
models = {"chat": "deepseek/deepseek-v4-pro",
          "responses": "deepseek/deepseek-v4-pro",
          "messages": "anthropic/claude-haiku-4.5"}
parameters = {
    "web_search": {"engine": "bocha", "max_results": 3, "max_uses": 1},
    "web_fetch": {"engine": "deepseek", "max_content_tokens": 2000, "max_uses": 1},
    "datetime": {"timezone": "Asia/Shanghai", "max_uses": 1},
}
questions = {
    "web_search": "请联网搜索一次 Python 官方文档,列出来源,再简要回答 Python 是什么。",
    "web_fetch": "请使用 web_fetch 抓取一次 https://example.com ,返回页面标题和一句摘要。",
    "datetime": "请调用 datetime 工具,告诉我上海当前的日期、时间和 UTC 偏移。",
}
body = {
    "model": models[protocol], "network": "global", "stream": False,
    "tools": [{"type": "ssy:" + tool_kind, "parameters": parameters[tool_kind]}],
    "ssy_tool_contexts": [],  # 选择补充历史协议;成功搜索也可能使用卡片内载体
}
field = "input" if protocol == "responses" else "messages"
body[field] = [{"role": "user", "content": questions[tool_kind]}]
if protocol == "messages":
    body["max_tokens"] = 2048
headers = {"Authorization": "Bearer " + os.environ["SSY_API_KEY"],
           "Content-Type": "application/json"}
if protocol == "messages":
    headers["anthropic-version"] = "2023-06-01"
request = urllib.request.Request(base + paths[protocol],
    data=json.dumps(body).encode(), headers=headers, method="POST")
with urllib.request.urlopen(request, timeout=180) as response:
    result = json.load(response)  # 保留完整对象,供结果提取和下一轮使用
print("响应 ID:", result.get("id"))

声明工具不代表模型一定调用。提示中明确要求使用对应工具有助于触发,但实际调用次数以响应及账单为准。max_uses:1 将该工具在一次 HTTP 请求内的新执行次数限制为一次;提高它仍不能超过平台总轮次和调用次数上限。

1.1 联网搜索 ssy:web_search

搜索的 engine 可写 bocha、deepseek、tavily。显式选择有效引擎会使用平台托管搜索。

不传 engine 时,平台先检查所选渠道是否支持该协议的原生联网工具,支持则交给原厂执行,否则使用平台默认搜索;当前生产与测试环境的默认引擎为 deepseek。希望明确使用某家供应商时,请显式传 engine。

平台托管搜索参数均放在该工具的 parameters 内:

参数 类型 含义、默认值与限制
engine 字符串 搜索供应商:bocha、deepseek、tavily,大小写不敏感;旧值 cn 对应 Bocha,global 对应 Tavily。显式选择会走托管搜索。非空且无法识别的引擎名回退默认托管引擎,不再判断原生支持
max_results 正整数 每次搜索最多保留多少条结果,默认 5,最多 50;Tavily 请求最多 20。同时影响供应商请求条数与平台返回裁剪,实际结果可能更少
max_total_results 正整数 本次 HTTP 请求内所有新搜索累计保留的结果条数上限。未设置时不增加这项限制,其余次数和轮数限制仍生效;剩余额度会收紧下一次搜索条数,耗尽后停止新的搜索执行
max_uses 正整数 本次 HTTP 内,这个搜索工具允许的新执行次数;未设置时沿用请求的工具调用上限。失败尝试也占次数,请求内复用已完成结果不重复占用。只想搜索一次可设为 1
max_calls 正整数 本次 HTTP 内所有托管工具共用的新执行尝试次数上限,搜索、Fetch、datetime 都计入;当前生产默认 20。只能收紧平台上限,不能放宽
max_rounds 正整数 本次 HTTP 内部的模型请求轮数上限,当前生产默认 10,包含首轮和最后作答轮;不能理解为搜索次数。只能收紧平台上限,设为 1 会让首轮直接禁止工具
allowed_domains 字符串数组 允许搜索的域名,传给供应商做域名筛选,例如 ["docs.python.org"]。托管路径仅 Bocha / Tavily 支持;DeepSeek 当前不传递该限制,也不在返回结果中补做域名过滤
blocked_domains 字符串数组 排除的域名,例如 ["reddit.com"]。托管路径仅 Bocha / Tavily 支持,DeepSeek 当前忽略
excluded_domains 字符串数组 blocked_domains 的兼容别名;同时提供有效列表时,以 blocked_domains 为准
search_depth 字符串 仅 Tavily 生效:basic、advanced、fast、ultra-fast;默认 basic,无效值忽略后使用默认。深度可能影响工具计费,具体按平台产品定价;Bocha / DeepSeek 忽略
num_results 正整数 旧版请求条数兼容参数,仅在未设置有效 max_results 时用于供应商请求。不是完整等价别名:结果返回仍按 max_results 默认的 5 条裁剪。新接入统一使用 max_results

max_total_results 按各次新搜索实际保留的结果条数累计,不按 URL 去重;两次搜索返回同一个 URL 也会分别计入。历史回放不占本次新搜索额度。max_uses 只控制该工具,max_calls / max_rounds 写在任一托管工具声明里都会收紧整次请求的共享预算,多个声明取更严格的值。最后需要留一轮让模型根据结果回答,因此“只搜一次”应设置 max_uses:1,不要使用 max_rounds:1。

域名列表应使用域名,不使用完整页面 URL。当前 Bocha 的允许、排除列表各最多 100 项;Tavily 的允许列表最多 300 项、排除列表最多 150 项。超出供应商适配器限制可能返回工具失败,不会自动截断成合法列表。需要域名筛选时明确选择支持它的引擎。

包含次数和域名限制的示例:

{"type":"ssy:web_search","parameters":{
  "engine":"bocha",
  "max_results":5,
  "max_total_results":10,
  "max_uses":2,
  "max_calls":3,
  "max_rounds":4,
  "allowed_domains":["docs.python.org"],
  "excluded_domains":["reddit.com"]
}}

这允许模型按需最多新搜两次,每次最多五条、总计最多十条;仍受平台限制,也不保证模型一定搜满次数。需要 Tavily 深度选项时,在其声明中设置,例如 {"engine":"tavily","search_depth":"basic","max_results":5}。

原生搜索参数与托管参数的适用范围不同:

参数 含义与适用范围
search_context_size 原生 Chat/Responses 搜索供模型参考的上下文规模,合法值 low / medium / high,未指定时由上游决定。托管搜索忽略它,它不是 max_results、累计结果数或精确 token 限额
user_location 原生搜索的近似用户位置对象,可包含 country、region、city、timezone,按对应协议转换;托管搜索当前不转发
filters.allowed_domains 原生 Responses 的域名筛选字段;托管搜索请使用上表的 allowed_domains
external_web_access 原生 Responses 的外部网页访问开关;托管搜索当前不转发

原生 Messages 可转发 max_uses 和域名列表;同时提供允许、排除列表时优先允许列表。上表的托管 max_results、max_total_results、max_calls、max_rounds 不会变成原厂内部执行预算。需要平台托管预算时,显式选择 engine。

以下选项当前不控制托管内置搜索,不要因为供应商直连接口支持就认为内置工具也支持:

参数 当前处理方式
topic、time_range、country、include_answer、include_raw_content 不转发给托管搜索供应商;填写后不生效
timeout 不覆盖平台统一的工具执行超时
max_content_tokens 仅用于 Fetch 正文截断,不限制搜索正文或摘要
timezone 用于 datetime,不用于托管搜索本地化
count、need_content、summary、freshness、include_domains、exclude_domains 等供应商字段 不是内置搜索的公共参数;使用上表的 max_results、allowed_domains、blocked_domains 等平台字段

搜索词由模型在实际调用中以 query 给出,写在用户问题里即可;parameters.query 不是固定搜索词配置。可选参数容错不等于所有字段都会生效,也不保证无效查询、供应商失败或计费故障仍然成功。

还可以使用对应协议的联网工具声明;下列 parameters.engine 是 SSY 扩展,显式传入同样选择平台托管搜索:

协议 对应请求字段示例
Chat "web_search_options":{"engine":"bocha"},放在请求顶层
Responses "tools":[{"type":"web_search","parameters":{"engine":"bocha"}}];也支持 web_search_preview
Messages "tools":[{"type":"web_search_20250305","name":"web_search","parameters":{"engine":"bocha"}}]

本页搜索示例统一使用 ssy:web_search,便于在三种协议间保持一致。无显式引擎时,原生与托管的结果字段可能不同。

可选附加参数中,未知字段、类型不符或越界值通常会被忽略、采用默认或限幅;这不代表每家供应商都支持每个参数。max_results 是上限,实际结果可能更少。必需查询缺失等执行错误会尽量作为模型可读结果继续处理。合法空结果不一定免费,应按供应商确认用量及产品规则计费。

1.2 网页抓取 ssy:web_fetch

{"type":"ssy:web_fetch","parameters":{
  "engine":"deepseek",
  "max_uses":1,
  "max_content_tokens":2000,
  "allowed_domains":["example.com"],
  "blocked_domains":["private.example.com"]
}}
参数 含义
engine 抓取供应商。当前生产已配置并验证 deepseek;搜索可用的 Bocha/Tavily 不代表也已配置 Fetch
max_uses 本次 HTTP 内该工具的新执行次数上限,仍受平台全局限制
max_content_tokens 托管抓取返回给模型的正文长度上限,默认 20000,最高 100000;超出时截断正文并返回 truncated:true
allowed_domains 可选允许域名列表;提供后只抓取列表内域名及其子域名
blocked_domains 可选禁止域名列表,匹配时拒绝抓取;excluded_domains 可作为别名,显式 blocked_domains 优先

待抓取 URL 由模型的运行时调用参数 url 给出。把 URL 写在用户问题中即可;parameters.url 不是固定 URL 的配置项。地址应为不含账号密码的完整 HTTP/HTTPS URL。域名不符合限制或地址无效时,工具会向模型返回失败信息,尽量继续回答。

托管路径在抓取完成后按 cl100k_base 计数并截断正文,max_content_tokens 不是供应商下载字节上限,也不保证等于所选模型的实际输入 token 数。

未指定 engine 时,平台先判断当前渠道及协议是否支持所声明的原生 Fetch;不支持则走平台默认抓取,当前生产默认是 DeepSeek。Chat 的 Fetch 使用托管路径。平台也识别 Messages 的 web_fetch_20250910 声明;原生是否执行取决于渠道能力,不能据此假定所有模型都支持。需要明确走已配置的托管抓取时使用上面的显式引擎写法。

错填为无法识别的非空引擎名时,使用默认托管引擎,不再选择原生工具;可识别但尚未配置 Fetch 产品的引擎仍可能返回工具失败信息,因此当前应选 deepseek。

1.3 当前时间 ssy:datetime

{"type":"ssy:datetime","parameters":{"timezone":"Asia/Shanghai","max_uses":1}}

timezone 使用 IANA 时区名称,如 Asia/Shanghai、UTC、America/New_York。声明中指定时区时,它优先于模型调用参数中的时区;未指定时,先使用模型传入的时区,再使用平台默认时区,当前生产默认 UTC。无效时区会回落到平台默认值,默认值也无效时回落到 UTC,不因错填时区中断请求。

结果包含 RFC3339 时间字符串 datetime、实际使用的 timezone、以秒为单位的整数 unix_timestamp、UTC 偏移 utc_offset。这是每次工具实际执行时的当前时间;回放历史保留的是旧时间,想知道最新时间需让模型再次调用。

datetime 没有搜索引擎参数,本地执行,工具本身免费;模型生成、处理工具结果和历史所用的 token 仍正常计费。

2. 三种协议的结果提取

以下响应只保留与提取有关的字段,来源和密文已替换为示意值;示例密文不能用于真实恢复。SSY 扩展字段与事件不是 OpenAI / Anthropic 官方标准。

协议 非流式搜索结果 流式搜索结果 下一轮恢复所需内容
Chat x_online_search[].search_results choices[].delta.search_results 完整 message + 所有 ssy_tool_contexts
Responses x_online_search[].search_results response.online_search.completed 事件的 online_search.search_results 完整 output + 所有 ssy_tool_contexts
Messages content 中的 web_search_tool_result.content;完整详情也在 x_online_search content_block_start.content_block 中的结果卡片 完整 assistant content;有补充包时一并保留

搜索列表用于展示,恢复载体用于续聊。不能只把 x_online_search 或最终回答文字塞进下一轮,就当作已恢复内部工具历史。第 2.1—2.6 节说明搜索结果,第 2.7—2.8 节说明 Fetch/datetime 的结果与续聊。

2.1 Chat 非流式

答案:choices[0].message.content。完整搜索列表:顶层 x_online_search;多次搜索对应多个元素。

{
  "choices":[{"message":{"role":"assistant","content":"最终回答"}}],
  "x_online_search":[{
    "type":"search_queries",
    "search_queries":["Python 官方文档"],
    "search_results":[{"url":"https://example.com","title":"文档标题","snippet":"摘要"}],
    "search_indexes":[{"index":1,"url":"https://example.com"}]
  }],
  "ssy_tool_contexts":[{"at":0,"data":"ssyctx.v1.<opaque>"}]
}

每个 x_online_search 元素的 type 可以是 search_queries,同时包含查询、结果、索引;不要据此忽略其 search_results。展示来源读取 url/title/snippet,可选字段还有 site_name/icon。

2.2 Chat 流式

普通文本在 choices[].delta.content;搜索字段直接平铺在 delta 中,不需要对 content 再做 JSON 解码。

data: {"choices":[{"index":0,"delta":{"type":"search_queries","search_queries":["Python 官方文档"]},"finish_reason":null}]}

data: {"choices":[{"index":0,"delta":{"type":"search_results","search_results":[{"url":"https://example.com","title":"文档标题","snippet":"摘要"}]},"finish_reason":null}]}

data: {"choices":[{"index":0,"delta":{"type":"search_indexes","search_indexes":[{"index":1,"url":"https://example.com"}]},"finish_reason":null}]}

event: ssy.tool_context
data: {"type":"ssy.tool_context","ssy_tool_contexts":[{"at":0,"data":"ssyctx.v1.<opaque>"}]}

data: [DONE]

每次搜索分别追加查询、结果和索引记录;不要只保留最后一组。无结果时可以只有查询帧。上述搜索帧不一定包含 content,文本拼接器应跳过缺失字段。

2.3 Responses 非流式

答案遍历 output[] 中 type:"message" 的 content[],读取 type:"output_text" 的 text。平台托管搜索列表仍在顶层 x_online_search。

{
  "output":[
    {"id":"ws_ssy_example","type":"web_search_call","status":"completed",
     "action":{"type":"search","query":"Python 官方文档"}},
    {"type":"message","role":"assistant",
     "content":[{"type":"output_text","text":"最终回答","annotations":[]}]}
  ],
  "x_online_search":[{"type":"search_queries","search_queries":["Python 官方文档"],
    "search_results":[{"url":"https://example.com","title":"文档标题","snippet":"摘要"}]}],
  "ssy_tool_contexts":[{"at":0,"data":"ssyctx.v1.<opaque>"}]
}

当前托管生成的 web_search_call.action 不保证有 sources。原生上游支持时,可通过 include:["web_search_call.action.sources"] 请求该官方来源字段,再读取返回的 action.sources;不能用它替代托管路径的 x_online_search。原生来源的语义见 OpenAI 联网搜索说明。

2.4 Responses 流式

搜索过程可以出现 response.web_search_call.in_progress/searching/completed 及 response.output_item.added/done。完整托管搜索结果读取下面的 SSY 扩展事件:

event: response.online_search.completed
data: {"type":"response.online_search.completed","sequence_number":6,"online_search":{"search_queries":["Python 官方文档"],"search_results":[{"url":"https://example.com","title":"文档标题","snippet":"摘要"}],"search_indexes":[{"index":1,"url":"https://example.com"}]}}

event: response.output_text.delta
data: {"type":"response.output_text.delta","output_index":1,"content_index":0,"delta":"最终回答"}

event: ssy.tool_context
data: {"type":"ssy.tool_context","ssy_tool_contexts":[{"at":0,"data":"ssyctx.v1.<opaque>"}]}

搜索列表路径为 online_search.search_results。文本按 output_index/content_index 聚合;最终以 response.completed.response 的完整对象为归档基础,并合入单独收集的上下文包。不要把已收到的 output_item.done 和最终 output 再重复追加。也要处理 response.failed/incomplete,HTTP 200 不代表流已正常完成。

2.5 Messages 非流式

答案取 content[] 中的 text 块。成功非空搜索在条件满足时返回 server_tool_use 与 web_search_tool_result,非流式完整搜索详情同时可读顶层 x_online_search。

{
  "content":[
    {"type":"server_tool_use","id":"srvtoolu_ssy_example","name":"web_search",
     "input":{"query":"Python 官方文档"}},
    {"type":"web_search_tool_result","tool_use_id":"srvtoolu_ssy_example",
     "content":[{"type":"web_search_result","url":"https://example.com",
       "title":"站点 · 文档标题 — 摘要","page_age":null,
       "encrypted_content":"ssyctx.v1.<opaque>"}]},
    {"type":"text","text":"最终回答"}
  ],
  "x_online_search":[{"type":"search_queries","search_queries":["Python 官方文档"],
    "search_results":[{"url":"https://example.com","title":"文档标题","snippet":"摘要"}]}]
}

搜索卡片读取 web_search_tool_result.content[] 的 url/title/page_age;标题可能拼有摘要前 200 字。encrypted_content 是恢复载体,不能当摘要展示。SSY 载体可能以 ssyctx.v1.、ssyblob.v1. 开头,其余卡片可能是 ssyref.v1. 引用;需要整组保留。

本次发布验证的 Claude 源成功搜索直接使用卡片密文,顶层 ssy_tool_contexts 即使入站是 [] 也可能没有新增包,这是正常结果。若未启用可用历史密钥,或搜索为空、失败、同轮混有客户端工具,可能返回 type:"text" 的 Platform web_search result:\n<JSON> 可读内容。可读文本不等于保留了完整隐藏工具历史。

2.6 Messages 流式

完整卡片可能直接出现在 content_block_start.content_block,随后即 content_block_stop,不一定有额外 delta:

event: content_block_start
data: {"type":"content_block_start","index":1,"content_block":{"type":"server_tool_use","id":"srvtoolu_ssy_example","name":"web_search","input":{"query":"Python 官方文档"}}}

event: content_block_stop
data: {"type":"content_block_stop","index":1}

event: content_block_start
data: {"type":"content_block_start","index":2,"content_block":{"type":"web_search_tool_result","tool_use_id":"srvtoolu_ssy_example","content":[{"type":"web_search_result","url":"https://example.com","title":"文档标题","page_age":null,"encrypted_content":"ssyctx.v1.<opaque>"}]}}

event: content_block_stop
data: {"type":"content_block_stop","index":2}

按 index 建立并保留完整内容块;文本继续处理 content_block_delta.delta.text。原生工具输入还可能有 input_json_delta.partial_json,需要按块拼接后解析。默认不要等待 online_search.completed:当前托管 Messages 路径不保证发送该事件。最终等待 message_stop,同时检查错误与停止原因。

2.7 Fetch 与 datetime:三种协议的结果字段

下表描述当前平台托管路径;原生供应商工具使用实际返回的协议字段。请求从首轮带上 ssy_tool_contexts:[],才能在 Chat/Responses 中稳定取得这里的扩展结果,并为三种格式选择精确历史恢复协议。

协议 非流式 Fetch / datetime 结果 流式 Fetch / datetime 结果
Chat 顶层 x_ssy_tool_results[] ssy.tool.completed 事件
Responses 顶层 x_ssy_tool_results[] ssy.tool.completed 事件;终态 response.completed 事件顶层也可能附带 x_ssy_tool_results
Messages content[] 中带 Platform web_fetch result:\n 或 Platform datetime result:\n 前缀的 text 块 content_block_start.content_block 中的上述完整文本块;随后还有正常的模型文本 delta

Chat/Responses 的数组元素及完成事件有相同的核心字段:

字段 含义
tool ssy:web_fetch 或 ssy:datetime
tool_call_id 本次模型工具调用的标识,用于关联、去重;不是工具账单的雪花 request ID
output 成功时为 JSON 字符串,需解码一次才能读取结果属性
failed 工具是否失败;失败时的 output 可能是错误 JSON 或普通文本,不要当成功结果解析

成功结果的结构如下;datetime 中的值只用于演示,不代表客户端发请求时的当前时间:

{"title":"Example Domain","content":"页面正文","truncated":false}
{"datetime":"2026-11-05T08:00:00+08:00","timezone":"Asia/Shanghai","unix_timestamp":1793836800,"utc_offset":"+08:00"}

truncated:true 表示 Fetch 正文达到长度限制。datetime 的 unix_timestamp 单位是秒;如客户端需要毫秒,显式乘以 1000。

Chat / Responses 非流式的相关字段示例,省略了常规模型回答:

{
  "x_ssy_tool_results":[{
    "type":"ssy.tool.completed",
    "tool":"ssy:web_fetch",
    "tool_call_id":"call_fetch_example",
    "output":"{\"title\":\"Example Domain\",\"content\":\"页面正文\",\"truncated\":false}",
    "failed":false
  }],
  "ssy_tool_contexts":[{"at":0,"data":"ssyctx.v1.<opaque>"}]
}

Chat / Responses 流式的两个结果事件片段:

event: ssy.tool.completed
data: {"type":"ssy.tool.completed","tool":"ssy:web_fetch","tool_call_id":"call_fetch_example","output":"{\"title\":\"Example Domain\",\"content\":\"页面正文\",\"truncated\":false}","failed":false}

event: ssy.tool.completed
data: {"type":"ssy.tool.completed","tool":"ssy:datetime","tool_call_id":"call_time_example","output":"{\"datetime\":\"2026-11-05T08:00:00+08:00\",\"timezone\":\"Asia/Shanghai\",\"unix_timestamp\":1793836800,\"utc_offset\":\"+08:00\"}","failed":false}

Responses 抓取过程还可能有 web_search_call item,action.type 为 open_page、action.url 为目标网址。这些字段描述过程,不包含完整抓取正文。datetime 不保证有原生工具 item,使用扩展结果读取。

Responses 的终态扩展位于整个事件的 x_ssy_tool_results,不要只读取 response.completed.response。 独立完成事件和终态数组可能是同一批结果,按 tool_call_id 去重;最终 response.output 仍用权威快照替换临时 item,不要重复追加。

Messages 当前托管路径示例:

{
  "role":"assistant",
  "content":[
    {"type":"text","text":"Platform web_fetch result:\n{\"title\":\"Example Domain\",\"content\":\"页面正文\",\"truncated\":false}\n"},
    {"type":"text","text":"Example Domain 是用于文档示例的域名。"}
  ],
  "ssy_tool_contexts":[{"at":0,"data":"ssyctx.v1.<opaque>"}]
}

datetime 同样使用文本块,前缀为 Platform datetime result:\n,后面是时间结果 JSON。流式结果块可以完整出现在 content_block_start.content_block.text,随后直接 content_block_stop,没有工具结果的 text_delta;只监听 delta 会漏掉结果。

Messages 客户端可按前缀区分结果块与最终回答,去掉前缀后尝试 JSON 解码。当前托管 Fetch/datetime 不保证返回 web_fetch_tool_result、x_ssy_tool_results 或 ssy.tool.completed,不要以这些字段缺失判定工具未执行。

2.8 Fetch 与 datetime 的续聊示例

三种格式都保留完整公共历史和所有补充载体,坐标规则与第 3 节一致。Fetch 续聊时可要求“读取上一次保存的抓取结果”;datetime 续聊时可询问“上一次工具返回的时间”。查询当前时间则应允许一次新的 datetime 执行。

Messages 的成功搜索卡片有 encrypted_content,而当前 Fetch/datetime 的可读文本块没有这个槽。只有可读文本不等于精确恢复隐藏的工具轮次:需要在首轮选择补充协议,并保存、回传所有 ssy_tool_contexts。

下面沿用第 1 节已经返回的非流式 body、result、protocol、tool_kind 和 headers,并使用第 3.2 节的 followup 函数。把该函数定义放到这段代码之前即可继续对话;无需重新发送已经完成的首轮请求。

# 先定义第 3.2 节的 followup 函数,再执行以下代码。
questions = {
    "web_search": "不要再次搜索。只从上一次保存的搜索结果中列出全部原始 URL。",
    "web_fetch": "不要再次抓取或搜索。只从上一次保存的抓取结果中返回准确的 title 属性。",
    "datetime": "不要再次调用工具。返回上一次 datetime 结果的 unix_timestamp。",
}
next_body = followup(protocol, body, result, questions[tool_kind])
next_body["stream"] = False
next_body["tool_choice"] = {"type": "none"} if protocol == "messages" else "none"
next_request = urllib.request.Request(
    base + paths[protocol], data=json.dumps(next_body).encode(),
    headers=headers, method="POST")
with urllib.request.urlopen(next_request, timeout=180) as response:
    next_result = json.load(response)

流式续聊时,先按第 3.3 节完整收集 SSE 的公共历史、结果与上下文包,再交给同一个 followup 函数。

该示例不为平台内置工具伪造客户端 tool_result;真实客户端工具仍须自行执行并配对回传。

3. 多轮对话必须保留两类信息

  1. 完整公共历史。 Chat 保存整个 choices[0].message;Responses 保存整个 output 数组;Messages 保存整个 assistant content 数组。保留 reasoning、phase、签名、客户端工具调用及未知的必要字段,不只保存最终文字,也不要重排已有条目。
  2. 所有补充上下文。 三种格式统一建议首次传 ssy_tool_contexts:[],收集 JSON 或 ssy.tool_context SSE 的全部包。当前 Chat/Responses 通常用一个包聚合整次 HTTP;Messages 成功搜索可以使用卡片,Fetch/datetime 的精确恢复仍需要补充包。多个包可能对应同一条 assistant 消息。

Messages 同协议续聊时,把完整 content 原样作为下一请求的 assistant content 回传;成功搜索的加密卡片可据此恢复,Fetch/datetime 同时回传补充包。不需要为平台的 server_tool_use 自行执行工具或伪造 user tool_result。真实客户端 tool_use / tool_calls 仍由客户端执行并正确回传结果。

整段会话请保持同一入口协议。载体还绑定了原协议及公共历史,仅把 Chat 改成 Responses / Messages、转换公共字段并重算坐标,不能保证恢复密封的内部历史。服务端在一次请求内适配不同上游,不等于客户端可以在后续 HTTP 请求中任意切换入口协议。

3.1 at 的坐标与平移

返回包中的 at 相对于本次返回的公共历史片段。提交下一轮时,要改为该片段在完整 messages/input 数组中的实际位置:

base = len(上一请求的完整 messages 或 input)
新包.at = base + 返回包.at
旧包.at 保持原值

at 数的是外层消息或 input item,不是内容块、搜索卡片或 token 数。Chat 数组中的 system/developer 消息也计数;Messages 顶层 system、Responses 顶层 instructions 不占数组下标,放在 input 中的真实 system/developer item 则计数。

Chat 有 system 消息时,三轮坐标如下;A/B/C 表示不同返回载体:

返回来源 本次请求的 messages 添加本次 assistant 的 base 新返回包 下一请求保留的包
第 1 轮 system(0)、user(1) 2 A:at=0 A:at=2
第 2 轮 system(0)、user(1)、assistant(2)、user(3) 4 B:at=0 A:at=2;B:at=4
第 3 轮 前述历史、assistant(4)、user(5) 6 C:at=0 A:at=2;B:at=4;C:at=6

Responses 的一次 output 可能含多个 item。例如原 input 长度为 2,本次返回 3 个 output item,则依次追加到 2/3/4,再加用户追问到 5;下一次追加响应的 base 是 6,不是“对话轮数 × 2”。

多个包可以有相同 at,例如 Messages 同一个 assistant 内的多个工具轮次。不能按 at 去重;如需去重,只能对完全相同的 (at,data) 去重。不要只保存最后一个包,也不要把旧包再次加上新 base。

3.2 可直接使用的 Python 追问函数

这个函数处理本页三个工具的单 choice、同协议非流式对话;流式需先完整组装为同形响应对象。它深拷贝上一份完整请求,保留 network、system/instructions、工具和其他参数,仅偏移新返回包。存在待客户端执行的工具调用时主动要求先完成配对。可选的 engine 参数只用于切换搜索引擎。

from copy import deepcopy

def followup(protocol, prev_request, response, text, engine=None):
    req = deepcopy(prev_request)
    field = "input" if protocol == "responses" else "messages"
    history = req[field]
    if not isinstance(history, list):
        raise ValueError("请从首轮使用完整的 messages/input 数组")
    base = len(history)  # 必须在追加本次输出之前计算
    if protocol == "chat":
        message = deepcopy(response["choices"][0]["message"])
        if message.get("tool_calls"):
            raise ValueError("先执行并回传客户端工具结果")
        public = [message]  # 不重建成只有 role/content 的消息
    elif protocol == "responses":
        public = deepcopy(response["output"])  # reasoning/phase 等 item 一并保留
        if any(item.get("type") == "function_call" for item in public):
            raise ValueError("先执行并回传客户端工具结果")
    elif protocol == "messages":
        content = deepcopy(response["content"])  # 保留完整卡片、签名和未知块字段
        if any(block.get("type") == "tool_use" for block in content):
            raise ValueError("先执行并回传客户端工具结果")
        public = [{"role": "assistant", "content": content}]
    else:
        raise ValueError("未知协议")
    history.extend(public)
    history.append({"role": "user", "content": text})

    contexts = deepcopy(req.get("ssy_tool_contexts", []))
    seen = {(c["at"], c["data"]) for c in contexts}
    fresh = response.get("ssy_tool_contexts") or []
    for raw in fresh:
        c = deepcopy(raw)
        c["at"] = base + c["at"]  # 只移动本次返回的坐标
        pair = (c["at"], c["data"])
        if pair not in seen:
            contexts.append(c)
            seen.add(pair)
    if "ssy_tool_contexts" in req or fresh:
        req["ssy_tool_contexts"] = contexts

    if engine is not None:
        changed = False
        for tool in req.get("tools", []):
            if tool.get("type") == "ssy:web_search":
                tool.setdefault("parameters", {})["engine"] = engine
                changed = True
        if not changed:
            raise ValueError("本示例需要先声明 ssy:web_search")
    return req

# 沿用第 1 节的 body/result/protocol;下一轮请求仍发到相同协议路径
next_body = followup(protocol, body, result, "请结合刚才的来源进一步说明。")
# 仅搜索示例:切换下一次新执行使用的引擎,保留全部旧历史与载体。
if tool_kind == "web_search":
    switched_body = followup(protocol, body, result, "请再检索一组来源。", engine="tavily")

继续第 3 轮时,传 followup(protocol, next_body, next_result, ...);不要又从第一轮 body 开始。切换引擎只改变未来新工具执行,旧搜索结果及旧载体保持原样,不会被改成新供应商的结果。

3.3 SSE 的归档规则

以上 JSON/SSE 展示的是文本与内置工具字段,不是通用多模态解析器。用于下一轮的归档应遵循:

  • Chat:按 choice/index 聚合完整 message;拼 content、reasoning 和工具参数片段,保留 phase、reasoning_details、annotations 及其他必要字段。托管单 choice 路径最后只有一个最终 finish 和整流一个 [DONE];不能只把显示文本拼起来当完整历史。
  • Responses:保存完整最终 response/output;若要边收边展示,按 item id/output_index 更新条目,最终快照替换临时状态。保留 reasoning、compaction、工具调用等 item,不能只取 output_text。
  • Messages:从 message_start 开始按块 index 聚合,处理 text/thinking/signature/input JSON 等 delta,原样保留 server_tool_use、web_search_tool_result、引用与密文;收到 message_stop 后归档。
  • 三协议都单独收集所有 ssy.tool_context 事件,将里面所有 ssy_tool_contexts 合并进该次完整响应,再调用追问函数;只有完全相同的 (at,data) 才可去重。
  • Chat/Responses 的 Fetch/datetime 另外收集 ssy.tool.completed 及 x_ssy_tool_results,按 tool_call_id 去重。Responses 终态快照替换 output 时,保留此前收集的补充结果以及终态事件顶层的扩展。
  • 不要在代理、SSE 分发器或 SDK 包装层过滤未知事件、额外 JSON 字段。若 SDK 没有保留这些数据,改用能读取原始 JSON/SSE 的入口。多模态、多个 choice 和客户端工具需要各自完整的协议聚合器。

若使用 Pydantic 风格 SDK 对象,优先保留原始 JSON;需要转换时,使用 model_dump(mode="json", exclude_unset=True),避免补入响应中原本没有的默认 null 字段。也不要统一使用 exclude_none=True,因为响应里原本存在的 null 同样应保留。历史绑定依赖原有公共结构,随意增删字段会影响恢复。

第 1 节提供可独立执行的标准库请求示例,第 3.2 节提供追问函数;构造 next_body 后,仍使用同一协议、同一正式入口发送请求。若把 stream 改为 true,应使用上述 SSE 聚合规则,不能继续用 json.load 读取整条流。客户端需要自行持久化完整会话与所有恢复载体,才能在进程退出后继续对话。

4. 如何选择供应商与计算费用

4.1 搜索供应商

对下一次请求中的工具声明修改 parameters.engine 即可,三种协议写法相同:

{"type":"ssy:web_search","parameters":{"engine":"deepseek","max_results":3}}

可选值为 bocha、deepseek、tavily。例如从 Bocha 切到 Tavily:保留上一请求的完整历史和全部恢复载体,用第 3.2 节的 followup(..., engine="tavily") 构造新请求,并明确要求“使用新的引擎再搜索一次”。不要修改旧搜索结果、旧载体或它们的位置。

声明中的 engine 选择该工具的供应商;请求中的 model 及响应中的模型 provider 表示大语言模型,与工具供应商不是同一个字段。切换引擎也不会自动触发工具,最终是否调用仍由模型决定。

4.2 抓取供应商与 datetime

Fetch 修改的是 ssy:web_fetch 自己的 parameters.engine,与搜索声明互不替代。当前生产已验证的 Fetch 引擎为 deepseek:

{"type":"ssy:web_fetch","parameters":{"engine":"deepseek","max_uses":1,"max_content_tokens":2000}}

followup(..., engine=...) 只修改 ssy:web_search,不修改 Fetch。需要调整下一次抓取的设置时,先构造完整追问请求,再修改其中 ssy:web_fetch 声明的 parameters;保留全部旧公共历史和载体。其他抓取引擎需平台先配置开放,不能直接沿用搜索供应商列表。datetime 本地执行,无供应商切换。

4.3 计费

行为 工具费用 模型费用
新执行一次托管搜索或 Fetch 每次独立记录工具账单 按各轮实际 token、缓存及定价计费
datetime 工具免费 处理调用、结果及历史的模型 token 正常计费
声明工具但未调用 不产生工具费 按模型实际用量计费
恢复旧结果、请求内复用同一次已完成执行 不重复收旧工具费 恢复的历史仍是本次模型输入,按实际用量与缓存规则计费

模型根据新问题发起新的搜索或 Fetch,仍会产生新的工具费用。托管工具与模型独立结算:此前已经成功的工具费用,不会因后续主模型最终失败而撤销。主请求因上游/平台最终失败时,各轮模型用户费用按当前规则豁免;用户主动取消或客户端断开按已确认用量处理。datetime 免费不表示整个模型请求免费。

5. SDK 地址、有效期与限制

OpenAI Python SDK 的 base_url 使用 https://router.shengsuanyun.com/api/v1;Anthropic Python SDK 会再追加 /v1/messages,其 base_url 应使用 https://router.shengsuanyun.com/api:

import os
from openai import OpenAI
from anthropic import Anthropic
openai_client = OpenAI(api_key=os.environ["SSY_API_KEY"],
    base_url="https://router.shengsuanyun.com/api/v1")
claude_client = Anthropic(api_key=os.environ["SSY_API_KEY"],
    base_url="https://router.shengsuanyun.com/api")

network、ssy_tool_contexts 等平台字段需要 SDK 的额外请求体支持;响应扩展也要确实保留。先验证 SDK 的原始响应/流接口,不假设它会自动回传 SSY 历史。

当前生产与测试环境的历史载体有效期为 24 小时;以签发时的平台配置为准,后续重新签发不代表旧载体自动续期。平台保存的是加密的生成历史增量,大载体可使用对象存储引用,不额外存储完整客户对话。恢复仍依赖客户端回传完整公共历史和载体,不能只传响应 ID。

SSY 载体过期、缺失、损坏或与历史不匹配时,会尽量降为已有可读历史;隐藏的完整工具过程可能无法恢复,模型也可能重新搜索并产生新费用。Messages 的原厂 opaque 数据遵循其来源协议;不要把 SSY 平台密文直接发给厂商 API。resp_ssy_... 不是可单独续聊的厂商响应 ID,本页 Responses 示例使用完整 input,不依赖 previous_response_id。

鉴权、模型权限、合法 URL、域名限制以及计费服务错误,不属于“可选附加参数忽略”的范围。工具失败应检查 failed 或可读结果中的错误,模型最终回答可能是在解释失败,不能只凭 HTTP 200 判断工具成功。

6. 协议参考与验证范围

官方协议参考:OpenAI 会话状态、OpenAI 联网搜索、Anthropic Web search tool。这些资料用于理解公共历史、原生来源及内容块;本文的 ssy:*、x_online_search、ssy.tool_context、ssy_tool_contexts 是 SSY 扩展。

根据 2026-11-05 发布说明,验证范围包括三协议流/非流的搜索、Fetch、datetime;完整公共历史及补充上下文回传;Messages 成功搜索卡片回传;旧、新两处搜索历史同时恢复;Bocha、DeepSeek、Tavily 搜索;原生搜索声明适配与托管兜底;未知/错类型可选参数及无效时区容错;Messages 搜索与客户端工具混用;跨 Gateway 的内联与 OSS 引用恢复;保留客户端工具及 system 缓存点后的 Claude 缓存命中。请求成功不代表一定调用工具,更不代表固定调用次数。

验证没有覆盖所有模型、SDK 版本、多模态组合、每种客户端工具混用情况或每种上游的原生执行路径,也没有在生产人为注入断连、上游故障或强制重调度。用户自有工具仍需遵循对应协议配对执行和回传,不由本页的内置工具续聊函数代办。

搜索与抓取直连接口补充说明

以下参数和响应字段对应上方 POST /v1/tools/search、POST /v1/tools/fetch 的直接调用。模型请求中的内置工具声明请使用前文的 parameters 参数表。

三家联网搜索怎么选

三个服务共用 POST /v1/tools/search 与同一套响应结构,只靠 model 区分,切换服务商不需要改代码结构。

服务model条数参数专有参数
Bochabocha/bocha-web-searchcount(1~50)summary 额外摘要、freshness 时间筛选、include / exclude 站点限定与排除
DeepSeekdeepseek/searchcount(1~50)ori_question 原始问题、localization、need_content 返回正文
Tavilytavily/tavily-searchmax_results(0~20)search_depth 搜索深度、topic / days / language 筛选、include_domains / exclude_domains、need_content

三家的关键词参数都叫 query,但条数参数不同:Tavily 用 max_results,另外两家用 count;三家都有 need_content 这一项(字段名一致,返回正文的能力以服务商实际支持为准)。

响应字段说明 · 联网搜索

字段类型说明
resultsarray结果列表;无结果时为 []
results[].titlestring网页标题
results[].urlstring网页链接,可直接交给 POST /v1/tools/fetch 抓取正文
results[].snippetstring网页摘要片段;不同服务商可能省略
results[].summarystring额外生成的摘要;仅在服务商给出摘要时返回
results[].contentstring网页正文;请求 need_content 且服务商支持时返回,未抓取到为空字符串
results[].datestring发布时间;格式随服务商不同
results[].scorenumber相关性打分;不同服务商可能省略
results[].site_namestring站点名称;不同服务商可能省略

响应字段说明 · 网页抓取

字段类型说明
titlestring页面标题
contentstringMarkdown 格式的网页正文
✓
抓取一次只处理一个 URL:搜索拿到多条 results[].url 后,按需逐条抓取即可。搜索与抓取的错误响应结构一致,都是 {"error": {"message", "type", "param", "code"}}。
← 上一页
Google 兼容 API
下一页 →
在 Agent 中使用内置模型联网接口

接口参考

以下为原文协议定义与示例,原站地址不代表蓝天已开通对应能力。蓝天接入地址和模型以本地配置为准。

蓝天 API 密钥
POST/v1/tools/search联网搜索(Bocha / DeepSeek / Tavily)

提交搜索请求并返回网页结果列表。三家服务共用本端点与同一套响应结构,通过 `model` 选择:`bocha/bocha-web-search`、`deepseek/search`、`tavily/tavily-search`。下方「请求参数」按服务商分成三张参数表,各家的专有参数只在对应模式下有效。

请求体 · 必填

application/json

object

anyOf · 1
字段类型说明
model必填string**必填**,固定为 `bocha/bocha-web-search`。

可选值:"bocha/bocha-web-search"

query必填string**必填**,搜索关键词。
countinteger返回结果条数上限,范围 1~50,省略时默认 10。
summaryboolean是否生成额外摘要,省略时默认开启;传 false 可关闭。
freshnessstring时间筛选:`noLimit`、`oneDay`、`oneWeek`、`oneMonth`、`oneYear`,或 `YYYY-MM-DD`、`YYYY-MM-DD..YYYY-MM-DD`。
includestring限定站点,多个域名用 `|` 或 `,` 分隔。
excludestring排除站点,多个域名用 `|` 或 `,` 分隔。
anyOf · 2
字段类型说明
model必填string**必填**,固定为 `deepseek/search`。

可选值:"deepseek/search"

query必填string**必填**,搜索关键词,长度为 1~128 个 Unicode 字符。
countinteger返回结果条数上限,范围 1~50,省略时默认 10。
ori_questionstring用户原始问题,用于把握上下文与检索意图。
localizationstring用于本地化或地域的 IP 地址。
need_contentboolean是否返回网页正文,默认 false。
anyOf · 3
字段类型说明
model必填string**必填**,固定为 `tavily/tavily-search`。

可选值:"tavily/tavily-search"

query必填string**必填**,搜索关键词。
max_resultsinteger返回结果条数上限,范围 0~20,省略时默认 10。Tavily 不使用 `count`。
search_depthstring搜索深度,不同深度可能对应不同价格。

可选值:"basic" · "fast" · "ultra-fast" · "advanced"

need_contentboolean传 true 时返回 Markdown 的网页正文。
topicstring主题筛选,以 Tavily 实际支持为准。
daysinteger按天数做时间筛选,以 Tavily 实际支持为准。
include_domainsarray限定结果域名列表。
展开结构

限定结果域名列表。

array

数组元素

string

exclude_domainsarray排除结果域名列表。
展开结构

排除结果域名列表。

array

数组元素

string

languagestring语言筛选,以 Tavily 实际支持为准。
{
  "model": "bocha/bocha-web-search",
  "query": "最近的文生图模型排行榜",
  "count": 10,
  "summary": false,
  "freshness": "oneWeek"
}

请求示例

参考地址:https://router.shengsuanyun.com/api。路径参数与凭据需替换;非 JSON 请求体需按对应格式准备。

curl -X POST 'https://router.shengsuanyun.com/api/v1/tools/search' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  --data '{
  "model": "bocha/bocha-web-search",
  "query": "最近的文生图模型排行榜",
  "count": 10,
  "summary": false,
  "freshness": "oneWeek"
}'

响应

200 搜索成功,`results` 为结果列表;无结果时为 `{"results": []}`。

application/json

未提供结构定义。

{
  "results": [
    {
      "title": "文生图模型排行榜",
      "url": "https://example.com/ranking",
      "snippet": "网页摘要。",
      "summary": "额外生成的摘要(不同服务商可能不返回)。",
      "content": "网页正文,仅在请求 need_content 且服务商支持时返回。",
      "date": "2026-10-20",
      "score": 0.87,
      "site_name": "Example"
    }
  ]
}
400 请求参数错误。

application/json

未提供结构定义。

{
  "error": {
    "message": "query is required",
    "type": "invalid_request_error",
    "param": "query",
    "code": "invalid_parameter"
  }
}
401 鉴权失败或 API Key 无效。

application/json

未提供结构定义。

{
  "error": {
    "message": "Invalid API key",
    "type": "authentication_error",
    "param": null,
    "code": "invalid_api_key"
  }
}
429 请求过于频繁或额度受限。

application/json

未提供结构定义。

{
  "error": {
    "message": "Rate limit exceeded",
    "type": "rate_limit_error",
    "param": null,
    "code": "rate_limit_exceeded"
  }
}
500 上游服务不可用或服务内部错误。

application/json

未提供结构定义。

{
  "error": {
    "message": "Upstream service unavailable",
    "type": "server_error",
    "param": null,
    "code": "upstream_error"
  }
}
POST/v1/tools/fetch网页抓取(deepseek/fetch)

提交一个 HTTP/HTTPS 网页 URL,返回该页标题与 Markdown 正文。一次请求抓取一个 URL,常与上面的联网搜索串联使用:先搜索拿到链接,再抓取正文喂给模型。

请求体 · 必填

application/json
字段类型说明
model必填string**必填**,固定为 `deepseek/fetch`。

可选值:"deepseek/fetch"

url必填stringuri**必填**,要抓取的 HTTP/HTTPS 网页地址,长度不超过 8192 个字符,不能带用户名和密码。
{
  "model": "deepseek/fetch",
  "url": "https://www.shengsuanyun.com/zh/"
}

请求示例

参考地址:https://router.shengsuanyun.com/api。路径参数与凭据需替换;非 JSON 请求体需按对应格式准备。

curl -X POST 'https://router.shengsuanyun.com/api/v1/tools/fetch' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  --data '{
  "model": "deepseek/fetch",
  "url": "https://www.shengsuanyun.com/zh/"
}'

响应

200 抓取成功,返回页面标题与 Markdown 正文。

application/json

未提供结构定义。

{
  "title": "页面标题",
  "content": "# Markdown 正文"
}
400 请求参数错误。

application/json

未提供结构定义。

{
  "error": {
    "message": "url is required",
    "type": "invalid_request_error",
    "param": "url",
    "code": "invalid_parameter"
  }
}
401 鉴权失败或 API Key 无效。

application/json

未提供结构定义。

{
  "error": {
    "message": "Invalid API key",
    "type": "authentication_error",
    "param": null,
    "code": "invalid_api_key"
  }
}
429 请求过于频繁或额度受限。

application/json

未提供结构定义。

{
  "error": {
    "message": "Rate limit exceeded",
    "type": "rate_limit_error",
    "param": null,
    "code": "rate_limit_exceeded"
  }
}
500 上游服务不可用或服务内部错误。

application/json

未提供结构定义。

{
  "error": {
    "message": "Upstream service unavailable",
    "type": "server_error",
    "param": null,
    "code": "upstream_error"
  }
}