
1. Claude code agent 到底由哪些东西组成一次把组件拆开看很多人第一次接触 Claude code agent会以为它就是一个“会写代码的模型”。真跑起来才发现它更像一支小型施工队有人负责看图纸有人负责搬砖有人负责验收还有人负责记账。模型只是那个“会思考的工头”真正让它能干活的是围绕它搭起来的一整套组件。我理解的 Claude code agent核心可以拆成六层工具与执行循环、规划与协调、子 agent、技能系统、任务系统、内存与上下文管理再往外还有并发后台任务、协作 agent 团队、自主 agent、worktree 工作隔离。这些名字听着唬人其实每一层都在解决一个具体问题——上下文太胖、进度会丢、任务没依赖、多个 agent 互相踩脚。这篇文章不打算只讲概念。我会从“统一 Key / API 通道”这个视角切入把每个组件的职责讲清楚然后给出可复制的配置片段和验证步骤。你跟着做能亲手跑通一个最小 agent 循环再逐步理解每个模块为什么存在。适合想搞懂 agent 架构、又不想只停留在 PPT 层面的开发者。先说结论agent 的组成不是越多越好而是每加一个组件都要对应一个真实痛点。下面按“从最小可用到逐步增强”的顺序拆。2. TaoToken 统一 Key 前置把 API 通道先打通在拆组件之前得先把“模型调用”这条通道打通。Claude code agent 的所有组件最终都要通过一个 API 通道去调用模型。如果每个组件、每个子 agent、每个队友都各自配一套 Key管理会非常乱。所以我习惯用一个统一 Key 的方式把 Base URL、Key、Model ID 三件套集中管理。TaoToken 在这里扮演的就是统一入口的角色。官网是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 。注意 API 地址不带 UTM 参数配置的时候别写错。为什么强调“统一 Key”因为后面你会看到子 agent 要新开上下文、队友 agent 要独立 loop、后台任务要并发跑如果每个都单独配 Key改一次模型就得改十几处。统一 Key 的好处是所有组件共享同一个 Base URL 和 Key只在需要时切换 Model ID。先拿 Key。打开 https://taotoken.net/api-keys 创建一个 API Key复制保存。然后确认你要用的模型 ID可以在 https://taotoken.net/models 查。我实测下来Claude 系列在 coding 场景表现稳定适合做 agent 的主模型。拿到三件套后建议用环境变量管理别硬编码进代码export TAOTOKEN_BASE_URLhttps://taotoken.net/api export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_MODELclaude-sonnet-4-5如果你用 Claude Code 这类工具配置方式不太一样。Claude Code 读取的是 settings 文件路径通常在~/.claude/settings.json。可以这样写{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的key, ANTHROPIC_MODEL: claude-sonnet-4-5 } }注意这里的环境变量名是ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY不是随便起的。Claude Code 内部按这套变量名读取。如果你用的是 Codex 类工具它读的是~/.codex/auth.json结构类似{ OPENAI_BASE_URL: https://taotoken.net/api, OPENAI_API_KEY: sk-你的key }三件套的核心就是Base URL 指向统一通道Key 用同一个Model ID 按场景选。配好之后先别急着写 agent用一条最简单的请求验证通道是否通。3. 可复制配置最小 agent 循环 工具分发通道打通后我们来看 agent 最核心的组件工具与执行循环。一个最简单的 agent本质就是“一个 while 循环 一组工具”。用户消息进来创建带工具定义的模型调用检查是否要继续调工具逐个执行工具并把结果塞回消息循环直到模型不再调工具。先写最小循环。用 Python 的 anthropic SDKimport os from anthropic import Anthropic client Anthropic( base_urlos.environ[TAOTOKEN_BASE_URL], api_keyos.environ[TAOTOKEN_API_KEY], ) MODEL os.environ[TAOTOKEN_MODEL] WORKDIR os.path.abspath(./workspace) def agent_loop(query): messages [{role: user, content: query}] while True: response client.messages.create( modelMODEL, systemYou are a coding agent., messagesmessages, toolsTOOLS, max_tokens8000, ) messages.append({role: assistant, content: response.content}) if response.stop_reason ! tool_use: return response.content results [] for block in response.content: if block.type tool_use: handler TOOL_HANDLERS.get(block.name) output handler(**block.input) if handler else fUnknown tool: {block.name} results.append({ type: tool_result, tool_use_id: block.id, content: str(output)[:50000], }) messages.append({role: user, content: results})这段代码就是 agent 的心脏。但只有 bash 一个工具时所有操作都走 shellcat截断不可预测sed遇到特殊字符就崩而且每次 bash 调用都是不受约束的安全面。所以第二步是加专用工具并做路径沙箱。路径沙箱的核心是把用户传进来的相对路径拼到工作目录后再 resolve 成绝对路径检查是否还在工作目录内from pathlib import Path def safe_path(p: str) - Path: path (Path(WORKDIR) / p).resolve() if not path.is_relative_to(WORKDIR): raise ValueError(fPath escapes workspace: {p}) return path def run_read(path: str, limit: int None) - str: text safe_path(path).read_text() lines text.splitlines() if limit and limit len(lines): lines lines[:limit] return \n.join(lines)[:50000]然后建一个分发图dispatch map把工具名映射到处理函数TOOL_HANDLERS { bash: lambda **kw: run_bash(kw[command]), read_file: lambda **kw: run_read(kw[path], kw.get(limit)), write_file: lambda **kw: run_write(kw[path], kw[content]), edit_file: lambda **kw: run_edit(kw[path], kw[old_text], kw[new_text]), }这里的**kw表示接收任意数量的关键字参数并打包成字典。循环里按名称查找处理函数找不到就返回 Unknown tool。对比一下加工具前只有 1 个 bash硬编码调用加工具后有 4 个工具用字典分发还多了路径安全。agent loop 本身不变——这就是好架构的特征扩展点集中在工具层循环保持稳定。工具定义TOOLS也要同步写每个工具要有 name、description、input_schema。description 写清楚模型才知道什么时候用哪个工具。4. 验证请求跑通一次真实工具调用配置写好了得验证。先跑一个最简单的请求确认通道和模型都正常resp client.messages.create( modelMODEL, max_tokens200, messages[{role: user, content: 用一句话说明什么是 agent loop}], ) print(resp.content[0].text)如果这一步报 401说明 Key 或 Base URL 有问题先回去检查环境变量。如果正常返回文本说明通道通了。接着验证工具调用。给 agent 一个明确任务“读取 workspace 下的 README.md统计有多少行”。预期行为是模型先返回一个tool_use块name 是read_fileinput 里带 path你的循环执行run_read把结果作为tool_result塞回模型再基于结果给出答案。跑通后你会看到类似这样的过程[assistant] tool_use: read_file {path: README.md} [tool_result] 前 50000 字符内容... [assistant] 这个文件共有 42 行。再验证路径沙箱。故意传一个越界路径run_read(../../etc/passwd)预期抛出ValueError: Path escapes workspace。这一步很重要它证明你的工具层有安全边界不是裸奔的 shell。验证子 agent 时可以给父 agent 一个 task 工具让它“新开一个子 agent 去统计 workspace 下所有 .py 文件的行数”。子 agent 以messages[]启动跑自己的循环最后只把摘要返回给父 agent。父 agent 的上下文里只多了一条 tool_result而不是子 agent 跑过的几十次工具调用记录。这就是上下文隔离的价值。验证技能系统时建一个skills/git/SKILL.md带 YAML frontmatter--- name: git description: Git workflow helpers --- Step 1: 检查当前分支... Step 2: 提交前先跑测试...系统提示里只放技能目录约 100 token/skill模型需要时调load_skill(git)才把完整正文约 2000 token注入。这样 10 个技能不会一上来就吃掉 20000 token。5. 本篇常见错排查401、local proxy failed、reading choices跑 agent 的过程中报错基本集中在几个地方。我按真实遇到的顺序列一下。401 Unauthorized。最常见。原因通常是 Key 没读到、Base URL 写错、或者环境变量名不对。检查三点TAOTOKEN_API_KEY是否真的 export 了TAOTOKEN_BASE_URL是否是https://taotoken.net/api注意结尾没有多余斜杠Claude Code 场景下变量名是否是ANTHROPIC_API_KEY而不是TAOTOKEN_API_KEY。改完记得重启终端或重新加载 settings。local proxy failed。这个报错通常出现在工具链试图走本地代理时。检查你的环境里有没有残留的HTTP_PROXY/HTTPS_PROXY变量有的话先 unset。另外确认 Base URL 直接指向https://taotoken.net/api不要中间再套一层本地转发。reading choices 相关报错。这类错误一般出现在解析模型响应时比如response.content为空、或者stop_reason不是预期值。排查方向确认max_tokens没设太小导致响应被截断确认模型 ID 拼写正确打印完整response看结构。如果是子 agent 场景检查子 agent 的messages是否以[{role: user, ...}]正确初始化。OAuth 相关报错。有些工具默认走 OAuth 登录流程如果你用的是 API Key 模式需要在配置里显式关闭 OAuth。Claude Code 场景下确认 settings 里没有冲突的登录配置Codex 场景下确认auth.json里是 API Key 而不是 OAuth token。工具调用死循环。模型反复调同一个工具通常是工具返回结果里没有足够信息让它判断“已完成”。检查tool_result内容是否被截断得太狠或者 description 是否写得太模糊。给工具加一个明确的成功/失败标识会有帮助。上下文爆炸。跑长任务时messages数组越来越大最后超限。这时候需要上下文压缩第一层 micro_compact把超过 3 轮的旧 tool_result 替换成占位符第二层 auto_compacttoken 超阈值时把完整对话存盘让模型做摘要用摘要替换所有消息第三层是模型主动调 compact 工具。三层配合活跃上下文始终可控。排查的核心思路是先确认通道401 类再确认工具层路径、参数最后确认循环逻辑stop_reason、消息结构。大部分问题都在前两层。6. 从组件到协作任务系统、团队与 worktree 隔离前面拆的是单个 agent 的组件。当任务变复杂单 agent 就不够了需要任务系统、协作团队和工作隔离。任务系统的核心是把内存里的扁平清单升级成持久化到磁盘的任务图。每个任务一个 JSON 文件有状态、前置依赖blockedBy和后置依赖blocks。任务图随时回答三个问题什么可以做pending 且 blockedBy 为空、什么被卡住等前置完成、什么做完了completed 并自动解锁后续。完成任务时自动把它的 ID 从其他任务的 blockedBy 里移除这就是依赖解除。协作 agent 团队的核心是每个队友一个独立 loop用磁盘上的团队配置和收件箱互相传消息。config.json是花名册inbox/*.jsonl是邮箱发消息就是往对方邮箱追加一行 JSON收消息就是读全部再清空。队友生命周期是 spawn → WORKING → IDLE → WORKING → SHUTDOWN。关机协议和计划审批协议共用同一个状态机发起方生成 request_id接收方 approve/reject状态从 pending 走到 approved 或 rejected。自主 agent 在队友基础上加了 IDLE 阶段空闲时轮询收件箱和任务看板发现未认领任务就自动认领。还有一个细节是身份重注入——上下文压缩后 agent 可能忘了自己是谁所以在消息过短时在开头插入身份块。worktree 工作隔离解决的是“多个 agent 同时改同一个文件”的问题。控制面在.tasks/执行面在.worktrees/。每个任务绑定一个独立 git worktree 目录用任务 ID 关联。创建 worktree 时自动把任务推进到 in_progress收尾时worktree_remove(name, complete_taskTrue)一个调用搞定拆除加完成。每个生命周期步骤写入events.jsonl崩溃后可以从磁盘状态重建现场。把这些组件串起来看Claude code agent 的组成就清晰了工具与循环是心脏规划与任务是大脑子 agent 和技能是手脚内存管理是呼吸并发和团队是协作worktree 是隔离。统一 Key 则是贯穿所有组件的血管。想动手的话可以从 API Keys 页面拿 Key再对着接入文档把最小循环跑起来想验证模型表现可以直接在模型对话里试如果要做长期编码或 Agent 项目Coding Plan 会更省心。