SubAgents 子代理定义解析(AI 视频下载总结器实战)

单靠一个对话窗口开发多模块项目,撑到第三周就到了极限。下载器、AI 总结、前端、支付四个模块互相拉扯,让同一个 Agent 从头管到尾,它要么记不住前面的决策,要么改一处崩三处。正是那段时间,我系统地用上了 SubAgents(子代理)模式——主 Agent 负责拆任务、派活、汇总,每个子 Agent 只干一件具体的事。这篇文章就围绕我在这个项目里怎么用 SubAgent、跟直接 Agent 比差在哪、踩过哪些坑、最后沉淀出什么协作规则来展开。

一、SubAgent 是什么

先说清楚概念。SubAgent 是主 Agent 派生的子任务执行者。在 AI 视频下载总结器项目里,我的做法是让主 Agent 先做整体规划,再按模块把任务派给不同的 SubAgent,每个子 Agent 有独立的上下文和清晰的边界,互不干扰。它的结构大概长这样:

主 Agent(规划)
  ├── SubAgent 1(实现下载器)
  ├── SubAgent 2(实现 AI 服务)
  ├── SubAgent 3(实现前端)
  └── SubAgent 4(写测试)

主 Agent 拿到大任务后,拆解成子任务并行/串行派发,每个子 Agent 独立完成自己的部分。

最初我以为这只是”多开几个聊天窗口”的花活,直到用它并行写了四个模块,才真正体会到它的价值在任务隔离——子 Agent 之间的上下文互不污染,A 改挂了不会拖累 B,单个子任务的失败也不会让整个项目归零。

二、与直接 Agent 的区别

光说不直观,我把直接 Agent 和主+子 Agent 两种方式放在一张表里对比:

维度 直接 Agent 主+子 Agent
任务规模 单一任务 大任务拆解
上下文 单一上下文 子 Agent 独立上下文
错误恢复 一错全错 子任务重试不影响整体
并行能力 串行 并行
复杂度 简单 复杂(需要协调)

一句话概括:直接 Agent 适合一条线走到头的活,主+子 Agent 适合能拆成多块的大项目。

我在项目里感受最直观的是”错误恢复”那一行。用直接 Agent 写下载器时,中途一个异常没处理,整个任务就断了,得从头再来;拆成子 Agent 之后,某个子任务失败,主 Agent 只需单独重试那一个,其他模块照常推进。代价是协调变复杂了,这个后面单独讲。

三、平台用 SubAgent 的典型场景

1. 大型功能开发

“做完整的视频总结功能”是一个大任务。我让主 Agent 拆解:

主 Agent Prompt:
"视频总结功能需要:
1. 后端 API(视频提交 + 总结接口 + SSE 流式)
2. 前端页面(提交表单 + 实时展示 + 思维导图)
3. AI Prompt 设计
4. 测试用例
请派 4 个 SubAgent 并行实现,最后汇总"

子 Agent 各自领任务并行执行。

这类任务如果让一个 Agent 串行做,先写后端再写前端,中间反复切换上下文,很容易把后端定好的接口字段忘干净。拆开后,前端子 Agent 拿到一份接口契约就能开工,两边同时跑,互相不踩。

2. 跨模块重构

“把用户系统从 SQLAlchemy 1.x 升级到 2.0″涉及多个文件:

主 Agent:
"请按以下顺序派 SubAgent:
1. SubAgent 1:升级 model 定义
2. SubAgent 2:升级 query/relationship
3. SubAgent 3:更新所有 service
4. SubAgent 4:跑测试并修复"

每个 SubAgent 只关心自己那部分,主 Agent 协调顺序和合并。

这里我坚持用串行派发而不是全并行,因为 model 定义不升级完,后面的 query 和 service 都会改错方向。主 Agent 像流水线班长一样卡住先后顺序,每一棒交出去时都带着上一棒的产出。

3. 大量相似任务

“为 20 个平台写下载器”是重复工作:

主 Agent:
"请派 SubAgent 循环为以下平台写下载器:
YouTube, B站, 抖音, 小红书, Twitter, TikTok, Instagram,
Vimeo, Dailymotion, Twitch, Reddit, Pinterest, Tumblr,
Facebook, LinkedIn, Threads, Bluesky, Mastodon, VK, Rutube
每个 SubAgent 写一个,最后汇总测试"

20 个 SubAgent 并行。

这种场景我只跑过一次就学乖了:并行开 20 个子任务,成本直接乘以 20,而且各平台反爬差异大,出来的代码质量参差。后来改成先让一个子 Agent 写 YouTube 版本当样板,再派 4 个并行的子 Agent 基于样板适配其他平台,成本和速度都更可控。

四、SubAgent 的关键设计

1. 任务边界

每个 SubAgent 的任务要清晰、单一:

# 好的任务
"实现 YouTube 下载器,返回 VideoInfo dataclass,含 yt-dlp 调用"

# 不好的任务(太大)
"实现整个下载器模块"

任务边界这条我踩过坑。有一次我偷懒,让一个子 Agent”实现整个下载器模块”,它交回来的代码里混杂了反爬、缓存、重试三套逻辑,接口命名前后矛盾,我花了一晚上才拆开。把任务切成单一职责之后,每个子 Agent 的产出都能独立验证,合并时也少了很多冲突。

2. 输入输出契约

# 明确告诉 SubAgent 输入是什么
"输入:URL 字符串
输出:VideoInfo dataclass(url, platform, video_id, title, duration, thumbnail, uploader, formats)
约束:必须 async 函数,30s 超时"

契约的价值在于:多个子 Agent 并行开发时,只要大家遵守同一份输入输出定义,各自的模块就能像乐高一样拼起来。我后来把这份契约写进了项目文档,子 Agent 派发时直接引用,接口不一致的问题基本绝迹。

3. 上下文共享

子 Agent 不共享上下文。主 Agent 通过 prompt 传关键信息:

主 Agent 传给子 Agent 的 prompt:
"项目用 FastAPI 0.110+、Python 3.11、SQLAlchemy 2.0。
数据库连接在 app.db 模块。
现有 Video 模型字段:url, platform, video_id, title, duration, thumbnail, uploader, status, error_msg, created_at。
你的任务:写 YouTube 下载器..."

这里有个矛盾点:上下文传少了,子 Agent 乱猜;传多了,token 成本又上去了。我的经验是只传”跟当前任务直接相关”的部分——数据库连接、要用的模型字段、技术栈版本,其余一律不塞。项目背景这类公共信息,用一个固定的 system prompt 缓存起来,每个子 Agent 进来先注入,效果和传完整上下文差不多,成本却低得多。

五、平台的具体用法

Claude Code 中

Claude Code 1.0+ 支持 Task 工具派生子 Agent:

// 主 Agent 调用
const result = await Task({
    description: '实现 YouTube 下载器',
    prompt: '...',
    subagent_type: 'general-purpose'
})

我在 Claude Code 里用它做大型重构,比在网页版来回粘贴省心得多。有一点要注意:Task 返回的是字符串结果,复杂结构化产出(比如完整文件内容)建议让子 Agent 直接写文件,主 Agent 再读取校验,避免结果被截断。

Cursor 中

Cursor 用 @ 提及文件或 Agent:

@file:src/services/downloader/base.py 请基于这个实现 YouTube 下载器

Cursor 的做法更像”圈定范围干活”,@ 一个文件,AI 就知道该往哪改。适合小步调整,不承担大型任务的协调职责,我一般把 Cursor 当子 Agent 的执行器来用。

自建多 Agent 框架

import asyncio

class MainAgent:
    def __init__(self):
        self.sub_agents = []
    
    async def dispatch(self, task: str, sub_agent: 'SubAgent'):
        sub_agent.context = self.build_context(task)
        result = await sub_agent.run(task)
        return result
    
    def build_context(self, task: str) -> str:
        return f"""
        项目背景:AI 视频下载总结器
        技术栈:FastAPI + SQLite + yt-dlp
        当前任务:{task}
        """

class SubAgent:
    async def run(self, task: str) -> str:
        # 独立 LLM 调用
        response = await openai.ChatCompletion.create(
            model='gpt-4',
            messages=[
                {'role': 'system', 'content': self.context},
                {'role': 'user', 'content': task}
            ]
        )
        return response.choices[0].message.content

这份简化代码是我第一版子代理框架的原型,核心就两件事:主 Agent 派活时带上构建好的上下文,子 Agent 用自己的独立对话跑任务。后面我往里加了重试、超时和结果校验,才敢拿它跑真实项目。

六、SubAgent 的协调模式

1. 串行(pipeline)

SubAgent 1 → SubAgent 2 → SubAgent 3

适用:有依赖关系的任务(先做 A,再做 B)。

重构那轮我就用的串行,每个子 Agent 的产出是下一个的输入,谁也不能跳步。

2. 并行(fork-join)

        ┌→ SubAgent 1
Main → ─┼→ SubAgent 2 → Join
        └→ SubAgent 3

适用:独立任务(同时跑更快)。

注意”Join”这一步,主 Agent 要负责合并结果并处理冲突,否则并行变成各写各的,最后没人收尾。

3. 主从递归

Main
├── Plan SubAgent(设计)
├── Code SubAgent(实现)
└── Test SubAgent(测试)

适用:复杂任务的多阶段处理。

这一层我是在支付模块上试的:先让 Plan 子 Agent 出设计,Code 子 Agent 照设计实现,Test 子 Agent 专门挑毛病。三个阶段互不干扰,比一个 Agent 既当裁判又当运动员要干净。

七、平台开发的真实案例

案例 1:实现完整支付流程

主 Agent: "实现 Stripe 订阅支付,需要 6 个文件:
1. api/payment.py
2. services/stripe_service.py
3. models/payment.py
4. schemas/payment.py
5. services/quota_service.py (更新)
6. tests/test_payment.py
请派 6 个 SubAgent 并行实现"

6 个 SubAgent 同时跑,10 分钟完成(人工要 3 小时)。

这个案例是我印象很深的一次提速。难点不在写代码,而在 6 个文件之间的依赖关系——payment 的 schema 没定,quota_service 就不知道字段。我让主 Agent 先把一份契约文件发给所有子 Agent,再并行开工,10 分钟拿回来的代码基本能拼起来。

案例 2:批量写文档

主 Agent: "为已实现的 12 个 API 写 OpenAPI 注释:
api/auth.py, api/video.py, api/summary.py, ...
每文件派 1 个 SubAgent,要求中英文 summary"

12 个 SubAgent 并行。

批量文档这类活是子代理模式的甜区,任务重复、边界清楚、结果可自动校验。不过我吸取了 20 个下载器的教训,12 个并行已经是我的成本上限,再多就分批跑了。

八、SubAgent 的限制

1. 上下文限制

子 Agent 拿不到主 Agent 全部历史,必须显式传上下文。

这意味着主 Agent 自身必须能”讲清楚任务”,讲不清,子 Agent 就瞎猜。我几次失败都发生在 prompt 偷懒的时候。

2. 协调成本

主 Agent 协调 N 个子 Agent,主 Agent 自身的上下文会爆。

子任务一多,主 Agent 要把每个子任务的上下文、进度、结果都背在身上,几轮下来自己先超限。我的对策是每完成一个子任务,就把它的结论压缩成一行摘要存进文件,让主 Agent 只记摘要。

3. 错误传播

子 Agent 失败,主 Agent 要重试或降级。一个子 Agent 反复失败会拖慢整体。

遇到反复失败的子 Agent,我先降级成”拆更小的任务重试”,还不行就人工接手,别让它无限重试烧钱。

4. 成本

每个子 Agent 都是一次 LLM 调用。20 个子任务 = 20 倍成本。

这是最容易被忽略的一条。并行不是免费的,派发前先算一笔账:这个任务拆几个划算,哪些可以合并。

九、成本优化

1. 复用子 Agent

// 一个 SubAgent 跑 10 个相似任务
const sub = new YouTubeDownloaderAgent()
for (const url of urls) {
    await sub.run(url)
}

vs

// 10 个 SubAgent 各跑 1 个
for (const url of urls) {
    await dispatch('youtube-downloader', url)
}

后者贵 10 倍。

相似任务复用同一个子 Agent,等于把”建立上下文”的成本摊到了多次执行上。我在批量测试时就是这么干的,一个子 Agent 循环跑几十个用例。

2. 用小模型做简单任务

// 简单格式化用 GPT-3.5
// 复杂生成用 GPT-4

简单任务用小模型,复杂生成用大模型,这是成本优化的分水岭。文档注释、代码格式化这类活,小模型完全够用;架构设计、跨模块重构才值得上大模型。

3. 缓存公共上下文

const systemPrompt = `项目背景...`  // 不变
subAgent.system = systemPrompt  // 复用

公共上下文是每个子 Agent 都要用的,缓存下来能省掉一大块重复的 token 开销。我把项目背景、技术栈、代码规范做成一个常量,所有子 Agent 共享。

十、SubAgent 与 Function Calling

SubAgent 适合”复杂任务”,Function Calling 适合”工具调用”,两者定位完全不同:

维度 SubAgent Function Calling
任务 复杂多步 单步工具
决策 Agent 自己 程序决定
灵活性 高 低

平台两者都用:

  • SubAgent:写大模块;
  • Function Calling:调用 API、查数据库。

判断标准就一条:任务要不要 Agent 自己动脑子。要动脑子、要拆步骤,用 SubAgent;只是调个接口、查个表,用 Function Calling 更便宜更快。

十一、最佳实践

1. 任务粒度

  • 太粗:1 个 SubAgent 写整个应用(容易跑偏)
  • 太细:1 个 SubAgent 写 1 行(成本爆炸)
  • 合适:1 个 SubAgent 写 1 个文件或 1 个功能

粒度是我调过最多的参数。写整个应用会跑偏,写 1 行是烧钱,落到”一个文件或一个功能”这个量级,产出质量、合并成本、可验证性三者才平衡。

2. 输入契约

明确告诉子 Agent:

  • 输入是什么(参数、文件);
  • 输出是什么(函数签名、数据结构);
  • 约束(性能、风格、库版本)。

3. 失败处理

async def dispatch_with_retry(task, max_retry=3):
    for i in range(max_retry):
        try:
            return await dispatch(task)
        except Exception as e:
            if i == max_retry - 1:
                # 标记失败,主 Agent 决定怎么办
                return {'status': 'failed', 'error': str(e)}
            await asyncio.sleep(2 ** i)

指数退避重试这段代码我直接挪用了,重试间隙按 2 的幂次递增,既给了模型”重新思考”的时间,又不会在失败边缘空转。

4. 结果验证

主 Agent 必须验证子 Agent 的结果:

result = await dispatch('write-youtube-downloader')
assert 'class YouTubeDownloader' in result.code
# 不通过 → 重试或修正 prompt

验证这步不能省。我见过子 Agent 交回一份”看起来完整但核心函数压根没写”的结果,没有断言检查就会直接混进主分支。

十二、踩坑

1. 子 Agent 串改接口

主 Agent 让子 Agent 实现函数 A,子 Agent 改函数 B 的签名。必须严格契约。

子 Agent 拿到任务后,为了”让代码能跑”,经常顺手改掉别的模块的接口,结果合并时崩一片。后来契约里写明”只允许新增,禁止修改他人接口”,这类问题才消停。

2. 上下文爆

主 Agent 把整个项目代码塞给子 Agent,token 超限。只传相关部分。

我犯过把整个项目塞给子 Agent 的错,第一轮就报 token 超限。后来改成只传当前任务相关的模型定义和调用关系,问题立刻消失。

3. 调试困难

子 Agent 失败要查原因,但子 Agent 的 prompt 链不直观。用日志记录每个子 Agent 的输入输出。

调试子代理最头疼的是不知道它内部发生了什么。我给每个子 Agent 的输入输出加了日志,失败时直接看它收到的 prompt 和返回结果,一两分钟就能定位是上下文没传够还是模型理解偏了。

4. 并行冲突

两个子 Agent 同时改同一个文件,主 Agent 必须协调。

并行写同一个文件是我遇到过的真事故。后来派活前先检查任务之间有没有文件交集,有交集的要么合并成一个子 Agent,要么明确”先写待定区域,主 Agent 最后合并”。

十三、与 Skills 关系

Skills 是一组预定义能力,SubAgent 是任务执行者:

  • Skills:写好的能力(”我是 yt-dlp 专家”)
  • SubAgent:执行任务(”去实现 YouTube 下载器”)

平台把常用工具封装为 Skills,让 SubAgent 调用:

# Skill:提供 yt-dlp 最佳实践
# SubAgent:调用 Skill 完成具体任务

我的理解是:Skills 是弹药库,SubAgent 是拿弹药上战场的人。子 Agent 在项目里积累的成功做法,我定期沉淀回 Skills,下次派活时直接引用,子 Agent 的起点一次比一次高。

十四、未来趋势

  1. 多 Agent 协作框架:AutoGPT、MetaGPT、LangGraph;
  2. Agent-as-a-Service:云厂商提供专业 Agent;
  3. 自我改进 Agent:Agent 反思+学习。

这些方向我都在跟。多 Agent 协作框架今年明显变多,但框架只是脚手架,任务怎么拆、上下文怎么传、结果怎么验,还是得靠项目里的人把规则定清楚。工具在变,协作方法论不会过时。

常见问题(FAQ)

Q1:SubAgent 与 RAG 关系?

RAG 提供知识,SubAgent 执行任务。互补。

Q2:多少个子 Agent 合适?

5-10 个最佳。再多主 Agent 协调不来。

Q3:SubAgent 会取代程序员?

不会。SubAgent 是工具,程序员决定用在哪。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 qiqicto@qq.com 举报,一经查实,本站将立刻删除。
赞 (0)
其AI的头像其AI普通用户

相关推荐

返回顶部