provider 模式下 tool-plan 请求恒为非流式,llm.stream 配置对其不生效
#186
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
provider 模式下 tool-plan 请求恒为非流式,
llm.stream配置对其不生效摘要
agentMode: provider时,tool-plan / 强制动作类请求永远走非流式(client.run()),配置项llm.stream在这条路径上只被写进审计记录和重试指纹,不驱动任何行为。对只接受流式请求的 OpenAI 兼容网关,这导致第一发请求就确定性失败,且因为返回 400 不在可重试状态集合内,不会重试,2 秒内整轮结束。
这不是上游抖动——同一配置下 100% 复现。
现象
配置:
启动立项策划后约 2 秒:
runtime 事件流(
.agent/runtime/events/project-supervisor.jsonl):agent.db中无任何provider_request.retry/retry_waiting记录——一次都没重试。lifecycle 只有一对started → failed(slotloop-1-repair-0),没有-transient-N。根因
1. 上游拒绝的是非流式请求
平台层自带 raw failure log(
logs/llm-raw/,相对进程 cwd,可用环境变量LLM_RAW_LOG_DIR覆盖)原样保留了上游响应:logs/llm-raw/<ts>-<pid>-<seq>-upstream_status_failed.output.txt同名
.input.json记录了我们实际发出的请求:该请求体是 plan 根 Supervisor 的第一发 tool-plan,被阶段策略强制为只能调用
agent.goal_contract(maxOutputTokens = 2000对应AGENT_RUNTIME_AUTONOMOUS_FORCED_ACTION_MAX_OUTPUT_TOKENS)。2.
LlmRunRequest没有stream字段server-rs/crates/platform-llm/src/lib.rs:167—— 流式与否不是请求的属性,而是由调用哪个方法决定:LlmClient::run()(lib.rs:1528)—— 非流式LlmClient::stream_run()(lib.rs:1574)—— 流式3. 全仓库只有三处走流式
apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_final_reply.rs:274apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver/entrypoints.rs:522apps/ai-game-creator-shell/src-tauri/src/agent/generation/loop_orchestration.rs:499tool-plan 走的是
apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/provider_retry.rs:1700:4.
llm.stream在这条路径上只被"记录"同文件内仅两处引用,均不影响行为:
provider_retry.rs:515—— 写进PlanProviderRequestContextValue.stream审计字段provider_retry.rs:627—— 参与 Provider 重试配置指纹的 sha256也就是说,审计记录会显示
stream: true,而实际发出的请求是stream: false——审计与事实不一致,这本身也值得单独关注。5. 400 不可重试,所以秒挂
重试状态白名单只含 429 / 500 / 502 / 503。本次是 400,直接终态失败。
对比:同一网关早前一次失败返回的是 500(
do_request_failed),属于可重试,运行时转了一圈-transient-1后才失败,耗时 4 秒。两者的差别只是"挂得多快",最终都失败。三种模式组合的表现
codex_app_serverprovider复现步骤
agentMode设为provider,apiKind设为openai_responsesbaseUrl指向一个要求stream=true的 OpenAI 兼容网关llm.stream设为truelogs/llm-raw/下最新的*-upstream_status_failed.*一对文件期望行为
以下二选一:
A. 让
llm.stream真正生效 —— tool-plan 等 provider 请求按配置走stream_run()。代价较大:流式响应下的工具调用装配、
reject_incomplete_tool_calls的判定时机、tool-plan 协议解析都要走另一套路径。该路径为 provider 模式下所有 Agent 共用,改动面覆盖全部创作链路。B. 让配置面诚实 —— 在配置校验层明确
llm.stream仅作用于最终回复/聊天/生成循环,对 tool-plan 无效;或在agentMode=provider且stream=true时给出提示。代价小,无行为变更,但不解决网关可用性。
附注
审计字段与事实不一致
PlanProviderRequestContextValue.stream与 Provider 重试指纹都记录llm.stream的配置值而非实际值。排查时若只看审计记录会被误导(本次即是如此——审计显示stream: true,实际发出stream: false,只有 raw log 暴露了真相)。raw failure log 目录会持续增长
排查时发现
apps/ai-game-creator-shell/src-tauri/logs/llm-raw/已累积 3278 个文件,无轮转或清理机制。每次失败写入一对.input.json+.output.txt,其中.input.json通常数十 KB。建议评估是否需要保留上限。该网关本身另有稳定性问题(不同问题,建议分开跟踪)
同一网关在
codex_app_server模式下可运行,但实测:needs-reconciliation195 秒这个时长与本仓库任何超时配置都不匹配(
requestTimeoutMs600s、Codex RPC 30s、Codex direct 900s/6600s/7200s),推测为网关侧连接保持上限。