未被钉住的厂商默认值

9 分钟读完

O29
运维 · 智能体运维:部署与运营

你的配置有一半是别人定的,而它变动时不带版本号。

Claude Opus 5.5 在 2026 年 9 月 22 日交付,其力度参数默认为 medium——而其他每一个支持力度的 Claude 模型默认都是 high——于是一个靠改模型字符串完成迁移的团队,把自己的智能体往下挪了一个推理档位、改变了每一轮会发出多少次工具调用,却没有任何 diff 可供评审。这是普遍问题,不是一次性事件:你生效的配置,是「你设置的那些值」与「厂商、SDK、网关和 harness 替你选的那些值」的并集,而只有前一半住在你的仓库里。钉住一个带日期的快照并不解决它,因为快照钉住的是权重,不是你的请求省略掉的那些参数。

STEP 1

有四层在决定你的请求究竟说了什么。

把一个请求按你的代码表达它的样子写下来,再把抵达模型时的样子写下来。两者之间的落差就是本页的主题,而它是由一群从不互相协调的方面拼出来的。

  • 供应方的 API 默认值。你省略的任何东西都会被赋一个值:推理力度、采样温度、思考是否开启、并行工具调用、安全过滤阈值、最大输出上限。这些是按模型而定、不是按供应方而定的——而这正是陷阱所在,因为那个值跟着模型走,而不是跟着端点走。
  • SDK 的默认值。重试次数、超时、连接池、流式行为,有时还包括一个「API 本来不会去碰」的请求字段的客户端默认值。一次小版本号提升就能挪动其中任何一个,而唯一的痕迹是一次锁文件更新。
  • 网关或平台的默认值。同一个模型放在 Bedrock、Vertex、Foundry 或你自己的网关后面,抵达时可能带着不同的上限、不同的重试行为与不同的区域路由。按平台的分歧本身就是一个你没选择过的默认值。
  • harness 与工具层。挂上了哪些工具、它们的描述这周读起来是什么样、步数上限、某个插件或配置文件贡献的系统提示片段。第三方工具漂移就是这一层里的同一个问题。

这件事为什么没有被既有实践覆盖,值得说得精确一点。灰度发布与版本化告诉你把(模型、提示、工具)三元组钉到带日期的快照上、并在每次运行上打戳,而你确实该这么做。但一个钉住的快照 ID 钉住的是权重;它对「你的请求留空的那个字段最终解析成什么值」一言不发,对「是你那四层里的哪一层把它填上的」也一言不发。

STEP 2

一次默认值变动,不带任何你能订阅的版本号。

三种形态,按「要多久才会被注意到」递增排列:

  • 一个新模型带着不同的默认值。就是 Opus 5.5 这一种。模型是你选的,所以这次变动是可归因的——但行为上的差量比版本号的差量所暗示的更大,而你的代码里什么也没变。厂商自己对这次迁移的指引是重跑一次力度扫描,而不是把设置搬过来——这等于承认这个参数在模型之间是不可移植的。
  • 同一个字段背后一项被移除的能力。在当前这一代 Claude 上,自适应思考始终开启,而一个显式关闭思考的请求在任何力度档位都返回 400;更早的 token 预算形态则完全不再被接受。照着上一份契约写的代码会大声失败,而这是好的那一种情形。
  • 同一个请求,不同的平台或 SDK。安静的那一种,也是会制造出「谜案持续一个月」的那一种:预发机群在某个 SDK 小版本、某个区域上,生产在另一个上,而行为差异被归因到负载。没有任何公告可供订阅,因为从厂商那侧看,什么也没变。

请留意这几种里你现有的告警能看见哪一种。一个 400 会传呼到人。而一个被悄悄压低的推理档位,产出的是「稍差一点的输出、加稍低一点的成本」——这正是「没有报错的质量回退」的特征,也正是质量回退检测存在的理由,以及当那次变动是「某个没人在记录的参数上的一次阶跃」时它最吃力的地方。

STEP 3

记录解析后的配置,而不是你意图中的配置。

整套纪律压在一个习惯上:把「请求最终变成了什么」与「它返回了什么」并排记下来。多数团队记的是提示词与补全,而这恰恰是回答不了这个问题的那一对。

# stamp this on every trace, from the request as sent + the response
config_fingerprint = sha256(
    model_id,              # dated snapshot, not an alias
    effort,                # resolved, including "unset -> provider default"
    max_tokens, temperature, top_p,
    thinking_mode,
    tool_catalog_hash,     # names + descriptions + schemas
    system_prompt_hash,
    sdk_version, gateway_version, harness_version,
    platform,              # api | bedrock | vertex | foundry
)

有两条性质让它有用、而不只是装饰。它必须区分显式设置与交给默认值——一个把 effort=null 记成 "medium" 的字段,恰好藏起了你想抓的那样东西,所以请把发送出去的值与生效的值都记下来(在厂商会上报生效值的地方)。而这个指纹必须是你指标上的一个维度、不只是轨迹里的一个字段,这样「按配置指纹看每轮输出 token 数」才是一张你能打开的图。那张图就是「一次默认值变动在任何人知道去找它之前的样子」:分布挪了、指纹变了,而这次关联告诉你是哪一层挪了它。链路追踪能承载这件事——只要你把它放在边界处的 span 属性里,而不是塞在调用深处。

STEP 4

把你所依赖的那些值,在 CI 里对着活的 API 断言掉。

一个针对默认值的契约测试只有十几行,而它是这里唯一在进入生产之前就会失败的控制。对你使用的每个模型发一个最小请求、把你在意的那些字段省掉,然后断言解析后的配置与一份已提交的快照相符。

  • 把期望的生效配置作为文件提交,每个(模型,平台)组合一份,并在每次运行时做 diff。一次失败的 diff 不是错误——它是一条带日期的通知,也正是你本来想从「一份你订阅不到的变更日志」里得到的东西。
  • 让它自洽而便宜。每个组合一个短请求,不带工具、不带重试、输出上限很小。它一天花几美分,换掉的是一整类事件。
  • 按计划跑,不要只在提交时跑。你要抓的那次变动不是随着你的提交到来的。每日一次才是要紧的节奏;按提交跑只会告诉你关于你自己改动的事,而那些你本来就知道。
  • 把 SDK 与网关也纳入断言。在锁文件里钉住它们的版本,并让测试记录是哪些版本产生了所观察到的默认值,这样一次「改变了行为的锁文件提升」就留下了纸面痕迹。

这与钉住与核验是同一种本能,只是往里推了一层:你钉不住厂商的默认值,所以你钉住一条关于它的断言,让构建来告诉你现实什么时候漂了。

STEP 5

你不可能把一切都钉住,所以按「那个默认值能对你做什么」来选。

穷尽式的显式化本身就是一种失效模式——一个点名四十个字段的请求是一个迁移隐患,因为你设置的每一个字段,都是你从此要对着一个在改进自家默认值的厂商去维护的字段。请改按后果排序。

  • 一律显式:任何会挪动「每完成一个任务的成本」或工具调用行为的东西。力度或推理档位、输出上限、并行工具调用、以及在确定性要紧处的温度。这些正是漂移会表现为「花销意外」或「行为变更」的参数,它们该与你的预算一并放在成本控制里。
  • 显式并加测试:任何涉及拒答、安全过滤或内容阈值的东西。一个被挪动的阈值会改变你的拒答率,而一个被改变的拒答率就是一次产品变更。请为它保留一个小而常驻的评测。
  • 接受并检测:那些你根本钉不住的东西。别名背后的路由、分词器修订、服务端的提示脚手架、由容量驱动的区域落位。这里的控制不是配置,而是一个你跑得足够频繁、足以抓住一次漂移的评测,再加上第三步那个指纹,好让你能把一次漂移与一次巧合分开。
  • 不要靠抄旧值来钉。最诱人的迁移做法是把上一个模型的默认值显式写下来,而那保住的是一个为不同权重校准过的数字。厂商自己对 Opus 5.5 迁移的建议恰好相反:对着你的评测扫这个参数,按证据挑一个档位。把旧值往前抄,正是一个团队最后为「一个被调成只需要 medium 的模型」付 high 的钱的方式。
STEP 6

把一次默认值变动当作一次发布,因为它本来就是。

当契约测试报警,或厂商公布了一个你打算采用的新模型时,接下来的工作是一套发布流程,而不是一次配置编辑。这些部件在你的迁移手册里已经有了;要点在于让一次默认值变动也去触发它们。

  • 用开关做金丝雀,并且让旧配置仍然可达。让回滚变成瞬时的,正是那个显式参数——你回滚不了一个默认值。面向智能体的特性开关是它的机制。
  • 在两个值上都跑评测套件,并做配对比较。问的不是「新默认值好不好」,而是「在我们自己的任务上,它与我们原来的那个之间的差别,是否超过噪声」。
  • 盯一周机械指标。每轮 token 数、每轮工具调用数、每任务轮数、拒答率、p95 延迟。它们的挪动早于任何质量指标,而且便宜到可以直接报警。
  • 保留一份带日期的默认值日记。每次观察到的变动一行,带上指纹与日期。三周之后,当有人反馈说智能体「变懒了」,嫌疑名单是一个文件,而不是一场考古——这与追踪协议修订是同一个论点,只是用在参数上、而不是用在线缆格式上。

请从最便宜的两块开始,并按这个顺序。第一,把每一个会挪动成本或工具调用行为的参数显式设置下来——即便你设的就是当前的默认值,因为那个值从此住在你的仓库里,于是下一次厂商变动就变成了一件不必发生的事。第二,加上那个每日契约测试,断言你所运行的每个(模型,平台)组合的解析后配置,并把它的 diff 放进一个有人会读的频道。本页其余一切都是精细化;而这两件事,把一类看不见的行为变更,变成了一条带日期的通知。