Codex SDK 校验 xhigh、max 与 ultra 时,不应只判断字符串是否属于 ReasoningEffort 枚举,而应先取得精确模型的能力元数据,再按语义分流:xhigh 和 max 作为模型级推理强度,与模型公布的 supported_reasoning_efforts 求交集;ultra 作为 Codex 高级编排模式,还要检查客户端是否支持主动多代理、当前任务是否允许该行为以及底层模型如何映射。
一个可靠 SDK 至少需要三道校验:输入格式校验、模型能力校验和运行时服务端校验。任何一道都不能替代另外两道。这样既能在调用前阻止明显无效组合,也能处理模型目录与后端短暂不同步的情况。
SDK 不应把模型 ID、effort 和产品模式塞进一个没有约束的字符串字典。可以先建立以下概念:
ModelDescriptor {
id: string
default_reasoning_effort: string | null
supported_reasoning_efforts: string[]
}
CodexCapabilities {
proactive_multi_agent: boolean
ultra_mode: boolean
}
RunOptions {
model: string
reasoning_effort: string | null
}
ModelDescriptor 来自模型目录,描述模型级能力;CodexCapabilities 描述客户端或任务运行器能力;RunOptions 是用户请求。将这些数据分开后,max 与 ultra 就不会被误放在同一条无条件排序链里。
输入格式校验只负责拒绝空值、非法类型和明显拼写错误。例如 effort 必须是非空字符串,模型 ID 必须存在。SDK 可以识别已知值,也可以保留未来自定义值,以避免协议升级时旧客户端崩溃。
function parseEffort(value) {
if (value == null) return null
if (typeof value !== "string" || value.trim() === "") {
throw new InvalidEffortFormat(value)
}
return value.trim().toLowerCase()
}
这一层通过只表示值能被解析。它不能告诉调用方当前模型支持 xhigh 或 max,也不能证明 ultra 可以启用。
对于模型级 effort,判断标准是当前模型的支持列表:
function validateModelEffort(model, effort) {
if (effort == null) return model.default_reasoning_effort
if (!model.supported_reasoning_efforts.includes(effort)) {
throw new UnsupportedReasoningEffort({
model: model.id,
requested: effort,
supported: model.supported_reasoning_efforts
})
}
return effort
}
这个函数对 xhigh、max 以及其他普通档位一视同仁。只要目标模型明确列出,就允许;没有列出,就拒绝。不要写成“所有 GPT 模型都支持 xhigh”或“Codex 新版本都支持 max”,因为能力属于精确模型,而不是品牌或客户端版本。
Ultra 不能直接套用上面的模型列表逻辑。它可能是 Codex 产品层的高级模式,会启用主动任务拆分和多代理协作。SDK 应把它转换为一个明确的执行计划:
function resolveUltra(model, codexCapabilities, taskPolicy) {
if (!codexCapabilities.ultra_mode) {
throw new UnsupportedCodexMode("ultra")
}
if (!codexCapabilities.proactive_multi_agent) {
throw new MissingCapability("proactive_multi_agent")
}
if (!taskPolicy.allow_parallel_agents) {
throw new TaskPolicyViolation("parallel agents disabled")
}
return {
codex_mode: "ultra",
model_effort: chooseUltraModelEffort(model)
}
}
chooseUltraModelEffort 必须由当前 Codex 版本或 provider 的明确规则提供,不能由 SDK 作者凭名称猜测。某个版本可能映射到 max,另一个环境可能要求 xhigh,未来还可能使用新的后端表示。
常见错误是读取 SDK 的 ReasoningEffort 枚举,然后把所有成员展示给每个模型。这样用户会看到模型实际上不支持的 max,或者把 ultra 当作普通模型参数。
正确界面应根据模型动态生成:
modelOptions = descriptor.supported_reasoning_efforts
if (codexCapabilities.ultra_mode && taskPolicy.allow_parallel_agents) {
productModes.push("ultra")
}
模型 effort 和产品模式最好使用两个控件或清晰分组。即使产品希望在同一个选择器里展示,也应在内部保留两种类型,并显示 Ultra 会启用额外代理行为。
SDK 应优先读取当前 Codex 运行环境提供的模型目录或模型元数据,而不是从博客复制静态表。模型目录至少应包含模型 ID、显示名、默认 effort 与支持列表。若 SDK 有缓存,还需要版本或过期策略。
缓存模型目录时要考虑三种变化:
模型或 provider 变化时,应使相关缓存失效。不能把官方服务的能力列表继续用于兼容网关。
如果用户没有指定 effort,SDK 应使用模型目录的默认值,而不是固定 medium:
requested = options.reasoning_effort
effective = requested ?? model.default_reasoning_effort
if (effective != null) {
effective = validateModelEffort(model, effective)
}
用户显式值可能来自会话、命令行、profile、项目配置和用户配置。SDK 需要先按 Codex 配置优先级解析出一个候选值,再做模型校验。若先校验低优先级值,可能误报一个最终不会生效的错误。
假设当前模型支持 max,用户随后切换到只支持 xhigh 的模型。SDK 不能沿用旧的有效结果缓存,必须使用新模型描述重新验证。推荐返回一个结构化决策:
EffortDecision {
requested: "max"
effective: "xhigh"
reason: "requested effort unsupported by selected model"
model: "<new-model-id>"
}
是否允许自动回退应由调用方策略决定。交互式界面可以提示用户选择;无人值守任务可以按预先配置的策略回退;高风险工作流则应直接失败,避免悄悄降低推理投入。
模型级 effort 可以维护偏好顺序,但必须与支持列表求交集:
function highestSupported(model, preferred) {
for (const effort of preferred) {
if (model.supported_reasoning_efforts.includes(effort)) {
return effort
}
}
return model.default_reasoning_effort
}
selected = highestSupported(model, ["max", "xhigh", "high"])
这里不要把 ultra 放进 ["ultra", "max", "xhigh"],因为 Ultra 不是单纯的模型级上一档。Ultra 校验失败时,是回退到普通单代理模式,还是终止任务,应由任务策略明确决定。
即使模型目录声称支持 max,服务端仍可能因灰度发布、区域差异或 provider 配置拒绝。SDK 必须保留运行时错误处理,并识别 invalid value、unsupported parameter 或模型不可用等错误。
try {
return await client.startThread(resolvedOptions)
} catch (error) {
if (isUnsupportedEffort(error)) {
throw new RuntimeCapabilityMismatch({
model: resolvedOptions.model,
effort: resolvedOptions.reasoning_effort,
server_message: error.message
})
}
throw error
}
默认不要在没有记录的情况下自动重试。若允许回退重试,应限制次数,并同时返回最初请求值、实际值和回退原因。
部分错误会直接列出当前支持值。SDK 可以把它作为临时运行时证据,更新本次会话的能力缓存,但不应永久覆盖官方模型目录,除非有明确版本信息。
一个安全流程是:
Ultra 可能产生多个子代理会话,因此只校验“功能存在”还不够。SDK 应允许调用方设置资源边界:
UltraPolicy {
allow_parallel_agents: true
max_agents: 4
max_total_tokens: 500000
max_wall_time_seconds: 1800
require_explicit_request: true
}
具体字段取决于运行环境,但原则是明确并发、总资源和超时。不要把单代理的 max token 限制误当成整个 Ultra 任务的总预算。
SDK 的结果或事件应至少暴露:
如果只返回一个 success=true,调用方无法知道 max 是否静默变成 high,也无法审计 Ultra 是否真的启用了多代理。
建议至少区分:
InvalidEffortFormat:输入为空或类型错误;UnknownModel:模型目录没有该模型;UnsupportedReasoningEffort:模型未声明该档位;UnsupportedCodexMode:客户端不支持 Ultra;TaskPolicyViolation:任务策略禁止多代理;RuntimeCapabilityMismatch:目录与服务端结果不一致。结构化错误便于 UI 给出正确提示,也方便无人值守任务选择是否回退。把所有情况压成“请求失败”会让排错非常困难。
SDK 至少应覆盖以下组合:
模型支持 [low, medium, high, xhigh] + 请求 xhigh => 通过
模型支持 [low, medium, high, xhigh] + 请求 max => 拒绝
模型支持 [low, medium, high, xhigh, max] + 请求 max => 通过
客户端无 Ultra 能力 + 请求 ultra => 拒绝
客户端支持 Ultra、任务禁用并发 + 请求 ultra => 拒绝
客户端支持 Ultra、任务允许并发 + 请求 ultra => 生成编排计划
模型切换后旧 max 失效 => 提示或按策略回退
还要测试模型目录缺失、缓存过期、服务端能力冲突和自定义未来值。未来值能被解析,不代表应自动显示或提交;只有模型目录声明后才进入有效选项。
Mock 模型目录可以验证算法,但无法发现真实后端与客户端发布不同步。集成测试应使用受控账户运行少量低风险任务,确认状态中记录的实际 effort,并覆盖一次服务端拒绝路径。
测试日志需要脱敏,但应保留客户端版本、模型 ID、provider、目录支持列表、请求值和错误代码。这样出现线上差异时,可以判断是 SDK 逻辑、缓存、模型目录还是服务端造成。
function resolveRunOptions(input, environment) {
const model = environment.catalog.require(input.model)
const effort = parseEffort(input.reasoning_effort)
if (effort === "ultra") {
return resolveUltra(model, environment.codex, environment.taskPolicy)
}
return {
model: model.id,
codex_mode: "standard",
model_effort: validateModelEffort(model, effort)
}
}
这个流程先确定模型,再解析 effort,随后按 Ultra 与普通模型档位分流。它不会用全局枚举冒充模型能力,也不会把产品模式直接发送给不理解它的后端。
新客户端认识 max,不代表所选模型支持。应查询模型描述。
Ultra 可能触发多代理编排,需要单独能力和策略检查。
这会浪费额度并掩盖配置问题。回退次数应受限且结果可审计。
支持列表属于模型与 provider 组合,不能跨模型复用。
若发生映射或回退,必须同时显示 effective effort。
Codex SDK 校验 xhigh、max 与 ultra 的正确方式,是把协议值、模型能力和产品编排分开处理。xhigh 与 max 必须存在于精确模型的 supported reasoning efforts 中;Ultra 需要额外验证 Codex 客户端、多代理能力和任务资源策略,再由当前实现决定底层模型 effort。SDK 应动态读取模型目录、在模型切换后重新校验、保留服务端运行时验证,并返回 requested 与 effective 两套状态。这样才能既兼容新模型,又避免把宽泛的工具 Schema 误当作当前模型能力。