世界百科live
查一个词条/概念的释义、起源与发展脉络(百科类不追时效);每条结果标出条目类型(百科/词条/教程/文档/问答/other)
- 端点
POST /v2/m1/wiki/run- 价格
- 1 credits(≈ ¥0.05 / 次)
- scope
l2:wiki- 默认条数 / 时间窗
- 10 条 ·
any - 结果结构
wiki.v1
这里是唯一权威口径:认证、三档一级 API、二级单元、授权 scope、计费、快照、限流、错误码。 所有示例都是真实响应(长数组已截断)——照着抄就能跑。
每个需要计费的端点都要求请求头 Authorization: Bearer <你的 key>。
key 形如 sk_live_ + 32 位;明文只在签发或领取时出现一次。
公开端点(不要 key):GET /v1/units、GET /v1/catalog、
GET /s/<token>、GET /healthz、GET /products、
GET /quickstart、GET /docs。
申请流程:GET /apply 填表 → 管理员审批 → GET /claim/<领取码> 领明文。
领取码默认 72 小时有效,过期让管理员重新批准(换新码,不会重复签 key)。
l1)POST /v1/search · 1 credits(≈ ¥0.05 / 次)
返回来源列表(标题 + 出处 + 说明 + 分数)+ 一条永久快照链接。answer 恒为 null。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
q |
string | 必填 | 查询词,1~500 字符,必填 |
count |
integer | 可选 | 返回条数 1~20,默认 10 |
freshness |
string | 可选 | 时间窗:day / week / month / year / any,默认 any |
provider |
string | 可选 | 选源偏好:auto(默认)/ deepseek / bocha;偏好没命中时响应 degraded=true 并写明原因 |
snapshot |
boolean | 可选 | 是否生成永久快照,默认 true |
site |
string[] | 可选 | 只在这些域名内检索(可传数组) |
lang |
string | 可选 | 语言偏好,形如 zh / en |
need_answer |
boolean | 可选 | 已弃用(B33):仍可用但按答案档计价,请改调 /v1/answer |
depth |
string | 可选 | 已弃用(B33):只接受 "deep",请改调 /v1/answer + depth |
format |
string | 可选 | 传 "model" 让每条 source 多一句 brief(写作引擎);不传则响应形状不变 |
| 字段 | 类型 | 说明 |
|---|---|---|
request_id |
string | 本次请求 id(排查时把它给我们) |
provider / provider_requested / provider_preference_honored |
string / string / boolean | 实际用的源、请求偏好的源、偏好是否被满足 |
sources[] |
array | title / url / snippet / publishedAt / domain / score / scoreRaw / scoreScale |
snapshot_url / h5_url |
string|null | 永久快照链接(snapshot:false 时为 null) |
latency_ms |
number | 本次检索耗时 |
usage |
object | count / credits_charged / credits_base / tier_discount / floor_applied / balance_after / quota_source;另含 revenue_cny / gross_margin_cny / cost_cny |
quality |
object | 质量闸门:usable / dropped / ratio / gate_passed |
degraded / degraded_reason |
boolean / string|null | 降级必须可见(fail-loud) |
{
"request_id": "r_m3x0kq9v2d4tq7a1",
"provider": "deepseek",
"provider_requested": "auto",
"provider_preference_honored": true,
"answer": null,
"sources": [
{
"title": "杭州三日游攻略:路线、交通与住宿",
"url": "https://example.com/hangzhou-3d2n",
"snippet": "这份杭州3天2晚攻略包含景点路线、交通、住宿、美食和游玩tips……",
"publishedAt": "2026-10-26T16:00:00.000Z",
"domain": "example.com",
"score": 0.5471,
"scoreRaw": 1.6412975788116455,
"scoreScale": "0-3"
}
],
"snapshot_url": "https://search.ozforce.cn/s/0m0sfptw98xs",
"h5_url": "https://search.ozforce.cn/s/0m0sfptw98xs",
"latency_ms": 469,
"usage": {
"count": 3,
"credits_charged": 1,
"credits_base": 1,
"tier_discount": 1,
"floor_applied": false,
"balance_after": 499,
"quota_source": "balance"
},
"quality": { "usable": 3, "gate_passed": true },
"degraded": false,
"degraded_reason": null
}
# 第一个请求:结果档 l1 —— 拿回来源列表 + 一条永久快照链接
curl -sS -X POST "https://search.ozforce.cn/v1/search" \
-H "Authorization: Bearer ${WS_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"q":"杭州 三日游 攻略","count":5,"freshness":"month","snapshot":true}'
rem Windows 命令行(cmd.exe):在同一窗口先 set WS_API_KEY=你的key,再粘贴下一行
curl -sS -X POST "https://search.ozforce.cn/v1/search" -H "Authorization: Bearer %WS_API_KEY%" -H "Content-Type: application/json" -d "{\"q\":\"杭州 三日游 攻略\",\"count\":5,\"freshness\":\"month\",\"snapshot\":true}"
// 存成 first.mjs,然后:node first.mjs(Node 18+ 自带 fetch,不用装任何包)
const BASE = 'https://search.ozforce.cn'
const KEY = process.env.WS_API_KEY
if (!KEY) {
console.error('先设置环境变量 WS_API_KEY(值是你的 API key)')
process.exit(1)
}
const res = await fetch(BASE + '/v1/search', {
method: 'POST',
headers: { Authorization: 'Bearer ' + KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ q: '杭州 三日游 攻略', count: 5, freshness: 'month', snapshot: true })
})
const data = await res.json()
if (!res.ok) {
console.error('失败', res.status, data.error)
process.exit(1)
}
console.log('扣费', data.usage.credits_charged, 'credits,余额', data.usage.balance_after)
console.log('永久链接', data.snapshot_url)
for (const s of data.sources) console.log('-', s.title, s.url)
# Python 3.8+,只用标准库
import json, os, urllib.request
BASE = 'https://search.ozforce.cn'
KEY = os.environ.get('WS_API_KEY')
if not KEY:
raise SystemExit('先设置环境变量 WS_API_KEY(值是你的 API key)')
body = json.dumps({'q': '杭州 三日游 攻略', 'count': 5, 'freshness': 'month', 'snapshot': True}).encode('utf-8')
req = urllib.request.Request(
BASE + '/v1/search', data=body, method='POST',
headers={'Authorization': 'Bearer ' + KEY, 'Content-Type': 'application/json'},
)
with urllib.request.urlopen(req) as res:
data = json.loads(res.read().decode('utf-8'))
print('扣费', data['usage']['credits_charged'], 'credits,余额', data['usage']['balance_after'])
print('永久链接', data['snapshot_url'])
for s in data['sources']:
print('-', s['title'], s['url'])
l1_answer)POST /v1/answer · 2 credits(≈ ¥0.1 / 次)
读搜索结果里的片段与摘要写答案,返回 answer + citations[] + sources[]。
答案一定带 [1][2][3] 引用;引用对不上时如实标 cited:false,不编造。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
q |
string | 必填 | 问题或查询词,1~500 字符 |
depth |
string | 可选 | 不传 = fast(快答案);传 "deep" 升到深答案档(另一个商品、另一个 scope) |
count |
integer | 可选 | 检索条数 1~20,默认 10 |
freshness |
string | 可选 | day / week / month / year / any |
provider |
string | 可选 | auto / deepseek / bocha |
snapshot |
boolean | 可选 | 默认 true |
need_answer |
— | 可选 | 不要传:这个端点天生就是答案档,传了会 400(同样不能传 needAnswer) |
| 字段 | 类型 | 说明 |
|---|---|---|
answer |
string|null | 答案正文;为空时 answer_reason / answer_message 写明原因(绝不静默) |
citations[] / cited |
number[] / boolean | 引用编号(对应 sources 下标)与"是否真带引用" |
answer_source |
string | provider / summarizer / deep / none —— 这段答案是谁给的 |
answer_model / summary |
string / object | 模型名与完整口径(tokens / cost_cny / latency_ms / cached) |
depth_degraded / depth_degraded_reason |
boolean / string|null | 深答案抓不到原文时退回快答案,会标 true 并给原因 |
deliverable |
boolean | 这一档此刻是否真的可交付(与 /healthz 的 sellable 同源) |
charged / credits_charged / refunded |
number / number / boolean | 这次扣了多少;没交付时按结果档结算并 refunded=true |
latency_ms |
object | search / answer / total(深答案档为 search / fetch / write / total) |
{
"request_id": "r_qms0v6hx8m4nah3j",
"product": "l1_answer",
"requested_product": "l1_answer",
"depth": "fast",
"charged": 2,
"refunded": false,
"deliverable": true,
"provider": "deepseek",
"answer": "天空的蓝色是阳光与大气分子、冰晶、水滴等共同作用的结果……蓝色光更容易被散射并进入人眼,因此天空呈蓝色 [1][2][3]。",
"answer_source": "summarizer",
"citations": [1, 2, 3],
"cited": true,
"depth_degraded": false,
"answer_model": "deepseek",
"summary": {
"model": "deepseek-flash",
"tokens_in": 473,
"tokens_out": 91,
"cost_cny": 0.001783,
"latency_ms": 1179,
"cached": false
},
"sources": [{ "title": "天空为什么是蓝色的", "url": "https://example.com/sky-blue", "domain": "example.com", "score": 0.6648 }],
"snapshot_url": "https://search.ozforce.cn/s/peh58hj5m8wt",
"latency_ms": { "search": 523, "answer": 1183, "total": 1706 },
"usage": {
"count": 3,
"credits_charged": 2,
"search_cny": 0.005,
"fetch_cny": 0,
"writer_cny": 0.001783,
"balance_after": 497
},
"degraded": false
}
# 快答案档:读片段写答案(同一个端点,不传 depth 就是 fast)
curl -sS -X POST "https://search.ozforce.cn/v1/answer" \
-H "Authorization: Bearer ${WS_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"q":"天空为什么是蓝色的","count":5}'
# 快答案档(不传 depth)
import json, os, urllib.request
BASE = 'https://search.ozforce.cn'
KEY = os.environ.get('WS_API_KEY')
if not KEY:
raise SystemExit('先设置环境变量 WS_API_KEY')
body = json.dumps({'q': '天空为什么是蓝色的', 'count': 5}).encode('utf-8')
req = urllib.request.Request(
BASE + '/v1/answer', data=body, method='POST',
headers={'Authorization': 'Bearer ' + KEY, 'Content-Type': 'application/json'},
)
with urllib.request.urlopen(req) as res:
data = json.loads(res.read().decode('utf-8'))
print(data['answer'])
print('引用编号', data['citations'], '永久链接', data['snapshot_url'])
l1_deep)POST /v1/answer · 4 credits(≈ ¥0.2 / 次)
从搜索结果里择优 K 篇真去抓原文(Markdown),再写带引用的答案;返回材料清单与成本/时延拆分。
数字、参数、对比类问题靠这一步才答得准。抓取失败不会让整次调用失败:退回快答案并标
depth_degraded:true。
请求参数与第 3 节相同,只是 depth 传 "deep";key 上需要
l1:deep(或 *)。
| 字段 | 类型 | 说明 |
|---|---|---|
materials[] / material_stats |
array / object | 读了哪几篇(哪几条读了原文、哪几条用摘要兜底、各多少字符、是否被截断) |
cost |
object | search / fetch / writer / total(¥)—— 花钱花在哪一目了然 |
citation_sources[] |
array | 引用编号 → 具体来源的映射证据 |
deep.fetch / deep.writer |
object | 逐条抓取与写作明细(含失败原因) |
# 深答案档:同一个端点 + depth:"deep"(会真去抓原文,更准也更慢)
curl -sS -X POST "https://search.ozforce.cn/v1/answer" \
-H "Authorization: Bearer ${WS_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"q":"天空为什么是蓝色的","depth":"deep","count":8}'
// 深答案:答案 + 引用编号 + 材料清单(读了哪几篇原文)
const BASE = 'https://search.ozforce.cn'
const KEY = process.env.WS_API_KEY
if (!KEY) { console.error('先设置环境变量 WS_API_KEY'); process.exit(1) }
const res = await fetch(BASE + '/v1/answer', {
method: 'POST',
headers: { Authorization: 'Bearer ' + KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ q: '天空为什么是蓝色的', depth: 'deep', count: 8 })
})
const data = await res.json()
if (!res.ok) { console.error('失败', res.status, data.error); process.exit(1) }
console.log(data.answer)
console.log('引用编号', data.citations.join(','), '· 是否带引用', data.cited)
console.log('读了', data.materials.length, '篇材料,永久链接', data.snapshot_url)
POST /v2/{middleware}/{unit}/run
单元是"已经替你调好一级 API 并按领域整理好"的成品。当前中间件是 m1,
下表每个单元就是一条独立商品(各自 scope、各自定价)。
| 单元 | 端点 | mode | 价格 | scope |
|---|---|---|---|---|
wiki世界百科 |
POST /v2/m1/wiki/run |
live | 1 credits | l2:wiki |
news即时新闻 |
POST /v2/m1/news/run |
scheduled | 1 credits | l2:news |
music流行音乐时 |
POST /v2/m1/music/run |
scheduled | 1 credits | l2:music |
travel旅行灵感 |
POST /v2/m1/travel/run |
both | 3 credits | l2:travel |
why十万个为什么 |
POST /v2/m1/why/run |
live | 3 credits | l2:why |
finance财经速览 |
POST /v2/m1/finance/run |
scheduled | 3 credits | l2:finance |
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
q |
string | 可选 | 主题词(不传就用单元声明的 defaultTopic) |
templates |
string[] | 可选 | 整体覆盖检索模板(用 {topic} 占位),条数上限见单元声明 |
count |
integer | 可选 | 本次要几条;最终取 min(请求, 单元 maxCount, 全局 20) |
freshness |
string | 可选 | day / week / month / year / any(覆盖单元默认时间窗) |
provider |
string | 可选 | auto / deepseek / bocha(偏好,不是硬绑定) |
snapshot |
boolean | 可选 | 默认 true |
summarize |
boolean | 可选 | true = 额外给一段带出处的总结(默认 false) |
writer |
object | 可选 | {"format":true} = 给每条结果补一句 brief(默认不补) |
live |
boolean | 可选 | true = 跳过当期归档,走一次实时检索(会产生正常的检索成本) |
| 字段 | 类型 | 说明 |
|---|---|---|
items[] 或 tracks[] |
array | 按单元的 resultSchema 决定(music.v1 用 tracks);字段见下方各单元 |
snapshot_url / live_url / h5_url / primary_url |
string|null | 快照链接、实时入口、人读入口、主推链接(按 snapshotPolicy 选) |
served_from / cost_source |
string | digest / on_demand / previous / live —— 这份是归档还是现搜、成本怎么记 |
usage |
object | credits_charged / balance_after 等 |
answer / why |
string|null / object | 单元自带答案时出现(why.v1 的 why = question/answer/citations/sources) |
{
"request_id": "r_8kq2s9v1n0xb7t3c",
"middleware": "m1",
"unit": "news",
"name": "即时新闻",
"domain": "news",
"result_schema": "news.v1",
"snapshot_policy": "freeze",
"items": [
{
"title": "人工智能,加速融入你我生活",
"summary": "在广东佛山,巡检无人机用上AI算法,为城市治理提供精准依据……",
"source": "example.com",
"url": "https://example.com/ai-news",
"publishedAt": "2026-10-28T16:00:00.000Z",
"heat": 84
}
],
"snapshot_url": "https://search.ozforce.cn/s/j5zj1m22mxfr",
"live_url": "https://search.ozforce.cn/u/m1/news",
"h5_url": "https://search.ozforce.cn/u/m1/news",
"primary_url": "https://search.ozforce.cn/s/j5zj1m22mxfr",
"answer": null,
"served_from": "live",
"cost_source": "live_search",
"usage": { "credits_charged": 1, "balance_after": 496 },
"degraded": false
}
# 二级单元:m1/wiki(结果结构更贴合该领域,价格见页面上的单元卡片)
curl -sS -X POST "https://search.ozforce.cn/v2/m1/wiki/run" \
-H "Authorization: Bearer ${WS_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"q":"人工智能","count":5,"snapshot":true}'
// 二级单元 m1/wiki:返回 items[](结构按单元的 resultSchema)
const BASE = 'https://search.ozforce.cn'
const KEY = process.env.WS_API_KEY
if (!KEY) { console.error('先设置环境变量 WS_API_KEY'); process.exit(1) }
const res = await fetch(BASE + '/v2/m1/wiki/run', {
method: 'POST',
headers: { Authorization: 'Bearer ' + KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ q: '人工智能', count: 5, snapshot: true })
})
const data = await res.json()
if (!res.ok) { console.error('失败', res.status, data.error); process.exit(1) }
console.log('共', data.items.length, '条,扣费', data.usage.credits_charged, 'credits')
console.log('永久链接', data.snapshot_url)
for (const item of data.items) console.log('-', item.title, item.url)
# 二级单元 m1/wiki
import json, os, urllib.request
BASE = 'https://search.ozforce.cn'
KEY = os.environ.get('WS_API_KEY')
if not KEY:
raise SystemExit('先设置环境变量 WS_API_KEY')
body = json.dumps({'q': '人工智能', 'count': 5, 'snapshot': True}).encode('utf-8')
req = urllib.request.Request(
BASE + '/v2/m1/wiki/run', data=body, method='POST',
headers={'Authorization': 'Bearer ' + KEY, 'Content-Type': 'application/json'},
)
with urllib.request.urlopen(req) as res:
data = json.loads(res.read().decode('utf-8'))
print('共', len(data['items']), '条,扣费', data['usage']['credits_charged'], 'credits')
print('永久链接', data['snapshot_url'])
查一个词条/概念的释义、起源与发展脉络(百科类不追时效);每条结果标出条目类型(百科/词条/教程/文档/问答/other)
POST /v2/m1/wiki/runl2:wikianywiki.v1按主题取当天的新闻速览,按发布时间倒序;已强制过滤时政/军事/外交/社会突发等话题
POST /v2/m1/news/runl2:newsdaynews.v1按主题取近一个月的热歌榜/新歌发行/榜单信息;只出榜单与外链,不托管任何音频
POST /v2/m1/music/runl2:musicmonthmusic.v1按目的地取攻略/推荐/季节玩法;冻结快照与实时入口都给
POST /v2/m1/travel/runl2:travelmonthtravel.v1有什么疑问直接问:实时调用一级答案 API 取一段带引用的答案(问题不可预知,所以不预生成)
POST /v2/m1/why/runl2:whyanywhy.v1(演示扩展性单元 · order 90)按主题取当日财经与行业动态;本文件是「加单元只加 JSON」这条硬标准的证据
POST /v2/m1/finance/runl2:financedaylist.v1一条 key 上写着它租了哪些商品;调了没租的入口就是 403 SCOPE_FORBIDDEN
(响应里给出你实际能调的商品清单)。
| scope token | 能调什么 |
|---|---|
* | 全部(一级三档 + 全部二级单元) |
l1 | 结果档 POST /v1/search |
l1:answer | 快答案档 POST /v1/answer(不传 depth) |
l1:deep | 深答案档 POST /v1/answer + depth:"deep" |
l2:* | 全部二级单元 |
l2:<单元> / l2:<中间件>/<单元> | 某一个单元(例:l2:wiki) |
三档一级 API 互不越权:拿 l1:deep 的 key 开不了 l1 与 l1:answer,反之亦然。
l1:* 这种通配恒为非法(400)—— 三档必须逐个写明。
计价单位是 credits:1 credit = ¥0.05。
每次调用都在响应里写 usage.credits_charged 与 usage.balance_after。
| 商品 | 价格 | 端点 |
|---|---|---|
l1 · 基础搜索 API | 1 credits(≈ ¥0.05 / 次) | POST /v1/search |
l1_answer · 快答案 API(读片段写答案) | 2 credits(≈ ¥0.1 / 次) | POST /v1/answer |
l1_deep · 深答案 API(读原文) | 4 credits(≈ ¥0.2 / 次) | POST /v1/search |
l2:wiki · 世界百科 | 1 credits(≈ ¥0.05 / 次) | POST /v2/m1/wiki/run |
l2:news · 即时新闻 | 1 credits(≈ ¥0.05 / 次) | POST /v2/m1/news/run |
l2:music · 流行音乐时 | 1 credits(≈ ¥0.05 / 次) | POST /v2/m1/music/run |
l2:travel · 旅行灵感 | 3 credits(≈ ¥0.15 / 次) | POST /v2/m1/travel/run |
l2:why · 十万个为什么 | 3 credits(≈ ¥0.15 / 次) | POST /v2/m1/why/run |
l2:finance · 财经速览 | 3 credits(≈ ¥0.15 / 次) | POST /v2/m1/finance/run |
两本账:预付余额(credits)与包月套餐额度。响应里的 usage.quota_source
告诉这次扣的是哪本账(balance / plan)。包月到期默认回落按量,不会突然断服。
查询:GET /v1/usage(已用/剩余/配额)、GET /v1/balance(余额/档位/已租商品)、
GET /v1/billing?period=YYYY-MM(月度账单,只含本 key)、
GET /v1/billing.csv?period=YYYY-MM(同数据的 CSV,带 BOM,Excel 直接开)。
会员折扣不会跌破成本线:折后低于该商品的最低成本线时按成本线收,
并用 usage.floor_applied / usage.cost_floor_credits 标出来(宪法 8.6)。
客户侧账单不含进价与毛利明细。
GET /s/{token}
每次 snapshot:true 的调用都会冻结一份副本,返回 https://search.ozforce.cn/s/<12 位 token>。
内容从此不再变化:20 天后、明年打开都和当时一字不差(正文逐字节冻结,页脚合规信息实时渲染);
同一个 token 永不覆盖。
双通道:/s/<token> 是人读的 HTML(不依赖前端 JS,离线保存也能读);
/s/<token>.json 是同一份内容的原始数据(长缓存、不可变)。
# 永久快照:把上面响应里的 snapshot_url 原样打开即可(不需要 key)
# https://search.ozforce.cn/s/<token> 人读的 HTML 页
# https://search.ozforce.cn/s/<token>.json 原始数据(长缓存、不可变)
curl -sS "https://search.ozforce.cn/s/<token>.json"
| 项 | 当前值 | 说明 |
|---|---|---|
| 同 key 限速 | 5 rps(突发 5) | 令牌桶;超了 429 RATE_LIMITED,响应带 retry_after |
| 日 / 月配额 | 按会员档位(见 /products 的计费说明) | 用尽 429 QUOTA_EXCEEDED;与余额是两本账 |
| 余额 | credits | 不足 402 INSUFFICIENT_CREDITS,响应带 balance / required |
| 单次条数上限 | 20 | count 越界直接 400,不静默夹取 |
| 请求体上限 | 1 MB | 超过 413 |
上游硬约束(实测):搜索 100 QPS、抓取 25 QPS,账号级且两种接口互不占用; 429 响应没有 Retry-After 头,所以退避必须由调用方自己做。我们已在服务内做了排队与降级, 客户侧看到的是"这次慢一点"或"degraded:true 并写明原因"。
| 端点 | 要 key | 用途 |
|---|---|---|
GET /v1/units | 否 | 单元目录(有哪些二级 API、每条多少钱) |
GET /v1/catalog | 否 | 商品目录:一级三档 + 全部二级,含价格与 rent_scope(机器可读真相) |
GET /v1/usage | 是 | 本 key 的日/月已用、剩余额度、余额、tier、scope、plan |
GET /v1/balance | 是 | 余额 + tier + 已租商品 + 套餐到期时间 |
GET /v1/billing | 是 | 本 key 某账期账单(?period=YYYY-MM) |
GET /v1/billing.csv | 是 | 同上,CSV(UTF-8 带 BOM) |
POST /v1/apply | 否 | 用程序提交申请表(返回 application_id) |
GET /s/{token}.json | 否 | 快照原始数据(不可变长缓存) |
GET /u/{middleware}/{unit} | 否 | 单元的实时入口:跑一次并 302 到快照页(给人看) |
GET /healthz | 否 | 健康检查(含 sellable 与 blockers:现在哪些档能交付) |
# 单元目录(公开,不要 key)
curl -sS "https://search.ozforce.cn/v1/units"
# 商品目录(公开,不要 key):每个商品的价格与 rent_scope
curl -sS "https://search.ozforce.cn/v1/catalog"
所有错误体统一长这样:{ "error": { "code": "...", "message": "...", ...业务字段 }, "request_id": "..." }。
状态码与 code 都取自实现(src/util/errors.mjs)。
| HTTP | code | 含义 / 怎么办 |
|---|---|---|
400 |
INVALID_ARGUMENT |
入参非法:q 空/超 500 字、count 越界、freshness 不在枚举内、body 不是 JSON 对象 |
401 |
INVALID_API_KEY |
没带 Authorization 头 / 不是 Bearer / key 形状不对 / key 不存在 |
401 |
KEY_REVOKED |
key 存在但已被吊销 |
402 |
INSUFFICIENT_CREDITS |
预付余额不足(响应带 balance / required) |
403 |
SCOPE_FORBIDDEN |
这个 key 没租该商品(响应带 required / granted / available) |
402 |
PLAN_EXPIRED |
包月套餐已到期且配置为 block(默认是回落按量,不会出现这个码) |
429 |
QUOTA_EXCEEDED |
日/月配额用尽(响应带 retry_after) |
429 |
RATE_LIMITED |
同一个 key 超速(响应带 retry_after) |
503 |
ANSWER_UNAVAILABLE |
答案档当前不可交付(缺写作引擎/抓取):扣费前就拒,charged:0 |
404 |
UNIT_NOT_FOUND |
middleware/unit 对不上 config/units/*.json 里的声明 |
503 |
DIGEST_NOT_READY |
定时单元的当期归档还没生成(响应带 date / slot / miss_policy) |
503 |
UNIT_CIRCUIT_OPEN |
该单元熔断冷却中(其它单元不受影响) |
504 |
UNIT_TIMEOUT |
该单元单次执行超时,沙盒被就地终止(其它单元不受影响) |
503 |
UNIT_CRASHED |
该单元沙盒崩溃,已隔离重启(其它单元不受影响) |
503 |
UNIT_UNAVAILABLE |
该单元已卸载/沙盒已释放(排空期的尾巴) |
503 |
UNIT_SEARCH_FAILED |
单元的多路检索全部失败(fail-loud,不会拿空列表冒充"今天没内容") |
429 |
PROVIDER_RATE_LIMITED |
上游搜索源限流(429,自动换源仍失败才抛给客户) |
504 |
PROVIDER_TIMEOUT |
上游搜索源超时 |
503 |
ALL_PROVIDERS_FAILED |
降级链全部失败(两家源都不可用) |
404 |
SNAPSHOT_NOT_FOUND |
快照 token 不存在 |
400 |
INVALID_TOKEN |
快照 token 非法(含 .. / \ 或超长) |
500 |
SNAPSHOT_WRITE_FAILED |
快照落盘失败:整次调用失败,绝不给"点了会变"的链接 |
410 |
CLAIM_EXPIRED |
领取码超过 TTL(72 小时),让管理员重新批准 |
503 |
APPLY_DISABLED |
公开申请入口被显式关闭(APPLY_ENABLED=false) |
l1(POST /v1/search):最便宜,answer 恒为 null。[1][2][3]?sources 的下标;citations 给出本次真正用到的编号。
编号对不上时 cited:false,我们不会编造引用。degraded:true?degraded_reason 写明原因。served_from 与 digest_date:digest = 当期归档,
previous = 最近一期(会显著标注是哪天的),live = 实时现搜。
想要实时就在 body 里加 "live": true。/u/<中间件>/<单元> 或 /s/<token>。