Skip to content

[code-review] openai.go 并行 tool call 按 Go map 随机序发射,agent 侧按到达顺序串行执行——模型 idx 顺序意图丢失,回放非确定(medium) #4244

Closed

Description

@topcheer

独立复核确认(初審 sa-137 + 复核 sa-141 双重验证)

问题

OpenAI provider 并行 tool call 的发射顺序由 Go map 随机遍历决定,模型 idx 表达的顺序意图丢失。

事实链

  1. 累积容器是 map:internal/provider/openai.go:732 toolCalls := make(map[int]*ToolCallDelta)(key = 模型原始 idx)
  2. 两处发射循环直接遍历 map(Go map 遍历顺序被 runtime 主动随机化):
    • openai.go:904-921(finish_reason=tool_calls 到达时)
    • openai_stream_flush.go:23-47(残留 flush 路径)
  3. 下游按到达顺序赋予语义,无任何重排:
    • internal/agent/agent.go:6055-6063:按事件到达顺序 append 到 toolCalls slice 与 content []ToolUseBlock(全库 grep 无 sort.*Index 消费点)
    • agent.go:3938:副作用工具严格按 slice 顺序串行执行(只读工具才有 pre-execute 并行)
  4. 跨 provider 不一致:Anthropic(anthropic_stream_dispatch.go:139 按块序)与 Gemini(gemini.go:502 按流序)均保序,仅 OpenAI 路径随机

触发场景

模型一条 assistant 消息返回 2+ 并行 tool call(delta.tool_calls[{index:0,...},{index:1,...}],args 分片累积,finish_reason="tool_calls")→ 发射循环遍历 map → 同一流每次解析顺序不同(2 call 时约 50% 颠倒)。

危害(medium)

  • 顺序敏感的耦合批次(mkdir→write_file、git_add→git_commit 等模型用 idx 表达意图的对)以随机顺序执行且无告警;batch-coupling 检测器只警告不重排
  • 同输入非确定输出:会话转录/回放顺序每次不同,破坏 deterministic-replay 与评测可重复性
  • 协议层安全(tool result 按 tool_call_id 配对),无崩溃/错配——故非 high

修复方向

两处发射循环前按 key 排序:

for _, idx := range slices.Sorted(maps.Keys(toolCalls)) { ... emit ... }

openai.go:904 与 openai_stream_flush.go:23 同改,下游无需改动。

severity: medium | 来源:本轮 provider 深读初審 + 独立复核 subagent 双确认

Activity

  1. topcheer commented on Oct 16, 2026

    @topcheer
    OwnerAuthor

    复核坐实+已修:PR #4247(两发射循环 keys 排序,伴测 50 轮重排断言发射序恒定)。跨 provider 一致性恢复(Anthropic/Gemini 均保序)。

  2. added a commit that references this issue on Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions