ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Qwen Code 工具执行状态(Tool Execution Status)设计解析:从终端状态到真实执行结果的精确度量

Qwen Code 工具执行状态(Tool Execution Status)设计解析:从终端状态到真实执行结果的精确度量 Qwen Code 工具执行状态Tool Execution Status设计解析从终端状态到真实执行结果的精确度量【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code导读在 Qwen Code 这类终端 AI 编码代理中工具调用tool call是 Agent 与文件系统、Shell、MCP 服务器交互的基本单元。传统的遥测体系只记录这次工具调用最终成功、失败还是被取消的终端状态却无法回答一个更关键的问题调度器是否真的进入了invocation.execute()执行体参数校验失败、权限拒绝、执行失败与执行后处理失败在终端状态上都是error但它们对排障、SLO 与模型行为的意义完全不同。本文基于 docs/design/2026-07-31-tool-execution-status.md 设计文档结合仓库源码Core 调度器、ACPSession.runTool、遥测指标与 Span 实现、测试用例完整解析executionStatus契约的动机、语义、遥测落地方式与兼容性约束。读完你将理解Qwen Code 如何用终端状态 × 执行状态双轴描述一次工具调用如何据此构建不含取消与未执行噪音的执行失败率 SLI以及埋点在CoreToolScheduler与 ACPSession.runTool中的具体实现与已知维护风险。动机终端状态无法回答是否真的执行了设计文档开篇点明了问题的根源2026-07-31-tool-execution-status.mdThe terminal tool-call status describes whether the overall call succeeded, failed, or was cancelled. It does not say whether the dispatcher actually enteredinvocation.execute().终端的tool-call status只描述整次调用最终是成功、失败还是被取消它不区分调度器是否真正进入了invocation.execute()。由此以下四类本质不同的失败被混为一谈校验失败Validation failures工具参数不符合声明式工具 schema调用尚未进入执行体权限拒绝Permission rejection被权限规则、hook、Plan 模式拦截执行体从未运行执行失败Execution failuresexecute()已进入但工具本身抛错或返回错误结果执行后处理失败Post-execution failures工具执行成功但后续的 hook、结果桥接、持久化等环节出错。如果只依赖终端状态这四类全部坍缩为error无法被准确度量、归因与优化。因此设计引入独立的执行结果execution outcome维度在终端状态之外单独记录执行层面的成败。契约executionStatus四态与双轴正交模型字段与类型定义ToolCallResponseInfo携带一个可选的executionStatus字段取值空间为四态联合类型。该类型定义在 Core 的 packages/core/src/core/turn.ts#L159-L163export type ToolExecutionStatus | not_started | success | error | cancelled;ToolCallResponseInfo本身在 turn.ts#L165-L179 中声明其中executionStatus?: ToolExecutionStatus为可选字段以保持与旧录制JSONL recording、第三方生产者及子代理结果投影的源码与录制兼容性。字段语义not_started调度器从未进入invocation.execute()校验失败、权限拒绝、计划模式拦截、重复 callId 等前置拒绝均属此类successexecute()正常完成errorexecute()已进入但执行失败cancelled执行前、执行中或执行后被取消。谁写入、谁变成 unknown设计明确规定CoreToolScheduler与 ACPSession.runTool总是写入该字段——它们是内置生产者的唯二入口旧录制older recordings、第三方生产者、子代理结果投影非交互buildResponse路径即重放另一个 Agent 报告的结果可能缺失该字段缺失值只在遥测边界telemetry boundary归一化为unknown且绝不从终端调用状态推断——例如终端error不会自动补一个error执行状态因为前置拒绝与真实执行失败无法从终端状态区分。终端状态与执行状态的正交关系两条轴刻意保持独立设计文档给出了完整的组合矩阵Terminal statusExecution statusExamplesuccesssuccessNormal tool completionsuccessnot_startedProtocol-level synthetic sibling responseerrorany valuePre-execution denial, execution error, post-processing error, or batch-hook overridecancelledany valueCancellation before, during, or after execution按terminal, execution二元组逐行解读唯一非法的组合是success/error与success/cancelled一次以success终结的调用执行状态只能是success或not_started。例如协议层合成的兄弟响应synthetic sibling response以终端success返回但从未执行对应success/not_started而执行失败、批量 hook 覆盖等一律以终端error呈现此时执行状态可以是任意值。执行状态冻结时机与批量快照冻结时机执行状态在invocation.execute()落定settle时冻结之后的 hooks、结果桥接result bridging、持久化persistence、批量处理batch processing均不能覆盖它。这意味着executionStatus精确反映执行体本身的成败不受下游处理影响批量快照PostToolBatch的启用状态及其父工具 Span 在调度器某批batch启动时快照snapshot。运行期重新配置 hooks 只影响下一批不会改变在飞批次的完成行为避免边跑边改配置导致同一批内行为不一致。遥测落地事件归一化、执行计数器与执行 Spantool_call事件的归一化规则归一化后的tool_call事件新增call_id与execution_status两个维度且在任何 sink 之前只归一化一次。事件类型定义见 packages/core/src/telemetry/types.ts#L177-L266其中call_id第 180 行与execution_status第 187 行均为可选字段构造器在 types.ts#L224-L225 处直接取call.status与call.response.executionStatus并保留success布尔字段以向后兼容。归一化规则设计文档原样列出实现见ToolCallEvent构造器空工具名empty tool names→unknown_toolsuccess由终端status重新计算success status success见 types.ts#L226终端错误但缺少错误类型 → 使用unknownsuccess与cancelled省略调用级错误字段error/error_type只在error时携带缺失的执行状态 →unknown。qwen-code.tool.execution.count与执行失败率原有的qwen-code.tool.call.count计数器终端status维度由终端遥测契约确立保持不变继续服务既有看板新增计数器qwen-code.tool.execution.count只使用execution_status与tool_type两个事件级维度。其指标定义见 packages/core/src/telemetry/metrics.ts#L102-L110[TOOL_EXECUTION_COUNT]: { description: Counts tool execution outcomes., valueType: ValueType.INT, assign: (c: Counter) (toolExecutionCounter c), attributes: {} as { execution_status: ToolExecutionStatus | unknown; tool_type: native | mcp; }, },全局配置的公共指标属性如 opt-in 的session.id也可能附加出现。session.id默认不附加因为每个 session 都是新值会产生无界的时间序列扇出需要通过QWEN_TELEMETRY_METRICS_INCLUDE_SESSION_ID或telemetry.metrics.includeSessionId显式开启见 metrics.ts#L72-L86 的注释。执行失败率execution failure rate定义execution_status error ──────────────────────────────────────── execution_status in {success, error}分母只取{success, error}显式排除cancelled、not_started与unknown——取消和未执行都不算执行失败这正是引入执行状态的核心价值。该计数器有两个刻意的信息边界错误类型、函数名、call ID、消息与 MCP 服务器名留在日志或 Span 中不进指标标签故意省略function_name维度仅凭指标无法把执行失败率归因到具体工具需要下钻tool_call日志同时携带call_id与function_name定位具体工具。这是隐私与基数控制的权衡——若把函数名放进标签指标基数将随工具集膨胀。执行 Span仅存在于execute()被尝试之后执行 Span只在调度器尝试execute()之后才存在它记录工具身份tool identity、冻结的执行状态与执行错误类型父工具 Spanparent tool span继续代表终端调用状态被取消的 Span 保持未设置UNSET而非 error——取消不是错误见 packages/core/src/telemetry/session-tracing.ts 中setToolSpanCancelled对SpanStatusCode.UNSET的使用Core 在工具解析与调用校验之后才打开父 Span更早的终端路径如解析前被拒由归一化事件与执行计数器覆盖不会从未解析的请求名合成 Span避免为根本未执行的调用伪造可观测对象。实现上执行 Span 的启停由startToolExecutionSpan/endToolExecutionSpan完成session-tracing.ts#L1241 与 session-tracing.ts#L1302endToolExecutionSpan在 session-tracing.ts#L1337-L1338 处将execution_status写入结束属性并根据执行状态决定错误/成功语义。QwenLogger 的字段边界QwenLogger接收归一化后的终端状态、执行状态、call ID 与工具类型但不接收 MCP 服务器名与函数参数。MCP 服务器名保持在 QwenLogger 之外仅提供给已配置的遥测日志与 Span 导出器exporter。这延续了隐私优先的设计日志系统不沉淀工具入参与服务器拓扑信息。兼容性与范围可选字段、JSONL 与调度器行为变化字段可选性与内部必填形状公开的 response 与事件字段保持可选内置生产者CoreToolScheduler、ACPSession.runTool内部使用必填形状。例如CoreToolScheduler内部定义CoreToolCallResponseInfo ToolCallResponseInfo { executionStatus: ToolExecutionStatus }packages/core/src/core/coreToolScheduler.ts#L550-L552强制内置路径必须携带执行状态旧 JSONL 录制不迁移、不回溯填充新录制在工具结果中写入executionStatus字段是加性的additive忽略未知字段的回放读取器replay readers不受影响Core、ACP、TUI 与非交互模式的手动录制投影manual recording projections拷贝该标量但不在面向用户的 JSON 输出中暴露——用户可见输出保持稳定。CancelledToolCall的可选字段与工具类型偏差在工具解析tool resolution之前被取消的调用其公开的CancelledToolCall变体可以省略tool与invocationcoreToolScheduler.ts#L601-L609 中两者均为可选消费方必须先守卫再使用此类解析前取消经遥测发出时tool_type默认native因为工具身份尚未解析——这是tool_type维度在预校验取消场景的已知偏差known skew下游统计时需留意。调度器错误语义的变化单工具失败不牵连兄弟调用设计文档明确改变了CoreToolScheduler.schedule()的错误语义逐调用执行错误不再 rejectschedule()结果通过既有的 update 与 completion 回调以终端error调用形式交付——一个工具失败不会中止其兄弟调用siblings方法仍返回Promisevoid且仍可因调度器级 setup 或队列失败而 rejecthandleConfirmationResponse()在 rethrow 之前将确认流错误终态化terminalize既保留既有失败信号又不让调用停留在awaiting_approval状态嵌入方embedders应从回调交付的调用中读取终端status与executionStatus不要指望任一公开入口返回已完成的调用。首发范围第一版覆盖CoreToolScheduler与 ACPSession.runTool。以下内容明确不在范围内推测执行speculation、直接/fork执行、MCP 内部重试、临时子代理结果对账provisional subagent result reconciliation、Shell 退出元数据、重试性retryability、所有权ownership与通用失败阶段。发布与看板切换要求Core 与 ACP 必须一起发布ship together——两者同时写入该字段避免新旧混合部署产生不一致看板应在部署时间或service.version切换单独监控unknown缺失值比例是数据质量信号绝不要用旧的success指标作为执行失败 SLI——它是终端语义无法区分执行失败与前置拒绝。源码印证两处生产者的实现细节Core 调度器写入、默认值与执行状态流转CoreToolScheduler是 Core 侧唯一生产者。从源码可见其执行状态流转初始默认let executionStatus: ToolExecutionStatus not_startedcoreToolScheduler.ts#L5170执行体捕获异常时置为errorcoreToolScheduler.ts#L5266、#L5309取消abort路径判定executionStatus aborted ? cancelled : errorcoreToolScheduler.ts#L6307并在异常类型缺失时用exceptionErrorType补充错误类型#L6328执行状态写入响应后随回调交付同时在日志调用处透传execution_status: response.executionStatuscoreToolScheduler.ts#L1120无执行状态的历史响应在重建错误响应时回退not_startedcoreToolScheduler.ts#L1294-L1305。此外重复 provider callId 的防御路径通过createNotStartedToolErrorResponseturn.ts#L255-L276生成executionStatus: not_started的响应——重复调用被拒绝时从未执行语义准确。ACPSession.runTool同一契约的第二生产端ACP 集成侧 packages/cli/src/acp-integration/session/Session.ts 同样强制内部元数据携带executionStatus第 720-722 行类型约束并在录制投影第 11438 行、缺失回退not_started第 11652 行、执行状态从not_started起始第 12097 行以及执行错误/取消判定第 13787、13905 行等位置与 Core 保持一致确保跨层语义统一。测试验证四态全覆盖packages/core/src/core/coreToolScheduler.test.ts 对执行状态进行了系统性断言四态均有覆盖success正常完成第 2261、2325、6587、12788 行等error执行失败第 2316、2378、12826、13473、13614 行等cancelled取消第 13508、13528、13556 行等not_started权限拒绝第 11553 行、取消于解析前第 9756、11624 行、批量中未执行第 4206、4265、4316 行、重复 callId 拒绝第 4777 行等前置拒绝场景。这些断言直接印证了设计文档的核心主张前置拒绝一律not_started执行失败才error两者在终端上都是error却能在执行轴区分。已知维护风险手埋的解析前取消不变量设计文档在末尾坦承了最重要的维护隐患The pre-execution cancellation invariant (everyawaitin the pre-execution path is followed by an abort check) is enforced by hand-placed checks at each call site inCoreToolSchedulerandSession.runToolrather than by a structural mechanism.执行前取消不变量每个执行前路径的await后必须跟随一次 abort 检查由CoreToolScheduler与Session.runTool中各调用点手埋检查保障而非结构性机制。后果是任一路径新增一个没有后续检查的await会静默重新引入本设计修复的过期执行stale-execution缺陷——取消信号到达后旧代码路径仍继续执行。设计文档给出的演进方向是未来重构应将await包裹进带守卫的 helper在此之前这两个路径的评审者必须手动核对不变量。小结executionStatus是 Qwen Code 遥测体系中一次语义精确化的设计它把一次工具调用拆成终端状态调用整体结局与执行状态execute()是否真正发生、结果如何两条正交轴使校验拒绝、权限拒绝、执行失败、执行后失败从混同的error中分离出来从而构建出干净的执行失败率 SLI。其落地遵循严格的边界纪律字段可选、内置生产者必填、缺失值仅在遥测边界归unknown、执行状态在execute()落定时冻结、执行 Span 只在实际执行后存在、指标故意省略function_name以控制基数。若你正在为 Agent 工具调用体系设计可观测性本文的契约矩阵、归一化规则与失败率定义可直接作为参考蓝本若你要为 Qwen Code 贡献代码请务必遵守解析前取消不变量与Core/ACP 同步发布的约束。延伸阅读本文的设计源头文档 docs/design/2026-07-31-tool-execution-status.md类型与响应契约见 packages/core/src/core/turn.ts调度器实现见 packages/core/src/core/coreToolScheduler.tsACP 生产者见 packages/cli/src/acp-integration/session/Session.ts指标与事件定义见 packages/core/src/telemetry/metrics.ts 与 packages/core/src/telemetry/types.tsSpan 实现见 packages/core/src/telemetry/session-tracing.ts行为验证见 packages/core/src/core/coreToolScheduler.test.ts。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表