工具计划与调度:规格、执行契约和并发门
工具何时可见、由谁执行,以及异步完成如何与请求历史对应。
学完你能做到
- 理解工具规格与执行实现的区别
- 解释 如何关联请求与结果
- 识别门与取消路径
本课目录 · 3 节
先有可用列表,再有执行入口
可见的工具规格说明工具名称、参数形状和用途。则关联工具身份与具体 。ToolRouter 持有与可见规格,负责判断暴露方式和分派请求。规格与执行实现必须对应,否则会请求不存在或不可用的能力。
这个版本支持直接暴露、延迟发现和 等方式。 指用代码组织调用的执行方式,不意味着任意工具都绕过框架。是否可用取决于本步工具计划、配置与功能开关。
解析:先保留身份
pub fn build_tool_call(item: ResponseItem) -> Result<Option<ToolCall>, FunctionCallError> {
match item {
ResponseItem::FunctionCall {
name,
namespace,
arguments,
encrypted_function_args,
call_id,
..
} => {
let tool_name = ToolName::new(namespace, name).with_default_namespace();
Ok(Some(ToolCall {
tool_name,这段是函数类调用的解析入口。后面的代码把参数装入 ToolPayload,并保留 。其他输出类型还有不同分支。
查看原文及相邻代码 ↗是一次调用的关联标识。工具名称可能有;仅看短名称不足以区分来源。参数解析不等于权限检查,成功解析也不等于执行成功。
调度:并发是显式能力
ToolCallRuntime 先询问工具是否支持。支持者取得共享读;不支持者取得独占写。因此多项调用可以交错推进,但并不是“一批调用全部同时跑”。执行门之前的就绪等待也能被取消。
if supports_parallel {
Either::Left(lock.read().await)
} else {
Either::Right(lock.write().await)
}共享与独占访问是这段调度的核心。相互依赖的操作仍应等待前一个结果,不应因为可就忽略数据依赖。
查看原文及相邻代码 ↗实际执行交给注册的实现。框架还处理开始、结束、和结果记录。在循环中,完成的结果按对应顺序收集;执行结束顺序、界面显示顺序和历史里的顺序不一定是同一个概念。
沿着源码读
以下定位均锁定本课程版本。先读注释与分支,再深入类型定义。
- 路由结构持有哪些内容
codex-rs/core/src/tools/router.rs:91–100 - 并发能力与调用解析
codex-rs/core/src/tools/router.rs:245–275 - 核心工具执行契约
codex-rs/core/src/tools/registry.rs:57–100 - 等待、执行门与分派
codex-rs/core/src/tools/parallel.rs:190–245 - 工具计划构造模块
codex-rs/core/src/tools/spec_plan.rs:1–45
实现推演
你想先读取两个独立文件,再根据读取内容修改一个文件。把这三件事分成可以共同推进的一组,以及必须等待的一步,并解释原因。
阅读练习无需模型账号。示例命令请先确认目录与环境。
自测与边界检查
为什么“工具支持”还不足以证明三步都能并行?
展开自测答案
支持标志只是执行层能力。修改依赖读取结果,存在数据依赖,必须等待相关读取完成。
工具规格是不是工具代码?
展开自测答案
不是。规格告诉如何请求能力;注册的实现完成执行。二者要保持名称、参数和能力边界一致。