找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1622

积分

0

好友

232

主题
发表于 5 天前 | 查看: 14| 回复: 0

AgentScope-Java架构示意图

你是否好奇:一个智能体是如何在没有预设逻辑的情况下,通过自我推理(Reasoning)和行动(Acting)来解决复杂的工程问题?本文将深入ReActAgent的核心机制,剖析其工具注册与执行的底层链路。我们不仅会实战演示如何构建一个能“自修复SQL”的AI DBA,还将挑战更高难度的课题——打造一个能够自主拆分任务、并行执行的全自动化项目测试专家。

一、AgentScope-Java的ReAct自我迭代机制剖析

本文旨在剖析其源码如何通过Toolkit注册工具,并驱动大语言模型(LLM)在reasoningacting之间构建自动化的“思考-执行”闭环,揭示智能体自我迭代的秘密。

开源地址:https://github.com/agentscope-ai/agentscope-java

在开始前,需在Maven项目中引入依赖。

<dependency>
    <groupId>io.agentscope</groupId>
    <artifactId>agentscope</artifactId>
    <version>1.0.2</version>
</dependency>

由于支持的模型平台有限,可前往百炼平台申请API Key用于测试。

基础的智能体调用测试代码如下:

import com.chugyoyo.cosmosagent.CosmosAgentApplication;
import com.chugyoyo.cosmosagent.common.LlmProvierEnum;
import com.chugyoyo.cosmosagent.dto.AIConfigurationDTO;
import com.chugyoyo.cosmosagent.service.AIConfigurationService;
import io.agentscope.core.ReActAgent;
import io.agentscope.core.message.Msg;
import io.agentscope.core.model.DashScopeChatModel;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest(classes = CosmosAgentApplication.class)
public class AgentScopeTest {
    @Autowired
    private AIConfigurationService aiConfigurationService;

    @Test
    public void test() {
        AIConfigurationDTO configuration = aiConfigurationService.getConfigurationByProvider(LlmProvierEnum.DASHSCOPE);
        ReActAgent agent = ReActAgent.builder()
                .name("Assistant")
                .sysPrompt("You are a helpful AI assistant.")
                .model(DashScopeChatModel.builder()
                        .apiKey(configuration.getApiKey())
                        .modelName("qwen-max")
                        .build())
                .build();
        Msg response = agent.call(Msg.builder()
                .textContent("Hello!")
                .build()).block();
        System.out.println(response.getTextContent());
    }
}

基础调用测试结果

接下来,为智能体加入MCP(模型上下文协议)能力。首先,根据AgentScope-Java的@Tool注解创建一个工具类。

package com.chugyoyo.cosmosagent.mcp.server;

import io.agentscope.core.tool.Tool;
import io.agentscope.core.tool.ToolParam;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SimpleTools {
    @Tool(name = "get_time", description = "Get current time")
    public String getTime(
            @ToolParam(name = "zone", description = "Timezone, e.g., Beijing") String zone) {
        log.info("Get time in zone: {}", zone);
        return java.time.LocalDateTime.now()
                .format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }
}

然后,在智能体构建时注册此工具集并调用。

import com.chugyoyo.cosmosagent.mcp.server.SimpleTools;
import io.agentscope.core.tool.Toolkit;
// ... 其他import

@SpringBootTest(classes = CosmosAgentApplication.class)
public class AgentScopeTest {
    @Autowired
    private AIConfigurationService aiConfigurationService;

    @Test
    public void test() {
        AIConfigurationDTO configuration = aiConfigurationService.getConfigurationByProvider(LlmProvierEnum.DASHSCOPE);
        // 准备工具集
        Toolkit toolkit = new Toolkit();
        toolkit.registerTool(new SimpleTools());

        ReActAgent agent = ReActAgent.builder()
                .name("Assistant")
                .sysPrompt("You are a helpful AI assistant.")
                .model(DashScopeChatModel.builder()
                        .apiKey(configuration.getApiKey())
                        .modelName("qwen-max")
                        .build())
                .toolkit(toolkit) // 注册工具集
                .build();

        Msg response = agent.call(Msg.builder()
                .textContent("Hello, what time is it now?")
                .build()).block();
        System.out.println(response.getTextContent());
    }
}

工具调用测试结果

测试显示,智能体成功调用了本地工具服务。那么,AgentScope-Java的底层是如何调度这些工具的呢?

通过源码分析,可以发现一条清晰的引用链:ReActAgent -> Toolkit -> ToolRegistry。在构建智能体时(调用.build()之后),工具就会被注册到工具注册器中。

工具注册流程

真正的调用过程始于agent.call(..)方法。

调用入口

其核心流程如下:

notifyPreCall(msgs)        // 1. 预处理通知
    .flatMap(this::doCall)     // 2. 实际执行
    .flatMap(this::notifyPostCall) // 3. 后处理通知
    .onErrorResume(createErrorHandler(msgs.toArray(new Msg[0]))) // 4. 错误处理

实际执行的核心在doCall方法中,它最终会进入executeReActLoop,开始ReAct循环。

// io.agentscope.core.ReActAgent#doCall(java.util.List<io.agentscope.core.message.Msg>)
@Override
protected Mono<Msg> doCall(List<Msg> msgs) {
    if (msgs != null) {
        msgs.forEach(memory::addMessage);
    }
    return executeReActLoop(null);
}

循环的每一次迭代(executeIteration)都遵循“推理-行动”模式:

private Mono<Msg> executeIteration(int iter, StructuredOutputHandler handler) {
    if (iter >= maxIters) {
        return summarizing(handler);
    }
    return checkInterruptedAsync()
            .then(reasoning(handler)) // 推理
            .then(Mono.defer(this::checkInterruptedAsync)) // 再次检查
            .then(Mono.defer(() -> actingOrFinish(iter, handler))); // 行动或者结束
}

推理阶段(reasoning)会准备消息、将工具集转换为LLM可识别的Function Call格式,然后调用模型的流式接口。

private Mono<Void> prepareAndStream() {
    List<Msg> messageList = messagePreparer.prepareMessageList(handler);
    // 在结构化输出模式下应用强制工具选择
    GenerateOptions options =
            handler != null
                    ? handler.createOptionsWithForcedTool(buildGenerateOptions())
                    : buildGenerateOptions();
    List<ToolSchema> toolSchemas = toolkit.getToolSchemas();
    return hookNotifier
            .notifyPreReasoning(ReActAgent.this, messageList)
            .flatMapMany(modifiedMsgs -> model.stream(modifiedMsgs, toolSchemas, options))
            .concatMap(this::processChunkWithInterruptCheck)
            .then();
}

推理与行动流程
消息准备
工具集转换

推理完成后,进入actingOrFinish方法。系统会判断LLM的返回中是否包含工具调用请求(ToolUseBlock)。如果存在,则执行工具调用,并将结果作为新一轮“推理-行动”循环的输入。

工具调用判断
工具调用执行

工具调用在io.agentscope.core.ReActAgent.ActingPipeline#execute中具体执行。

工具执行细节

由此,一个完整的“推理(Re)- 行动(Act)- 观察结果 - 再推理”的闭环得以形成。只要提示词清晰、工具完备,一个智能体调用就能驱动复杂的多步骤任务执行。

然而,纯粹的Agentic模式在实践中仍面临挑战,例如模型的幻觉和错误会在迭代中被放大。因此,在实际的Java应用开发中,通常需要结合提示词工程、重试机制、结果校验等工程化手段来构建更稳定可靠的智能系统。

二、基于AgentScope-Java的自动化数据库查询实践

为了让智能体能够自主查询数据库,我们需要为其提供以下MCP能力:

  1. 查询数据库的所有表结构。
  2. 安全地执行自定义SQL(通常需进行校验,避免DDL/DML操作)。

以下是相应的工具类实现:

package com.chugyoyo.cosmosagent.mcp.server;

import io.agentscope.core.tool.Tool;
import io.agentscope.core.tool.ToolParam;
import lombok.extern.slf4j.Slf4j;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.sql.DataSource;
import java.sql.*;
import java.util.*;

@Slf4j
public class DatabaseTools {
    private static DataSource dataSource;
    private static final ObjectMapper jsonMapper = new ObjectMapper();

    public static void setDataSource(DataSource ds) {
        dataSource = ds;
    }

    /**
     * 工具 1: 获取数据库所有表的设计结构
     * LLM 需要此信息来理解表字段,以便编写正确的SQL。
     */
    @Tool(name = "get_database_schema", description = "Fetch metadata of all tables, including table names, column names, and column types. Use this before generating SQL.")
    public String getDatabaseSchema() {
        if (dataSource == null) return "Error: DataSource is not initialized.";
        Map<String, List<Map<String, String>>> schema = new HashMap<>();
        try (Connection conn = dataSource.getConnection()) {
            DatabaseMetaData metaData = conn.getMetaData();
            // 1. 获取所有表
            try (ResultSet tables = metaData.getTables(null, null, "%", new String[]{"TABLE"})) {
                while (tables.next()) {
                    String tableName = tables.getString("TABLE_NAME");
                    List<Map<String, String>> columnsList = new ArrayList<>();
                    // 2. 获取该表的所有列
                    try (ResultSet columns = metaData.getColumns(null, null, tableName, "%")) {
                        while (columns.next()) {
                            Map<String, String> columnInfo = new HashMap<>();
                            columnInfo.put("name", columns.getString("COLUMN_NAME"));
                            columnInfo.put("type", columns.getString("TYPE_NAME"));
                            columnInfo.put("remarks", columns.getString("REMARKS"));
                            columnsList.add(columnInfo);
                        }
                    }
                    schema.put(tableName, columnsList);
                }
            }
            return jsonMapper.writeValueAsString(schema);
        } catch (Exception e) {
            log.error("Failed to fetch schema", e);
            return "Error fetching schema: " + e.getMessage();
        }
    }

    /**
     * 工具 2: 执行自定义SQL
     * 包含基础的安全校验(规则级)。
     */
    @Tool(name = "execute_sql", description = "Execute a SELECT SQL query. The SQL must be a read-only statement. DDL and DML (INSERT, UPDATE, DELETE, DROP) are strictly forbidden.")
    public String executeSql(
            @ToolParam(name = "sql", description = "The SQL query string to execute. Must be valid SQL.") String sql) {
        log.info("Agent requesting to execute SQL: {}", sql);
        if (dataSource == null) return "Error: DataSource is not initialized.";
        // --- 安全校验层 ---
        String normalizedSql = sql.trim().toUpperCase();
        if (!normalizedSql.startsWith("SELECT") && !normalizedSql.startsWith("WITH")) {
            return "Security Alert: Only SELECT queries are allowed. Your query must start with SELECT or WITH.";
        }
        // 简单的黑名单
        Set<String> blackSet = new HashSet<>(Arrays.asList(
                "DROP", "DELETE", "UPDATE", "INSERT", "ALTER", "TRUNCATE",
                "GRANT", "REVOKE", "EXEC", "SHOW"
        ));
        if (blackSet.stream().anyMatch(normalizedSql::contains)) {
            return "Security Alert: The SQL contains forbidden DDL/DML keywords or multiple statements. Query rejected.";
        }
        // --- 执行查询 ---
        try (Connection conn = dataSource.getConnection();
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();
            List<Map<String, Object>> resultList = new ArrayList<>();
            int rowLimit = 50;
            int rowCount = 0;
            while (rs.next()) {
                if (rowCount >= rowLimit) break;
                Map<String, Object> row = new HashMap<>();
                for (int i = 1; i <= columnCount; i++) {
                    row.put(metaData.getColumnLabel(i), rs.getObject(i));
                }
                resultList.add(row);
                rowCount++;
            }
            if (rowCount >= rowLimit) {
                log.warn("Query result truncated at {} rows", rowLimit);
            }
            String jsonResult = jsonMapper.writeValueAsString(resultList);
            return jsonResult.isEmpty() ? "No results found." : jsonResult;
        } catch (SQLException e) {
            log.warn("SQL Execution failed: {}", e.getMessage());
            return "SQL Execution Error: " + e.getMessage();
        } catch (Exception e) {
            return "System Error: " + e.getMessage();
        }
    }
}

数据库工具测试

单元测试通过后,我们将这些工具整合到一个Web控制器中,构建一个AI DBA接口。

package com.chugyoyo.cosmosagent.controller;

// ... import 略
import javax.sql.DataSource;

@Slf4j
@RestController
@RequestMapping("/agentic")
public class AgenticController {
    @Autowired
    private AIConfigurationService aiConfigurationService;
    @Autowired
    private DataSource dataSource;

    @GetMapping("/auto-select-from-db")
    public ApiResp<String> autoSelectFromDb(@RequestParam String question) {
        AIConfigurationDTO configuration = aiConfigurationService.getConfigurationByProvider(LlmProvierEnum.DASHSCOPE);
        Toolkit toolkit = new Toolkit();
        DatabaseTools databaseTools = new DatabaseTools();
        DatabaseTools.setDataSource(dataSource);
        toolkit.registerTool(databaseTools);

        ReActAgent agent = ReActAgent.builder()
                .name("Assistant")
                .sysPrompt("你是一个资深 DBA,你需要根据用户的问题,使用数据库工具来查询数据库。")
                .model(DashScopeChatModel.builder()
                        .apiKey(configuration.getApiKey())
                        .modelName("qwen-max")
                        .build())
                .toolkit(toolkit)
                .build();

        Msg response = agent.call(Msg.builder()
                .textContent(question)
                .build()).block();
        log.info("Response: {}", response.getTextContent());
        return ApiResp.success(response.getTextContent());
    }
}

通过HTTP请求测试:

GET http://localhost:8080/agentic/auto-select-from-db?question=请查询最近的一条聊天记录所对应的整个聊天内容

AI DBA查询结果
查询执行日志

验证成功,智能体通过调用get_database_schemaexecute_sql工具,自动完成了从理解表结构到生成并执行SQL的全过程。

三、迈向全自动化测试:多工具整合与挑战

基于上述实践,我们进一步扩展工具集,目标是构建一个能自主测试项目的智能体。我们设计了以下工具集:

工具名 核心作用
get_database_schema 读取数据库表结构
execute_sql 执行SQL查询
get_project_api_docs 扫描 @Controller,生成API文档
get_class_structure 反射获取DTO字段详情
invoke_api 通过HTTP调用接口
save_execution_report 将测试结果写入Markdown文件

将这些工具全部注册给一个ReActAgent,让它执行全面测试任务。

@Test
public void test() {
    AIConfigurationDTO configuration = aiConfigurationService.getConfigurationByProvider(LlmProvierEnum.DASHSCOPE);
    Toolkit toolkit = new Toolkit();
    toolkit.registerTool(new ProjectDocTools(applicationContext));
    toolkit.registerTool(new ClassInspectorTools());
    toolkit.registerTool(new ReportingTools());
    toolkit.registerTool(new ApiInvokerTools(restTemplate));
    DatabaseTools.setDataSource(dataSource);
    toolkit.registerTool(new DatabaseTools());

    ReActAgent agent = ReActAgent.builder()
            .name("Assistant")
            .sysPrompt("你是一个有 10 年互联网大厂经验的测试专家,请根据提供的 API 文档,回答用户的问题")
            .model(DashScopeChatModel.builder()
                    .apiKey(configuration.getApiKey())
                    .modelName("qwen-max")
                    .build())
            .toolkit(toolkit)
            .build();

    Msg response = agent.call(Msg.builder()
            .textContent("请对项目里的各个接口进行一轮流程测试,然后将测试报告写到本地文件中,必要时可以调用工具。")
            .build()).block();
    System.out.println(response.getTextContent());
}

初步自动化测试结果
测试执行过程

测试取得部分成功,但智能体仅测试了两个接口后便停止。这可能是因为大模型在接收到某些错误或完成部分任务后,自行判断应结束流程(AgentScope-Java未打印所有中间推理日志)。同时,我们也注意到线程池的使用,表明其内部通过异步方式调用工具以提升效率。

异步线程调用
Token消耗情况

为引导智能体进行更全面的测试,我们优化了提示词:

String content = """
        请对项目里的所有接口进行一轮流程测试,然后将测试报告写到本地文件中,必要时可以调用工具。
        注意:
        1. 如果错误的话,可以找原因然后想方法去执行,必要时可以查询 SQL 去数据库里找数据
        2. 如果失败超过 10 次,这个接口将不再进行测试,标记最后一次失败的原因
        3. 请保证所有接口都被测试过
        """;

优化提示词后的执行

执行中暴露了更多问题:

  1. /{id}这类路径参数处理失败,未尝试构造测试数据。
  2. 测试卡在/mcp/sse长连接接口。
  3. 模型的“注意力”有限,难以理解过于复杂或冗长的指令列表。

进一步添加提示词约束:

4. 面对 /mcp/sse 接口这种长连接的不测试
5. 像 ../{id}/.. 这种路径参数,直接替换为测试的变量,然后进行请求

路径参数处理失败

问题仍未完全解决。根本原因在于单智能体、长上下文的ReAct模式存在局限性:上下文过长会导致模型负担加重,复杂任务容易使模型“注意力分散”。因此,任务拆分与子任务独立执行变得至关重要,这些都指向了提示词工程多智能体协作的设计。

四、借鉴Claude Code:迈向多智能体协作系统

当前遇到的注意力分散、长连接阻塞、路径参数处理失败、上下文过长等挑战,是智能体在复杂工业场景落地的普遍痛点。业界先进的产品如Claude Code,采用了不同的策略:它通常先启动一个规划阶段,将“测试所有接口”这样的大任务拆解为[获取接口列表, 过滤SSE, 对接口A查看DTO, 获取测试数据, 执行接口A, 记录结果...]等一系列原子子任务,并可能使用多个不同专长的智能体协作完成。

多智能体协作示意图

根据Anthropic公开发表的《How we built our multi-agent research system》文章,构建高效多智能体系统的核心在于提示词工程。文中总结了八大原则,其中对我们的启发最大的是:教会编排者如何授权(任务分发)根据查询复杂度扩展投入

受此启发,我们尝试在AgentScope-Java上层构建一个简单的多智能体协作框架。核心思路是:新增一个“执行子任务”的工具,主智能体负责规划并调用此工具,该工具内部会创建一个独立的子智能体来执行具体任务。

package com.chugyoyo.cosmosagent.mcp.server;

import io.agentscope.core.ReActAgent;
import io.agentscope.core.message.Msg;
import io.agentscope.core.model.DashScopeChatModel;
import io.agentscope.core.tool.Tool;
import io.agentscope.core.tool.ToolParam;
import io.agentscope.core.tool.Toolkit;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SubTaskAutomationTool {
    private final String apiKey;
    private final Toolkit globalToolkit; // 全局原子工具池

    public SubTaskAutomationTool(String apiKey, Toolkit globalToolkit) {
        this.apiKey = apiKey;
        this.globalToolkit = globalToolkit;
    }

    @Tool(name = "execute_subtask",
            description = "Delegate a specific sub-task to a specialized sub-agent. " +
                    "Use this to handle complex steps in parallel or break down a large goal.")
    public String executeSubtask(
            @ToolParam(name = "taskName", description = "Brief name of the sub-task") String taskName,
            @ToolParam(name = "instruction", description = "Detailed instructions for the sub-agent") String instruction,
            @ToolParam(name = "contextData", description = "Specific data needed (e.g., API path, table name)") String contextData) {
        log.info("--- Starting Sub-Agent: [{}] ---", taskName);
        try {
            ReActAgent subAgent = ReActAgent.builder()
                    .name(taskName)
                    .sysPrompt(String.format(
                            "你是一个专项任务执行者。任务名称:%s。你的目标是根据提供的上下文和指令," +
                                    "利用工具独立完成任务并给出最终结果。不要废话,直接执行。", taskName))
                    .model(DashScopeChatModel.builder()
                            .apiKey(apiKey)
                            .modelName("qwen-max")
                            .build())
                    .toolkit(globalToolkit) // 子智能体拥有操作原子工具的能力
                    .build();
            String prompt = String.format("任务指令: %s\n上下文数据: %s", instruction, contextData);
            Msg response = subAgent.call(Msg.builder().textContent(prompt).build()).block();
            String result = response.getTextContent();
            log.info("--- Sub-Agent [{}] Finished ---", taskName);
            return String.format("Sub-task [%s] execution result: %s", taskName, result);
        } catch (Exception e) {
            log.error("Sub-task execution failed", e);
            return "Error executing sub-task: " + e.getMessage();
        }
    }
}

应用此协作模式的测试代码如下:

@Test
public void test() {
    AIConfigurationDTO config = aiConfigurationService.getConfigurationByProvider(LlmProvierEnum.DASHSCOPE);
    // 1. 准备底层的原子工具
    Toolkit atomicToolkit = new Toolkit();
    atomicToolkit.registerTool(new ProjectDocTools(applicationContext));
    atomicToolkit.registerTool(new DatabaseTools());
    atomicToolkit.registerTool(new ApiInvokerTools(restTemplate));

    // 2. 注册“递归任务工具”到编排者工具集
    Toolkit orchestratorToolkit = new Toolkit();
    orchestratorToolkit.registerTool(new SubTaskAutomationTool(config.getApiKey(), atomicToolkit));
    orchestratorToolkit.registerTool(new ProjectDocTools(applicationContext)); // 主智能体也需要规划能力

    // 3. 初始化主智能体(编排者)
    String prompt = """
            你是一个高级编排者,你的职责是:
            1. 分析用户的任务,拆分任务为多个子任务。
            2. 对于每个任务,分别调用 execute_subtask 这个 tool,让子智能体去执行任务
            3. 汇总 execute_subtask 子智能体的结果
            4. 判断是否需要继续执行任务,需要的话,重复步骤 1-3
            """;
    ReActAgent leadAgent = ReActAgent.builder()
            .name("LeadAgent")
            .sysPrompt(prompt)
            .model(DashScopeChatModel.builder().apiKey(config.getApiKey()).modelName("qwen-max").build())
            .toolkit(orchestratorToolkit)
            .build();

    // 4. 下达宏观指令
    Msg msg = leadAgent.call(Msg.builder().textContent("请全面测试项目中的所有用户相关接口").build()).block();
    System.out.println(msg.getTextContent());
}

多智能体任务拆分

执行发现,主智能体开始了任务拆分,但子任务存在重复工作(如多个子任务都去获取API文档),且最终执行不充分,未覆盖所有接口。这表明我们的任务拆分逻辑和提示词引导仍需优化。

我们进一步改进了提示词,采用少样本(Few-Shot)示例引导和“一步一步思考”(Chain-of-Thought)的提示策略。

String prompt = """
        你是一个高级编排者,你的职责是:
        1. 分析用户的任务,拆分任务为多个子任务。
        2. 对于每个任务,分别调用 execute_subtask 这个 tool,让子智能体去执行任务
        3. 汇总 execute_subtask 子智能体的结果
        4. 判断是否需要继续执行任务,需要的话,重复步骤 1-3
        例如:
        '''task-plan
        当前任务:请全面测试项目中的所有用户相关接口
        拆分子任务 1: 获取所有的用户接口 API DOC,确认任务范围和内容
        拆分子任务 2:测试 http://localhost:8080/user/register 接口
            目标:验证用户注册功能是否正常
            输出格式:[状态码,响应体摘要]
            必要时可以调用工具,例如查询数据库
        拆分子任务 3: 测试 http://localhost:8080/user/login 接口
            目标:验证用户登录功能是否正常
            输出格式:JSON 格式,包含登录结果和状态码
        当前任务:汇总子任务的结果,包括测试结果和必要的日志,写一个测试报告到本地文件 test-report.md
        '''
        请一步一步地思考!
        """;

五、回归具体任务:通过精准提示词实现高效自动化

在实践中我们发现,对于高度复杂的任务,让AI完全自主规划仍不可靠。更务实的策略是结合具体业务,由开发者提供明确、具体的任务规划,AI负责严格执行。我们新增了文件读写工具,并将一个完整的测试流程拆解为清晰、顺序执行的子任务。

系统提示词:

你是一个拥有 10 年互联网大厂测试经验的测试专家,需要完成给定的任务。

用户提示词(具体任务规划):

当前任务:请全面测试项目中的所有 /agent/、/chat/ 路径的接口
拆分子任务 1: 查看是否有 API DOC 文件,如果有则跳过,否则新建文件 api-docs.md
拆分子任务 2: 若文件 api-docs.md 为空,获取最新的 API DOC 内容,然后写入该文件
拆分子任务 3: 读取 api-docs.md,生成测试计划,将测试计划写入 api-test-plan.md
拆分子任务 4: 根据 api-test-plan.md 中的测试计划,执行测试用例,将测试结果写入 api-test-results.md
注意:
- 请一步一步地思考。
- 子任务执行是调用 execute_subtask 工具,任务内容必须清晰、上下文完整。

在此规划下,智能体成功生成了结构化的API文档、详细的测试计划以及最终的测试结果报告,执行流程规范且结果可追溯。

生成的API文档(部分):

### Project API Documentation ###
- [[DELETE]] [/api/agents/deleteAgent]
  Controller: AgentController#deleteAgent
  Params: [Long id]
  Returns: ApiResp
- [[POST]] [/api/agents/saveUpdateLink]
  Controller: AgentController#saveUpdateLink
  Params: [AgentLinkDTO dto]
  Returns: ApiResp

生成的测试计划(部分):

# API Test Plan
## /agent/ Endpoints
### DELETE /api/agents/deleteAgent
- **Positive Test Case:** Provide a valid `id`...验证删除成功。
- **Negative Test Case 1:** Attempt to delete with an invalid `id`...确保请求失败并返回适当错误。
### POST /api/agents/saveUpdateLink
- **Positive Test Case:** Send a valid `AgentLinkDTO`...确认创建或更新符合预期。

生成的测试结果(部分):

### POST /api/agents/saveUpdateLink
- **Positive Test Case:** Send a valid `AgentLinkDTO`...
  - Result: Failed, Status: 200, Response: {"code": 500,"message":"连线不存在"...}
- **Negative Test Case 1:** Send an incomplete `AgentLinkDTO`...
  - Result: Failed, Status: 200, Response: {"code": 500,"message":"Validation failed..."}

精准规划下的执行流程

采用这种“人类规划,AI执行”的模式后,任务完成度和可靠性显著提升。然而,这又引出一个更深层的问题:如果所有流程都需要如此精细的人工规划,那么自动化测试的价值是否被削弱?

答案是,在现阶段,AI更适合作为“增强”工具而非“替代”工具。它可以高效执行重复、规范的步骤,并在人类定义的框架内发挥灵活性和推断能力。未来的演进方向是:通过积累高质量的API文档(由AI辅助生成和人工维护)、构建领域知识库、优化工具描述等方式,逐步降低对精细提示词的依赖,让智能体承担更多规划职责,最终向全流程自主化演进。

总结

从剖析AgentScope-Java单智能体的ReAct闭环机制,到实践数据库自动查询,再到尝试构建多智能体协作的自动化测试专家,我们深入探索了Agentic模式的应用与挑战。

实验表明,通过精心的提示词工程工具化任务拆分,可以显著提升智能体在复杂场景下的任务完成率。借鉴业界先进的多智能体系统设计原则,为我们优化智能体行为提供了宝贵思路。然而,在工程落地中,“人类规划,AI执行”的增强模式在当前阶段更为可靠务实。

未来的智能体开发,将更侧重于工具接口的友好性、任务编排的智能性以及系统整体的鲁棒性。让智能体在明确的边界和引导下自我优化与协作,是迈向更高级别人工智能应用的必经之路。




上一篇:Java高并发秒杀系统架构设计:7大核心场景与解决方案实战
下一篇:C# WinForms构建工业视觉系统:相机标定、图像处理与色彩识别实战
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-24 18:58 , Processed in 0.311684 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表