模型联网接口
用同一把胜算云 Key 调用联网搜索、网页抓取和当前时间工具。支持直接调用搜索 / 抓取接口,也支持在 Chat、Responses、Messages 请求中声明内置工具,由平台执行并继续模型作答。客户端配置步骤见独立指南《在 Agent 中使用内置模型联网接口》。
https://router.shengsuanyun.com/apiAuthorization: Bearer YOUR_API_KEY端点列表
内置服务端工具:搜索、抓取与当前时间
在 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. 多轮对话必须保留两类信息
- 完整公共历史。 Chat 保存整个
choices[0].message;Responses 保存整个output数组;Messages 保存整个 assistantcontent数组。保留 reasoning、phase、签名、客户端工具调用及未知的必要字段,不只保存最终文字,也不要重排已有条目。 - 所有补充上下文。 三种格式统一建议首次传
ssy_tool_contexts:[],收集 JSON 或ssy.tool_contextSSE 的全部包。当前 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 | 条数参数 | 专有参数 |
|---|---|---|---|
| Bocha | bocha/bocha-web-search | count(1~50) | summary 额外摘要、freshness 时间筛选、include / exclude 站点限定与排除 |
| DeepSeek | deepseek/search | count(1~50) | ori_question 原始问题、localization、need_content 返回正文 |
| Tavily | tavily/tavily-search | max_results(0~20) | search_depth 搜索深度、topic / days / language 筛选、include_domains / exclude_domains、need_content |
三家的关键词参数都叫 query,但条数参数不同:Tavily 用 max_results,另外两家用 count;三家都有 need_content 这一项(字段名一致,返回正文的能力以服务商实际支持为准)。
响应字段说明 · 联网搜索
| 字段 | 类型 | 说明 |
|---|---|---|
results | array | 结果列表;无结果时为 [] |
results[].title | string | 网页标题 |
results[].url | string | 网页链接,可直接交给 POST /v1/tools/fetch 抓取正文 |
results[].snippet | string | 网页摘要片段;不同服务商可能省略 |
results[].summary | string | 额外生成的摘要;仅在服务商给出摘要时返回 |
results[].content | string | 网页正文;请求 need_content 且服务商支持时返回,未抓取到为空字符串 |
results[].date | string | 发布时间;格式随服务商不同 |
results[].score | number | 相关性打分;不同服务商可能省略 |
results[].site_name | string | 站点名称;不同服务商可能省略 |
响应字段说明 · 网页抓取
| 字段 | 类型 | 说明 |
|---|---|---|
title | string | 页面标题 |
content | string | Markdown 格式的网页正文 |
results[].url 后,按需逐条抓取即可。搜索与抓取的错误响应结构一致,都是 {"error": {"message", "type", "param", "code"}}。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 | **必填**,搜索关键词。 |
count | integer | 返回结果条数上限,范围 1~50,省略时默认 10。 |
summary | boolean | 是否生成额外摘要,省略时默认开启;传 false 可关闭。 |
freshness | string | 时间筛选:`noLimit`、`oneDay`、`oneWeek`、`oneMonth`、`oneYear`,或 `YYYY-MM-DD`、`YYYY-MM-DD..YYYY-MM-DD`。 |
include | string | 限定站点,多个域名用 `|` 或 `,` 分隔。 |
exclude | string | 排除站点,多个域名用 `|` 或 `,` 分隔。 |
anyOf · 2
| 字段 | 类型 | 说明 |
|---|---|---|
model必填 | string | **必填**,固定为 `deepseek/search`。 可选值:"deepseek/search" |
query必填 | string | **必填**,搜索关键词,长度为 1~128 个 Unicode 字符。 |
count | integer | 返回结果条数上限,范围 1~50,省略时默认 10。 |
ori_question | string | 用户原始问题,用于把握上下文与检索意图。 |
localization | string | 用于本地化或地域的 IP 地址。 |
need_content | boolean | 是否返回网页正文,默认 false。 |
anyOf · 3
| 字段 | 类型 | 说明 |
|---|---|---|
model必填 | string | **必填**,固定为 `tavily/tavily-search`。 可选值:"tavily/tavily-search" |
query必填 | string | **必填**,搜索关键词。 |
max_results | integer | 返回结果条数上限,范围 0~20,省略时默认 10。Tavily 不使用 `count`。 |
search_depth | string | 搜索深度,不同深度可能对应不同价格。 可选值:"basic" · "fast" · "ultra-fast" · "advanced" |
need_content | boolean | 传 true 时返回 Markdown 的网页正文。 |
topic | string | 主题筛选,以 Tavily 实际支持为准。 |
days | integer | 按天数做时间筛选,以 Tavily 实际支持为准。 |
include_domains | array | 限定结果域名列表。展开结构限定结果域名列表。
数组元素
|
exclude_domains | array | 排除结果域名列表。展开结构排除结果域名列表。
数组元素
|
language | string | 语言筛选,以 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"
}
}