面向智能体的特性开关:提示、模型、工具、策略都是可切换面。
经典的特性开关在控制代码路径。智能体的面积比这大——提示、工具注册、模型版本、策略阈值、检索配置,这些都是你希望不发布就能放量、限定范围、随时收回的东西。本文讲什么该放进开关、为何对任何爆炸半径不可忽略的开关"默认关"都没得商量,以及审计轨迹必须长成什么样,才让事后回看每一次切换都站得住脚。
可切换的面比代码大。
一个经典的特性开关把 if 分支套在某条代码路径上。对智能体而言那只是小情况——真正要紧的开关,套住的是 rollout-and-versioning 里那个行为契约中你希望独立移动的部分。按爆炸半径大致从大到小:
- 模型版本——某个租户或人群解析到的是哪个带日期的快照。这是你手上单一影响最大的开关。
- 提示版本——本次运行加载的是哪个内容寻址的提示。不发布也能改行为。
- 工具注册——本次运行里某个工具是否对模型可见;注册清单是数据,不是代码。
- 策略阈值——某条护栏用的置信度截断、每任务的成本上限、自动审批的金额上限。按人群调,而不是写死。
- 检索配置——用哪个索引、top-k 取多少、用哪个 rerank;过去是一次发布,现在该是一个开关。
- 采样参数——温度、top-p、最大步数。这些是会大幅改行为的小数字;一旦你有多于一个生产人群,就该把它们放进开关。
认知重构:智能体的特性开关不是"是否显示这个按钮"——它是对行为契约某个部件、按请求生效的覆写。要用得起这个契约该有的认真劲儿来对待它。
对任何爆炸半径不可忽略的开关,默认关。
标准的特性开关纪律是"默认关,证明了再扩大"。智能体的开关需要把这条规矩按得更死。原因是成本不对称:一个为新提示或新工具默认开的开关,从它存在的那一刻起就把每个租户暴露出去;一小时后发现的回归早已经触及了真实客户、真实 token 和真实副作用。一个默认关的开关要求按人群显式 opt-in,从而强制了灰度加对比这套纪律。
两条能截住常见滑坡的规矩:(1)智能体开关的默认分支必须是在位行为,永远不是新的那个,哪怕新的在 dev 看起来很安全。(2)"默认开、排除坏租户"和"默认开"是同一个 bug——等你知道谁坏的时候,影响已经落地。
按请求上下文限定范围,而非只按 user-id。
对智能体开关,真正要紧的求值单位是带着完整智能体上下文的那次请求——租户、用户、run_id、解析出的发布三元组、即将调用的工具、本次运行至此花了多少钱。一个只建在 user-id 之上的开关平台,回答不了"只在本次运行至此花费不到 $0.50 的请求上暴露新的搜索工具",也回答不了"只在已经选择加入 beta 人群的内部租户上放量新提示"。
# flags/eval.py — per-request evaluation with full agent context def resolve_flag(name, ctx): # ctx carries tenant, user, run_id, release, spend_so_far, tool rule = active_rule(name) if rule.scope == "tenant" and ctx.tenant in rule.allow: return rule.on if rule.scope == "cohort" and cohort_of(ctx.user) in rule.allow: return rule.on if rule.scope == "cost_cap" and ctx.spend_so_far < rule.under: return rule.on return False # off-by-default fallback
按请求求值、把解析出的值连同发布三元组一起写进运行日志,开关就成了一条轨迹可归因的行为契约的一部分。省掉这条日志,就有了一个事后无法复现其影响的开关。
开关的寿命:要么退役,要么付长尾账单。
陈旧的代码路径开关只是讨人嫌;陈旧的智能体开关是隐患。一个长期存在的、套住某个策略阈值的开关会慢慢变成那条策略——只是没人复审过它,它服务的人群已经漂移,三个月前打开它的那个租户也早忘了它。把这事按住的两条做法:
- 每个开关从落地的那天起就有归属人和退役计划——要么它成为默认(在位翻一翻),要么它被删掉。"我们就让这开关为某一个租户永远开着"等于把开关变成永久配置;那就显式地用一条配置项去做,而不是一个没人管的开关。
- 每季度审一遍开关的年龄与使用情况——90 天里所有人群都取同一个值的开关,应当是代码;30 天里没被求值过的开关,应当被删掉。
每次切换、每次求值都可观测——否则这个开关等于不存在。
把行为放进开关的全部意义,是不发布就能切。这份权力要配得上代价,那个切换本身就必须可观测:谁在什么时间为哪个范围把什么从什么改成什么,以及——单独地——每一次在新值下跑过的求值,按 run_id 与 tracing-and-observability 里的日志条目可关联。没有切换日志,你回答不了"这次回归是改提示开始的,还是翻阈值开始的?";没有按请求的求值日志,你回答不了"哪些运行是在新值下跑的?"。
还有一条:开关平台自身必须fail closed。当开关服务在运行途中不可达,求值返回在位的默认值,而不是新行为。否则开关层的一次故障,就成了对每个开关"开"分支的一次未宣告铺开——这一类事故,你不想用最难受的方式去遇见。