第14章 Agent-as-Tool(智能体即工具)

第14章 Agent-as-Tool(智能体即工具)

本章目标

  • 理解 Agent-as-Tool 模式的设计理念
  • 掌握 SubAgentTool 的使用方法
  • 学会将智能体封装为可调用的工具
  • 了解多轮对话会话管理机制

14.1 Agent-as-Tool 概述

14.1.1 什么是 Agent-as-Tool?

Agent-as-Tool(智能体即工具) 是一种将智能体封装为工具的模式,使得一个智能体可以通过工具调用来使用另一个智能体的能力。这种模式实现了智能体之间的层级协作。

┌─────────────────────────────────────────────────────────────┐
│                    Agent-as-Tool 模式                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              主智能体 (Supervisor)                   │   │
│   │  ┌─────────────────────────────────────────────┐   │   │
│   │  │               Toolkit                        │   │   │
│   │  │  ┌─────────────┐  ┌─────────────────────┐   │   │   │
│   │  │  │ 普通工具     │  │  SubAgentTool       │   │   │   │
│   │  │  │ (搜索/计算)  │  │  (子智能体工具)      │   │   │   │
│   │  │  └─────────────┘  └─────────┬───────────┘   │   │   │
│   │  └────────────────────────────┬─────────────────┘   │   │
│   └────────────────────────────────┼─────────────────────┘   │
│                                    │                         │
│                                    ▼                         │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              子智能体 (Sub-Agent)                    │   │
│   │  ┌─────────────────────────────────────────────┐   │   │
│   │  │  专业能力(研究、分析、翻译等)              │   │   │
│   │  └─────────────────────────────────────────────┘   │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
│   调用流程:                                                 │
│   1. 用户请求 → 主智能体                                     │
│   2. 主智能体决定调用 SubAgentTool                           │
│   3. SubAgentTool 执行子智能体                               │
│   4. 子智能体返回结果 → 主智能体                             │
│   5. 主智能体整合结果 → 用户                                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘

14.1.2 核心优势

优势说明
能力组合主智能体可以调用多个专业子智能体
会话管理支持多轮对话,保持上下文
解耦设计子智能体独立开发、测试、部署
动态选择主智能体可以根据任务选择合适的子智能体
事件转发支持流式输出和事件转发

14.2 SubAgentTool 核心组件

14.2.1 SubAgentProvider 接口

SubAgentProvider 用于创建子智能体实例:

import io.agentscope.core.agent.Agent;

/**
 * 子智能体提供者
 * 每次调用 provide() 返回一个新的智能体实例
 */
@FunctionalInterface
public interface SubAgentProvider<T extends Agent> {
    
    /**
     * 提供一个新的智能体实例
     */
    T provide();
}

14.2.2 SubAgentConfig 配置

import io.agentscope.core.tool.subagent.SubAgentConfig;
import io.agentscope.core.session.Session;
import io.agentscope.core.agent.StreamOptions;

// 创建子智能体配置
SubAgentConfig config = SubAgentConfig.builder()
    // 工具名称(可选,默认从智能体名称生成)
    .toolName("call_researcher")
    
    // 工具描述(可选,默认从智能体描述获取)
    .description("调用研究员智能体进行深度研究")
    
    // 是否转发事件到父智能体(支持流式输出)
    .forwardEvents(true)
    
    // 流式输出选项
    .streamOptions(StreamOptions.defaults())
    
    // 会话存储(用于多轮对话状态保持)
    .session(session)
    
    .build();

14.2.3 SubAgentTool 类

import io.agentscope.core.tool.subagent.SubAgentTool;
import io.agentscope.core.tool.subagent.SubAgentProvider;
import io.agentscope.core.tool.subagent.SubAgentConfig;

// 创建子智能体工具
SubAgentTool researcherTool = new SubAgentTool(
    // 智能体提供者(lambda 表达式)
    () -> createResearcherAgent(),
    
    // 配置
    SubAgentConfig.builder()
        .toolName("call_researcher")
        .description("调用研究员进行信息研究和分析")
        .forwardEvents(true)
        .build()
);

// 工具暴露的参数:
// - session_id: 可选,用于多轮对话
// - message: 必需,发送给子智能体的消息

14.3 基本使用

14.3.1 创建子智能体工具

import io.agentscope.core.ReActAgent;
import io.agentscope.core.tool.Toolkit;
import io.agentscope.core.tool.subagent.SubAgentTool;
import io.agentscope.core.tool.subagent.SubAgentConfig;

public class AgentAsToolExample {

    public static void main(String[] args) {
        String apiKey = System.getenv("DASHSCOPE_API_KEY");

        // ========================================
        // 1. 创建子智能体工具
        // ========================================
        
        // 研究员智能体工具
        SubAgentTool researcherTool = new SubAgentTool(
            () -> createResearcherAgent(apiKey),
            SubAgentConfig.builder()
                .toolName("call_researcher")
                .description("调用研究员智能体进行深度信息研究和分析")
                .forwardEvents(true)
                .build()
        );

        // 翻译员智能体工具
        SubAgentTool translatorTool = new SubAgentTool(
            () -> createTranslatorAgent(apiKey),
            SubAgentConfig.builder()
                .toolName("call_translator")
                .description("调用翻译员智能体进行多语言翻译")
                .forwardEvents(true)
                .build()
        );

        // ========================================
        // 2. 创建主智能体(使用子智能体工具)
        // ========================================
        Toolkit toolkit = new Toolkit();
        toolkit.registerAgentTool(researcherTool);
        toolkit.registerAgentTool(translatorTool);

        ReActAgent supervisor = ReActAgent.builder()
            .name("Supervisor")
            .sysPrompt("""
                你是一个任务协调者。
                
                你有以下专业助手可以调用:
                - call_researcher: 用于深度研究和信息收集
                - call_translator: 用于翻译任务
                
                根据用户的需求,选择合适的助手来完成任务。
                你可以:
                1. 直接回答简单问题
                2. 调用专业助手处理复杂任务
                3. 整合多个助手的结果给出最终回答
                """)
            .model(createModel(apiKey))
            .toolkit(toolkit)
            .memory(new InMemoryMemory())
            .build();

        // ========================================
        // 3. 使用主智能体
        // ========================================
        System.out.println("用户: 请研究一下人工智能在医疗领域的最新应用\n");
        
        Msg response = supervisor.call(
            Msg.builder()
                .role(MsgRole.USER)
                .content(TextBlock.builder()
                    .text("请研究一下人工智能在医疗领域的最新应用")
                    .build())
                .build()
        ).block();
        
        System.out.println("助手: " + response.getTextContent());
    }

    private static ReActAgent createResearcherAgent(String apiKey) {
        return ReActAgent.builder()
            .name("Researcher")
            .description("专业研究员,擅长深度信息收集和分析")
            .sysPrompt("""
                你是一位专业研究员。
                
                你的能力:
                1. 收集和整理信息
                2. 分析数据和趋势
                3. 提供详细的研究报告
                
                请根据用户的研究需求,提供详细、准确、有洞察力的分析。
                """)
            .model(createModel(apiKey))
            .memory(new InMemoryMemory())
            .toolkit(new Toolkit())
            .build();
    }

    private static ReActAgent createTranslatorAgent(String apiKey) {
        return ReActAgent.builder()
            .name("Translator")
            .description("专业翻译员,支持多语言翻译")
            .sysPrompt("""
                你是一位专业翻译员。
                
                你的能力:
                1. 中英文互译
                2. 保持原文风格和语气
                3. 处理专业术语
                
                请提供准确、流畅的翻译结果。
                """)
            .model(createModel(apiKey))
            .memory(new InMemoryMemory())
            .toolkit(new Toolkit())
            .build();
    }
}

14.3.2 多轮对话支持

SubAgentTool 支持多轮对话,通过 session_id 参数保持上下文:

// 子智能体工具调用时的参数
// 第一次调用(新会话):
{
    "message": "请分析这篇文章的主题"
}

// 后续调用(继续会话):
{
    "session_id": "abc-123-def",  // 从前一次响应中获取
    "message": "请进一步解释第二点"
}

会话管理示例:

import io.agentscope.core.session.InMemorySession;
import io.agentscope.core.session.Session;

// 创建会话存储
Session session = new InMemorySession();

// 配置带会话的子智能体工具
SubAgentConfig config = SubAgentConfig.builder()
    .toolName("call_analyst")
    .description("数据分析师,支持多轮分析对话")
    .session(session)  // 启用会话持久化
    .build();

SubAgentTool analystTool = new SubAgentTool(
    () -> createAnalystAgent(apiKey),
    config
);

// 主智能体可以通过 session_id 进行多轮对话
// 第一次调用返回:
// session_id: abc-123
// 分析结果: ...

// 主智能体可以使用同一个 session_id 继续对话

14.4 事件转发与流式输出

14.4.1 启用事件转发

SubAgentConfig config = SubAgentConfig.builder()
    .toolName("call_writer")
    .forwardEvents(true)  // 启用事件转发
    .streamOptions(StreamOptions.builder()
        .streamThinking(true)   // 转发思考过程
        .streamToolCall(true)   // 转发工具调用
        .build())
    .build();

14.4.2 流式输出处理

// 主智能体使用流式模式
supervisor.stream("请帮我写一篇关于 AI 的文章")
    .doOnNext(event -> {
        // 可以接收到子智能体的流式事件
        if (event.getMessage() != null) {
            System.out.print(event.getMessage().getTextContent());
        }
    })
    .blockLast();

14.5 完整示例:研究助理系统

import io.agentscope.core.ReActAgent;
import io.agentscope.core.memory.InMemoryMemory;
import io.agentscope.core.message.Msg;
import io.agentscope.core.message.MsgRole;
import io.agentscope.core.message.TextBlock;
import io.agentscope.core.model.DashScopeChatModel;
import io.agentscope.core.tool.Toolkit;
import io.agentscope.core.tool.subagent.SubAgentConfig;
import io.agentscope.core.tool.subagent.SubAgentTool;
import java.util.Scanner;

/**
 * 研究助理系统
 * 主智能体协调多个专业子智能体完成复杂研究任务
 */
public class ResearchAssistantSystem {

    public static void main(String[] args) {
        String apiKey = System.getenv("DASHSCOPE_API_KEY");

        // ========================================
        // 创建专业子智能体工具
        // ========================================
        
        // 文献研究员
        SubAgentTool literatureReviewer = new SubAgentTool(
            () -> createSpecialist(apiKey, "LiteratureReviewer", """
                你是一位文献研究专家。
                
                你的专长:
                1. 查找和分析学术文献
                2. 总结研究现状和趋势
                3. 识别研究空白和机会
                
                请提供详细的文献综述和分析。
                """),
            SubAgentConfig.builder()
                .toolName("call_literature_reviewer")
                .description("调用文献研究员进行学术文献检索和综述")
                .forwardEvents(true)
                .build()
        );

        // 数据分析师
        SubAgentTool dataAnalyst = new SubAgentTool(
            () -> createSpecialist(apiKey, "DataAnalyst", """
                你是一位数据分析专家。
                
                你的专长:
                1. 分析数据模式和趋势
                2. 进行统计推断
                3. 可视化数据洞察
                
                请提供数据驱动的分析和建议。
                """),
            SubAgentConfig.builder()
                .toolName("call_data_analyst")
                .description("调用数据分析师进行数据分析和解读")
                .forwardEvents(true)
                .build()
        );

        // 报告撰写员
        SubAgentTool reportWriter = new SubAgentTool(
            () -> createSpecialist(apiKey, "ReportWriter", """
                你是一位专业报告撰写员。
                
                你的专长:
                1. 组织和结构化信息
                2. 撰写清晰专业的报告
                3. 提炼关键发现和建议
                
                请将研究结果整理成结构化的报告。
                """),
            SubAgentConfig.builder()
                .toolName("call_report_writer")
                .description("调用报告撰写员整理和撰写研究报告")
                .forwardEvents(true)
                .build()
        );

        // ========================================
        // 创建主研究协调员
        // ========================================
        Toolkit toolkit = new Toolkit();
        toolkit.registerAgentTool(literatureReviewer);
        toolkit.registerAgentTool(dataAnalyst);
        toolkit.registerAgentTool(reportWriter);

        ReActAgent coordinator = ReActAgent.builder()
            .name("ResearchCoordinator")
            .sysPrompt("""
                你是一位研究项目协调员。
                
                你可以调用以下专业助手:
                - call_literature_reviewer: 进行文献研究
                - call_data_analyst: 进行数据分析
                - call_report_writer: 撰写研究报告
                
                工作流程:
                1. 理解用户的研究需求
                2. 分解任务并分配给合适的专家
                3. 整合各专家的结果
                4. 提供最终的研究成果
                
                请高效协调团队完成研究任务。
                """)
            .model(DashScopeChatModel.builder()
                .apiKey(apiKey)
                .modelName("qwen-max")
                .stream(true)
                .build())
            .toolkit(toolkit)
            .memory(new InMemoryMemory())
            .maxIters(15)  // 增加迭代次数以支持多工具调用
            .build();

        // ========================================
        // 交互式对话
        // ========================================
        System.out.println("=== 研究助理系统 ===");
        System.out.println("可用专家: 文献研究员、数据分析师、报告撰写员");
        System.out.println("输入 'exit' 退出\n");

        Scanner scanner = new Scanner(System.in);
        
        while (true) {
            System.out.print("你: ");
            String input = scanner.nextLine().trim();
            
            if ("exit".equalsIgnoreCase(input)) {
                break;
            }
            
            if (input.isEmpty()) continue;

            System.out.print("协调员: ");
            coordinator.stream(input)
                .doOnNext(event -> {
                    if (event.getMessage() != null) {
                        String text = event.getMessage().getTextContent();
                        if (text != null && !text.isEmpty()) {
                            System.out.print(text);
                        }
                    }
                })
                .blockLast();
            System.out.println("\n");
        }
        
        scanner.close();
    }

    private static ReActAgent createSpecialist(
            String apiKey, String name, String prompt) {
        return ReActAgent.builder()
            .name(name)
            .sysPrompt(prompt)
            .model(DashScopeChatModel.builder()
                .apiKey(apiKey)
                .modelName("qwen-plus")
                .stream(true)
                .build())
            .memory(new InMemoryMemory())
            .toolkit(new Toolkit())
            .build();
    }
}

14.6 最佳实践

14.6.1 设计建议

建议说明
明确分工每个子智能体应该有明确的专业领域
清晰描述工具描述应该让主智能体知道何时调用
适度层级避免过深的嵌套调用
会话管理复杂任务使用会话保持上下文
错误处理处理子智能体可能的失败情况

14.6.2 工具描述示例

// 好的工具描述
SubAgentConfig.builder()
    .toolName("call_code_reviewer")
    .description("""
        调用代码审查专家。使用场景:
        - 需要审查代码质量和安全性
        - 需要代码优化建议
        - 需要检查最佳实践合规性
        输入: 要审查的代码或代码描述
        输出: 详细的审查报告和建议
        """)
    .build();

// 避免的描述
SubAgentConfig.builder()
    .toolName("call_agent")
    .description("调用一个智能体")  // 太模糊
    .build();

14.6.3 与其他模式的对比

模式适用场景通信方式
Agent-as-Tool层级协作,主从关系工具调用
MsgHub平等对话,多方讨论消息广播
Pipeline流水线处理,顺序执行输出传递
A2A分布式部署,跨服务调用网络协议

14.7 本章小结

本章介绍了 Agent-as-Tool 模式:

  1. 核心概念:将智能体封装为工具,实现层级协作
  2. SubAgentTool:子智能体工具的核心实现
  3. SubAgentConfig:配置选项(名称、描述、会话、流式输出)
  4. 多轮对话:通过 session_id 保持上下文
  5. 事件转发:支持流式输出到主智能体

Agent-as-Tool 模式非常适合构建"主管-专家"类型的多智能体系统。


练习

  1. 创建一个包含 3 个专业子智能体的客服系统
  2. 实现带会话管理的多轮对话子智能体
  3. 比较 Agent-as-Tool 和 MsgHub 在同一任务上的使用差异
  4. 尝试嵌套调用:主智能体 → 子智能体 → 孙智能体

上一章:第13章-多智能体辩论 | 下一章:第15章-A2A协议

← 返回目录