我们是由枫哥组建的IT技术团队,成立于2017年,致力于帮助IT从业者提供实力,成功入职理想企业,我们提供一对一学习辅导,由知名大厂导师指导,分享Java技术、参与项目实战等服务,并为学员定制职业规划,全面提升竞争力,过去8年,我们已成功帮助数千名求职者拿到满意的Offer:IT枫斗者IT枫斗者-Java面试突击


一、前言:什么是 Subagent?

1.1 Subagent 诞生背景

在AI Agent的Skills按需加载机制解决了基础Token冗余问题后,行业仍存在核心痛点:多轮对话场景下,上下文窗口会被海量对话历史、中间推理结果持续挤占。最终导致大模型响应速度变慢、关键事实遗忘、指令遵循能力大幅下降,单体Agent的“单兵作战”模式无法支撑复杂任务。

为解决该问题,AI Agent架构从单体模式升级为主从协同模式,Subagent(子代理)设计模式应运而生。

1.2 Subagent 核心定义

Subagent(子代理)是一种AI Agent协同设计模式:主代理(Orchestrator)负责解析用户整体意图、拆分任务,将独立子任务委托给全新独立上下文的子代理执行;子代理完成专属任务后,仅向主代理返回精简摘要,不保留冗余中间过程。

1.3 核心优势

  • 上下文隔离:子代理的推理、工具调用过程完全独立,不会污染主代理对话历史,避免无关信息干扰主任务决策。
  • 单一职责专注:每个子代理可针对专属任务,定制独立的系统提示词、专属工具集,专业化能力更强。
  • 高可扩展可复用:以插件化形式新增子代理能力,无需修改主代理核心逻辑,灵活拓展Agent功能边界。

本文将通过三个迭代版本,层层拆解Subagent核心原理:基础同步单层委托 → 异步消息驱动并发架构 → 配置驱动动态插件系统,覆盖从demo落地到生产级架构的全流程。

二、核心前置基础:大模型 Function Calling 机制

Subagent的本质是基于工具调用机制的任务委托,吃透OpenAI规范的Function Calling流程,是理解Subagent实现的核心前提。

2.1 标准工具调用7步流程

  1. 定义工具:通过JSON Schema规范描述工具名称、功能、入参结构;
  2. 挂载请求:将工具定义随用户请求一并发送给大模型;
  3. 模型决策:大模型根据用户指令,自主判断是否需要调用工具、匹配目标工具及参数;
  4. 响应解析:从模型返回的tool_calls字段中,提取工具名、调用参数;
  5. 本地执行:代码层调用对应本地函数,执行具体业务逻辑;
  6. 结果回填:将工具执行结果封装为tool角色消息,追加至对话历史;
  7. 生成最终响应:大模型结合工具执行结果,生成面向用户的最终答案。

2.2 基础单体Agent完整实现(无Subagent)

下述代码为所有Agent架构的基础模板,单体Agent将所有逻辑集中在一个对话循环,也是后续Subagent迭代的基底:

import os
import json
from pathlib import Path
from dotenv import load_dotenv
from openai import OpenAI

# 加载环境变量(DEEPSEEK_API_KEY等)
load_dotenv()

# ---------- 工具定义:读取文件工具 ----------
tools = [
    {
        "type": "function",
        "function": {
            "name": "read_file",
            "description": "读取文本文件内容。",
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {"type": "string", "description": "要读取的文件路径"},
                    "encoding": {"type": "string", "enum": ["utf-8", "gbk"], "description": "文件编码格式"}
                },
                "required": ["path"]
            }
        }
    }
]

# ---------- 工具具体实现 ----------
class ReadFileTool:
    def execute(self, path: str, encoding: str = "utf-8") -> str:
        try:
            file_path = Path(path).expanduser()
            if not file_path.exists():
                return f"❌ 文件不存在: {path}"
            return file_path.read_text(encoding=encoding)
        except Exception as e:
            return f"❌ 读取失败: {str(e)}"

file_tool = ReadFileTool()

# ---------- 初始化大模型客户端 ----------
client = OpenAI(
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com"
)

# 系统提示词与模型配置
SYSTEM = "你是一个文件读取助手,必要时可以调用工具帮助用户读取文件内容。"
MODEL = "deepseek-chat"

# ---------- 核心Agent循环 ----------
def agent_loop(messages: list):
    while True:
        # 调用大模型
        response = client.chat.completions.create(
            model="deepseek-chat",
            messages=messages,
            tools=tools,
            tool_choice="auto"
        )
        msg = response.choices[0].message
        
        # 追加助手回复至对话历史
        messages.append(msg)
        
        # 无工具调用,任务结束,返回最终答案
        if not msg.tool_calls:
            return msg.content

        # 解析并执行所有工具调用
        for tool_call in msg.tool_calls:
            if tool_call.function.name == "read_file":
                args = json.loads(tool_call.function.arguments)
                print(f"\033[33m🔧 调用工具: {tool_call.function.name}, 参数: {args}\033[0m")
                result = file_tool.execute(**args)
                print(f"✅ 工具执行结果:\n{result[:200]}\n")
                # 回填工具结果至对话历史
                messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "name": tool_call.function.name,
                    "content": result
                })

# 交互式入口
if __name__ == "__main__":
    history = [{"role": "system", "content": SYSTEM}]
    while True:
        try:
            query = input("\033[36m用户 >> \033[0m")
        except (EOFError, KeyboardInterrupt):
            break
        if query.strip().lower() in ("q", "exit", ""):
            break
        
        history.append({"role": "user", "content": query})
        final_answer = agent_loop(history)
        
        if final_answer:
            print(f"\033[32m助手: {final_answer}\033[0m\n")

单体架构核心弊端:所有推理、工具调用、中间结果全部堆积在主对话上下文,复杂任务下上下文急剧膨胀,引发模型性能与精度双重下降。

三、初代架构:同步 Subagent(上下文隔离核心实现)

3.1 核心设计思路

新增task专属工具,主代理通过调用该工具触发子代理;子代理拥有完全独立的上下文、专属工具集、独立推理循环,任务完成后仅返回精简摘要,隔离所有中间过程,彻底解决主上下文膨胀问题。

该设计模式又称 Agent as Tool:子代理被封装为普通工具,主代理无需感知子代理逻辑,仅通过标准工具调用完成任务委托,架构极简、通用性强。

3.2 同步Subagent完整改造代码

import os
import json
from pathlib import Path
from dotenv import load_dotenv
from openai import OpenAI

load_dotenv()

# ---------- 改造:主代理工具集(新增task委托工具) ----------
tools = [
    {
        "type": "function",
        "function": {
            "name": "task",
            "description": "生成一个子代理任务。对于可以独立运行的复杂或耗时任务,请使用此功能。子代理将完成任务并在完成后进行汇报。",
            "parameters": {
                "type": "object",
                "properties": {
                    "prompt": {"type": "string", "description": "子任务提示词"},
                    "description": {"type": "string", "description": "任务的简短描述"}
                },
                "required": ["prompt"]
            }
        }
    }
]

# ---------- 改造:子代理专属工具集(权限隔离) ----------
child_tools = [
    {
        "type": "function",
        "function": {
            "name": "read_file",
            "description": "读取文本文件内容。",
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {"type": "string", "description": "要读取的文件路径"},
                    "encoding": {"type": "string", "enum": ["utf-8", "gbk"], "description": "文件编码格式"}
                },
                "required": ["path"]
            }
        }
    }
]

# 工具实现、客户端初始化保持不变
class ReadFileTool:
    def execute(self, path: str, encoding: str = "utf-8") -> str:
        try:
            file_path = Path(path).expanduser()
            if not file_path.exists():
                return f"❌ 文件不存在: {path}"
            return file_path.read_text(encoding=encoding)
        except Exception as e:
            return f"❌ 读取失败: {str(e)}"

file_tool = ReadFileTool()

client = OpenAI(
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com"
)

# 改造:主代理、子代理独立系统提示词
SYSTEM = "你是AI助手,使用任务工具来委派探索性工作或子任务。"
SUBAGENT_SYSTEM = "你是AI助手的编码子代理。完成给定任务后,总结你的发现。"
MODEL = "deepseek-chat"

# ---------- 核心:子代理独立执行函数 ----------
def run_subagent(prompt: str) -> str:
    # 1. 全新独立上下文,与主代理完全隔离
    sub_messages = [
        {"role": "system", "content": SUBAGENT_SYSTEM},
        {"role": "user",   "content": prompt}
    ]

    # 2. 最大步数限制,防止无限循环调用工具
    for _ in range(30):
        response = client.chat.completions.create(
            model=MODEL,
            messages=sub_messages,
            tools=child_tools,  # 子代理专属工具集
            tool_choice="auto"
        )
        msg = response.choices[0].message

        # 追加子代理推理记录(仅留存于子上下文)
        sub_messages.append(msg)

        # 无工具调用则任务完成,返回摘要
        if not msg.tool_calls:
            return msg.content or "(无摘要)"

        # 子代理独立执行工具调用
        for tool_call in msg.tool_calls:
            if tool_call.function.name == "read_file":
                args = json.loads(tool_call.function.arguments)
                result = file_tool.execute(**args)
                sub_messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "name": tool_call.function.name,
                    "content": result
                })

    return "(无摘要)"  # 循环超限兜底

# ---------- 改造:主代理循环(支持子任务委托) ----------
def agent_loop(messages: list):
    while True:
        response = client.chat.completions.create(
            model=MODEL,
            messages=messages,
            tools=tools,
            tool_choice="auto"
        )
        msg = response.choices[0].message
        messages.append(msg)

        if not msg.tool_calls:
            return msg.content

        # 处理工具调用,新增task子代理路由逻辑
        for tool_call in msg.tool_calls:
            if tool_call.function.name == "task":
                args = json.loads(tool_call.function.arguments)
                desc = args.get("description", "子任务")
                print(f"\033[33m🧩 task ({desc}): {args['prompt'][:80]}\033[0m")
                # 委托子代理执行任务
                result = run_subagent(args["prompt"])
                print(f"✅ 子代理摘要:\n{result[:200]}\n")
            else:
                result = f"未知工具: {tool_call.function.name}"
            
            # 将子代理摘要回填主上下文(仅留存最终结果)
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": str(result)
            })

# 交互式入口(不变)
if __name__ == "__main__":
    history = [{"role": "system", "content": SYSTEM}]
    while True:
        try:
            query = input("\033[36m用户 >> \033[0m")
        except (EOFError, KeyboardInterrupt):
            break
        if query.strip().lower() in ("q", "exit", ""):
            break
        
        history.append({"role": "user", "content": query})
        final_answer = agent_loop(history)
        
        if final_answer:
            print(f"\033[32m助手: {final_answer}\033[0m\n")

3.3 同步Subagent核心执行流程

主代理执行逻辑

  1. 调用LLM,根据主对话历史判断是否需要委托子任务;
  2. 识别到task工具调用后,触发run_subagent函数;
  3. 阻塞等待子代理执行完毕,获取摘要结果;
  4. 将摘要回填主上下文,继续完成主任务推理。

子代理执行逻辑

  1. 初始化全新独立上下文,无任何主代理历史数据;
  2. 加载专属系统提示词、专属工具集,实现职责与权限隔离;
  3. 独立执行工具调用、多轮推理,完成专属任务;
  4. 精简结果后返回,丢弃所有中间执行过程。

3.4 同步架构致命瓶颈

同步调用为阻塞式执行:主代理委托子任务后,整个程序会卡住,直至子代理完全执行完毕。针对大文件读取、多轮搜索、外部API调用等耗时任务,会导致用户无法输入新指令、系统无法响应并发请求,用户体验极差,无法适配生产交互场景。

四、进阶架构:异步 Subagent(非阻塞并发架构)

为解决同步阻塞问题,基于异步I/O重构架构,通过异步客户端+双消息队列+多协程并发,实现子任务后台执行、主代理持续响应,彻底消除阻塞痛点。

4.1 基础改造:同步客户端升级为异步客户端

核心改动:将OpenAI同步客户端替换为AsyncOpenAI,所有LLM、I/O操作改为await异步等待,释放事件循环,支持并发调度。

4.2 核心架构:双队列解耦设计

引入两个异步队列,实现输入、处理、输出全环节解耦,基于生产者-消费者模式实现并发:

  • 入站队列(inbound):接收用户所有输入消息,用户输入后立即入队,无需等待任务处理完成;
  • 出站队列(outbound):接收Agent处理完成的最终结果,独立协程负责输出展示。

4.3 异步Subagent完整实现代码

import os
import json
import asyncio
from pathlib import Path
from dotenv import load_dotenv
from openai import AsyncOpenAI

load_dotenv()

# 工具定义、工具实现与同步版本一致
tools = [
    {
        "type": "function",
        "function": {
            "name": "task",
            "description": "生成一个子代理任务。对于可以独立运行的复杂或耗时任务,请使用此功能。子代理将完成任务并在完成后进行汇报。",
            "parameters": {
                "type": "object",
                "properties": {
                    "prompt": {"type": "string", "description": "子任务提示词"},
                    "description": {"type": "string", "description": "任务的简短描述"}
                },
                "required": ["prompt"]
            }
        }
    }
]

child_tools = [
    {
        "type": "function",
        "function": {
            "name": "read_file",
            "description": "读取文本文件内容。",
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {"type": "string", "description": "要读取的文件路径"},
                    "encoding": {"type": "string", "enum": ["utf-8", "gbk"], "description": "文件编码格式"}
                },
                "required": ["path"]
            }
        }
    }
]

class ReadFileTool:
    def execute(self, path: str, encoding: str = "utf-8") -> str:
        try:
            file_path = Path(path).expanduser()
            if not file_path.exists():
                return f"❌ 文件不存在: {path}"
            return file_path.read_text(encoding=encoding)
        except Exception as e:
            return f"❌ 读取失败: {str(e)}"

file_tool = ReadFileTool()

# 初始化异步客户端
client = AsyncOpenAI(
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com"
)

SYSTEM = "你是AI助手,使用任务工具来委派探索性工作或子任务。"
SUBAGENT_SYSTEM = "你是AI助手的编码子代理。完成给定任务后,总结你的发现。"
MODEL = "deepseek-chat"

# 改造:异步子代理执行函数
async def run_subagent(prompt: str) -> str:
    sub_messages = [
        {"role": "system", "content": SUBAGENT_SYSTEM},
        {"role": "user",   "content": prompt}
    ]

    for _ in range(30):
        response = await client.chat.completions.create(
            model=MODEL,
            messages=sub_messages,
            tools=child_tools,
            tool_choice="auto"
        )
        msg = response.choices[0].message
        sub_messages.append(msg)

        if not msg.tool_calls:
            return msg.content or "(无摘要)"

        for tool_call in msg.tool_calls:
            if tool_call.function.name == "read_file":
                args = json.loads(tool_call.function.arguments)
                result = file_tool.execute(**args)
                sub_messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "name": tool_call.function.name,
                    "content": result
                })

    return "(无摘要)"

# ---------- 异步Agent核心类(双队列+三协程) ----------
class AsyncSubagent:
    def __init__(self):
        self.inbound = asyncio.Queue()    # 入站消息队列
        self.outbound = asyncio.Queue()   # 出站结果队列
        self._running = False             # 运行状态标记
        self.history = [{"role": "system", "content": SYSTEM}]

    # 异步任务处理核心循环
    async def agent_loop(self, user_msg: str) -> str:
        self.history.append({"role": "user", "content": user_msg})
        
        while True:
            response = await client.chat.completions.create(
                model=MODEL,
                messages=self.history,
                tools=tools,
                tool_choice="auto"
            )
            msg = response.choices[0].message
            self.history.append(msg)
            
            if not msg.tool_calls:
                return msg.content
            
            for tool_call in msg.tool_calls:
                func_name = tool_call.function.name
                args = json.loads(tool_call.function.arguments)
                if func_name == "task":
                    desc = args.get("description", "子任务")
                    print(f"\033[33m🧩 task ({desc}): {args['prompt'][:80]}\033[0m")
                    result = await run_subagent(args["prompt"])
                    print(f"✅ 子代理摘要:\n{result[:200]}\n")
                else:
                    result = f"未知工具: {func_name}"
                
                self.history.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "content": str(result)
                })

    # 消费入站队列:持续处理用户任务
    async def run(self) -> None:
        self._running = True
        print("智能体循环已启动")
        while self._running:
            try:
                # 1秒超时,定期检查运行状态,实现优雅停机
                msg = await asyncio.wait_for(self.inbound.get(), timeout=1.0)
                try:
                    response = await self.agent_loop(msg)
                    if response:
                        await self.outbound.put(response)
                except Exception as e:
                    print(f"消息处理异常: {e}")
                    await self.outbound.put(f"抱歉,处理消息时出错:{e}")
            except asyncio.TimeoutError:
                continue

    # 消费出站队列:持续输出结果
    async def output(self):
        print('打印输出')
        while self._running:
            try:
                final_answer = await asyncio.wait_for(self.outbound.get(), timeout=1.0)
                if final_answer:
                    print(f"\n\033[32m助手: {final_answer}\033[0m")
                    print("\033[36m用户 >> \033[0m", end="", flush=True)
            except asyncio.TimeoutError:
                continue

    # 停止服务
    def stop(self) -> None:
        self._running = False

# ---------- 主函数:三协程并发调度 ----------
async def main():
    agent = AsyncSubagent()
    # 启动处理协程、输出协程
    task = asyncio.create_task(agent.run())
    output_task = asyncio.create_task(agent.output())

    # 输入协程:非阻塞接收用户输入
    while True:
        query = await asyncio.to_thread(input, "\033[36m用户 >> \033[0m")
        if query.strip().lower() in ("q", "exit", ""):
            break
        await agent.inbound.put(query)

    # 优雅停机
    agent.stop()
    await task
    await output_task

if __name__ == "__main__":
    asyncio.run(main())

4.4 三大协程并发调度机制

异步架构通过三个独立协程实现全程非阻塞,由事件循环统一调度:

  1. 输入协程:通过asyncio.to_thread封装阻塞的input方法,不占用事件循环,持续接收用户新指令并放入入站队列;
  2. 处理协程:持续消费入站队列,执行主代理逻辑、委托子任务,遇到LLM等待、子任务执行等阻塞I/O时,主动释放事件循环;
  3. 输出协程:独立消费出站队列,实时打印任务结果,与任务处理完全解耦。

核心价值:子代理执行耗时任务时,系统可正常接收、处理用户新指令,真正实现后台任务执行+前台实时响应

五、生产级架构:插件化 Subagent(配置驱动动态扩展)

同步、异步版本的子代理均存在硬编码问题:新增子代理能力需修改代码、新增工具路由、重启服务,无法适配生产环境高频迭代、多人协作的场景。插件化架构实现配置驱动、零代码扩展、热插拔能力,是工业级Agent的标准实现。

5.1 插件化核心设计思想

借鉴Claude Code Subagents设计,将子代理能力配置文件化:通过固定格式的Markdown文件(frontmatter元数据+提示词正文)定义子代理,系统启动时自动扫描、加载、注册子代理,无需修改主程序代码。

单个子代理配置文件包含5大核心配置:

  • name:子代理唯一标识;
  • description:能力描述(主代理路由决策依据);
  • system_prompt:子代理专属系统提示词;
  • tools:工具白名单(权限隔离,最小权限原则);
  • model:可选,专属大模型(区分速度/精度场景)。

5.2 配置文件解析能力实现

编写通用加载函数,自动扫描指定目录下的所有子代理配置文件,解析元数据与提示词:

import os
import json
import re
from pathlib import Path
from dotenv import load_dotenv
from openai import OpenAI

load_dotenv()

# 加载目录下所有插件化子代理配置
def load_agents(agents_dir="./agents"):
    agents = []
    agents_path = Path(agents_dir)
    if not agents_path.exists():
        return agents
    
    # 遍历所有md格式配置文件
    for file_path in agents_path.glob("*.md"):
        content = file_path.read_text(encoding="utf-8")
        # 匹配frontmatter元数据+正文提示词
        match = re.match(r"^---\n(.*?)\n---\n(.*)$", content, re.DOTALL)
        if match:
            frontmatter = match.group(1)
            body = match.group(2).strip()
            
            # 简易解析YAML键值对,无额外依赖
            metadata = {}
            for line in frontmatter.split('\n'):
                if ':' in line:
                    key, val = line.split(':', 1)
                    val = val.split('#')[0].strip()
                    metadata[key.strip()] = val
                    
            agents.append({
                "name": metadata.get("name", file_path.stem),
                "description": metadata.get("description", "A subagent"),
                "tools": [t.strip() for t in metadata.get("tools", "").split(",") if t.strip()],
                "model": metadata.get("model", "deepseek-chat"),
                "system_prompt": body
            })
    return agents

5.3 动态工具生成与权限隔离

系统加载子代理配置后,自动为每个子代理生成独立的Function Call工具,主代理可通过LLM自主路由匹配最优子代理;同时基于配置白名单实现工具权限隔离。

# 加载所有插件子代理
loaded_agents = load_agents()

# 动态生成主代理工具集:每个子代理对应一个独立调用工具
tools = []
for agent in loaded_agents:
    tools.append({
        "type": "function",
        "function": {
            "name": f"call_{agent['name'].replace('-', '_')}",
            "description": agent['description'],
            "parameters": {
                "type": "object",
                "properties": {
                    "prompt": {"type": "string", "description": "分配给该子代理的具体任务要求和上下文"}
                },
                "required": ["prompt"]
            }
        }
    })

# 兜底通用task工具(无插件时生效)
if not tools:
    tools = [
        {
            "type": "function",
            "function": {
                "name": "task",
                "description": "以全新上下文派生一个子代理。子代理共享文件系统,但不共享对话历史。",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "prompt": {"type": "string", "description": "子任务提示词"},
                        "description": {"type": "string", "description": "任务的简短描述"}
                    },
                    "required": ["prompt"]
                }
            }
        }
    ]

# 子代理全局工具映射表(权限匹配)
AVAILABLE_CHILD_TOOLS = {
    "Read": child_tools[0],
    "read_file": child_tools[0],
}

# 子代理专属工具集
child_tools = [
    {
        "type": "function",
        "function": {
            "name": "read_file",
            "description": "读取文本文件内容。",
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {"type": "string", "description": "要读取的文件路径"},
                    "encoding": {"type": "string", "enum": ["utf-8", "gbk"], "description": "文件编码格式"}
                },
                "required": ["path"]
            }
        }
    }
]

# 工具实例、客户端初始化
class ReadFileTool:
    def execute(self, path: str, encoding: str = "utf-8") -> str:
        try:
            file_path = Path(path).expanduser()
            if not file_path.exists():
                return f"❌ 文件不存在: {path}"
            return file_path.read_text(encoding=encoding)
        except Exception as e:
            return f"❌ 读取失败: {str(e)}"

file_tool = ReadFileTool()
client = OpenAI(
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com"
)

# 全局提示词配置
SYSTEM = "你是主代理,你可以调用工具将任务分配给不同的专业子代理来协助用户。请根据用户的需求选择合适的子代理。"
SUBAGENT_SYSTEM = "你是文件助手的编码子代理。完成给定任务后,总结你的发现。"
MODEL = "deepseek-chat"

5.4 插件化子代理执行与动态路由

重构子代理执行函数,支持读取插件配置、动态过滤工具权限;优化主代理路由逻辑,自动匹配对应子代理:

# 插件化子代理执行函数
def run_subagent(agent_config: dict, prompt: str) -> str:
    # 读取插件自定义配置
    system_prompt = agent_config.get("system_prompt", SUBAGENT_SYSTEM)
    model = agent_config.get("model", MODEL)
    
    # 根据白名单过滤可用工具(权限隔离)
    agent_tools_names = [t.lower() for t in agent_config.get("tools", [])]
    allowed_tools = []
    for tool_name in agent_tools_names:
        if tool_name in ["read", "read_file"]:
            allowed_tools.append(AVAILABLE_CHILD_TOOLS["read_file"])
            
    # 无配置则使用默认工具集
    if not allowed_tools:
        allowed_tools = child_tools

    # 独立上下文执行任务
    sub_messages = [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": prompt}
    ]
    for _ in range(30):
        response = client.chat.completions.create(
            model=model,
            messages=sub_messages,
            tools=allowed_tools if allowed_tools else None,
            tool_choice="auto" if allowed_tools else None
        )
        msg = response.choices[0].message
        sub_messages.append(msg)
        
        if not msg.tool_calls:
            return msg.content or "(无摘要)"
        
        for tool_call in msg.tool_calls:
            if tool_call.function.name == "read_file":
                args = json.loads(tool_call.function.arguments)
                result = file_tool.execute(**args)
                sub_messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "name": tool_call.function.name,
                    "content": result
                })
    return "(无摘要)"

# 主代理动态路由循环
def agent_loop(messages: list):
    while True:
        response = client.chat.completions.create(
            model="deepseek-chat",
            messages=messages,
            tools=tools if tools else None,
            tool_choice="auto" if tools else None
        )
        msg = response.choices[0].message
        messages.append(msg)
        
        if not msg.tool_calls:
            return msg.content
        
        for tool_call in msg.tool_calls:
            func_name = tool_call.function.name
            args = json.loads(tool_call.function.arguments)
            
            # 路由1:插件化子代理调用
            if func_name.startswith("call_"):
                # 名称归一化匹配
                agent_name_from_func = func_name[5:].replace("_", "-")
                agent_config = next((a for a in loaded_agents if a['name'] == agent_name_from_func), None)
                
                if agent_config:
                    print(f"\033[33m🧩 启动子代理 ({agent_config['name']}): {args['prompt'][:80]}...\033[0m")
                    result = run_subagent(agent_config, args["prompt"])
                    print(f"✅ 子代理 {agent_config['name']} 返回结果:\n{result[:200]}...\n")
                else:
                    result = f"找不到子代理: {agent_name_from_func}"
            
            # 路由2:通用兜底task工具
            elif func_name == "task":
                desc = args.get("description", "子任务")
                print(f"\033[33m🧩 task ({desc}): {args['prompt'][:80]}\033[0m")
                result = run_subagent({"name": "default"}, args["prompt"])
                print(f"✅ 子代理摘要:\n{result[:200]}\n")
            
            else:
                result = f"未知工具: {func_name}"
            
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": str(result)
            })

5.5 插件化架构核心优势

  • 零代码扩展:新增代码审查、文档生成、数据解析等子代理,仅需新增MD配置文件,无需改主代码;
  • 智能路由:通过子代理自然语言描述,LLM自动匹配最优子代理,无需人工硬编码路由规则;
  • 安全可控:工具白名单实现最小权限隔离,避免子代理越权操作;
  • 成本优化:支持不同子代理绑定不同模型,简单任务用轻量模型、复杂推理用高精度模型;
  • 易维护可追溯:所有子代理能力模块化、配置化,多人协作无冲突,迭代清晰。

六、三大Subagent实现模式全方位对比

对比维度 同步基础Subagent 异步并发Subagent 插件化生产Subagent
上下文隔离 ✅ 支持 ✅ 支持 ✅ 支持
非阻塞并发 ❌ 同步阻塞 ✅ 全程非阻塞 ✅ 可叠加异步能力
插件化扩展 ❌ 硬编码 ❌ 硬编码 ✅ 配置驱动、热插拔
工具权限隔离 基础支持 基础支持 精细化白名单控制
代码复杂度 中(可复用、易维护)
适用场景 简单脚本、单用户离线工具 交互式应用、需要实时响应的场景 生产级项目、持续迭代的复杂Agent系统

七、全文核心总结

  1. Subagent核心本质:基于大模型Function Calling的任务委托+上下文隔离,通过主从代理拆分复杂任务,解决单体Agent上下文膨胀、能力单一的问题。
  2. 架构迭代核心逻辑
  • 初代同步版:解决上下文污染问题,实现基础任务拆分;
  • 进阶异步版:解决阻塞卡顿问题,实现并发响应;
  • 生产插件版:解决扩展困难、维护复杂问题,实现工业化可落地。

⭐️推荐:

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐