1. 为什么要在 Claude Code 里塞一个第三方模型当 subagent
第一次听到“让第三方模型作为 subagent 与 Claude 协作”这个玩法时,我脑子里冒出来的第一个念头是:这不是多此一举吗?Claude 自己就能写代码、能读文件、能跑命令,为什么还要再挂一个别的模型进来?后来在一个真实项目里被逼着试了一次,才发现这个思路的价值远比表面看起来大。
先说清楚这个方案到底在干什么。Claude Code 本身是一个跑在终端里的智能编程助手,它能理解你的代码库、执行 shell 命令、读写文件、做多步推理。而 subagent 机制允许你定义一个“子代理”,把某类特定任务分派给它去处理,主代理负责统筹调度。默认情况下这个子代理也是 Claude 系列模型,但 Claude Code 的架构允许你通过配置,把 subagent 指向一个完全不同的模型服务——只要那个服务暴露了兼容的 API 接口。
这就打开了一个很有意思的空间。你可以让 Claude 做它最擅长的事:全局规划、代码架构理解、多文件重构、复杂逻辑推理。同时把一些“量大管饱”的活儿丢给第三方模型:批量生成单元测试、格式化转换、简单的 CRUD 代码填充、文档字符串补全、日志分析。核心逻辑是用不同模型的能力差异和成本差异来做任务分层,而不是把所有 token 都烧在同一个模型上。
适合谁来参考这个方案?三类人最值得看。第一类是日常重度使用 Claude Code 的独立开发者,每个月的 API 账单让你肉疼,想找个办法把成本压下来又不牺牲核心体验。第二类是对多模型协作感兴趣的工程师,想在实际项目里验证“不同模型分工”到底靠不靠谱。第三类是团队里负责搭建 AI 辅助开发流程的人,需要一套可配置、可切换、可回退的方案,而不是把宝全押在一家服务上。
我踩过的第一个坑就是:以为配好就能用,结果发现 subagent 的调用链路、上下文传递、错误处理跟主代理完全不是一回事。下面把我趟出来的完整路径拆开讲,包括配置怎么写、任务怎么分、出问题怎么查。
2. 整体架构设计与任务分层思路
2.1 主代理与子代理的职责边界怎么划
在动手配置之前,必须先想清楚一件事:哪些任务交给 Claude 主代理,哪些丢给第三方 subagent。这个边界划不好,要么第三方模型接不住任务频繁报错,要么 Claude 被架空、整个流程还不如单模型跑得顺。
我的划分原则基于三个维度:任务复杂度、上下文依赖度、输出确定性。
高复杂度、强上下文依赖、需要跨文件推理的任务,比如“重构这个模块的依赖注入方式”“分析这个 bug 的根因并给出修复方案”“设计新功能的接口契约”,这些必须留给 Claude 主代理。因为这类任务需要理解整个代码库的结构、历史决策、隐含约定,第三方模型拿到的上下文往往是裁剪过的,很容易给出看似合理实则破坏架构的建议。
低复杂度、上下文自包含、输出格式明确的任务,比如“给这个函数生成 docstring”“把这个 JSON 转成 TypeScript 类型定义”“为这个纯函数写 5 个边界测试用例”“把这段日志里的错误码提取成表格”,这些非常适合丢给 subagent。它们的特点是:输入输出边界清晰,不需要理解全局,错了也容易发现和回滚。
中间地带的任务需要谨慎处理。比如“给这个类补全 getter/setter”,看起来简单,但如果这个类有特殊的命名约定或者继承关系,第三方模型可能生成风格不一致的代码。我的做法是:中间地带先给 subagent 试,但在 prompt 里把约定和示例塞进去,如果连续两次输出不合格,就升级回主代理处理。
2.2 为什么选“subagent 模式”而不是“多开一个终端”
有人可能会问:我直接开两个终端,一个跑 Claude Code,一个跑第三方模型的 CLI,不也能协作吗?何必折腾 subagent 配置?
这个区别很关键。多开终端是人工协作,你得手动把 Claude 的输出复制到另一个终端,再把结果贴回来,上下文全靠你自己维护。而 subagent 模式是程序化协作,主代理在推理过程中自动判断“这个子任务适合分派”,然后通过配置好的接口调用第三方模型,拿到结果后继续自己的推理链路。整个过程对你是透明的,你只需要在最终输出里看到结果。
更重要的是,subagent 模式下上下文传递是可控的。你可以精确指定传给第三方模型的内容:是只传当前文件,还是传当前文件加相关类型定义,还是传一段裁剪过的代码片段。这种精细控制是多开终端做不到的。而且错误处理、重试、超时这些工程问题,subagent 框架帮你兜底了,你不需要自己写胶水代码。
2.3 第三方模型选型的几个硬指标
不是所有模型都能当 subagent。我在选型时踩过坑,总结下来必须满足这几个条件:
第一,API 兼容性。Claude Code 的 subagent 调用走的是特定的接口协议,你的第三方模型服务需要提供兼容的 endpoint。有些模型只提供自己的 SDK,没有兼容层,那就需要你自己写一个适配服务转发请求。这个适配服务的复杂度取决于两边协议的差异程度。
第二,上下文窗口够用。subagent 拿到的上下文虽然经过裁剪,但一个中等规模的函数加上相关类型定义,轻松就上千 token。如果第三方模型的上下文窗口只有 4K,那基本只能处理最碎片的任务,实用性大打折扣。我的经验是至少 32K 起步,64K 以上才比较从容。
第三,输出稳定性。这点最容易被忽视。第三方模型如果输出格式飘忽不定,比如该返回 JSON 的时候给你返回一段自然语言解释,那 subagent 的解析逻辑就会崩。选型时一定要用真实任务压测,看它在结构化输出上的表现。我一般会跑 20 个同类任务,统计格式合规率,低于 90% 的直接淘汰。
第四,延迟可接受。subagent 是在主代理推理链路里同步调用的,如果第三方模型响应要 30 秒,整个交互体验就会非常卡。实测下来,P95 延迟控制在 5 秒以内比较舒服,超过 10 秒就需要考虑异步化或者换模型。
| 指标 | 最低要求 | 推荐值 | 不达标的后果 |
|---|---|---|---|
| API 兼容性 | 有兼容 endpoint 或可适配 | 原生兼容 | 需要额外写适配层 |
| 上下文窗口 | 32K | 64K+ | 只能处理碎片任务 |
| 结构化输出合规率 | 90% | 95%+ | 解析频繁失败 |
| P95 延迟 | 10s | 5s 以内 | 交互卡顿明显 |
| 并发限制 | 满足日常用量 | 有弹性配额 | 高峰期任务排队 |
2.4 成本与收益的粗略测算
说点实在的。我拿一个中等规模项目做了两周对比:纯 Claude 跑完所有任务,和 Claude 主代理加第三方 subagent 分层的方案,在输出质量基本持平的前提下,token 成本降了大约四成。降幅主要来自那些批量、重复、低复杂度的任务被分流了。
但要注意,这个收益不是白来的。你需要花时间配置、调试、处理第三方模型偶尔的“抽风”。如果项目本身任务量不大,比如一天就跑几十次交互,那省下来的钱可能还不够你折腾的时间成本。这个方案适合任务量大、任务类型有明显分层、且你对成本敏感的场景。小项目或者探索性项目,直接用 Claude 单跑更省心。
3. 核心配置细节与实操要点
3.1 配置文件的结构与关键字段
Claude Code 的 subagent 配置通常放在项目根目录的配置文件夹里,或者用户级的全局配置目录。具体路径取决于你的安装方式和版本,但结构大同小异。核心是一个描述 subagent 的配置文件,里面定义了模型端点、认证方式、能力声明和触发条件。
我以最常见的配置结构为例说明关键字段。首先是name和description,这两个字段决定了主代理在什么情况下会考虑调用这个 subagent。description写得越具体,主代理的判断越准。比如你写“处理简单代码任务”,主代理可能把复杂任务也丢过来;你写“为纯函数生成单元测试,输入为函数源码,输出为测试代码”,主代理的匹配精度会高很多。
然后是endpoint和apiKey相关字段。这里有个坑:不要把 API key 硬编码在配置文件里。用环境变量引用,配置文件里只写变量名。我见过有人直接把 key 写进去然后提交到了代码仓库,虽然可以撤销,但那一瞬间的暴露风险是实打实的。
model字段指定第三方模型的具体名称或标识。maxTokens控制单次调用的最大输出长度,这个值要跟你的任务类型匹配。生成 docstring 可能 512 就够,生成测试用例可能要 2048。设太小会截断,设太大浪费配额。
timeout字段容易被忽略。默认值可能偏长,导致第三方模型卡住时整个流程跟着卡。我一般设 15 到 30 秒,超过就判定失败走回退逻辑。
{ "name": "test-generator", "description": "为纯函数生成单元测试,输入函数源码,输出测试代码", "endpoint": "https://your-model-service.example.com/v1/chat/completions", "apiKeyEnv": "THIRD_PARTY_MODEL_KEY", "model": "your-model-name", "maxTokens": 2048, "timeout": 20000, "capabilities": ["code-generation", "structured-output"] }3.2 上下文裁剪策略:传什么、不传什么
这是整个方案里最需要花心思的地方。第三方模型拿到的上下文质量,直接决定它的输出能不能用。传多了浪费 token 还可能干扰判断,传少了信息不足输出跑偏。
我的裁剪策略分三层。第一层是任务必需:当前处理的函数或代码块的完整源码,这是底线,不能省。第二层是类型与接口定义:如果函数依赖了自定义类型、接口、常量,把这些定义也带上,否则第三方模型可能凭空造一个不存在的类型。第三层是风格示例:从项目里挑一两个风格规范的同类函数作为参考,让第三方模型模仿。
不传的东西同样重要。整个代码库的目录结构不传,第三方模型不需要知道项目有多大。无关模块的源码不传,避免干扰。敏感配置和密钥不传,这个不用解释。历史对话记录不传,除非任务本身依赖上下文。
实际操作中,我会在 subagent 的 prompt 模板里用占位符标记这些部分,主代理在分派任务时填充。比如模板里写“以下是目标函数:{{target_code}},以下是相关类型定义:{{type_defs}},以下是风格参考:{{style_examples}}”,主代理负责从当前上下文里提取并填充。
注意:上下文裁剪不是越少越好。我早期为了省 token 把类型定义省了,结果第三方模型生成的测试用例引用了不存在的类型,编译都过不了。后来加上类型定义,虽然每次多花几百 token,但返工率大幅下降,总体反而更省。
3.3 触发条件的精细控制
主代理什么时候会调用 subagent?这取决于你在配置里定义的触发条件,以及主代理自己的判断。如果不加控制,可能出现两种极端:要么主代理从不调用 subagent,配置形同虚设;要么主代理过度调用,把本该自己处理的任务也丢出去。
我的做法是用 description 做软引导,用显式指令做硬控制。软引导就是在 description 里写清楚适用场景,让主代理在语义匹配时倾向于调用。硬控制是在项目的指令文件里明确写“遇到 X 类任务时,优先分派给 test-generator subagent”。
还有一种更精细的控制方式:给 subagent 定义triggers字段,列出触发关键词或模式。比如["生成测试", "写单测", "补充测试用例"]。主代理在解析任务时如果命中这些模式,就会考虑分派。这种方式比纯语义匹配更可控,但需要你维护关键词列表。
实测下来,软引导加少量硬控制的组合最舒服。全硬控制太死板,遇到没预设的任务类型就抓瞎;全软引导太飘,主代理的判断不稳定。我一般只对最高频的两三类任务做硬控制,其余靠 description 引导。
3.4 错误处理与回退机制
第三方模型不是百分百可靠的。网络抖动、服务限流、输出格式错误、超时,这些都会发生。如果没有回退机制,一次失败就可能让整个任务链断掉。
我的配置里必设三层回退。第一层是重试:对于网络类错误,自动重试 2 到 3 次,每次间隔递增。第二层是降级:重试仍失败,把任务交回主代理处理,虽然成本高但保证任务完成。第三层是跳过:如果这个子任务不是关键路径,标记为跳过并记录,继续后续流程。
回退逻辑的配置因框架而异,但核心思路是:不要让 subagent 的失败阻塞主流程。我见过有人配置里没写回退,结果第三方服务挂了的那个下午,整个 Claude Code 会话全部卡死,只能手动重启。
还有一个细节:记录失败原因。每次 subagent 调用失败,把错误类型、输入摘要、时间戳记到日志里。积累一段时间后分析,能发现规律。比如某个模型在特定任务类型上总是超时,那就把它从这类任务的候选里移除。
4. 完整实操流程与关键环节实现
4.1 环境准备与依赖确认
动手之前先把环境理清楚。你需要确认几件事:Claude Code 的版本支持 subagent 配置(较新的版本都支持,但具体字段名可能有差异,查一下对应版本的文档);第三方模型服务的 API 能正常访问,用 curl 或 Postman 先跑通一个最简单的请求;环境变量管理工具就绪,确保 API key 不会泄露到配置文件里。
我习惯先用一个最小请求验证连通性。构造一个最简单的 chat completion 请求,只发一句“回复 OK”,看能不能正常拿到响应。这一步能排除掉认证错误、endpoint 写错、网络不通等基础问题。很多人一上来就配复杂任务,失败了分不清是配置问题还是任务问题,白白浪费时间。
curl -X POST "$THIRD_PARTY_ENDPOINT" \ -H "Authorization: Bearer $THIRD_PARTY_MODEL_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "your-model-name", "messages": [{"role": "user", "content": "回复 OK"}], "max_tokens": 10 }'拿到正常响应后,再验证结构化输出能力。发一个要求返回 JSON 的请求,看返回内容能不能被直接解析。这一步很关键,因为 subagent 的很多任务依赖结构化输出。
4.2 编写 subagent 配置文件
环境通了之后开始写配置。我建议从最简单的单 subagent 开始,不要一上来就配好几个。先跑通一个,验证整个链路,再逐步增加。
配置文件的核心是前面提到的那些字段。我额外加了一个systemPrompt字段,用来给第三方模型设定角色和输出规范。这个 prompt 写得好不好,直接影响输出质量。我的模板大致是:“你是一个代码辅助工具,负责{{task_type}}。输出必须严格遵循以下格式:{{output_format}}。不要添加额外解释,不要使用 markdown 代码块包裹,直接输出内容。”
output_format部分要尽可能具体。比如要求返回 JSON 时,把 schema 写出来,包括字段名、类型、是否必填。第三方模型看到明确的 schema,输出合规率会明显提升。
配置写完后,用一个真实但简单的任务测试。比如拿项目里一个纯函数,让 subagent 生成 docstring。观察整个流程:主代理有没有正确识别任务、有没有正确裁剪上下文、第三方模型输出是否符合预期、结果有没有正确回传。任何一环出问题,回到对应部分调整。
4.3 任务分派的实际运行观察
配置跑通后,进入实际使用阶段。这时候要观察主代理的分派行为是否符合预期。我会在项目里开一个日志文件,记录每次 subagent 调用的输入输出摘要。跑上一天后分析:哪些任务被分派了、分派得对不对、有没有该分派没分派的、有没有不该分派却分派了的。
常见的分派偏差有两类。漏派:主代理自己把任务干了,没走 subagent。这通常是 description 写得不够具体,或者任务表述跟 description 的语义距离太远。解决办法是补充 description 里的同义表述,或者在指令文件里加显式规则。误派:主代理把复杂任务丢给了 subagent,结果输出质量差。这通常是 description 写得太宽泛,需要收窄适用范围。
我还会统计 subagent 的实际节省效果。对比同样任务如果走主代理会消耗多少 token,走 subagent 消耗多少,算出差额。如果某个任务类型走 subagent 反而更贵(比如因为反复重试),那就把它从分派列表里移除。
4.4 输出质量的验收与修正
第三方模型的输出不能直接信,必须有验收环节。我的做法是在 subagent 返回结果后,加一道轻量校验。对于代码类输出,校验能不能通过语法解析;对于结构化输出,校验能不能通过 schema 验证;对于文本类输出,校验长度和关键字段是否齐全。
校验不通过的,走回退逻辑交回主代理。校验通过的,也不是直接采用,而是让主代理做一次快速审查。主代理的审查 prompt 大致是:“以下是 subagent 生成的{{task_type}}结果,请检查是否符合项目规范,如有问题直接修正,如无问题原样返回。”这一步增加了一点成本,但能拦住大部分低级错误。
实测下来,加了验收环节后,最终输出的一次通过率从七成出头提升到九成以上。多花的这点审查成本,远比返工重做划算。
提示:验收环节的 prompt 要简短,不要让主代理重新做一遍任务。它的角色是审查者不是执行者,重点看格式、规范、明显错误,不要陷入细节重写。
5. 常见问题与排查技巧实录
5.1 调用失败类问题速查
subagent 调用失败是最常见的问题,原因五花八门。我整理了一张速查表,按现象倒查原因。
| 现象 | 可能原因 | 排查方法 | 解决方式 |
|---|---|---|---|
| 连接超时 | endpoint 错误或网络不通 | curl 直接测 endpoint | 修正地址或检查网络 |
| 401 未授权 | API key 错误或过期 | 检查环境变量是否加载 | 更新 key 并重启会话 |
| 429 限流 | 并发超限或配额用尽 | 查看服务端配额面板 | 降低并发或申请提额 |
| 输出截断 | maxTokens 设太小 | 对比输出长度和限制值 | 调大 maxTokens |
| 格式解析失败 | 模型未遵循输出规范 | 查看原始返回内容 | 强化 systemPrompt 约束 |
| 响应极慢 | 模型负载高或任务太重 | 测简单请求的延迟 | 换模型或拆分任务 |
这张表覆盖了我遇到过的八成问题。剩下两成通常是组合问题,比如限流导致重试、重试导致超时、超时触发回退、回退又遇到主代理繁忙。这种连锁反应排查起来麻烦,我的建议是先看日志里的时间线,把每个环节的耗时和结果列出来,通常能定位到第一个出问题的环节。
5.2 输出质量不稳定的应对
第三方模型输出质量飘忽,是比调用失败更头疼的问题。调用失败至少是明确的,质量不稳定则是“有时候好用有时候不好用”,很难定位。
我的经验是,质量不稳定通常有三个根源。根源一是 prompt 不够具体。同一个任务,prompt 里说“生成测试”和说“为以下纯函数生成 5 个单元测试,覆盖正常输入、边界值、异常输入三类场景,使用项目现有的测试框架语法”,输出质量天差地别。解决办法是把 prompt 模板打磨到不能再具体。
根源二是上下文裁剪不当。前面提过,类型定义缺失会导致输出引用不存在的类型。还有一种情况是传了太多无关代码,第三方模型被干扰,输出了跟任务无关的内容。解决办法是定期审查裁剪逻辑,确保传的都是任务必需的。
根源三是模型本身的能力边界。有些模型在某些任务类型上就是弱,比如复杂逻辑推理、长链条依赖分析。这种不是配置能解决的,只能调整任务分派,把这类任务收回给主代理。识别方法是统计不同任务类型的输出合格率,合格率持续偏低的类型,直接从分派列表移除。
5.3 成本失控的预警与止损
用 subagent 的初衷之一是省钱,但如果配置不当,反而可能更贵。我遇到过几种成本失控的情况。
情况一是重试风暴。第三方服务不稳定,每次调用失败都重试,重试又失败,token 消耗翻倍。解决办法是设置重试上限,并且对连续失败的服务做熔断,一段时间内不再调用。
情况二是上下文膨胀。裁剪逻辑写得太宽松,每次传的上下文越来越大,单次调用成本飙升。解决办法是给上下文设 token 上限,超过就强制裁剪。
情况三是误派导致的返工。复杂任务被误派给 subagent,输出不合格,交回主代理重做,等于同一任务花了两份钱。解决办法是收窄 description,减少误派。
我建议每周看一次成本报表,对比 subagent 和主代理的 token 消耗比例。如果 subagent 占比异常高,或者单位任务的成本比纯主代理还高,就要停下来排查。
5.4 多 subagent 协作的进阶玩法
跑通单个 subagent 后,可以尝试多个 subagent 分工。比如一个负责生成测试,一个负责生成文档,一个负责代码格式化。主代理根据任务类型分派给不同的 subagent。
多 subagent 的配置复杂度上升,但收益也明显。不同任务用最适合的模型,整体效率更高。不过要注意几点:subagent 之间不要互相调用,所有调度由主代理统一负责,否则链路会变得难以追踪。每个 subagent 的职责要清晰不重叠,否则主代理分派时会犹豫。统一日志格式,方便跨 subagent 分析。
我目前在一个项目里配了三个 subagent:测试生成、文档补全、日志分析。运行了一个月,整体 token 成本比纯主代理降了约四成五,输出质量没有明显下降。关键是把每个 subagent 的边界划清楚了,主代理分派时基本不纠结。
6. 我踩过的坑和几条实在建议
配置 subagent 的过程中,有几个坑让我印象特别深,写出来给后来者省点时间。
第一个坑是以为配置改完就生效。实际上很多配置需要重启 Claude Code 会话才会加载。我改完配置直接测试,发现没反应,排查了半天以为是配置写错了,结果重启一下就好了。所以改完配置先重启,再测试。
第二个坑是忽略了第三方模型的 tokenizer 差异。同样一段文本,不同模型算出来的 token 数不一样。我按 Claude 的 token 数估算上下文大小,结果第三方模型那边实际 token 数超了限制,请求被拒。后来改成按第三方模型的 tokenizer 重新估算,问题解决。
第三个坑是没有给 subagent 设独立的超时。默认超时可能很长,第三方模型卡住时整个会话跟着卡。设了独立超时后,卡住就快速失败走回退,体验好很多。
几条实在建议。从简单任务开始,先跑通 docstring 生成这种最碎片的任务,验证链路,再逐步扩展到复杂任务。保持回退路径畅通,任何时候 subagent 挂了,主代理都能接管,这是底线。定期审查分派日志,看看有没有该派没派、不该派却派了的情况,持续优化。不要追求全自动,subagent 的输出该审查还是要审查,省下的时间不值得冒质量风险。
最后分享一个小技巧:给每个 subagent 起一个语义明确的名字,比如test-gen、doc-fill、log-parse,而不是subagent-1、subagent-2。主代理在分派时,名字本身也是语义信号,能帮助它更准确地匹配任务。这个改动很小,但实测对分派准确率有可感知的提升。