plan 根不再维护结构化计划,砍掉 update_agent_plan

run 19 跑通全链路用了 14 轮,其中只有 5 轮在干活:goal_contract、delegate、
file.read、action_history、acceptance_update。浪费的 9 轮里有 5 轮是纯
plan_update.explanation_only——Runtime 明确标了这个事件——每轮 blocked、每轮烧一次
Provider 调用。

plan 根的流程形状是固定的四步(冻结 → 委派 → 取证 → 交审批),Runtime 自己就知道,
模型维护一份结构化计划不产生任何信息,却提供了一个「看起来像动作、实际什么都不
推进」的合法输出。本地原型没有这个概念,它的工具全是推进动作,也就没有这种输出。

移除不会卡住收束:structured_plan_completion_blocker 第一行就是
agent_runtime_has_structured_plan(plan_revision > 0),从不调用就恒为假,那道门
不参与;plan 根的收束本来就由 runtime.plan_gdd 的审批门管。前端 planSteps 为空时
不渲染步骤条,plan 根的进度改由 current_action / waiting_on / next_step 呈现。

既有的空转自愈本来就会在连续空转后把这个函数摘掉(provider_request_builders 的
idle repair),run 19 第 12 轮那次 acceptance_update 正是被它救回来的。这次只是把
「出事后补救」提前成「从头就不给」。

一并清掉两段已经失效的合同文字:plan/common.md 里的 user.input_request 协议段
(该工具上一笔已从 plan 根移除),以及 update_agent_plan 的用法段。prompt 头部
改成说明「本 run 不维护结构化计划,流程形状固定,每轮只做当前阶段该做的那件事」。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-21 08:33:10 +00:00
parent a021f18b98
commit 2bdf6a732b
3 changed files with 25 additions and 15 deletions
@@ -1,10 +1,8 @@
用户只描述玩法类型、机制或相似体验时,不代表授权复刻现有游戏。所有专业 Agent 必须创建原创标题、阵营、资源、单位名称、角色造型、界面术语和视觉语言;禁止沿用、翻译或近似改写现有游戏的专有角色、单位名、Logo、贴图、标志性布局与受保护视觉语言。除非用户明确提供有权使用的项目内素材,否则不得把 Sunflower、Peashooter、向日葵、豌豆射手、僵尸等知名塔防元素写入策划、记忆、代码、图片提示或正式产物。
用户输入请求协议:user.input_request 使用 {"questions":[{"id":"唯一 snake_case","header":"最多 12 字符","question":"单句问题","options":[{"label":"短选项","description":"一条影响说明"},{"label":"另一选项","description":"一条影响说明"}]}]},一次 1-3 题、每题 2-3 个选项且始终允许自由输入。它必须是本轮唯一函数调用,不得同批调用 update_agent_plan、其他动作函数或 respond_to_user。只有 Project Supervisor 或没有父委派身份的静态 Agent 开发试聊可直接调用;委派专业 Agent 和动态隔离 child 必须把澄清需要回传父 Agent。
静态委派协议:新 agent.delegate 必须提交 1-8 条 acceptanceCriteria、0-16 个精确项目内非私有 expectedArtifacts,以及 nullable repairOfDelegationId/runId/continuationOfDelegationId/questionsSha256/answersSha256,普通委派后三项传 null。专业 Agent 收到的 task 会携带完整合同。Supervisor 认领回执后必须区分 evidence-ready、needs-user-input 与 needs-repair;前者仍需语义验收,needs-repair 不能作为成功。专业 Agent 若缺少会实质改变结果的用户事实,不能调用 user.input_request,必须以最终回复首行 `AGC_NEEDS_USER_INPUT_V1`,下一行短 JSON `{"questions":[...]}` 返回 1-3 个结构化问题;Runtime 会把它作为内部回执交给 Supervisor。Supervisor 对每个原 delivery 逐一用现有 user.input_request 提问,收齐对应答案后最多创建一次 continuation 委派,并同时提交 continuationOfDelegationId、questionsSha256、answersSha256Runtime 会自动派生稳定 continuation identity,不得把多个 delivery 的问题或答案混入同一 continuation。
每 6 轮只是一次进度 checkpoint 与停滞检测,不是上下文压缩或 run 的终止上限;只要 observation 出现新的独立进展,就在同一 run 继续下一窗口,只有窗口没有新进展时才按停滞处理。真正的上下文压缩仅由 token 阈值或显式 compact 触发。
必须直接调用 update_agent_plan、与当前请求广告的工具一一对应的动作函数 respond_to_user;只有步骤或状态真实变化时,update_agent_plan 才可单独作为持久进度 checkpoint;当前 in_progress 步骤已具备执行条件时,必须在同一响应附带具体动作,不能反复只改 explanation。update_agent_plan 也可在同一响应中按顺序附带最多三个动作或最终回复,动作与最终回复不得共存。工具结果会由 Runtime 作为 observation 返回不要假装工具已执行,不要把计划、动作或回复放进普通文本,不要 markdown,不要泄露密钥。
必须直接调用与当前请求广告的工具一一对应的动作函数,或在本阶段确实无事可做时调用 respond_to_user。本 run 不维护结构化计划,也没有 update_agent_plan 可调;工具结果会由 Runtime 作为 observation 返回不要假装工具已执行,不要把动作或回复放进普通文本,不要 markdown,不要泄露密钥。
@@ -620,7 +620,7 @@ fn game_creator_project_supervisor_plan_tool_plan_system_prompt() -> String {
// 「合同说有、请求里没有」的自相矛盾。
let tool_catalog = agent_runtime_plan_root_supervisor_tools().join("");
let prompt_header = format!(
"你正在使用 Genarrative AI 游戏创作多智能体 Runtime。你必须直接调用当前请求广告的原生函数:复杂任务首次拆解、实际进度变化、steer 调整顺序或最终收束时调用 update_agent_plan,并提交 explanation 与完整 steps;无需更新时不要调用 update_agent_plan。steps 只允许 pending、in_progress、completed 且同时最多一个 in_progress;已完成步骤必须保留且不得回退,所有必要步骤 completed 前不得调用 respond_to_userRuntime 不会按工具动作下标代替你更新进度。本 run 的原生可执行工具目录只有:{tool_catalog},并且**按阶段开放**——每一轮只广告当前阶段能真正推进链路的那几个,没有出现在本轮函数目录里的,这一阶段调用不了,也不需要调用。澄清卡不由你发:子 Agent 的问询信封由 Runtime 直接转成决策卡,你只会在用户答完之后被恢复。写入、补丁、删除、命令、预览、素材生成、任务图、记忆、黑板、isolated child 与 MCP 工具在本 run 都不存在,调用它们只会失败。"
"你正在使用 Genarrative AI 游戏创作多智能体 Runtime。你必须直接调用当前请求广告的原生函数,不要把动作或回复写进普通文本。本 run 不维护结构化计划——流程形状是固定的(冻结目标合同 → 委派策划子 Agent → 取证验收 → 交审批),进度由 Runtime 自己记录,你只需要每一轮做当前阶段唯一该做的那件事。本 run 的原生可执行工具目录只有:{tool_catalog},并且**按阶段开放**——每一轮只广告当前阶段能真正推进链路的那几个,没有出现在本轮函数目录里的,这一阶段调用不了,也不需要调用。澄清卡不由你发:子 Agent 的问询信封由 Runtime 直接转成决策卡,你只会在用户答完之后被恢复。写入、补丁、删除、命令、预览、素材生成、任务图、记忆、黑板、isolated child 与 MCP 工具在本 run 都不存在,调用它们只会失败。"
);
// `$platform` 整段是 command.start/exec/poll/stdin/terminate 的用法合同,
// plan 根一个 command 工具都没有;GDD 里的平台事实由 Runtime 另行注入,与
@@ -1494,9 +1494,10 @@ mod tests {
fn plan_common_paragraphs_are_verbatim_slices_of_the_shared_common_section() {
let common = required_runtime_prompt_section("common");
let plan_common = required_runtime_prompt_section("planCommon");
// `用户输入请求协议` 不再继承:plan 根没有 user.input_request,澄清卡由
// Runtime 在 parent-wake 屏障处按信封原文直接构造。
let inherited = [
"用户只描述玩法类型、机制或相似体验时,不代表授权复刻现有游戏。",
"用户输入请求协议:",
"静态委派协议:",
];
let mut matched = 0;
@@ -378,10 +378,19 @@ pub(crate) fn retain_plan_root_supervisor_native_tools(
functions: &mut Vec<LlmFunctionTool>,
stage: PlanRootSupervisorStage,
) -> Result<(), String> {
let mut allowed = BTreeSet::from([
AGENT_RUNTIME_UPDATE_PLAN_FUNCTION_NAME.to_string(),
AGENT_RUNTIME_RESPOND_FUNCTION_NAME.to_string(),
]);
// plan 根不带 `update_agent_plan`。它的四步流程(冻结→委派→取证→审批)是
// Runtime 早就知道的固定形状,模型维护一份结构化计划不产生任何信息,却提供了
// 一个「看起来像动作、实际什么都不推进」的合法输出:实测一次跑通的 run 里 14
// 轮有 5 轮是纯 `plan_update.explanation_only`,全部被 blocked,每轮烧一次
// Provider 调用。既有的空转自愈本来就会在连续空转后把这个函数摘掉
// `provider_request_builders` 里的 idle repair),这里只是把"出事后补救"
// 提前成"从头就不给"。
//
// 移除它不会卡住收束:`structured_plan_completion_blocker` 第一行就是
// `agent_runtime_has_structured_plan``plan_revision > 0`),从不调用就恒为
// 假,那道门不参与;plan 根的收束由 `runtime.plan_gdd` 的审批门管。前端
// 步骤条为空时不渲染,plan 根的进度改由 current_action/waiting_on/next_step 呈现。
let mut allowed = BTreeSet::from([AGENT_RUNTIME_RESPOND_FUNCTION_NAME.to_string()]);
for tool in agent_runtime_plan_root_supervisor_tools_for_stage(stage) {
allowed.insert(
native_runtime_function_name(tool)
@@ -2160,10 +2169,9 @@ mod tests {
let mut staged = functions.clone();
retain_plan_root_supervisor_native_tools(&mut staged, stage)
.expect("retain plan root tools");
let mut expected = vec![
AGENT_RUNTIME_UPDATE_PLAN_FUNCTION_NAME.to_string(),
AGENT_RUNTIME_RESPOND_FUNCTION_NAME.to_string(),
];
// plan 根只保留 respond_to_user 这一个协议函数;update_agent_plan 从
// 头就不广告。
let mut expected = vec![AGENT_RUNTIME_RESPOND_FUNCTION_NAME.to_string()];
for tool in agent_runtime_plan_root_supervisor_tools_for_stage(stage) {
expected.push(native_runtime_function_name(tool).expect("plan root function name"));
}
@@ -2183,8 +2191,8 @@ mod tests {
.iter()
.any(|function| function.name.starts_with(AGENT_RUNTIME_NATIVE_MCP_PREFIX)));
}
// 广告层不得再出现 user.input_request澄清卡由 Runtime 在 parent-wake 屏障处
// 直接按信封原文构造Supervisor 没有调用它的时机
// 广告层不得再出现 user.input_request澄清卡由 Runtime 在 parent-wake 屏障处
// 直接按信封原文构造)与 update_agent_planplan 根不维护结构化计划)
let user_input_function =
native_runtime_function_name("user.input_request").expect("user input function name");
for stage in [
@@ -2198,6 +2206,9 @@ mod tests {
assert!(!staged
.iter()
.any(|function| function.name == user_input_function));
assert!(!staged
.iter()
.any(|function| function.name == AGENT_RUNTIME_UPDATE_PLAN_FUNCTION_NAME));
}
}