可观测性

响应头与扩展字段、控制台日志与用量、调用告警与 webhook,以及 OpenTelemetry 链路导出。

更新于 2026-10-25阅读约 23 分钟

查看 .md

SciRouter 在响应头与响应体中返回单次调用的实际情况,在控制台请求日志中提供完整的时间线与尝试明细。这些都是 OpenAI 格式之外的附加项,官方 SDK 忽略不认识的字段,调用方无需修改代码。

响应头

#

非流式响应(对话补全、Messages 与向量)带下列响应头。流式响应只带 X-Request-Id、X-SciRouter-Cache 与限额响应头(表中注明流式也发出的除外);其余各项在调用结束后才能确定,放在流末尾的扩展分片中,见响应体的 scirouter 字段。

响应头说明
X-Request-Id本次调用的编号,始终由服务端生成,不沿用请求中携带的值。报障时提供该值,平台据此定位单次调用
request-id与 X-Request-Id 取值相同(Anthropic SDK 读取该名称),/v1 的每个响应都带
X-SciRouter-Model实际提供服务的模型 id
X-SciRouter-Provider实际提供服务的厂商 id。同一模型可能接入多个厂商的线路,失败时自动转移
X-SciRouter-Attempts上游尝试总数(含跳过的线路)。值为 2 及以上表示发生过自动转移;费用只按最终成功的一次结算
X-SciRouter-Upstream-Request-Id厂商返回的请求 id,厂商未返回时不带。向厂商提交工单时用于对账
X-SciRouter-Cost-Quota本次消耗的配额,命中缓存时为 0。流式响应头在正文之前发出,此时消耗未知;流式调用的消耗见末尾扩展分片中的 scirouter.cost_quota
X-SciRouter-CacheHIT、MISS、PARTIAL(仅向量)或 BYPASS;另有 X-SciRouter-Cache-Age、X-SciRouter-Cache-TTL,见缓存与幂等
X-SciRouter-Variant-Switch请求带了会改变计价档位的参数、被自动改用模型变体时返回;值为触发的参数,以逗号分隔。目前只出现在 /messages,流式响应同样在正文之前发出,见 Messages(Anthropic 格式)
X-SciRouter-Max-Tokens-ClampedMessages(Anthropic 格式)的 max_tokens 超过模型或套餐的单次上限、平台按上限发出时返回,格式为 requested=…; effective=…; limit=model(套餐的上限更小时为 limit=plan)。流式响应同样在正文之前发出
X-SciRouter-Param-Actions有参数被平台去掉、翻译、模拟、整形或自愈时返回,如 dropped=seed,top_k; translated=reasoning(xhigh→high); emulated=response_format。五组固定顺序,超过 512 字节截断。三种格式均返回,流式响应同样在正文之前发出。各参数的处理见参数如何被处理

限额响应头

#

限额响应头与 OpenAI 同名,SDK 已有的退避逻辑可直接识别:

响应头说明
x-ratelimit-limit-requests每分钟请求数上限
x-ratelimit-remaining-requests每分钟请求数余量
x-ratelimit-reset-requests距当前窗口结束的时长,如 42s
x-ratelimit-limit-tokens每分钟 token 数上限
x-ratelimit-remaining-tokens每分钟 token 数余量
x-ratelimit-reset-tokens距当前窗口结束的时长
  • 余量按 Key 与账号两级中较小的一级返回。没有限额时不返回这组响应头。
  • 流式响应的限额响应头在第一个分片之前写入。例外:排队较久、心跳已先发出响应头时,这组响应头与 X-SciRouter-Cache 均不带。
  • 被限频的 429 响应仍带 Retry-After 与 error.details.retry_after_seconds。
  • 浏览器跨源调用时,上述响应头均列在 Access-Control-Expose-Headers 中,fetch 可以读取。

响应体的 scirouter 字段

#

非流式响应的顶层多一个 scirouter 对象:

json
{
  "id": "chatcmpl-…",
  "choices": [],
  "usage": {},
  "scirouter": {
    "request_id": "req_…",
    "model": "YOUR_MODEL_ID",
    "provider": "…",
    "cost_quota": 18240,
    "cache": "miss",
    "attempts": 2,
    "upstream_request_id": "…",
    "timings": { "queue_wait_ms": 830, "ttfb_ms": 412, "total_ms": 5688 }
  }
}

数值为示例,choices 与 usage 省略了内容。

字段说明
timings.queue_wait_ms在线路容量队列中等待的时长,未排队时为 0。该段耗时表示厂商分配的容量已满,与模型推理速度无关
timings.ttfb_ms成功的那次尝试从发出到收到上游首字节的时长;未到达上游时为 null
timings.total_ms端到端总耗时

以下字段按需返回:

字段说明
saved_quota、cache_age_s、cache_ttl_s、cache_items响应缓存相关,见缓存与幂等
tool_rounds、tool_calls使用平台托管工具时返回,见 MCP 与托管工具
variant_switch{from, to, params},自动改用模型变体时返回
max_tokens_clamped{requested, effective, limit},Messages 的输出上限被按上限发出时返回
param_actions{dropped, translated, emulated, reshaped, healed},各项为参数名列表,与响应头 X-SciRouter-Param-Actions 内容相同
schema_valid结构化输出经平台模拟、且带 X-SciRouter-Validate-Schema: 1 时返回,表示正文是否符合 schema
finish_detail值为 repetition 时表示模型陷入复读、平台中断了上游,此时 finish_reason 为 length
prompt_cache{read, write, write_1h, saved_quota}:命中上游提示词缓存、写入 5 分钟缓存、写入 1 小时缓存的输入 token 数,saved_quota 为命中节省的配额。未到达上游或四项均为 0 时不返回
endpoint_providerprovider 的旧名,取值相同。新代码读取 provider

param_actions、schema_valid、finish_detail 的规则见参数如何被处理。

提示词缓存的命中部分按缓存命中价计费、写入部分按写入价计费,节省的配额不并入 cost_quota。一段时间内的命中率见控制台用量页的「上游缓存命中」一栏,统计口径见缓存与幂等。

流式响应的扩展分片

#

流式响应在 data: [DONE] 之前多一个 choices 为空的分片,带同一个 scirouter 字段。该分片的形状与 OpenAI 最后一个 usage 分片相同,SDK 均可识别:

text
data: {"id":"chatcmpl-…","object":"chat.completion.chunk","created":…,"model":"…","choices":[{"delta":{"content":"…"},…}]}
data: {"id":"chatcmpl-…","object":"chat.completion.chunk","created":…,"model":"…","choices":[],"scirouter":{"request_id":"req_…","attempts":1,…}}
data: [DONE]

其中 cost_quota 为本次的准确消耗。上游未输出任何分片即结束的流不带该分片;流开始后出错时,最后一个分片为 {"error": {…}},没有扩展分片,也没有 [DONE]。

请求日志

#

控制台 /console/logs 可按 request_id 查询单条记录,也可按结束原因、来源、慢请求、缓存命中、调用格式(OpenAI / Anthropic)、错误码与自定义时间区间(最长 90 天)筛选。同一个 Key 同时供 OpenAI SDK 与 Claude Code 使用时,可按调用格式分开查看。

每条记录可展开为调用详情:

部分内容
时间线准入 → 路由 → 排队 → 每次尝试 → 上游首字节 → 推流 → 结算,未发生的阶段不显示。两个首字节(平台发给调用方的 / 上游返回的)各有一条标记线,差值为 SciRouter 侧的耗时
路由实际厂商、每次尝试的结果与耗时
诊断提示只解释已有的事实:被 max_tokens 截断、主要耗时在排队、发生过转移、用量为估算、客户端中途断开
复制报障信息将 request_id、时间、模型、错误码、厂商请求 id 汇总为一段文本,用于报障

归因标签

#

一个 Key 下运行多个实验时,账单只能按 Key 区分。在请求体中带 OpenAI 原生的 metadata 字段(字符串键值对),每次调用即带上自定义的归因标签:

python
import os

from openai import OpenAI

client = OpenAI(api_key=os.environ["SCIROUTER_API_KEY"], base_url="https://api.scirouter.cn/v1")

client.chat.completions.create(
    model="YOUR_MODEL_ID",
    messages=[{"role": "user", "content": "…"}],
    metadata={"exp": "abc", "run": "12"},
    user="researcher-42",
)
typescript
import OpenAI from 'openai'

const client = new OpenAI({ apiKey: process.env.SCIROUTER_API_KEY, baseURL: 'https://api.scirouter.cn/v1' })

await client.chat.completions.create({
  model: 'YOUR_MODEL_ID',
  messages: [{ role: 'user', content: '…' }],
  metadata: { exp: 'abc', run: '12' },
  user: 'researcher-42',
})
项目规则
键的数量最多 8 个
键1–32 个字符,只含小写字母、数字、_、.、-
值字符串,最长 64 个字符,不能含控制字符(换行、制表符等)
超出限制返回 400
user(/v1/messages 为 metadata.user_id)超过 512 个字符时截断保存,不报错
  • metadata 与 user 不转发给模型厂商,只记录在控制台日志中。
  • 日志页可按标签筛选(?tag=exp:abc,点击记录上的标签即可);用量页可按标签分组查看花费、错误率与截断率(窗口不超过 30 天)。
  • 站内对话(Chat)的每次调用自动带 chat_session 标签,值为会话 id:日志页可从一条消息跳转到对应调用,也可筛选出一场对话的全部调用。
  • session_id 是保留键:取值相同的调用归入同一个会话,控制台按会话列出各条执行链路,导出时也带该值,见会话 id。

用量页

#

控制台 /console/usage 可按模型、Key、项目、来源、状态、标签分组,查看请求数、Tokens、配额、错误率与截断率;按模型分组时另有 P50 / P95 延迟。开启「与上期对比」后,上一个等长窗口画在同一张图上。窗口可选近 24 小时、7 天、30 天、90 天,或自定义区间(最长 90 天)。

团队工作区还可按成员分组。统计口径:

  • 请求数不含响应缓存命中。命中单独计数,这些调用未调用模型、不计费。
  • 延迟分位只在按模型分组时提供。分位数不能跨模型合并,按其他维度分组时表中没有 P50 / P95 两列,图上也不能选择 P95,表格上方有说明。

实时限额

#

控制台概览页的「实时」卡每 10 秒刷新一次,显示:

  • 每分钟请求数与每分钟 token 数在当前窗口的用量(与 x-ratelimit-* 响应头为同一组读数);
  • 同时进行的模型调用数;
  • 同时运行的 agent 数;
  • 正在进行的请求;
  • 近 1 小时的错误。

agent 指 Chat 的一轮、课题的一步或研读的一次生成,一个 agent 可能同时调用多次模型。agent 数已满时新的 agent 排队,不报错。

在团队工作区中,卡片显示团队的限额:在团队工作区发起的调用(包括团队项目下的 Key)按团队限额计、成员共用,不占个人限额。进行中的请求与错误只列出当前用户自己的。

程序中读取同一组读数,使用每次响应的 x-ratelimit-* 响应头。

导出

#

日志页的「导出当前筛选」将当前筛选的记录导出为 CSV(UTF-8 BOM,Excel 可直接打开)或 JSON Lines。单次上限 50 000 行;超过时先提示命中条数并要求缩小范围,不导出部分结果。

  • 文件中不含提示词、返回片段与请求参数。
  • 包含已打码的来源 IP、user、标签、saved_quota、调用格式 api_format 等列;列顺序固定,新列只追加在末尾。
  • 时间列按账号设置的显示时区输出,列名中注明时区(如 created_at (Asia/Shanghai))。

调用告警

#

账号页「通知」中有五项调用告警,默认开启,选择通知渠道后即发送。每 5 分钟检查一次:

通知项触发条件冷却
错误率飙升单个 Key 近 15 分钟的错误(不含限频)超过 20%,且样本 ≥ 20每个 Key 1 小时
延迟劣化单个模型近 15 分钟的 P95 比近 7 天基线高出一倍以上,且样本 ≥ 20每个模型 1 小时
频繁被限频近 15 分钟 429 ≥ 30 次1 小时
配额即将耗尽按近 24 小时的消耗速度,剩余配额不足 3 天24 小时
回答频繁被截断单个模型近 1 小时被 max_tokens 截断的回答超过 30%,且样本 ≥ 20每个模型 24 小时

告警正文只含数字与名称,不含链接;每条写明应查看控制台的哪一页。

通用 webhook

#

通知渠道除企业微信、飞书、Bark 外,还可以是自有的 https 地址(须为公网地址;本机与内网地址被拒绝)。渠道创建时显示一次签名密钥(whsec_…),之后无法读回;更换密钥须删除渠道后重建。

每条提醒以一次 JSON POST 发送:

json
{
  "id": "whd_01HZX…",
  "event": "error_rate_spike",
  "scope": "user",
  "subject": "错误率飙升",
  "text": "…纯文本…",
  "markdown": "…Markdown…",
  "data": { "key": "生产", "percent": "35", "requests": "40", "errors": "14", "topCode": "UPSTREAM_ERROR", "window": "15 分钟", "site": "SciRouter", "time": "2026-09-22 10:30" },
  "site": "SciRouter",
  "time": "2026-09-22T02:30:00Z"
}
请求头取值说明
X-SciRouter-Event通知项 id;试发时为 test事件类型
X-SciRouter-Delivery投递 id重试时不变,用于去重
X-SciRouter-Signaturet=<unix 秒>,v1=<hex>签名,验证方法见下

secret 为渠道创建时显示的完整字符串(含 whsec_ 前缀),直接作为 HMAC 的 key,不做 base64 解码。v1 为以 secret 为 key、对 {t}.{原始请求体} 计算的 HMAC-SHA256 十六进制值。验签示例:

python
import hashlib
import hmac
import time


def verify(secret: str, raw_body: bytes, signature: str) -> bool:
    parts = dict(item.split("=", 1) for item in signature.split(","))
    t, v1 = parts["t"], parts["v1"]
    expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, v1) and abs(time.time() - int(t)) < 300
  • 接收端返回任意 2xx 即视为成功;5 秒未响应或返回非 2xx 时再重试 3 次(分别在 0.5、1、2 秒后)。
  • 连续失败 10 次后渠道自动停用,原因记录在渠道的「上次失败」中;修复地址后重新启用即可。此处的「一次」指一条提醒的完整投递(含 3 次重试);投递成功即清零,24 小时内没有新的失败也重新计数。
  • data 中的键与通知模板的变量同名,后台修改模板不影响 data。

Prometheus 指标

#

自部署时,网关的 /metrics 提供调用指标。对外经 nginx 访问时返回 404,只供内网抓取;生产环境须配置 Basic Auth,用户名默认为 collector。

指标标签
scirouter_request_duration_secondsmodel、source、status
scirouter_request_ttfb_secondsmodel、source
scirouter_tokens_totalmodel、direction
scirouter_attempts_totalprovider、outcome
scirouter_ratelimited_totalscope
scirouter_finish_reason_totalmodel、reason

另有提示词缓存与响应缓存的计数。标签只到模型、厂商、来源、状态一级,不含用户与 Key。后端仓库附带一份 Grafana 面板(server/scirouter/scripts/grafana/scirouter.json)。按用户或按 Key 查看时,使用控制台的用量页与日志页。

链路导出

#

日志中的一条记录对应一次调用。Chat 的一轮、课题与研读的一次运行、/v1 的托管工具循环通常包含多次模型调用以及其间的工具、检索与等待,平台将其记录为一条执行链路:以运行为根的树,每个节点有起止时刻、结局与用量。

添加导出目的地后,这些链路以 OTLP/HTTP JSON 发送到调用方自有的 Langfuse 或任意 OpenTelemetry 后端,与应用自身的链路一起查看。

添加目的地

#
配置位置配置者导出的链路可带正文
控制台侧栏「链路导出」用户本人个人工作区内的:个人 Key 的 /v1 调用,个人工作区内的 Chat、课题、研读可以(默认关闭)
团队详情中的「链路导出」团队 owner / admin(成员不可见)该团队工作区内的,含团队项目下的 Key 发起的 /v1 调用不可以

平台运维另在管理后台配置平台级目的地,导出全部链路的元数据,不带正文。每个目的地的配置项:

配置项说明
地址OTLP/HTTP 的基地址,导出时请求 POST {地址}/v1/traces。只接受 https、端口 443、公网可达的地址;地址中不能含用户名与密码,也不能含 ? 或 #
类型langfuse 或 otel。langfuse 另加请求头 x-langfuse-ingestion-version: 4 与 Langfuse 识别的若干属性,见导出内容
鉴权不鉴权、Basic(用户名与凭据)、Bearer、自定义请求头(请求头名与凭据)。凭据加密保存,保存后无法读回;地址改到另一台主机时须重新填写凭据,已保存的凭据不会发往新地址
采样率0–1,默认 1(全部导出),见采样、重试、停用与测试
带上内容默认关闭,只有个人目的地可以开启,见导出内容

个人默认最多配置 3 个目的地,每个团队最多 5 个。

Langfuse

#
  1. 在 Langfuse 项目的 Settings → API Keys 中新建一对 key:public key(pk-lf-…)与 secret key(sk-lf-…)。
  2. 在「链路导出」中添加目的地,按下表填写:
配置项取值
类型langfuse
地址Langfuse Cloud 欧洲区 https://cloud.langfuse.com/api/public/otel,美国区 https://us.cloud.langfuse.com/api/public/otel;自托管填 https://<域名>/api/public/otel
鉴权Basic(langfuse 类型只支持 Basic):用户名填 public key,凭据填 secret key
  1. 点击「测试」。成功时 Langfuse 中出现一条名为 scirouter connectivity test 的链路。

自托管的 Langfuse 同样须使用 https、端口 443 且公网可达;只在内网可达的实例无法连接。

其他 OpenTelemetry 后端

#

类型选择 otel,地址填写后端 OTLP/HTTP 接收端的基地址(不含 /v1/traces,平台自动追加):

后端地址鉴权
自建 OpenTelemetry Collector(再转发给 Jaeger、Tempo 等)接收端对外的 https 地址,如 https://otel.example.org按 Collector 的配置:bearertokenauth 扩展对应 Bearer,basicauth 对应 Basic
JaegerOTLP/HTTP 接收端对外的 https 地址按前置反向代理的要求填写
Honeycombhttps://api.honeycomb.io(欧洲区 https://api.eu1.honeycomb.io)自定义请求头:请求头名 x-honeycomb-team,凭据填 Honeycomb 的 API Key
  • 平台只发送 OTLP/HTTP 的 JSON 编码,不使用 gRPC;接收端须接受 application/json(Collector 与 Jaeger 的 OTLP 接收端均支持)。
  • Collector 与 Jaeger 的 OTLP/HTTP 接收端默认使用 4318 端口与明文 http,平台只连接 https 的 443 端口:须在前面加一层 https 反向代理,或为接收端配置证书并监听 443。
  • 单次发送的请求体默认不超过 4 MiB,接收端的请求体上限须大于该值。

导出内容

#

一条链路是 trace id 相同的一组 span,每个节点对应一个 span:

节点span 名gen_ai.operation.nameLangfuse 类型
运行:Chat 的一轮、课题 / 研读的一次运行、/v1 托管工具循环的根(v1_tool_loop)invoke_agent {名字}invoke_agentagent
步骤invoke_agent {步骤种类}invoke_agentagent(主 agent)/ chain(其余)
模型调用chat {模型 id}chatgeneration;验收评审的调用为 evaluator
检索execute_tool {名字}execute_toolretriever
工具、沙箱、MCP、读技能、读回原文、留言execute_tool {名字}execute_tooltool
等待:排队等名额、撞沙箱闸放回、等待用户回答wait {名字}无span
截断标记:该链路记录的节点数已达上限,之后的节点不再记录marker truncated无event
  • 重试、换模型、续写、压缩、退回队列不单独成为 span,记为所在节点上的 span event(事件名为 retry、fallback、continue、compaction、requeue 或 other;能对应到某次调用时带该调用的 scirouter.request_id)。
  • 模型调用的 span kind 为 CLIENT,其余为 INTERNAL;出错节点的 status 为 ERROR,消息为错误码。
  • resource 只有 service.name = scirouter;instrumentation scope 为 scirouter.traceexport,版本为 gen-ai-dev/1.42.0-dev。属性名遵循 OpenTelemetry GenAI 语义约定的该版本;该约定处于 Development 阶段,上游改名时平台同步修改,scope 的版本号标明所用版本。

每个节点都有的属性:

属性说明
gen_ai.operation.name见上表;等待与截断标记没有该属性
gen_ai.conversation.id会话 id:Chat 会话、课题、论文,或 /v1 的 metadata.session_id;不属于任何会话时没有该属性
scirouter.trace.kindchat / campaign / paper / api
scirouter.node.typerun / step / generation / tool / retrieval / sandbox / mcp / skill / recall / post / wait / marker
scirouter.statusok / error / cancelled / skipped;运行收尾时仍未结束的节点为 running
scirouter.error_code出错时的错误码

按节点类型另有的属性:

节点属性
模型调用gen_ai.provider.name(厂商 id,没有时为 scirouter)、gen_ai.request.model、gen_ai.usage.input_tokens、gen_ai.usage.output_tokens、gen_ai.usage.cache_read.input_tokens(命中提示词缓存的部分,大于 0 时才有)、gen_ai.response.finish_reasons;scirouter.request_id(控制台日志可按它查到该次调用)、scirouter.cost_quota、scirouter.attempts、scirouter.provider、scirouter.purpose(turn / review 验收评审 / compaction 压缩摘要 / other)、scirouter.first_token_ms
工具类gen_ai.tool.name;scirouter.cost_quota(工具自身按次的花费,有时才返回);scirouter.tool.<键>:只含白名单中的计数、布尔值与短枚举,即 argsBytes、resultChars、results、sources、papers、reused、prefetched、gated、empty、sandboxStatus、wallMs、timeout、exitCode、round、rounds、toolCalls、failure
运行、步骤gen_ai.agent.name

类型为 langfuse 时,每个 span 另加:

属性说明
langfuse.observation.type上文节点表中的 Langfuse 类型
langfuse.trace.name链路标题,如「第 3 轮对话」
session.id与 gen_ai.conversation.id 相同,Langfuse 的 Sessions 据此将多条链路归为一个会话
langfuse.observation.completion_start_time模型调用的首字时刻
user.id仅团队目的地:节点所属成员的用户 id。个人目的地不带

trace id 与 span id 由平台的链路 id、节点 id 经 SHA-256 截取为 16 / 8 字节,同一节点每次导出的 id 相同;带 traceparent 的链路直接使用调用方的 trace id,见 traceparent。

正文默认不导出。节点中只有上述计数、长度与枚举,不含提示词、回答、检索词与网址。个人目的地开启「带上内容」后,模型调用另带 gen_ai.input.messages 与 gen_ai.output.messages 两个属性(按约定的消息结构序列化的字符串:输入整段记为一条 user 消息,输出记为一条 assistant 消息):

  • 内容取自请求日志保存的正文片段,因此只有该次调用保存了正文时才有(账号设置「数据保留」中的「保存请求与响应正文」,见隐私);
  • 平台内部的验收评审与压缩摘要调用一律不带正文;
  • 单个节点带上正文后超过请求体上限时,该节点不带正文发送;
  • 团队与平台级目的地不能开启该选项。

导出时机:

  • 导出每分钟运行一轮。Chat、课题、研读的链路在整次运行结束后一次发送;/v1 的节点在各自结束后发送。
  • 节点结束 2 分钟后才发送(等待全部落库),因此后端中看到的数据比调用晚两三分钟。
  • 每个节点对每个目的地只发送一次。例外:对方已接收、平台尚未记录进度时实例恰好重启,该批会重发一次。
  • 只发送归属该目的地的节点,同一条链路中其他用户的调用不会一并发出。
  • 向量调用(/embeddings)不在链路中。

traceparent

#

/v1/chat/completions、/v1/messages、/v1/responses 识别 W3C Trace Context 的 traceparent 请求头。带该请求头时,本次调用记录在调用方的 trace 之下:

  • 链路 id 为调用方的 trace id;本次调用(使用托管工具时为循环的根节点)的父节点为调用方的 span id。导出时两者原样使用,平台的节点挂在发起调用的 span 之下,在后端中属于同一棵树。
  • 同一个 trace id 的多次请求,在控制台中也属于同一条链路。
  • 只识别 version 00:00-<32 位小写十六进制 trace id>-<16 位小写十六进制 span id>-<2 位十六进制 flags>。格式错误、id 全为零或带多个 traceparent 时视为未带,不报错;不读取 tracestate;flags 中的采样位不影响平台是否记录与导出。
  • 未带时本次请求自成一条链路,链路 id 为本次调用的 request_id(托管工具循环的各轮沿用第一轮的值)。

traceparent 只负责关联两侧的链路。要在后端中看到完整的树,还须添加指向同一后端的导出目的地,见添加目的地。

bash
curl https://api.scirouter.cn/v1/chat/completions \
  -H "Authorization: Bearer $SCIROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -H "traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01" \
  -d '{
    "model": "YOUR_MODEL_ID",
    "messages": [{"role": "user", "content": "…"}],
    "metadata": {"session_id": "notebook-42"}
  }'

Python(OpenAI SDK 与 OpenTelemetry SDK)在每次调用时用 extra_headers 带上当前 span:

python
import os

from openai import OpenAI
from opentelemetry import trace
from opentelemetry.propagate import inject

client = OpenAI(api_key=os.environ["SCIROUTER_API_KEY"], base_url="https://api.scirouter.cn/v1")
tracer = trace.get_tracer("my-agent")

with tracer.start_as_current_span("summarize-paper"):
    headers = {}
    inject(headers)  # 把当前 span 写成 traceparent 头
    response = client.chat.completions.create(
        model="YOUR_MODEL_ID",
        messages=[{"role": "user", "content": "…"}],
        metadata={"session_id": "notebook-42"},
        extra_headers=headers,
    )
  • 整个脚本在同一个 span 下运行时,也可以在创建 client 时用 default_headers={"traceparent": …} 一次带上。
  • 安装 OpenTelemetry 的 httpx 自动埋点(opentelemetry-instrumentation-httpx)后,OpenAI SDK 发出的请求自动带 traceparent,无需手动设置。

会话 id

#

请求体 metadata 中的 session_id 是保留键,取值为调用方自定义的会话 id。traceparent 决定一条链路中节点的父子关系,session_id 决定多条链路是否属于同一个会话,两者可同时使用。

  • 控制台:会话链路逐行列出该会话中的链路(调用次数、Token、配额、耗时,表头为整个会话的合计)。session_id 同时是普通的归因标签,日志页按 session_id:<值> 可筛选出该会话的全部调用。
  • 导出:写入 gen_ai.conversation.id,langfuse 类型另写 session.id。
  • 规则与其他标签相同,见归因标签:值为字符串,最长 64 个字符,不能含控制字符,占 8 个键中的一个;格式错误时返回 400。
  • /v1/messages 同样写在 metadata 中(user_id 之外的字符串键均视为标签);/v1/responses 写在其自身的 metadata 中。

采样、重试、停用与测试

#
项目规则
采样按链路 id 的哈希判定,同一条链路整条导出或整条不导出
失败与重试对方返回 2xx 视为已接收(含 OTLP 的部分成功);连接失败、10 秒未响应、返回非 2xx 均视为失败。失败的批次不丢弃,1 分钟后重试,之后每次等待时间翻倍,最长 1 小时;成功一次后失败计数清零
停用连续失败 10 次后自动停用,目的地上注明原因(对方最近一次的响应,截取 300 字,凭据会被抹去)。修复后修改配置保存或重新启用:失败计数清零,从停止处继续发送;停用较久的只补发最近 24 小时的链路
测试用已保存的配置发送一条只含一个 span 的合成链路(span 名 scirouter connectivity test,属性 scirouter.test = true),当场返回对方的状态码、错误原因与耗时。不计入导出条数,也不改变失败计数与状态
平台暂停导出不能新建、不能测试;已有目的地可以查看、修改、删除,但不发送。恢复后从停止处继续发送(同样最多补发 24 小时)

易误读的字段

#
  • finish_reason: "length" 表示回答被 max_tokens 截断,与模型故障无关。需要完整回答时调大 max_tokens。
  • attempts 统计的是尝试次数,不等于失败次数:2 可能是一次失败加一次成功,也可能是一条线路已满被跳过加一次成功。
  • 首字节有两种口径。SDK 测得的首字节包含网络与边缘节点的耗时;timings.ttfb_ms 只计网关到上游的一段。判断模型速度以后者为准。
  • 命中响应缓存(cache: "hit")的调用不经过上游、不计费,attempts 为 0,timings.ttfb_ms 为 null。

隐私

#
  • 请求日志默认不保存提示词与返回正文。在账号设置「数据保留」中开启「保存请求与响应正文」后,之后的调用才会保存(脱敏后每段最多 16 000 字,更长的只保留开头,并在日志详情中标注)。
  • 正文由平台保留 7 天后自动清空(天数由平台策略决定,页面上显示当前值)。关闭开关只影响之后的请求,已保存的正文按期过期。
  • 调用记录本身(模型、耗时、token、配额、状态、标签等)保留 90 天,到期整行删除;按小时、按天汇总的用量不受影响。
  • 日志不存储在浏览器中。响应中的厂商只返回 id(控制台中显示名称),不返回接口地址与线路信息。
  • 执行链路只发送到已添加的导出目的地:个人工作区的链路发往用户本人添加的目的地,团队工作区的链路发往团队 owner / admin 添加的目的地,平台级目的地只接收元数据。只有个人目的地开启「带上内容」时才带正文,见链路导出。发出后的存储方式与保存时长由接收方决定。
  • 开始

  • 接入编程工具

  • 接口

  • 专题

  • 网页端指南

↑ ↓ 选择 · Enter 打开 · Esc 关闭

请验证你的身份

为了保护你的账户,这个操作需要再验证一次。

验证码已发送到你绑定的手机号。5 分钟内的其他敏感操作不会再问。

Cookie 偏好

您可以随时回到这里修改。页脚有常驻入口。

必要

维持登录状态、记住主题与语言偏好。没有它们本站无法正常工作,因此无法关闭。

统计

了解哪些功能有人用、用户在哪一步流失。只收集维度(页面、操作类型、计数),不收集您输入的任何内容。

本站不加载任何第三方统计脚本,也不做会话录屏。完整说明