Skip to content
编程开物
编程开物

一段代码,一段Prompt,一物成型。 探索编程、AI应用、架构设计与产品设计,分享工程实践,记录技术学习、工作总结与产品创造。

  • 首页
  • 编程基础
    • 计算机网络
  • 人工智能
    • AI概念和理论
    • 人工智能应用
    • 数据工程
  • 企业架构
    • 传统应用架构设计
    • AI应用架构设计
  • 项目管理
  • 产品设计
  • 技术教程
  • 行业动态
  • 关于我
编程开物

一段代码,一段Prompt,一物成型。 探索编程、AI应用、架构设计与产品设计,分享工程实践,记录技术学习、工作总结与产品创造。

第 7 章 Tool System:给 AI 装上”手和脚”

编码者, 2026年9月17日2026年9月17日

本章目标:深入理解 Tool System——Harness 中连接模型与真实世界的桥梁。掌握工具的本质、Schema 设计、发现/注册/调度/执行的完整链路,以及错误处理、超时、权限、组合等关键机制。


7.1 Tool 的本质

Tool(工具)的本质,用一句话概括:

工具是模型可以请求调用的、由 Harness 实际执行的、带结构化接口的外部函数。

这句话里有三个关键词,每个都值得展开:

  1. “模型可以请求调用”:模型不是”自动调用”工具,而是”请求”调用。模型输出一个工具调用(Tool Calling)请求——工具名 + 参数——运行时框架(Harness)决定是否执行、如何执行。
  2. “由 Harness 实际执行”:模型本身不执行工具,它只生成一串描述”我想调用什么”的 token。真正读写文件、执行命令的,是 Harness 里的函数实现。这个”模型提议、系统执行”的分离,是 Agent 安全架构的基石。
  3. “带结构化接口”:工具通过 JSON Schema 定义接口,模型根据这个接口生成结构化的参数。接口的清晰度,直接决定模型使用工具的正确率。

一个更本质的理解:工具是模型能力的”边界”。模型能做多少事,完全取决于 Harness 给它提供了多少工具。一个没有 Bash 工具的 Coding Agent,无论如何也无法执行命令。所以,设计工具,本质上是设计 Agent 的能力边界。

这个”边界”理解有一个重要推论:工具的取舍,就是能力的取舍。你给了 Agent 一个”删除文件”的工具,就给了它”删除文件”的能力,也给了它”误删文件”的风险。所以工具设计不仅是”加能力”,更是”做权衡”——每加一个工具,都要问”这个能力值得对应的风险吗?”。


7.2 Tool Schema

Tool Schema(工具模式)是工具对模型暴露的接口契约,通常包含三个部分:

  1. name(名称):工具的唯一标识,模型用它来指定调用哪个工具。
  2. description(描述):用自然语言说明工具做什么、何时用、有何限制。这是模型”决定是否调用”的依据。
  3. input_schema(参数模式):JSON Schema 定义参数的结构,模型据此生成参数。

一个完整的工具定义示例:

{
  name: "Read",
  description: "读取指定路径的文件内容。返回文件的完整文本。用于查看代码、配置、文档。",
  input_schema: {
    type: "object",
    properties: {
      file_path: { type: "string", description: "要读取的文件的绝对路径" },
      offset: { type: "number", description: "从第几行开始读(1 起,可选)" },
      limit: { type: "number", description: "最多读多少行(可选)" }
    },
    required: ["file_path"]
  }
}

这里有一个接口的定义形态与接口的传输形态的区别。JSON Schema 是模型看到的形态——请求的 tools 字段里就是它。但在 Claude Code 源码里,工具的作者并不直接写 JSON Schema:inputSchema 是一个 Zod 模式,JSON Schema 只在发往模型 API 的边界上由框架转换出来。让工具作者写类型安全的东西,让框架去做不讨好的序列化——这是”接口与实现分离”在 Schema 层的又一次体现(7.4 还会看到同一个思想的另一面)。

Schema 设计的质量,直接决定模型使用工具的正确率。一个 description 模糊的工具(如”做某事”),模型必然频繁误用;一个参数描述清晰的工具,模型几乎不会用错。

Schema 设计的黄金法则:把工具的 description 和参数 description 当成”写给一个聪明但完全不了解你系统的新同事看的 API 文档”来写。

几个具体的 Schema 设计要点:

  1. description 要回答三个问题:这个工具做什么?什么时候该用?有什么限制或副作用?
  2. 参数描述要避免歧义:单位(秒还是毫秒)、时区、枚举值、默认值,都要说清楚。
  3. required 要精确:必填参数标 required,可选参数给默认值说明。
  4. 避免”万能工具”:一个参数巨多、职责模糊的”万能工具”,不如几个职责单一的小工具好用。

7.3 Tool Discovery

Tool Discovery(工具发现)回答的问题是:模型怎么知道有哪些工具可用?

答案很简单:把工具定义注入上下文。在每次请求模型前,Harness 把所有可用工具的名称、描述、参数 Schema 作为请求的一部分发给模型(通常放在 System Prompt 或专门的 tools 字段里)。模型”读到”这些定义后,就知道自己有什么”手和脚”。

但这里有一个重要的工程权衡:工具越多,注入上下文的 token 越多。

假设你有 100 个工具,每个工具的定义平均 200 token,那么每次请求光工具定义就消耗 2 万 token。这对于上下文是巨大的负担。

解决方案是按需发现(Lazy Discovery),常见有几种做法:

  1. 分组注入:把工具按类别分组,只注入当前可能用到的组。
  2. 动态检索:维护一个工具索引,根据当前任务的关键词,检索并注入最相关的工具定义。
  3. 渐进发现:先注入一份精简的”工具目录”,当模型表示需要某类工具时,再注入完整定义。

Claude Code 采用的是混合策略,且实现得比想象中更”吝啬”:常用核心工具(Read/Write/Edit/Bash 等)始终注入完整定义;大量”长尾”工具(各种 MCP 工具、专用工具)被标记为延迟(deferred)——它们在上下文里只以名称出现,连一句描述都没有,模型必须先调用 ToolSearch 工具检索,才能拿到它的参数 Schema,也才能调用它。第三种做法(分组注入)在这里更多体现为按需注入:部分工具只在特定功能被启用时才出现,例如 Worktree 相关工具仅在 worktree 场景下注入。

ToolSearch 的查询支持三种形态,本身就说明了”检索什么样的工具定义”是个需要设计的接口:

"select:Read,Edit,Grep"   按名精确取
"notebook jupyter"        关键词检索,返回最匹配的若干项
"+slack send"             名称必须含 slack,其余词参与排序

值得琢磨的是那份”目录”为什么只有名字、没有描述。给每个工具配一句简介,看起来对模型更友好,但那是要按工具数量线性付费的 token——几百个 MCP 工具的简介加起来就是一笔固定开销,而绝大多数工具在一次会话里根本不会被用到。Claude Code 的取舍是:目录只保证”模型知道自己有什么”,不保证”模型理解它”——理解的成本留给真正需要它的那一次 ToolSearch。源码里还留有一条旁证:曾试过为每个工具加一段检索提示(searchHint),但 A/B 试验判断无收益后停止了——在该版本中,检索主要靠工具名称本身,这也反过来要求工具命名必须”自解释”。

延迟的动机也值得说清楚:MCP 工具默认延迟,首要原因不是省 token,而是”工作流相关”——一个接入 Slack 的 MCP 服务器,对正在改代码的 Agent 毫无用处,它的 schema 出现在每一轮请求里既是浪费也是干扰。所以 MCP 还留了一个反选开关:服务器可以声明 alwaysLoad,强制自己的工具出现在初始 prompt 里。

这个”核心常驻 + 长尾按需”的策略,是解决”工具多 vs 上下文有限”矛盾的成熟方案。


7.4 Tool Registry

Tool Registry(工具注册表)是工具系统的”总目录”——集中管理所有工具的元信息(名称、描述、Schema、实现函数的引用)。

一个简单的 Tool Registry 实现:

interface ToolDefinition {
  name: string;
  description: string;
  inputSchema: Record<string, unknown>;
  execute: (input: unknown) => Promise<ToolResult>;  // 实现函数
}

class ToolRegistry {
  private tools = new Map<string, ToolDefinition>();

  register(tool: ToolDefinition) {
    this.tools.set(tool.name, tool);
  }

  get(name: string): ToolDefinition | undefined {
    return this.tools.get(name);
  }

  list(): ToolDefinition[] {
    return [...this.tools.values()];
  }

  // 生成注入上下文的工具定义(不含实现函数)
  // 内部统一 camelCase,仅在发给模型 API 时转成 input_schema
  getSchemas() {
    return this.list().map(({ name, description, inputSchema }) => ({
      name,
      description,
      input_schema: inputSchema,   // API 边界:camelCase → snake_case
    }));
  }
}

Registry 的价值在于集中管理 + 统一注入:所有工具在一个地方注册,统一生成注入上下文的 Schema,统一查找执行函数。这让工具系统”可扩展”——新增一个工具,只需 register 一次。

在 Claude Code 中,这一步还额外承担授权职责:getTools(permissionContext) 会按 deny 规则在生成阶段就裁掉被禁用的工具。被裁掉的工具对模型不存在,而不是”存在但调用时被拒”——两种做法对模型行为的影响完全不同:前者让模型根本不会去尝试,后者会诱导模型反复试探。更进一步的裁剪发生在执行上下文维度(7.12)。

注意 getSchemas() 的一个细节:它只返回”给模型看的接口”,不含”实现函数”。这个”接口与实现分离”是工具注册表的核心设计——模型只需要知道”接口”,实现是 Harness 自己的事。

Claude Code 的工具注册表在这三点上更进一步:

  1. 不是所有工具都静态注册。 内置工具是静态的,MCP 工具则来自运行时状态,在每次组装请求时才按当前连接的服务器过滤注入(src/tools.ts)。服务器断开,工具就消失——注册表是”组装出来的”,而非一张写死的表。
  2. 权限元数据随工具携带。 每个工具自带 isReadOnly / isDestructive 等声明(7.10),框架不必读实现就能做授权与调度判断。
  3. 工具集按上下文裁剪。 同一个注册表,喂给子智能体与喂给主线程的内容并不相同(7.12)。

7.5 Tool Dispatcher

Tool Dispatcher(工具调度器)回答的问题是:模型请求调用的工具,怎么路由到正确的实现?

Dispatcher 的核心逻辑其实很简单——根据工具名查找实现:

async function dispatchToolCall(toolCall: ToolCall, registry: ToolRegistry) {
  const tool = registry.get(toolCall.name);
  if (!tool) {
    return { is_error: true, content: `未知工具: ${toolCall.name}` };
  }
  return tool.execute(toolCall.input);
}

但真实世界的 Dispatcher 远不止查找这么简单,它还要处理:

  1. 参数校验:执行前用 Schema 校验参数,参数错误时返回清晰的错误而非让执行函数崩溃。
  2. 权限检查:执行前检查权限,未授权的工具调用被拦截。
  3. 并发调度:多个工具调用可以并行执行(独立的)或串行执行(有依赖的)。
  4. 超时控制:为工具执行设置超时。

Claude Code 的 runTools(src/services/tools/toolOrchestration.ts)实现了这些。它的调度判据不是调用之间的逻辑依赖,而是每次调用自身的 isConcurrencySafe(input) 谓词:

  1. 安全批:连续的并发安全调用被攒成一批,用 runToolsConcurrently 并行执行,并发上限默认为 10(可用环境变量 CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY 调整)。
  2. 不安全批:非并发安全的调用单独成批,用 runToolsSerially 串行执行。

这个”按谓词而非按依赖”的选择,是一条重要的架构判断:并发真正的风险不是”逻辑依赖”,而是”资源冲突”。只有当一次调用对系统状态只读时,才谈得上安全并发——这是保守的充分条件,而不是精确的依赖分析。谓词本身还被 try/catch 包裹,抛异常时保守地判为”不安全”。

更值得注意的是,这个谓词是按每次调用计算的,而不是按工具固定:

工具isConcurrencySafe 实现效果
Read / Grep / Glob / WebFetch / WebSearch恒返回 true只读,可并行
Edit / Write未定义,走 buildTool 默认值 false恒串行
Bash返回 this.isReadOnly(input)逐条命令动态判定

Read 永远只读,所以永远可以并行;Edit / Write 永远会改文件,所以永远串行;而 Bash 是按命令内容判定的——ls、git status 这类只读命令可以和别的只读工具并行,rm、git push 则必须独占。把”这次调用安全吗”做成一个逐调用的谓词,而不是给工具贴一个静态标签,是工具调度层最简明的正确性设计。

权限检查与执行路径:每次调用都经由 CanUseToolFn 检查后才执行(checkPermissionsAndCallTool,src/services/tools/toolExecution.ts)。

Dispatcher 是工具系统的”指挥中心”——它把”模型的意图”精确地路由到”正确的执行”,并在路由过程中完成校验、权限、并发、超时等所有”控制”动作。


7.6 Tool Executor

Tool Executor(工具执行器)是工具的实际实现——真正去读文件、执行命令、查数据库的那段代码。

Executor 的设计要点:

  1. 单一职责:每个 Executor 只做一件事,做好一件事。
  2. 清晰的返回结构:统一的结果结构(内容 + 错误标记 + 可选的附加信息),便于上层统一处理——包括把结果交给模型、把错误标记出来、更新会话状态。
  3. 副作用隔离:有副作用的操作(写文件、执行命令)必须走权限检查,不能绕过。
  4. 资源管理:正确管理文件句柄、网络连接、子进程等资源的创建和释放。

一个 Read 工具的 Executor 示例:

async function executeReadFile(
  input: { file_path: string }
): Promise<{ content: string; is_error: boolean }> {
  try {
    const content = await fs.readFile(input.file_path, "utf-8");
    return { content, is_error: false };
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    return { content: `读取文件失败: ${message}`, is_error: true };
  }
}

注意这个 Executor 的一个关键设计:它不抛异常,而是把错误作为返回值。这样上层循环就不会因为一个工具失败而崩溃,而是把错误作为”结果”交给模型,让模型决定下一步(第 3 章的 Tool Error 处理)。

这个”不抛异常”的设计是 Agent 工具系统与普通函数库的关键区别:普通函数库抛异常让调用方处理,Agent 工具系统把错误转化为结果让模型处理。

值得注意的是,这条约定并不依赖每个 Executor 自觉遵守:执行器之上还有一层兜底 try/catch(src/services/tools/toolExecution.ts),把漏出的异常统一转换成 is_error: true 的工具结果。架构不变量要由框架强制,而不是靠约定——这才是它可靠的原因。真实源码里这两层是并存的:Executor 尽力把可预期的失败(文件不存在、命令非零退出)转成结果,框架兜住不可预期的崩溃。


7.7 Tool Result

Tool Result(工具结果)是 Executor 返回、最终呈现给模型的内容,也是模型继续推理的依据。它的设计直接影响 Agent 的决策质量。

工具结果的最佳实践:

  1. 结构化:返回 JSON 而非自由文本,便于模型解析。
  2. 精炼:返回”有用的信息”,而非”全部信息”。搜索工具返回”3 个关键匹配及上下文”,而非”300 个匹配的全部内容”。
  3. 带错误语义:用 is_error 明确标记失败,让模型知道”这是错误,不是正常结果”。这里要区分两层结构:Executor 交给 Harness 的是一个内部结果对象(含数据、附带消息、上下文修改器等字段);Harness 再把它转换为模型真正看到的 tool_result 内容块(content + is_error)。只有内容进上下文,控制字段不进。工具结果的”模型可见面”是被 Harness 精心裁剪过的——模型看到什么、看不到什么,本身就是一个设计决策。
  4. 大小可控:结果的尺寸管理是上下文侧的责任(第 6.6 节讲了截断、摘要与外部卸载四条策略),但工具有义务配合——例如 Claude Code 要求每个工具声明 maxResultSizeChars,超过阈值的结果由框架落盘,上下文中只留预览与文件路径。工具侧的配合点很朴素:声明清楚”我这个工具的正常输出有多大”。

一个常被忽视的细节:工具结果的”可读性”。模型要”读”这些结果来推理,如果结果格式混乱、噪声大,模型的理解就会出错。因此,工具结果的格式设计,本质上是”给模型看的输出设计”。

一个具体的设计问题:工具结果要不要”自我描述”? 比如,一个搜索工具返回 {"matches": [...], "count": 42, "truncated": true},还是返回一段带上下文的自然语言描述?答案是:结构化数据 + 必要的上下文。纯数据(count: 42)缺乏上下文——它没说是否被截断、是否已按相关性排序;纯文本难以解析。两者的结合最好。


7.8 Tool Error

工具执行失败是常态,不是例外。文件不存在、命令报错、网络超时、权限不足……都是常见失败。

工具错误的处理策略(第 3 章已提及,这里深化):

  1. 错误作为结果返回(而非抛出异常):让模型看到错误、理解错误、决定对策。这是 Agent Self-correction(自我纠正)能力的基础。
  2. 错误信息要”可操作”:好的错误信息告诉模型”发生了什么、为什么、怎么办”。比如”文件不存在:src/foo.ts。可能路径拼写错误,建议用 Glob 工具查找正确路径”,而不是冷冰冰的”Error: ENOENT”。
  3. 错误分类:区分”可重试错误”(网络超时)和”不可重试错误”(文件不存在,重试也白费),让模型和系统做出不同应对。

“可操作的错误信息”值得展开。它是”Self-correction”能否成功的决定性因素。如果错误信息只说”失败了”,模型只能瞎猜原因;如果错误信息说”文件 src/foo.ts 不存在,建议用 Glob 查正确路径”,模型就能精准地走下一步。好的错误信息,是在”教”模型怎么修。


7.9 Tool Timeout

工具执行可能”卡死”——一个命令挂起不返回、一个网络请求无限等待。如果没有超时控制,整个 Agent 会被一个工具卡死。

超时设计要点:

  1. 分类超时:不同工具设不同超时。读文件应该秒级返回,执行测试可能分钟级,编译大型项目可能更久。
  2. 超时后的处理:超时不是简单地”杀掉”——要返回一个清晰的超时错误给模型,让模型决定是重试、换策略还是放弃。
  3. 可中断性:对于长命令(如运行一个服务器),需要支持”超时但进程继续在后台跑”或”超时并强制终止”两种模式。

第 1 条”分类超时”在 Claude Code 里有具体数字(以 2026-03-31 版本为准):Bash 命令的默认超时是 2 分钟,上限 10 分钟,都可用环境变量覆盖。这个”默认 2 分钟”是刻意保守的——它假定绝大多数命令都该很快返回,真需要更久的命令必须由调用方(也就是模型)自己声明 timeout 参数。把”这次要等多久”交给发起方判断,比让框架用一个统一的长超时更精确,也避免了”一个卡住的命令拖住整个 Agent”。

Claude Code 对长命令还有专门处理:它支持 run_in_background 参数让命令在后台运行,Agent 可以先做别的事,完成后会收到通知。更值得注意的是,系统还会在命令超时后自动把它转入后台——模型并没有主动要求,框架就替它做了这个决定,因为”杀死一个可能还在正常工作的长任务”往往是更糟的选择。

“后台执行 + 稍后检查”是一个重要的模式:它突破了”工具调用是同步阻塞”的假设。对于”启动一个开发服务器”这类”永不返回”的命令,同步等待永远超时;而后台执行让 Agent 能”启动服务器 → 做别的事 → 再回来验证”。


7.10 Tool Permission

工具权限是 Tool System 与 Permission 系统(第 11 章)的交汇点。核心思想:不是所有工具都能随便调用,危险工具需要权限控制。

四类工具(只读 / 写 / 执行 / 网络)的风险分级及其对应的审批强度,在第 11 章展开。这里只强调 Tool System 侧的那件事——检查点落在流水线的哪个位置:

模型请求工具 → Dispatcher 路由 → 【权限检查】 → Executor 执行 → Result 返回

权限检查位于 Dispatcher 与 Executor 之间,是”模型的意图”变成”真实副作用”的唯一闸门。它必须在 Executor 之前,且 Executor 不能绕过它——这是第 11 章所有权限策略得以生效的前提。位置错了,再完备的策略也只是文档。

顺带一提,工具身上还不止这一种标记:isReadOnly(只读)、isDestructive(不可逆)、isConcurrencySafe(可并发,7.5)等等。它们的共同点是——把”这个工具会不会惹麻烦”从执行代码里提取成声明式元数据,让框架可以在不读实现的情况下做出授权与调度决策。这是工具系统能被”治理”的原因。


7.11 Tool Composition

Tool Composition(工具组合)是”把简单工具组合成复杂能力”的思想。单个工具的能力有限,但组合起来可以完成复杂任务。

组合的两种形式:

  1. 模型驱动的组合:模型在循环中依次调用多个工具,完成一个复合任务(如”先 Glob 找文件 → 再 Read 读内容 → 再 Edit 修改 → 再 Bash 测试”)。这是 Agent Loop 天然支持的组合。
  2. 系统定义的高阶工具:Harness 把一组常见操作封装成”复合工具”。Claude Code 里有两种典型形态:Skill 把一段预置指令封装成可调用的能力;ToolSearch 更特殊——用工具去发现工具,把”检索工具目录 + 按需装载 Schema”本身变成一次工具调用(7.3)。

组合的价值在于抽象层次的提升:模型不必每次都”手写”一系列低级操作,而是可以直接调用一个高阶工具完成整件事。这既提高效率,也降低出错率。

而要论组合的最高形态,还是”用 Agent 当工具”(Agent as a Tool)——把”委派一个子智能体”封装成一个工具调用。Claude Code 中承担这个角色的工具现在叫 Agent(早期版本名为 Task,为兼容旧的权限规则与已恢复会话而保留为别名)。这模糊了”工具”和”Agent”的边界,是多智能体架构的入口(第 30 章 Subagent Architecture 系统展开)。


7.12 Built-in Tools

Built-in Tools(内置工具)是一个 Coding Agent Harness 必备的核心工具集。Claude Code 源码 src/tools/ 下共 40 个工具目录,本节按四个层级介绍其中最关键的部分。

先明确一件事:源码目录名不等于模型侧的工具名。src/tools/FileReadTool/ 里导出的工具叫 Read,src/tools/WebSearchTool/ 导出的是 WebSearch。下文一律使用模型侧工具名——那才是模型实际看到、并在调用时使用的名字:

  • 基础(读、写、搜、跑):Read、Write、Edit、Glob、Grep、Bash
  • 任务与委派:TodoWrite、Agent、AskUserQuestion
  • 发现与扩展:ToolSearch、Skill、NotebookEdit、WebFetch、WebSearch、LSP
  • 协作与模式:SendMessage、TaskCreate、TaskStop、EnterPlanMode

下面对每个工具给出四件事:类别与实现位置、输入 Schema、作用、值得注意的设计亮点。Schema 均取自源码原文(2026-03-31 版本),只保留模型可见的字段。

7.12.1 基础六件套

这六个工具覆盖 Coding Agent 的核心需求:读、写、搜、跑。它们同时也是 Part IV 的 Mini Claude Code 要实现的目标清单。

Read|文件读取|src/tools/FileReadTool/

{
  file_path: string,    // 要读取的文件的绝对路径(required)
  offset?: number,      // 从第几行开始读(1 起,可选)
  limit?: number,       // 最多读多少行(可选)
  pages?: string,       // PDF 专用取页范围,如 "1-5"、"3"、"10-20"
}

作用:读取文件内容。file_path 必须是绝对路径。

亮点:

  1. 它不是一个”纯文本读取器”。除文本外,还支持图片、PDF、Jupyter Notebook——返回结构是一个按 type 区分的联合类型(文本 / 图片 base64 / PDF / Notebook)。模型”看”的能力和”读”的能力,在同一个工具里统一了。
  2. offset / limit 是”逃生舱”,不是常规分页。它们的 describe 写着 “Only provide if the file is too large to read at once”——工具在自己的说明里主动劝退无谓的分页调用。告诉模型”什么时候不该用这个参数”,和告诉它”这个参数是什么”同样重要。
  3. 它是唯一一个把结果大小上限设为 Infinity 的工具。这看起来反直觉——”无限”怎么会是安全设计?源码注释给出了理由:Read 的输出如果落盘,就会产生”Read 文件 → 落盘 → 再 Read 读回来”的循环,所以它必须自己限制自己(靠行数上限),而不是交给通用的落盘机制。
  4. “文件未变化”提示:重复读取同一个未修改的文件时,工具返回一句”文件自上次读取以来未变化,请参考此前的结果”,而不是把内容再发一遍。这是对上下文的主动节省。

Write|文件写入|src/tools/FileWriteTool/

{
  file_path: string,    // 要写入的文件的绝对路径(required,必须绝对,不能相对)
  content: string,      // 写入的内容(required)
}

作用:写入文件,文件不存在则创建。

亮点:

  1. 两个字段,没有第三个。连”是否覆盖”这样的参数都不存在——覆盖是默认行为,框架用别的方式(权限与校验)来兜底,而不是靠加参数。
  2. 它的输出 Schema 比输入丰富得多:返回 type: 'create' | 'update'、structuredPatch(差异补丁)、originalFile、gitDiff。这些不进模型上下文,而是供给 UI 展示、检查点与撤销。输入极简、输出详尽,是工具 schema 设计的一个常见模式:对模型的要求越少越好,给框架的信息越多越好。
  3. 因为它是”整体重写”,所以改文件时更推荐 Edit(见下)。

Edit|精确编辑|src/tools/FileEditTool/

{
  file_path: string,     // 要修改的文件的绝对路径(required)
  old_string: string,    // 将被替换的原文(required)
  new_string: string,    // 替换后的新文本(required,必须与 old_string 不同)
  replace_all?: boolean, // 是否替换全部匹配项(默认 false)
}

作用:在文件中做精确的字符串替换。

亮点:

  1. new_string 的 describe 里写死了校验规则:”must be different from old_string”。Schema 的描述本身就在承担”防止无意义调用”的职责——模型读到这句话,就不太会提交一个没有变化的编辑。
  2. replace_all 默认 false,这是安全默认值:默认只改一处,改动范围可预期。
  3. 它能容忍”引号风格差异”:当文件里是弯引号而模型给出直引号时,工具会做归一化匹配(utils.ts 里有专门处理)。这是把模型常见的”手误”在工具层吸收掉,而不是让模型付出一次失败重试的代价。
  4. 精确编辑优于整体重写:Edit 比 Write 更高效(只传改动部分)、更安全(误伤范围小)、更省 token。以 Edit 为主、Write 为辅,是 Coding Agent 成熟度的标志。

Glob|文件搜索|src/tools/GlobTool/

{
  pattern: string,   // glob 模式,如 "**/*.ts"(required)
  path?: string,     // 搜索的目录,省略则用当前工作目录
}

作用:按文件名模式查找文件。

亮点:

  1. path 的 describe 里写了一段异常具体的叮嘱:”IMPORTANT: Omit this field to use the default directory. DO NOT enter undefined or null — simply omit it”。如果不是真的观察到模型反复写 "undefined" 字符串,不会有这句提示。工具描述是被真实失败案例塑形的,这句话本身就是一份工程记录。
  2. 结果有硬上限(100 个文件),并返回 truncated 标记——把”结果被截断了”这一事实显式告诉模型,让模型自己决定是否缩小范围,而不是让它以为看到的就是全部。

Grep|内容搜索|src/tools/GrepTool/

{
  pattern: string,        // 正则表达式(required)
  path?: string,          // 搜索路径
  glob?: string,          // 按 glob 过滤文件,如 "*.{ts,tsx}"
  output_mode?: 'content' | 'files_with_matches' | 'count',  // 默认 files_with_matches
  '-B'?: number,          // 匹配行之前的上下文行数(仅 content 模式)
  '-A'?: number,          // 匹配行之后的上下文行数
  '-C'?: number,          // 上下文行数(-A/-B 的别名)
  context?: number,
  '-n'?: boolean,         // 显示行号
  '-i'?: boolean,         // 忽略大小写
  type?: string,          // 按文件类型过滤
  head_limit?: number,    // 结果数量上限
  offset?: number,        // 结果偏移
  multiline?: boolean,    // 是否允许多行匹配
}

作用:在文件内容中按正则搜索。

亮点:

  1. 参数名直接用 ripgrep 的命令行旗标(-A / -B / -C / -n / -i)——让模型把已有的 rg 知识直接迁移过来,这比重新发明一套语义化命名更省描述、更少歧义。
  2. 默认模式是 files_with_matches 而非 content。默认值的选择就体现了上下文意识:先给文件名,模型再决定打开哪个——两步走比一次性倾倒所有匹配行更省上下文。
  3. head_limit / offset 提供分页能力,multiline 让跨行模式成为可能。这两个参数的存在说明:搜索工具的结果必须可裁剪,否则一个宽泛的正则就能吃掉整个上下文预算。

Bash|命令执行|src/tools/BashTool/

{
  command: string,              // 要执行的命令(required)
  description?: string,         // 用主动语态清晰描述这条命令做什么
  timeout?: number,             // 超时毫秒数(上限 10 分钟)
  run_in_background?: boolean,  // 后台运行,完成时通知
  dangerouslyDisableSandbox?: boolean,  // 关闭沙箱执行(字段名自带警告)
}

作用:执行 shell 命令。这是能力最强、也最危险的工具。

亮点(这个工具的 schema 值得逐条读):

  1. description 是一个”给非技术读者看的说明”字段,它的 describe 用了大量篇幅给出正反例,并明确禁止使用”complex”、”risk”这类词——因为这个词会出现在权限提示里给用户看。ls 要写成 “List files in current directory”,而不是 “Run complex shell command”。工具 schema 里混着一条写作规范,因为这里是人机交互的界面。
  2. _simulatedSedEdit 字段被显式地从模型可见的 schema 里剔除(.omit())。源码注释解释了原因:这个字段由权限组件在用户批准 sed 编辑预览后填充,如果暴露给模型,模型就能”用一个无害命令 + 一次任意文件写入”来绕过权限检查与沙箱。这是本书里”Schema 即安全边界”最直白的一个例子。
  3. sleep 被列入不允许自动转后台的命令——”Sleep should run in foreground unless explicitly backgrounded by user”。这类细节无法从架构图推出来,只能从被真实行为教育过的源码里读到。
  4. run_in_background 字段本身是条件注入的:后台任务被禁用时,这个字段会从 schema 里直接移除(.omit())。模型看不到它,就不会去尝试它——能力门控做在 schema 层,而不是靠提示词劝阻。
  5. dangerouslyDisableSandbox 暴露了一处真实张力。这个字段名自带警告,而工具的提示词在它周围立了一套相当细致的规矩(受 allowUnsandboxedCommands 门控):
    • 默认:始终在沙箱内执行,不要设置这个字段;
    • 例外:仅当出现沙箱限制导致失败的证据时——提示词列了一张清单(”Operation not permitted” 错误、特定路径访问被拒、对非白名单主机的连接失败等)——才重试;
    • 它特意提醒模型排除误判:命令失败的原因很多(文件不存在、参数错误、网络问题),不要一股脑归咎于沙箱;
    • 并且逐条判定:即使刚用过这个开关,下一条命令仍然要默认回到沙箱内。
    一边要求”默认绝不用”,一边授权”有证据时立刻用”——这两句话必须同时存在:没有逃生舱的沙箱会让 Agent 在合法任务上卡死,没有告诫的逃生舱则会变成默认路径。而且”立即重试,不要询问”并不等于绕过控制——用户仍然会被询问。安全设计里最难的部分,往往不是”禁止什么”,而是”给禁止留一个可控的例外”。

7.12.2 任务与委派

TodoWrite|任务清单|src/tools/TodoWriteTool/

{
  todos: Array<{
    content: string,                    // 任务描述(不能为空)
    status: 'pending' | 'in_progress' | 'completed',
    activeForm: string,                 // 进行中时的表述,不能为空
  }>,
}

作用:维护结构化任务清单。

亮点:

  1. 每次提交整份清单,而不是增量修补——没有 add / remove / update 之类的命令式字段。这使操作幂等,也天然可恢复:模型不需要记住”我上次改到哪了”,框架拿到的永远是完整状态。
  2. activeForm 强制模型从”过程视角”描述任务:不是”读取配置”,而是”正在读取配置”。这个字段只服务于 UI——让用户看到 Agent 此刻在做什么。一个纯粹为人而存在、模型自身并不需要的字段。
  3. 输出里的 verificationNudgeNeeded:当所有任务都标记完成、而清单里却没有一项与”验证”相关时,这个标记会被置位,框架据此自动提醒模型”你是不是该跑一下测试”。“过早停止”这个 Agent 的经典失效模式,在这里被做成了一个可检测的信号。
  4. 它的输出同时返回 oldTodos 与 newTodos——框架据此能计算出”本次变更了什么”,用于 UI 与状态追踪。

Agent|子智能体|src/tools/AgentTool/

{
  description: string,          // 任务的简短描述(3-5 个词)(required)
  prompt: string,               // 交给子智能体执行的任务(required)
  subagent_type?: string,       // 子智能体类型
  model?: 'sonnet' | 'opus' | 'haiku',   // 模型覆盖
  run_in_background?: boolean,  // 后台运行,完成时通知
  name?: string,                // 给子智能体命名,使其可被 SendMessage 寻址
  team_name?: string,           // 团队上下文
  mode?: string,                // 权限模式,如 "plan"
  isolation?: 'worktree' | 'remote',   // 隔离运行:临时 git worktree / 远程环境
  cwd?: string,                 // 运行目录
}

作用:委派一个子智能体执行任务,返回其结论。这是”用 Agent 当工具”(7.11)的具体实现,是多智能体架构的入口。

亮点:

  1. 它把”上下文隔离”做成了一个参数:isolation: "worktree" 会创建一个临时 git worktree,让子智能体在仓库的独立副本上工作。这是”并行 Agent 不互相踩踏”的工程解法——不靠约定,靠文件系统层面的隔离。
  2. schema 级的能力门控:run_in_background、cwd 等字段会依据特性开关与环境变量被 .omit() 掉。源码注释同时说明了为什么用 .omit() 而不是条件展开——后者会破坏 Zod 的类型推断。这类”实现细节的坑”往往决定了架构能否保持类型安全。
  3. subagent_type 决定了子智能体拿到哪些工具:探索型、验证型、通用型各有自己的工具集与模型。这正是 7.12.5 要讲的”工具集随上下文裁剪”的入口。
  4. run_in_background 让委派变成非阻塞:主线程可以继续做事,子智能体完成时收到通知。这是把”并发”从工具调用层(7.5)提升到了智能体层。

AskUserQuestion|交互提问|src/tools/AskUserQuestionTool/

{
  questions: Array<{
    question: string,      // 完整的问题,以问号结尾
    header: string,        // 极短标签(如 "Auth method"),显示为选项组标题
    options: Array<{
      label: string,       // 选项显示文本(1-5 个词)
      description: string, // 该选项的含义或后果
      preview?: string,    // 聚焦时展示的预览内容(如代码片段、界面草图)
    }>,                    // 必须 2-4 个选项
    multiSelect: boolean,  // 是否允许多选(默认 false)
  }>,                      // 1-4 个问题
}

作用:向用户提问,获取澄清或让用户在方案间做选择。

亮点:

  1. 它的 Schema 就是一份 UI 规格。header 的长度上限、options 的数量上限(2-4)、questions 的数量上限(1-4),全部编码在 Schema 里——模型不需要”知道”该问几个问题,它根本问不出第五个。
  2. 没有 “Other” 选项,因为”其他”是自动提供的——describe 明确告诉模型”不要自己造一个 Other 选项”。把不变的部分从模型手里拿走,是减少调用错误最有效的手段之一。
  3. preview 字段把”选项比较”升级成了可视化比较:模型可以给出代码片段、ASCII 布局草图、配置示例,让用户在看得见结果的情况下选择。这是”人机协作”里少见的、把交互质量做进 schema 的例子。
  4. Schema 层还带了一条业务规则校验:问题之间必须互不重复(一个 .refine() 检查)。校验逻辑可以住在 Schema 里,而不必等执行时才报错。
  5. 最后,它证明了”人”可以被建模成一种工具:当任务信息不足时,模型不是瞎猜,而是调用这个工具向用户澄清。这是”人机协作”在工具层面的体现。

7.12.3 工具发现与扩展

ToolSearch|工具发现|src/tools/ToolSearchTool/

{
  query: string,        // "select:<tool_name>" 直接选取,或关键词检索
  max_results?: number, // 返回上限(默认 5)
}

作用:检索被延迟(deferred)的工具,把它们的完整 Schema 装载进上下文,使它们变得可调用。

亮点:这是一个”用工具发现工具”的元工具——7.3 已详细讨论。这里只强调它的存在意义:工具集合本身成了可以被查询的对象。当工具数量大到无法一次性注入上下文时,”发现工具的能力”就必须先成为一种工具。

Skill|技能调用|src/tools/SkillTool/

{
  skill: string,    // 技能名,如 "commit"、"review-pr"、"pdf"
  args?: string,    // 传给技能的参数
}

作用:调用一个预定义的技能。Skill 把”一段预置的指令 + 工具许可”封装成一个原子能力——模型调用的不是一个函数,而是一套工作流。

亮点:它的输出 Schema 里带着 allowedTools——技能不仅能”告诉模型怎么做”,还能声明”这段时间里你可以用哪些工具”。这是”能力封装”走得更远的一步:连权限范围都可随技能切换。

NotebookEdit|Notebook 编辑|src/tools/NotebookEditTool/

{
  notebook_path: string,     // Notebook 文件的绝对路径(required)
  cell_id?: string,          // 目标单元格 ID(插入时表示插在它之后)
  new_source: string,        // 单元格的新内容(required)
  cell_type?: 'code' | 'markdown',
  edit_mode?: 'replace' | 'insert' | 'delete',   // 默认 replace
}

作用:编辑 Jupyter Notebook 的单元格。

亮点:它没有复用 Write / Edit。Notebook 是 JSON 结构而非纯文本,用字符串替换去改它既脆弱又容易破坏格式——一个通用的字符串编辑器,解决不了一个结构化编辑器的问题。这是”工具粒度应当匹配数据粒度”的例证。

WebFetch|网页抓取|src/tools/WebFetchTool/

{
  url: string,      // 要抓取内容的 URL(required)
  prompt: string,   // 对抓取到的内容运行的提示词(required)
}

作用:抓取网页,并用指定提示词对内容做处理,返回处理结果。

亮点:它抓取的内容不直接进上下文——模型看到的是”应用 prompt 之后的结果”,而不是原始 HTML。把”取回”和”理解”合并成一次调用,避免一页网页的噪声(导航、脚注、脚本)污染上下文。这也是一个天然的注入防线:原始文本不落地,间接提示词注入的载体就少了一条通路(第 11.13 节)。

WebSearch|网络搜索|src/tools/WebSearchTool/

{
  query: string,               // 搜索关键词(至少 2 个字符)(required)
  allowed_domains?: string[],  // 只在这些域名中搜索
  blocked_domains?: string[],  // 排除这些域名
}

作用:执行网络搜索。

亮点:allowed_domains / blocked_domains 让模型自己就能把搜索范围收窄。这对第 11 章的网络权限是一种补充:权限系统控制”能不能上网”,而这两个参数控制”往哪儿看”——把范围控制做成工具的能力,而不只是外部的限制。

7.12.4 协作与模式

这一层工具存在的理由是:Agent 不只需要和世界打交道,还要和自己、和用户、和其他 Agent 打交道。它们中的多数在第 30 章展开,这里看它们的 Schema 各自透露了什么。

LSP|代码智能|src/tools/LSPTool/

{
  operation: 'goToDefinition' | 'findReferences' | 'hover' | 'documentSymbol'
           | 'workspaceSymbol' | 'goToImplementation'
           | 'prepareCallHierarchy' | 'incomingCalls' | 'outgoingCalls',  // required
  filePath: string,      // 文件路径(required)
  line: number,          // 行号(1 起,与编辑器显示一致)(required)
  character: number,     // 字符偏移(1 起,与编辑器显示一致)(required)
}

作用:通过 Language Server Protocol 获取代码智能信息——跳转定义、查找引用、悬停类型、调出调用层级。

亮点:line / character 的 describe 都特意写明”1 起,与编辑器显示一致“。源码里其实存在两套 Schema——模型侧是一张扁平表,内部还另有一份按 operation 区分的可辨识联合(用于给出更精确的校验错误)——给模型看的和给自己校验用的,可以是两份不同的 Schema。这与 7.2 讲的”用 Zod 定义、发送时才转 JSON Schema”是同一个思路的延伸:接口的每一层受众,都可以有自己的形态。

TaskCreate|任务创建|src/tools/TaskCreateTool/

{
  subject: string,       // 任务标题(required)
  description: string,   // 需要做什么(required)
  activeForm?: string,   // 进行中时在 spinner 里显示的表述,如 "Running tests"
  metadata?: object,     // 任意附加元数据
}

作用:在任务清单中创建一项可被其他 Agent 看见的任务。

亮点:它和 TodoWrite 长得像,但服务的是完全不同的问题。TodoWrite 管的是单个 Agent 自己的执行进度(给人看的);TaskCreate 管的是多智能体协作中的可寻址工作单元——任务能被认领、被查询、被停止。同样是”任务”,一个是私有的执行状态,一个是共享的协调对象,两者不可互相替代。这也解释了它们的可见性为何不同:TaskCreate 只对”进程内队友”开放(在 IN_PROCESS_TEAMMATE_ALLOWED_TOOLS 白名单里),而 TodoWrite 对异步子智能体同样开放——各自跟着自己服务的那件事走(7.12.5)。

TaskStop|停止任务|src/tools/TaskStopTool/

{
  task_id?: string,     // 要停止的后台任务 ID
  shell_id?: string,    // 已废弃:请改用 task_id(为兼容旧工具 KillShell 而保留)
}

作用:按 ID 停止一个正在运行的后台任务。

亮点:Schema 与运行时的分工在这里体现得很清楚。两个字段在 Schema 里都是可选的,因为工具要向后兼容一个叫 KillShell 的旧工具;但 validateInput 会在运行时强制要求二者至少提供一个,否则报错。“能不能通过校验”由运行时说了算,Schema 只负责描述形状——这是把兼容性的负担从模型(它只需要知道 task_id)转移到框架内部的一个干净做法。

SendMessage|消息发送|src/tools/SendMessageTool/

{
  to: string,           // 接收方:队友名,或 "*" 广播(required)
  message: string | {   // 消息内容:纯文本,或结构化消息(required)
    type: 'shutdown_request' | 'shutdown_response' | 'plan_approval_response',
    ...                  // 各类型自带 request_id / approve / reason 等字段
  },
  summary?: string,     // 5-10 个词的摘要,用于 UI 预览
}

作用:向另一个 Agent(或整个团队)发送消息。

亮点:

  1. to 字段的描述文本是条件注入的:启用多端点拓扑时,描述会变成”队友名 / * 广播 / uds:<socket-path> 本地对等体 / bridge:<session-id> 远程对等体”。同一份 Schema 在不同部署形态下呈现不同的描述——字段集合不变,但模型对它的理解随环境而变。
  2. message 是一个联合类型:纯文本,或结构化消息。而结构化消息的三个变体——shutdown 请求、shutdown 响应、计划批准响应——把”协作礼仪”编码成了协议。给队友发一条消息”和”请队友关闭自己”、”批准队友的计划”是三类不同性质的事,让它们共用 message: string 会丢失全部语义。这是工具 Schema 承载”协议”而非仅”参数”的例子。

EnterPlanMode|模式切换|src/tools/EnterPlanModeTool/

{
  // No parameters needed —— 空 Schema
}

作用:请求进入计划模式(Plan Mode)——只读探索、先出方案、待用户批准后再动手。

亮点:

  1. 一个没有参数的工具也是工具。z.strictObject({}),源码里的注释只有一句”No parameters needed”。工具存在的意义,有时就是”一个需要被记录、被审批的状态转换”,而不是”一次数据处理”。
  2. 它的启停规则体现了一处对称性设计:在 --channels 模式下 ExitPlanMode 需要终端对话框而被禁用,于是 EnterPlanMode 也被一并禁用——源码注释写道,”这样计划模式就不会成为一个模型能进、却出不来的陷阱”。能力的开启与关闭必须成对考虑:只禁用出口而不禁用入口,等于制造一个陷阱。

同层还有任务家族的 TaskGet / TaskList / TaskUpdate / TaskOutput,团队家族的 TeamCreate / TeamDelete,以及模式与隔离类的 ExitPlanMode / EnterWorktree / ExitWorktree。它们的设计思想与上述几条一致,此处不再逐一展开(第 30 章系统讲解多智能体架构)。

源码范围说明(重要):本节介绍的工具都有完整实现文件。但该版本源码树中还有一批只有引用、没有实现目录的工具——它们在 src/tools.ts 里被引用,却不存在于 src/tools/ 下,内部逻辑待验证。据实测(src/tools.ts 全文比对 src/tools/ 目录),这批工具共 12 个,且触发机制分两类,不应混为一谈:

  • 11 个由 feature() 门控 + require() 动态加载(引用散布在 src/tools.ts:107–134):MonitorTool、SendUserFileTool、PushNotificationTool、SubscribePRTool、OverflowTestTool、CtxInspectTool、TerminalCaptureTool、WebBrowserTool、SnipTool、ListPeersTool、WorkflowTool。
  • 1 个由环境变量门控的静态 import:TungstenTool——它在 src/tools.ts:60 被静态导入,在 :215 处由 process.env.USER_TYPE === 'ant' 决定是否进入工具集。它不是 feature() 动态加载的那一类。

例如 SendMessage 的提示词反复提到的 ListPeers,就属于第一类。这正是”泄露源码能看到什么”的边界:40 个有实现目录的工具 + 12 个只有引用的工具(第 17 章)。

顺带说明一个容易踩的坑:src/tools/ 下实际有 42 个子目录,但其中 shared/(共享工具模块)与 testing/(测试辅助)不是工具,扣除后才是 40 个——统计工具数量时不能直接数目录。

7.12.5 从工具集看到的三个规律

回顾这些主要的工具,有几条规律值得单独拎出来:

  1. 能力边界是双层的。一层是”提供了哪些工具”,另一层是”在哪个执行上下文里提供哪些工具”。同一个 Harness,主线程、子智能体、异步智能体、协作队友拿到的工具集并不相同。先说”拿不到什么”。子智能体的禁用清单(ALL_AGENT_DISALLOWED_TOOLS,src/constants/tools.ts:36-46)包含 TaskOutput、ExitPlanMode、EnterPlanMode、TaskStop,以及 Agent 与 AskUserQuestion。前几项的理由在源码注释里写得很直白——TaskOutput 是”防止递归”,ExitPlanMode 是因为”计划模式是主线程抽象”。后两项则值得注意:Agent 只在非内部构建下被禁(源码注释:允许它可”启用嵌套智能体”),而 AskUserQuestion 的禁用理由源码未直接说明——架构推论:子智能体若反过来向用户提问,就会绕开主线程的人机交互通道,因此把它从子智能体手里拿走是合理的。再说”拿到什么”。协调者模式(coordinator mode)下工具集被收窄到四个:Agent、TaskStop、SendMessage、SyntheticOutput(COORDINATOR_MODE_ALLOWED_TOOLS,src/constants/tools.ts:107-112)。注意第四个 SyntheticOutput 很容易被漏掉——“协调者只做调度、不产出内容”是一个很自然的直觉,但源码并没有采纳它:协调者仍然需要一个输出通道。
  2. 门控做在 Schema 层,而不是提示词层。后台任务被禁用时,run_in_background 直接从 schema 里消失;_simulatedSedEdit 被 .omit() 掉以防绕过权限。模型看不到的参数,比”被劝阻的参数”可靠得多——这是本章最重要的工程结论之一。
  3. Schema 不只是接口契约,还是三样东西的载体:给权限提示用的 description 写作规范(Bash)、给用户界面用的字段约束(AskUserQuestion 的选项数量)、给安全边界用的字段裁剪(Bash 的 .omit())。把工具 schema 只当成”参数说明”,就浪费了它一半的用途。

本章小结

本章深入了 Tool System 的完整链路,核心要点:

  1. 工具的本质:模型可请求调用、Harness 实际执行、带结构化接口的外部函数。工具定义了 Agent 的能力边界。
  2. 完整链路:Schema(接口契约)→ Discovery(注入上下文)→ Registry(集中注册)→ Dispatcher(路由调度)→ Executor(实际执行)→ Result(结果返回)。
  3. 健壮性三件套:错误处理(错误作为结果返回)、超时控制(分类超时)、权限检查(危险工具需审批)。
  4. 声明式元数据:工具用 isReadOnly / isConcurrencySafe / isDestructive 等谓词把自己的副作用讲清楚,框架据此做出并发与授权决策——并发安全是按每次调用判定的,不是给工具贴的静态标签。
  5. 设计哲学:Schema 是给模型的 API 文档;结果是给模型的输出设计;权限是 Agent 安全的关键防线。

工具是 Agent 的”手和脚”。但工具要靠模型自己想到去用——而有一类能力,我们希望人一敲就能触发,不必等模型判断。下一章我们看 Command(斜杠命令)系统:它是把一段操作固化成可复用入口的机制,也是”能力的三种扩展形态”中的第一种。

更多内容:

《AI Agent 架构设计与工程实践指南》——从 LLM、Agent、Harness 到 Mini Claude Code – 编程开物

Post Views: 6
AI应用架构设计 技术教程 AI AgentAI Agent ArchitectureAI Agent HarnessAI Agent 工程AI Agent 架构AI Application ArchitectureAI 工程AI 应用AI 应用架构AI 智能体AI 智能体架构Tool System

文章导航

Previous post

站内搜索

微信公众号

广告赞助

近期文章

  • 第 7 章 Tool System:给 AI 装上”手和脚”
  • 第 6 章 Context Engineering:Agent 的”工作内存”
  • 第 5 章 主流 AI Agent 架构模式
  • 第 3 章 AI Agent Loop:现代 AI Agent 背后的核心架构
  • 第 4 章 Agent Harness是什么?
  • Token经济:从10亿亿到3500亿亿,Token正在形成智能经济模型
  • 第 2 章 LLM Application 的基本架构
  • 第 1 章 重新认识 AI Agent
  • 《AI Agent 架构设计与工程实践指南》——从 LLM、Agent、Harness 到 Mini Claude Code
  • 2025年企业级编程技术栈趋势简报

近期评论

  • 《AI Agent 架构设计与工程实践指南》——从 LLM、Agent、Harness 到 Mini Claude Code - 编程开物 发表在《第 3 章 AI Agent Loop:现代 AI Agent 背后的核心架构》
  • 《AI Agent 架构设计与工程实践指南》——从 LLM、Agent、Harness 到 Mini Claude Code - 编程开物 发表在《第 4 章 Agent Harness是什么?》
  • 第 4 章 Agent Harness是什么? - 编程开物 发表在《《AI Agent 架构设计与工程实践指南》——从 LLM、Agent、Harness 到 Mini Claude Code》
  • 《AI Agent 架构设计与工程实践指南》——从 LLM、Agent、Harness 到 Mini Claude Code - 编程开物 发表在《第 2 章 LLM Application 的基本架构》
  • 《AI Agent 架构设计与工程实践指南》——从 LLM、Agent、Harness 到 Mini Claude Code - 编程开物 发表在《第 1 章 重新认识 AI Agent》

归档

  • 2026 年 9 月 (9)
  • 2025 年 8 月 (1)
  • 2025 年 7 月 (1)
  • 2025 年 6 月 (10)
  • 2025 年 5 月 (10)
  • 2025 年 4 月 (5)
  • 2025 年 2 月 (1)
  • 2024 年 12 月 (4)
  • 2024 年 11 月 (7)
  • 2024 年 9 月 (1)
  • 2024 年 8 月 (4)
  • 2024 年 7 月 (1)
  • 2024 年 2 月 (1)
  • 2023 年 12 月 (3)
  • 2023 年 11 月 (6)
  • 2023 年 10 月 (4)
  • 2023 年 9 月 (2)
  • 2023 年 8 月 (38)
  • 2022 年 2 月 (1)
  • 2022 年 1 月 (13)
  • 2021 年 1 月 (1)
  • 2020 年 10 月 (1)
  • 2020 年 1 月 (1)
  • 2014 年 7 月 (2)

分类

  • IT咨询 (5)
    • IT咨询框架 (3)
  • IT项目管理 (2)
  • 人工智能 (12)
    • AI概念和理论 (1)
    • 人工智能应用 (2)
    • 数据科学 (3)
  • 企业架构 (13)
    • AI应用架构设计 (8)
    • 传统应用架构设计 (2)
  • 工具Tips (3)
  • 技术教程 (8)
  • 生活笔记 (23)
  • 编程基础 (3)
    • 计算机网络 (2)
  • 编程笔记 (56)
    • .NET技术栈 (3)
    • C语言编程 (1)
    • Golang技术栈 (1)
    • iOS App开发 (1)
    • Python编程 (18)
    • UE虚幻引擎 (1)
    • Unity游戏开发 (9)
    • Wordpress (5)
    • 工具 (1)
  • 行业动态 (16)
©2026 编程开物 | WordPress Theme by SuperbThemes | 沪ICP备17019044号-3