Python · API · LLM-Bridge

一个 reasoning_effort,翻译给三种后端

LLM-Bridge 复盘:OpenAI 给了一个统一的 reasoning_effort 字段,可三家后端接受深度的方式完全不同——SDK 选项、config 覆盖、模型名里编码。

OpenAI 的请求格式里有个标准字段 reasoning_effort,取值 low / medium / high / xhigh 这类,用来控制模型「想多深」。LLM-Bridge 对外收这个字段,可对内——三家后端接受深度的方式,一个像样的都对不上。这篇讲一个字段怎么翻译成三种完全不同的落法。

claude:先把 SDK 的默认值按下来

claude 走 Agent SDK,深度是 SDK 的 effort 选项,取值 low / medium / high / xhigh / max。翻译本身不难,难的是默认值

SDK 自己的默认是 high。这个默认是给「写代码的 agent」定的——它要深思、要多轮推理。可 LLM-Bridge 是个聊天网关,大多数请求就是随口问一句,用 high 又慢又费 credit(headless claude 烧的是月度 Agent SDK 额度)。所以网关把默认主动压到 medium

DEFAULT_EFFORT = "medium"  # SDK 默认是 high,对聊天太深、太费额度

EFFORT_MAP = {
    "minimal": "low", "low": "low", "medium": "medium",
    "high": "high", "xhigh": "xhigh", "max": "max",
}
effort = EFFORT_MAP.get(request.reasoning_effort or "", DEFAULT_EFFORT)

请求里显式写了 reasoning_effort 就照它来,没写就用 medium 而不是 SDK 的 high接一个第三方 SDK,它的默认值是按它的场景调的,未必是你的场景——该覆盖就覆盖,别默默继承。

codex:从请求字段到 -c 配置覆盖

codex 是 CLI 子进程,深度不是命令行开关,得靠 -c 传一条 config 覆盖进去:

mapped_effort = EFFORT_MAP.get(effort or "")
if mapped_effort:
    args += ["-c", f'model_reasoning_effort="{mapped_effort}"']

-c model_reasoning_effort="high" 相当于临时改写 codex 的一条配置项。请求字段 → 中间词表 → CLI 配置覆盖,中间转了两道手。没传 effort 就不加这个参数,让 CLI 用它自己的默认。

agy:深度不在字段里,在模型名里

到 agy(Antigravity CLI)这里,reasoning_effort 字段直接被忽略——不是没实现,是它的模型本身就把深度编码进了名字

Gemini 3.5 Flash (Low)
Gemini 3.5 Flash (Medium)
Gemini 3.5 Flash (High)

(Low) / (Medium) / (High) 是三个不同的模型 slug,不是同一个模型的一个参数。你要浅一点,就选 gemini-3.5-flash-low;要深一点,选 -high。深度的旋钮长在模型选择里,而不是一个独立字段上。于是这条通道诚实地不处理 reasoning_effort,并在文档里写明:agy 的深度请通过选模型来控制。

同一个概念,在三家的抽象里位置都不一样:claude 是 SDK 选项、codex 是 config 项、agy 是模型标识的一部分。适配层的活儿就是认清它在每家落在哪,然后把请求字段接过去。

两张映射表,因为词表根本不一样

你可能注意到 claude 和 codex 各有一张 EFFORT_MAP,长得还不一样。这不是复制粘贴忘了合并,是两家的词表本来就不同

  • OpenAI 的 minimal:claude、codex 都没有对应档,统一映射到 low
  • 顶格档:claude 有 maxmax 就映到 max;codex 最高只到 xhigh,所以 codex 的表里 max → xhigh,封顶。
# claude:  "max": "max"      —— SDK 支持 max
# codex:   "max": "xhigh"    —— codex 没有 max,封到 xhigh

一个统一字段要落到 N 个后端,就得为每个后端维护一张「我的词表 → 它的词表」的映射,并诚实处理两边对不齐的档位。这类枯燥的词表对齐,正是「统一 API」这四个字底下真正的工作量。

顺带:别让用户环境偷改你的请求

跟 effort 同一类的还有一个隐形变量:codex 会读用户的 ~/.codex/config.toml,把里面的 skills、plugins、甚至 reasoning 设置一并带进每个请求。对一个聊天网关,这有两个坏处——那些 skills 平白多出几万个 input token,用户如果全局开了 xhigh reasoning,你的每个请求都被拖慢,而且你在代码里设的 effort 会被用户环境悄悄改写

所以 codex 默认加 --ignore-user-config

if self.ignore_user_config:
    args.append("--ignore-user-config")

它只隔离「用户的个性化配置」,认证不受影响(登录态照样从 ~/.codex 读)。这样网关请求就是干净的:深度完全由请求里的 reasoning_effort 决定,而不是被用户某天随手改的全局配置偷偷左右。可配置,想带用户配置的人自己打开。

小结

一个 reasoning_effort 字段,翻译给三种后端:

  • claude:SDK 的 effort 选项,关键是把 SDK 默认的 high 主动压到 medium——第三方默认值按它的场景调,未必是你的;
  • codex:转成 -c model_reasoning_effort="…" 的 config 覆盖,请求字段绕两道手到 CLI;
  • agy:深度编码在模型名里((Low/Medium/High)),字段被忽略,靠选模型控制;
  • 两张映射表minimal 两家都没有映到 lowmax 在 claude 是 max、在 codex 封到 xhigh——词表对齐是统一 API 的真实工作量;
  • --ignore-user-config:隔离用户全局配置,别让它偷偷给请求加 20k token、改你设的 effort。

一句话:「统一 API」听起来是抹平差异,做起来是为每一个差异,写一条诚实的映射。

留言

  • 加载中…

留言先审后发,通过后公开显示;邮箱只有站主可见。