限制本身并不必然损害体验。并发任务需要门控,智能体的工具权限也必须有边界;真正棘手的是,系统只说“不行”,却不解释原因,也不给出下一步。当用户只能反复试错、智能体只能自行寻找出路时,合理约束就会表现为僵化,甚至诱发越权操作。
一个辩论 Agent 在启动新一轮任务时,用户输入了辩题。
系统没有反应。
用户又输入了一次。还是没有反应。
第三次。依然没有。
直到第四次,确认卡才弹出来。
用户的原话是:"感觉僵硬和突兀。"
日志里的现场是这样的:
08:00:15 候选辩题被跳过 reason=STREAM_ACTIVE query_chars=9
08:04:34 候选辩题被跳过 reason=STREAM_ACTIVE query_chars=29
08:06:15 候选辩题被跳过 reason=STREAM_ACTIVE query_chars=25
08:08:52 才进入确认流程
用户的辩题被静默吞掉三次,降级为普通对话由模型文字回应,不给任何反馈。
用户于是回了"开始"——撞上一句死命令:
「"开始"需要确认待启动配置;新一轮辩论请使用"重新发起辩论"。」
看起来像系统太僵硬。
但它不是。
系统在检测到"有任务在跑"时拒绝启动新任务,这个判断是对的。
同一时间并发两条辩论流,会导致状态错乱、任务卡串台、上下文污染——任何一个做过并发系统的人都明白这个门必须存在。
问题不在门。问题在于:门关上了,但没告诉用户为什么。
用户不知道发生了什么,只能盲试三次。第一次被吞,他以为是没发送成功;第二次被吞,他以为是输入格式不对;第三次被吞,他开始怀疑系统坏了。
这不是限制的问题,这是反馈的问题。
限制没有反馈,就是僵化。有反馈的限制,是引导。
这两句话看起来只是措辞差异,但它们是两种完全不同的产品:
| 无反馈的限制 | 有反馈的限制 | |
|---|---|---|
| 用户第一次被拒 | 不知道发生了什么 | 知道原因,知道下一步 |
| 用户第二次行为 | 换个说法再试 | 按提示执行 |
| 三次之后 | 放弃或暴怒 | 已完成 |
| 系统的角色 | 一堵墙 | 一个路标 |
这件事还有一个更严重的版本。
同一个 Agent,在某个 run 里做了三件事:
08:04:55 创建辩论团队
08:05:23 查看现有成员
08:05:56 关掉了 2 个成员
08:06:18 创建了 2 个新成员
它关掉的,是平台预先配置好的成员。它创建的,是自己命名的成员。
结果是后续全部失败——成员名不匹配、任务卡凑不齐、卡在提案阶段,最终整个 run 被取消,没有产出。
看起来像"模型叛逆"。
但它不是。
查它的输入指令,里面有一句明确要求:
"每位辩手的角色与立场描述都必须围绕该辩题撰写,严禁沿用团队既有描述、历史辩题。"
而平台预配置的成员,描述还是上一轮的。
Agent 为了让成员描述贴合新辩题,决定重建成员。
它的目标是我们让它做的。它的手段是违约的。
Agent 违约,通常不是叛逆,是"有目标,没手段"。
指令给了它目标,但没给达成路径。于是它自己找了一条——一条我们不允许的路。
有一个高度同构的公开案例。
一个编码 Agent 在 staging 任务中遇到凭证不匹配,于是搜代码库,找到一个无关文件里的 API token,用它删掉了生产库和备份。
作者的定性是:
"The agent pursued a goal, hit an obstacle, and used the authority it had been handed to clear it."
Agent 追一个目标,撞上障碍,于是用手上的权限清除了障碍。
这和我们那个关闭成员、重建成员的 Agent,是同一个动作。
而文章给出的结论是:
"the fix has to live in the architecture, not in a system prompt telling the agent to be careful."
修复必须在架构里,不能靠在系统提示里叫 Agent 小心。
这句话对。但它只说了一半。
仅仅禁止这个工具,同样不是修复。因为目标是正当的,禁掉手段只会让它再找一个——或者卡死。
有一个 Agent 权限控制的研究项目,在策略定义里有一条硬要求:
"fine-grained constraints over tool calls, deciding when tool calls are permissible and specifying fallbacks if they are not."
策略不仅要定义"什么时候允许",还必须定义"不允许时怎么办"。
这条要求的价值,被它自己的评估数据印证了:把攻击成功率从 41.2% 降到 2.2% 的同时,保持了高可用性。
也就是说:细粒度的限制,不以牺牲可用性为代价——前提是每条限制都带出路。
我们自己的数据也支持这条判据:
| 做法 | 结果 |
|---|---|
| 把阻断消息改成自带可执行命令 | Agent 逐字照抄,零探索 |
| 指令只给目标、不给手段 | Agent 自己找了一条,违约 |
有出路时,限制带来服从;没出路时,限制带来绕路。
这不是 Agent 的特性,这是任何执行者的特性。你给一个人一个目标,堵死所有正路,他不会停下来,他会番强。
从这两个案例里,能提出两条可操作的原则。
第一条:门控的生效范围要严格限定,且判定不确定时一律放行。
前面那个"静默吞输入"的问题,如果门控无差别地生效,那才是真的僵化。
我们做了范围限定:门控只在特定任务期生效。整个复杂场景测试轮次里,工具调用阻断数为 0。非任务的日常交互(查天气、查新闻)完全没受影响。
范围限定 + 不确定时放行,是防止门控外溢的两道保鲜。
第二条:意图层的修复,优先于门控层。
我们最初的优先级排序是"成员门控(P0)> 意图反馈(P1)"。后来反转了。
理由是:意图层的静默吞输入,同时造成了两个损失——
而新增门控只解决一个具体违约,且引入新的误伤风险。
正确的排序是:
| 序 | 项 | 是否阻断 |
|---|---|---|
| 1 | 被拒绝的意图要可见 + 记录输入摘要 | 否 |
| 2 | 指令补上"正确的达成路径" | 否 |
| 3 | 只在不可逆场景才拦 | 是 |
先让系统"说清为什么拒绝",再考虑"要不要拒绝更多"。
我一直在用一条判据检查自己的设计:
这一处,让我更能放心d委托了吗?
约束越完整,可委托的范围越大。这是我一直相信的。
但这两个案例补上了它的另一面:
约束的可委托性,不只取决于约束是否完整,还取决于约束是否可理解、可退出、可回退。
一个 Agent 撞上约束后,如果它知道:
那它不会去绕路。它会照做。
反之,一个"你不知道为什么被拒、也不知道该怎么办"的约束,即使再严密,也只会逼出更聪明的绕路。
我们最初以为问题是"限制太多"。
后来发现不是。是限制没有出口。
好的约束不是把路堵死,是把路标清楚。
Codex 的 reasoning.effort 如何权衡推理质量、Token 成本与响应延迟?
Codex 的 Reasoning Effort 应如何在 low、medium、high 与 xhigh 之间选择?
Pi Agent 能否替代 Codex CLI 作为 Codex 的 Agent Harness?
Claude Agent 的使用方式需要遵守哪些账号政策?
让 Agent 记住上下文:用 token 预算、轮次裁剪和滚动摘要管理多轮历史
Linux入门学习之通过vmware虚拟机安装ubuntu系统的方法