1. 从主 Agent 上下文爆炸说起Subagent 到底解决什么问题如果你用 AgentScope 写过稍微复杂一点的任务大概率遇到过这种情况主 Agent 一开始还挺聪明任务跑到第三四轮就开始忘事前面读过的文件内容、工具返回结果全堆在上下文里token 消耗飙升推理质量断崖式下跌。这不是模型不行是主线程被塞爆了。Subagent子代理就是冲着这个问题来的。一句话概括让主 Agent 像项目经理一样把独立子任务派给下属去干自己只负责统筹和汇总。每个子代理本质上是 HarnessAgent 的一个临时独立实例有自己的子会话、独立推理、独立执行干完把结果通过工具调用回传给主 Agent。它能做什么三个核心价值第一避免主线程膨胀主 Agent 不用把所有细节塞进自己的上下文第二可并行多个子代理同时干活互不干扰第三可独立处理每个子代理专注单一任务效率更高。适合谁适合已经在用 AgentScope 搭多智能体、或者准备把单体 Agent 拆成分工协作架构的开发者。前置知识上你需要了解 Skill给 Agent 加工具能力和 Workspace工作区的基本概念——Skill 是加工具Subagent 是加人手。但这里有个现实问题子代理一多模型调用就分散了。主 Agent 用一个模型reviewer 子代理用另一个remote-researcher 又走远端服务Key 管理立刻变成一团乱麻。我试过在多个子代理里分别配不同厂商的 Key结果调试时根本分不清哪次调用扣的哪个额度。所以这篇会把 Subagent 机制讲透的同时用 TaoToken 统一 Key 和 API 通道让所有子代理走同一个入口配置和排障都清爽很多。2. TaoToken 前置准备统一 Key 与 API 通道接入在动手写 Subagent 声明之前先把模型通道统一掉。TaoToken 的作用是给你一个统一的 API 入口主 Agent 和所有子代理都通过它调用模型不用在每个子代理里塞不同的厂商 Key。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 端点是 https://taotoken.net/api 这个不加 UTM。你需要准备三样东西我把它叫做三件套Base URL、API Key、Model ID。Base URL 就是 https://taotoken.net/api API Key 在控制台的 API Keys 页面生成Model ID 则是你要调用的具体模型标识比如 qwen3-max、gpt-4o-mini 这类。这三件套在后面的 AgentScope 配置里会反复出现主 Agent 和每个子代理都要用到。生成 Key 的入口在这里https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。进去之后创建一个 Key复制保存好后面配置里会用到。注意 Key 只在创建时完整显示一次丢了就重新建一个。如果你还没决定用哪个模型可以先到模型对话页面试一下https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 。在里面发几条消息确认通道通了、模型响应正常再回到代码里配置。这一步别省很多人直接上代码结果报 401 又回头查浪费时间。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有完整的端点和参数说明。控制台在 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 可以看调用记录和额度消耗——这个在排查到底是哪个子代理在烧 token时特别有用。为什么要在 Subagent 场景下强调统一 Key因为子代理是独立实例每个实例都要初始化模型客户端。如果你给 reviewer 配一个 Key、给 researcher 配另一个 Key一旦某个子代理报错你得挨个排查。统一走 TaoToken 之后所有子代理的模型调用都经过同一个 Base URL出问题只看一个地方。而且子代理的 maxIters 通常设得比主代理小统一通道后你能在控制台清楚看到每个子代理的调用量方便调优。3. 可复制配置Subagent 声明与 TaoToken 三件套落地这一节是核心直接给可复制的配置片段。AgentScope 里声明子代理有三种方式文件声明、编程声明、远程 HTTP 声明三者互斥一个声明只能选一种来源模式。我先把 TaoToken 三件套落到配置里再分别演示。先看文件声明。在 workspace/subagents/ 目录下放一个 Markdown 文件文件名去掉 .md 就是 agent_id。比如 reviewer.md--- description: 代码评审专家负责审查代码质量、发现潜在 bug workspace: mode: isolated path: ./defs/reviewer model: qwen3-max maxIters: 8 tools: [read_file, grep_files] --- 你是一个专注代码评审的子 agent。逐行检查代码逻辑指出潜在的空指针、边界条件和性能问题输出格式为问题列表加修复建议。这里 model 字段填的就是 TaoToken 的 Model ID。但光有 Model ID 不够还需要 Base URL 和 API Key。AgentScope 的模型客户端初始化时把这三件套传进去ModelClient modelClient ModelClient.builder() .baseUrl(https://taotoken.net/api) .apiKey(System.getenv(TAOTOKEN_API_KEY)) .model(qwen3-max) .build();注意 Base URL 是 https://taotoken.net/api 不要加 UTM 参数那是给网页链接用的。API Key 建议走环境变量别硬编码在代码里。Model ID 按你实际要用的填。再看编程式声明适合需要动态配置的场景HarnessAgent.builder() .name(orchestrator) .model(modelClient) .workspace(workspace) .subagent(SubagentDeclaration.builder() .name(reviewer) .description(代码审查专家) .workspace(Path.of(./defs/reviewer)) .workspaceMode(WorkspaceMode.ISOLATED) .model(qwen3-max) .maxIters(8) .tools(List.of(read_file, grep_files)) .build()) .subagent(SubagentDeclaration.builder() .name(remote-researcher) .description(远端调研子 agent) .url(http://agent-task-server:8080) .headers(Map.of(Authorization, Bearer System.getenv(TAOTOKEN_API_KEY))) .build()) .build();远程 HTTP 声明这里headers 里的 Authorization 用的还是 TaoToken 的 Key这样远端服务也能走统一通道。互斥约束要记住url 不能和 workspace 同时出现workspace 不能和 inlineAgentsBody 同时出现。声明来源的合并顺序是内置 general-purpose → 编程声明 → 文件声明 → 自定义工厂。同名后面的覆盖前面的但 general-purpose 是保留名不会被覆盖。内置的 general-purpose 子代理开箱即用能力镜像主 Agent共享主工作区固定是 leaf 节点不能再招下属。如果你用 Codex 的 auth.json 或 Cline MCP 这类工具三件套的写法是Base URL 填 https://taotoken.net/api Key 填你的 TaoToken KeyModel ID 填具体模型。CC Switch 里也是同样三件套别只填 Key 忘了 Base URL这是最常见的配置遗漏。4. 验证请求一次多子代理并发调用的完整动作配置写完得验证它真的能跑。这一节给一次多子代理并发调用的完整动作从 agent_spawn 到 task_output 收结果。先看工具一览。agent_spawn 创建子代理并执行首个任务关键参数有 agent_id必填、task可选首条任务、label可选标签、timeout_seconds默认 30 秒0 表示后台异步最大 600 秒。agent_send 给已有子代理发后续消息用 agent_key 或 label 定位。agent_list 列出活跃子代理。task_output 查后台任务结果block 默认 true 会阻塞查状态建议用 false。task_cancel 取消任务task_list 列出所有任务。并发调用的动作是这样的主 Agent 先 spawn 两个子代理timeout_seconds 设 0 走后台异步然后主 Agent 继续处理其他事过一会儿用 task_output(blockfalse) 查状态。// 第一步并发派发两个任务timeout_seconds0 表示后台异步 String spawnResult1 agent_spawn( reviewer, 审查 src/main/java/com/example/OrderService.java 的空指针风险, review-task-1, 0 ); String spawnResult2 agent_spawn( remote-researcher, 调研当前项目依赖的日志库最新稳定版本, research-task-1, 0 ); // 第二步不要立即轮询先返回给用户稍后再查 // 第三步查任务状态blockfalse 不阻塞 String status1 task_output(task-id-1, false, 30000); String status2 task_output(task-id-2, false, 30000); // 第四步确认完成后取结果 String result1 task_output(task-id-1, true, 300000); String result2 task_output(task-id-2, true, 300000);成功结果长这样task_output 返回的 JSON 里 status 字段是 COMPLETEDresult 字段是子代理的产出文本。如果 status 是 RUNNING说明还在跑继续等FAILED 就要看 error 字段排查CANCELLED 是你自己取消的。异步任务的生命周期是 PENDING → RUNNING → COMPLETED / FAILED / CANCELLED。PENDING 是任务已创建写入存储RUNNING 是子代理正在干活COMPLETED 是结果已回传。这里有个坑agent_spawn 返回的 agent_key 是完整 key不是 agent_id、不是 session_id、也不是 task_id。agent_send 必须用这个完整 agent_key用错了就定位不到子代理。RuntimeContext 透传也值得说一句。子代理的 session_id 是新生成的sub-但 userId 会从父代理透传过来确保权限隔离一致性。所以你在子代理里做权限判断时拿到的 userId 和主代理是一致的。防递归机制这里也验证一下所有声明创建的子代理都被标记为 leaf不能再注册子代理钩子即使绕过 leaf 标记agent_spawn 还有硬编码的 MAX_SPAWN_DEPTH 3。主 Agent → 子代理 → 孙代理最多三层绝不可能无限嵌套。你可以试着让子代理再 spawn会直接被拦。5. 本篇常见错排查401、local proxy failed 与 reading choices配置和验证跑通之前大概率会踩几个坑。这一节对照真实报错逐个排查。第一个高频错误是 401 Unauthorized。报错信息通常是401 Unauthorized: invalid api key或authentication failed。原因基本是三件套没配全或配错。排查顺序先确认 Base URL 是不是 https://taotoken.net/api 注意不要带 UTM 参数也不要漏了 /api 路径再确认 API Key 是不是从 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 生成的、有没有复制完整最后确认 Model ID 是不是当前 Key 有权限调用的模型。三个都对还报 401就去控制台看 Key 是不是被禁用或额度耗尽。第二个错误是local proxy failed或connection refused。这个通常出现在远程 HTTP 声明的子代理上。报错信息类似local proxy failed: dial tcp 127.0.0.1:8080: connect: connection refused。原因是远端服务地址填错了或者远端服务没启动。排查确认 url 字段填的是远端服务真实可达的地址不是本地回环确认远端服务已经起来如果远端服务也要调模型确认它的 Base URL 也指向 https://taotoken.net/api 。第三个错误是reading choices相关报错信息类似error reading choices: unexpected end of JSON input或reading choices: EOF。这个多半是模型返回体解析失败常见原因是 Base URL 配成了网页地址而不是 API 地址或者请求被中间层拦截返回了 HTML。排查确认 Base URL 是 https://taotoken.net/api 而不是官网首页确认没有额外的代理层篡改响应如果用了自定义 HTTP 客户端检查超时设置是不是太短导致响应被截断。第四个错误是 OAuth 相关报错信息类似OAuth token expired或invalid_grant。如果你用的是需要 OAuth 的模型通道token 过期就会这样。排查重新走一遍授权流程拿新 token确认 token 没有硬编码在代码里导致过期后不刷新。用 TaoToken 统一 Key 的话这类问题会少很多因为 Key 管理集中在控制台。还有一个容易忽略的agent_send 报agent not found。原因是你用了 agent_id 或 session_id 去定位但 agent_send 要的是 agent_spawn 返回的完整 agent_key。排查把 agent_spawn 的返回值完整存下来agent_send 时原样传入。排障时建议开着控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 看调用记录里有没有对应的请求。如果请求根本没到说明是本地配置问题如果到了但报错说明是 Key 或模型权限问题。接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里有各端点的详细参数对着查比瞎试快。6. 把子代理编排跑顺从统一 Key 到长期 Coding Plan子代理编排跑通之后你会发现真正的瓶颈不在机制而在模型调用的稳定性和成本控制。主 Agent 加多个子代理调用量是单 Agent 的好几倍如果每个子代理都配不同通道成本根本算不清。统一走 TaoToken 之后所有调用在一个控制台可见哪个子代理烧得多一目了然调 maxIters 和模型选择都有依据。几个实操建议。第一子代理的 maxIters 设小通常比主代理小避免子代理消耗过多 token。第二description 是关键它是主模型决定把任务派给谁的核心依据写清楚何时使用 / 输出格式 / 禁止事项。第三工作区模式是核心决策ISOLATED 让子代理有独立文件空间SHARED 让子代理和主代理共享文件根据任务是否需要访问主代理文件来选。第四异步任务不要创建后立即轮询先返回给用户再用 task_output(blockfalse) 查状态。如果你打算长期跑多智能体协作比如让子代理持续做代码审查、调研、测试可以考虑 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。它适合长期编码和 Agent 场景比按次调用更划算。模型对话入口在 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 验证模型通不通先用它。API Keys 在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。最后说个我踩过的坑一开始我给每个子代理都配了独立的模型客户端结果 reviewer 用 qwen3-max、researcher 用 gpt-4o-mini调试时分不清哪次调用扣的哪个额度。后来全部统一走 TaoToken主 Agent 和子代理共用三件套控制台一看就清楚。子代理机制本身不复杂复杂的是多实例下的配置一致性统一 Key 通道能省掉一大半排障时间。