Joye Dev

Back

feat(agent): gate advanced image models behind user confirmation

**PR:**feat(agent): gate advanced image models behind user confirmation (#4580)


正文来源:飞书学习文档。以下为通过个人 Feishu API 获取并转换后的完整 Markdown 正文。

Voyager Merged PR 学习 - 2026-07-10 - PR #4580#

今日选择#

**PR:**feat(agent): gate advanced image models behind user confirmation (#4580)

**作者:**Horcrux / magicismight

**Merge 时间:**2026-07-09T17:18:42Z(Australia/Melbourne 2026-07-10 03:18:42)

链接:https://github.com/adastralab-ai/voyager/pull/4580

**模块:**backend/workers/agent/src/tools, backend/workers/agent/src/prompts, backend/workers/agent/src/routes, agent-eval/cases/image, agent-eval/asserts

**学习标签:**agent-runtime, image-generation, user-confirmation, credit-control, tool-schema, terminal-result, agent-eval

为什么值得学#

  • 它把“高级模型更适合”从 agent 自主决策改成用户授权协议:模型只能触发确认卡,不能在同一轮直接传 advanced modelId。
  • 它没有只靠 prompt 约束,而是在 image_generation runtime 里加 guard:未授权的 2K/4K + Lite 组合终态失败,不再静默升级或静默降级。
  • 它把失败结果的 message 透传给模型,避免把业务 guard 错误归因为“服务临时故障”。
  • 它同步更新 eval harness:记录 toolSequence、暴露 choice card、引入 noAdvancedImageArgs 断言,测试的是协议行为而不是最终文本。

关键代码#

1. tool schema 把授权规则前置#

**文件:**backend/workers/agent/src/tools/toolDefs.ts,PR diff hunk @@ -262 和 @@ -273

.describe(
  "Optional; unset renders 1K on the default model... Resolutions above 1K run only on advanced models, so they follow the same approval rule as modelId... without one the call fails."
)

.describe(
  "Optional. NEVER set this yourself: advanced models ... are only ever the user's decision. Pass an advanced modelId only when the user pinned that model ... or answered a request_user_choice..."
)
plaintext

设计点:把 tool 参数说明从“模型自己挑合适模型”改成“模型只能执行已授权选择”。这类约束必须写在 schema/tool description 层,因为这里是模型决定参数的最近边界。

2. runtime guard 删除静默升级路径#

**文件:**backend/workers/agent/src/tools/imageGenerationTool.ts,PR diff hunk @@ -81

const resolvedModelId = modelId ?? imageModelId ?? DEFAULT_IMAGE_MODEL_ID;
if (resolution != null && resolution !== "1K" && resolvedModelId === NANO_BANANA_LITE_IMAGE_MODEL_ID) {
  return {
    status: "failed",
    reason: "error",
    errorCode: "resolution_requires_approved_model",
    message: "The requested resolution needs an advanced image model, which only the user can approve...",
  };
}
plaintext

设计点:之前 explicit 2K/4K 会把 fallback model 升到 gpt-image-2;现在如果没有 pin 或 card approval,就终态失败。这样 credit spending 的边界从 prompt 约束变成 runtime invariant。

3. failure message 作为恢复指令传给模型#

**文件:**backend/workers/agent/src/tools/imageTaskTool.ts,PR diff hunk @@ -47

value:
  output.message ??
  `The image service failed server-side (${output.errorCode ?? "unknown error"}) ...`,
plaintext

设计点:同样是 failed/error,业务 guard 和后端临时故障需要不同恢复策略。允许 tool result 携带 message 后,模型能把“去询问用户授权”当成下一步,而不是把它讲成服务失败。

4. eval 断言禁止未授权高级参数#

**文件:**agent-eval/asserts/noAdvancedImageArgs.ts,新增文件 @@ -0,0 +1,41

const offending = seq
  .filter((step) => step.name === "image_generation")
  .map((step) => ({ modelId: step.input?.modelId, resolution: step.input?.resolution }))
  .filter((args) => ADVANCED_MODELS.has(args.modelId ?? "") || ADVANCED_RESOLUTIONS.has(args.resolution ?? ""));
plaintext

设计点:eval 不再只看最终回答是否“看起来合理”,而是读 trajectory metadata,确认 agent 没有偷偷把高级模型或高分辨率塞进 tool args。

和最近学习记录的关系#

有直接关系。最近几条学习记录围绕 image generation 的跨层契约展开:#4314 把 gpt-image-2 迁到 AI Gateway route;#4344 把附件图作为 referenceAssetIds 进入工具边界;#4309 把 Nano Banana Lite 作为跨层 model contract;#4516 把 terminal image failure 表达成结构化结果;#4389 把 home composer 的 creation directive 和 image model routing 接进 agent protocol。

#4580 是这条链路的 credit-control / approval-control 后续:当 composer 或对话能影响 image model 时,系统必须区分“模型觉得应该升级”和“用户已经授权升级”。它把这个区别落在 prompt、tool schema、runtime guard 和 eval 四层。

我会怎么吸收#

  • 涉及成本、权限、外部副作用的 agent 工具,不要只靠 prompt。需要把“未授权不可执行”写成 runtime guard,并返回模型可恢复的结构化失败。
  • 用户偏好或 pin 不是绝对锁。更好的模型是“强默认 + 明确条件下重新询问”,这样既尊重用户选择,也保留处理超出能力请求的空间。
  • eval 应该抓 tool trajectory,而不是只评估 finalText。特别是 agent 协议类需求,关键回归通常藏在 tool args 里。

边界/风险#

  • PR 自己说明单轮 harness 覆盖不了多轮状态:例如“本次对话都使用”后的后续轮、拒绝后不重复询问、对已生成结果不满意后重新打开选择,这些还需要线上或多轮 eval 覆盖。
  • modelId description 很长,短期可控,但长期可能变成高熵 prompt 规则堆叠;后续如果确认协议稳定,可以考虑把 approval state 做成更显式的 runtime/session state。
  • PR 还发现 place-generated-image eval 的旧断言和 main 上 skill 行为不一致,这不是本 PR 风险,但说明 image eval 套件仍有历史债。

候选说明#

今天(Australia/Melbourne 2026-07-10)窗口查到 6 个 merged PR;昨天窗口查到 15 个。最终选 #4580,因为它有明确的工程设计:用户授权、成本控制、tool/runtime 双边界和 eval 验证。#4581 与它同主题但更偏 composer UI/入口;#4582 是 media panel source tabs;#4592 是 2 行 focus 小改;#4544/#4424 偏 brand/settings polish。日志里已记录 #4389,因此跳过去重,没有重复讲。

🗂️ 这是知识库中的🔬 研究。

内容可能仍在补充或修订中。

← Back