11-Agent设计原理和基础实战

2 阅读24分钟

掌握Agent的核心原理:七大设计范式(ReAct、Plan-Execute、Reflexion、REWOO、Self-Ask、LATS、Multi-Agent)、Tool定义、AiServices模式,实现能自主推理和行动的智能体

时间:60分钟 | 难度:⭐⭐⭐⭐ | Week 2 Day 11


官方Example信息

  • GitHub链接ServiceWithToolsExample.java
  • 相关Example:ServiceWithToolsExample、ChatWithToolsExample
  • 所在路径:src/main/java/dev/langchain4j/examples/
  • 代码行数:约100-200行
  • 难度:高级 ⭐⭐⭐⭐

学习目标

  • 理解Agent的本质和ReAct循环
  • 掌握Agent七大范式的区别和选型
  • 掌握@Tool和@P注解定义工具
  • 学会使用AiServices创建Agent
  • 能手动实现Agent Loop
  • 掌握Agent的错误处理和超时控制
  • 能监控和调试Agent行为

🚀 快速入门:什么是Agent?

Agent的本质

Agent = LLM + Tool + 决策循环

传统方式(Chain):
输入 → 步骤1 → 步骤2 → 步骤3 → 输出
(固定流程,人类决定每一步)

Agent方式:
输入 → LLM思考 → 选择工具 → 执行 → 观察结果 → 继续思考...
(动态流程,LLM自己决定下一步)

Agent vs Chain 的区别

Chain(链式):
  "先分析代码,再检查性能,再检查安全"
  → 固定3步,即使代码很简单也要走完
  → 人类编排流程

Agent(智能体):
  "帮我审查这段代码"
  → LLM自己决定:先看看代码结构...
  → 发现有SQL拼接,调用安全检查工具
  → 发现有性能问题,调用性能分析工具
  → 综合所有结果,给出建议
  → LLM自主编排流程

深度讲解

1️⃣ ReAct循环:Agent的思维模式

ReAct = Reasoning(推理) + Action(行动)

┌──────────────────────────────────┐
│          ReAct 循环              │
│                                  │
│  用户输入                        │
│     │                            │
│     ▼                            │
│  ┌──────────┐                    │
│  │ 思考     │ LLM分析问题        │
│  │(Reason)  │ 决定下一步行动      │
│  └────┬─────┘                    │
│       │                          │
│       ▼                          │
│  ┌──────────┐                    │
│  │ 行动     │ 调用选中的工具      │
│  │(Action)  │ 传入参数           │
│  └────┬─────┘                    │
│       │                          │
│       ▼                          │
│  ┌──────────┐                    │
│  │ 观察     │ 获取工具返回结果    │
│  │(Observe) │ 分析结果           │
│  └────┬─────┘                    │
│       │                          │
│       ▼                          │
│  够了吗?──── 否 ──→ 回到思考    │
│    │                              │
│    是                             │
│    │                              │
│    ▼                              │
│  最终回答                         │
└──────────────────────────────────┘

ReAct Demo:最简单的ReAct实现

/**
 * ReAct 范式 Demo
 * 核心循环:Think(推理) → Act(行动) → Observe(观察) → 重复
 *
 * 这个例子展示了ReAct的完整过程:
 * 用户问"杭州今天适合跑步吗?" →
 *   Think: 需要知道天气 → Act: 调用天气工具 → Observe: 25°C晴天
 *   Think: 需要知道空气质量 → Act: 调用AQI工具 → Observe: AQI 45
 *   Think: 信息足够了 → 最终回答
 */
@Service
public class ReActDemo {

    private final ChatLanguageModel model;
    private final List<ToolSpecification> toolSpecs;
    private final Map<String, ToolExecutor> executors;

    private static final int MAX_ITERATIONS = 5;

    /**
     * ReAct 主循环 — 这是整个范式的核心
     */
    public String run(String userQuestion) {
        List<ChatMessage> messages = new ArrayList<>();
        messages.add(SystemMessage.from("""
            你是一个helpful助手。使用工具获取信息后再回答。
            每次只调用一个最相关的工具。
            信息足够时,直接给出最终回答。
            """));
        messages.add(UserMessage.from(userQuestion));

        for (int i = 1; i <= MAX_ITERATIONS; i++) {

            // ============ THINK(推理)============
            // LLM 分析当前信息,决定下一步
            Response<AiMessage> response = model.generate(messages, toolSpecs);
            AiMessage aiMessage = response.content();
            messages.add(aiMessage);

            // ============ 判断:够了吗? ============
            if (!aiMessage.hasToolExecutionRequests()) {
                // LLM认为信息足够,直接给出最终回答
                log.info("[ReAct] 第{}轮结束,给出最终回答", i);
                return aiMessage.text();
            }

            // ============ ACT(行动)============
            // 执行LLM选择的工具
            for (ToolExecutionRequest toolReq : aiMessage.toolExecutionRequests()) {
                log.info("[ReAct] 第{}轮 → Act: 调用工具 {}({})",
                    i, toolReq.name(), toolReq.arguments());

                String toolResult = executors.get(toolReq.name())
                    .execute(toolReq, null);

                // ============ OBSERVE(观察)============
                // 把工具结果反馈给LLM
                log.info("[ReAct] 第{}轮 → Observe: {}", i, toolResult);
                messages.add(ToolExecutionResultMessage.from(toolReq, toolResult));
            }
            // → 回到循环顶部,LLM继续Think...
        }

        return "达到最大迭代次数,无法完成推理";
    }
}

// ===== 工具定义 =====
public class WeatherTools {

    @Tool("查询指定城市的当前天气(温度、天气状况)")
    public String getWeather(@P("城市名称") String city) {
        // 实际项目中调用天气API
        return "{"city":"" + city + "","temp":"25°C","condition":"晴天"}";
    }

    @Tool("查询指定城市的空气质量指数AQI")
    public String getAirQuality(@P("城市名称") String city) {
        return "{"city":"" + city + "","aqi":45,"level":""}";
    }
}

运行过程(日志输出)

[ReAct]1轮 → Act: 调用工具 getWeather({"city":"杭州"})
[ReAct]1轮 → Observe: {"city":"杭州","temp":"25°C","condition":"晴天"}
[ReAct]2轮 → Act: 调用工具 getAirQuality({"city":"杭州"})
[ReAct]2轮 → Observe: {"city":"杭州","aqi":45,"level":"优"}
[ReAct]3轮结束,给出最终回答

最终回答:杭州今天非常适合跑步!气温25°C,晴天,空气质量AQI 45(优),
建议选择早晨或傍晚时段,注意防晒和补水。

关键理解:每轮循环中,LLM 自主决定"调用哪个工具"还是"直接回答"。这就是 ReAct 的核心 — 推理驱动行动

💡 对比:后面第4️⃣节的"手动实现Agent Loop"是 ReAct 的生产级版本,增加了错误处理、超时控制、多工具并行等能力。


ReAct之外:Agent七大范式全景

ReAct只是Agent设计的范式之一。根据思考、行动、观察三者的编排方式不同,业界发展出了七大核心范式:

┌──────────────┬──────────────────┬─────────────┬───────────┐
│ 范式          │ 一句话本质         │ LLM调用次数  │ 核心优势   │
├──────────────┼──────────────────┼─────────────┼───────────┤
│ ReAct        │ 边想边做           │ N次(每步1次)│ 灵活通用   │
│ Plan-Execute │ 先想后做           │ 2+N次       │ 全局规划   │
│ Reflexion    │ 做完回头看         │ 3N次(最贵) │ 自我改进   │
│ REWOO        │ 想一次,做一次     │ 2次(最便宜)│ 成本最低   │
│ Self-Ask     │ 大问题拆小问题     │ N次         │ 多跳推理   │
│ LATS         │ 像下棋一样搜索     │ 分支×深度   │ 找最优解   │
│ Multi-Agent  │ 分工协作           │ Agent数×轮数│ 专业分工   │
└──────────────┴──────────────────┴─────────────┴───────────┘

范式一:Plan-and-Execute(计划-执行)

本质:先制定完整计划,再逐步执行。规划和执行可以用不同模型(强模型规划、弱模型执行 = 省钱)。

用户问题
   │
   ▼
┌──────────┐
│ Planner  │  ← 强模型(GPT-4o)只调用1次
│ 规划全部   │  → 输出:[步骤1, 步骤2, 步骤3, ...]
└────┬─────┘
     │
     ▼
┌──────────┐
│ Executor │  ← 弱模型(GPT-4o-mini)逐步执行
│ 逐步执行   │  → 每步一个结果
└────┬─────┘
     │
     ▼
┌──────────┐
│ Replanner│  ← 可选:根据执行结果动态调整计划
│ 重新规划   │
└──────────┘
/**
 * Plan-and-Execute 范式实现
 * 核心思想:分离规划和执行,降低成本
 */
@Service
public class PlanAndExecuteAgent {

    @Autowired @Qualifier("strongModel")   // GPT-4o 做规划
    private ChatLanguageModel planner;

    @Autowired @Qualifier("fastModel")     // GPT-4o-mini 做执行
    private ChatLanguageModel executor;

    public String execute(String query) {
        // Phase 1: 规划 — 一次LLM调用,生成完整步骤
        String plan = planner.generate("""
            请将以下任务分解为3-5个具体执行步骤,每步一行,格式为"1. xxx":
            任务:%s
            """.formatted(query));

        List<String> steps = parseSteps(plan);
        log.info("[Plan] 生成{}个步骤", steps.size());

        // Phase 2: 执行 — 用便宜模型逐步执行
        StringBuilder context = new StringBuilder();
        for (int i = 0; i < steps.size(); i++) {
            String stepResult = executor.generate("""
                任务上下文:%s
                已完成的步骤结果:
                %s
                请执行当前步骤:%s
                """.formatted(query, context, steps.get(i)));

            context.append("步骤").append(i + 1).append(":")
                   .append(stepResult).append("\n");
            log.info("[Execute] 步骤{}/{} 完成", i + 1, steps.size());
        }

        // Phase 3: 综合 — 用强模型生成最终答案
        return planner.generate(
            "请基于以下执行结果,给出最终完整答案:\n" + context);
    }
}
// 成本对比:规划1次(强) + 执行N次(弱) + 综合1次(强)
// vs ReAct:每步都用强模型 → Plan-Execute省约60%成本

vs ReAct

ReActPlan-and-Execute
规划方式每步临时决定预先制定完整计划
全局视角❌ 没有✅ 有
灵活性高(随时调整)中(按计划执行)
成本高(每步用强模型)(执行用弱模型)

适用场景:复杂多步任务、成本敏感场景、步骤之间有明确依赖关系。


范式二:Reflexion(自我反思)

本质:做完之后回头审视结果,从错误中学习,带着教训重新执行。一种元认知机制。

用户问题
   │
   ▼
┌──────────┐
│ Actor    │ ← 第1次执行,得到初步结果
│ 执行       │
└────┬─────┘
     │ 初步结果
     ▼
┌──────────┐
│Evaluator │ ← 评估结果质量(打分 / 运行测试)
│ 评估       │
└────┬─────┘
     │ 评分:6/10,有问题
     ▼
┌──────────┐
│Reflector │ ← 反思:"我漏掉了边界条件处理..."
│ 反思       │ → 教训存入记忆
└────┬─────┘
     │ 带着教训
     ▼
┌──────────┐
│ Actor    │ ← 第2次执行,避免之前的错误
│ 重新执行   │ → 评分:9/10 ✅
└──────────┘
/**
 * Reflexion 范式实现
 * 核心思想:通过自我反思迭代改进结果
 */
@Service
public class ReflexionAgent {

    private final ChatLanguageModel model;

    public String execute(String query) {
        List<String> reflectionMemory = new ArrayList<>();  // 反思记忆
        String bestResult = null;
        int bestScore = 0;

        for (int attempt = 0; attempt < 3; attempt++) {
            // Step 1: 执行(带上历史反思教训)
            String reflections = reflectionMemory.isEmpty()
                ? "无" : String.join("\n", reflectionMemory);

            String result = model.generate("""
                任务:%s
                请避免以下历史错误:
                %s
                请认真执行任务。
                """.formatted(query, reflections));

            // Step 2: 评估(可以是LLM评估,也可以是运行测试)
            String evaluation = model.generate("""
                请评估以下结果的质量(1-10分),并指出具体问题:
                任务:%s
                结果:%s
                输出格式:分数:X  问题:xxx
                """.formatted(query, result));

            int score = extractScore(evaluation);
            log.info("[Reflexion] 第{}次尝试,得分:{}/10", attempt + 1, score);

            if (score > bestScore) {
                bestScore = score;
                bestResult = result;
            }

            // Step 3: 足够好则提前返回
            if (score >= 8) return result;

            // Step 4: 反思并记忆(关键步骤!)
            String reflection = model.generate("""
                你的回答得了 %d/10 分。问题是:%s
                请用一句话总结教训,下次如何改进?
                """.formatted(score, evaluation));

            reflectionMemory.add("第%d次教训:%s".formatted(attempt + 1, reflection));
        }
        return bestResult;  // 返回最优结果
    }
}
// 特点:每次尝试约3次LLM调用(执行+评估+反思),最贵但准确率最高

适用场景:代码生成(生成→测试→反思→修复)、写作改进(初稿→审核→反思→重写)、需要高准确性的推理任务。


范式三:REWOO(无观察推理)

本质:一次性规划所有工具调用,批量执行后再综合。把N次LLM调用压缩到仅2次,成本最低

对比:
ReAct:  LLM → Tool → LLM → Tool → LLM → Tool → LLM  (7次LLM调用)
REWOO:  LLM(规划全部) → Tool → Tool → Tool → LLM(综合)  (2次LLM调用)

流程:
┌──────────────┐
│   Planner    │  ← 第1次LLM调用
│  一次性规划    │  → #E1 = search("Java性能优化")
│  所有工具调用  │  → #E2 = analyzeCode(代码)
│  (用变量引用)│  → #E3 = checkSecurity(代码)
└──────┬───────┘
       │
       ▼
┌──────────────┐
│   Worker     │  ← 不调LLM,纯工具执行
│  顺序执行工具  │  → 解析变量依赖
│  收集所有结果  │  → 可并行执行无依赖的工具
└──────┬───────┘
       │ 所有工具结果
       ▼
┌──────────────┐
│   Solver     │  ← 第2次LLM调用
│  综合所有结果  │  → 生成最终答案
└──────────────┘
/**
 * REWOO 范式实现
 * 核心思想:用变量引用预规划所有工具调用,减少LLM调用次数
 */
@Service
public class RewooAgent {

    private final ChatLanguageModel model;
    private final Map<String, Function<String, String>> tools;

    public String execute(String query) {
        // Step 1: Planner — 一次LLM调用,规划所有工具
        String plan = model.generate("""
            请为以下任务规划工具调用。用#E1、#E2等变量引用前序结果。
            可用工具:search(query), analyzeCode(code), checkSecurity(code)
            任务:%s
            输出格式(每行一个步骤):
            #E1 = search("相关查询")
            #E2 = analyzeCode(代码)
            #E3 = checkSecurity(代码)
            """.formatted(query));

        // Step 2: Worker — 按顺序执行,解析变量依赖(不调用LLM)
        Map<String, String> results = new LinkedHashMap<>();
        for (String step : plan.lines().filter(l -> l.startsWith("#E")).toList()) {
            String varName = step.split("=")[0].trim();          // #E1
            String toolCall = step.split("=", 2)[1].trim();     // search("xxx")

            // 将变量引用替换为实际结果
            for (var entry : results.entrySet()) {
                toolCall = toolCall.replace(entry.getKey(), entry.getValue());
            }

            String result = executeTool(toolCall);
            results.put(varName, result);
        }

        // Step 3: Solver — 一次LLM调用,综合所有结果
        String allResults = results.entrySet().stream()
            .map(e -> e.getKey() + " = " + e.getValue())
            .collect(Collectors.joining("\n\n"));

        return model.generate("""
            任务:%s
            工具执行结果:
            %s
            请基于以上结果给出完整答案。
            """.formatted(query, allResults));
    }
}
// 关键优势:只需2次LLM调用,成本比ReAct降低70%+
// 局限:无法根据中间结果动态调整工具调用计划

适用场景:成本敏感(LLM调用次数降低70%+)、工具调用依赖关系明确、批量数据处理。


范式四:Self-Ask(自问自答)

本质:将复杂问题递归拆解为子问题,逐个解答后合成最终答案。

问题:"LangChain4J 最适合用哪种向量数据库部署在K8s上?"
  │
  ├─ 子问题1"LangChain4J 支持哪些向量数据库?"
  │  └─ 回答:Milvus, Chroma, Pinecone, Redis...
  │
  ├─ 子问题2"这些数据库中哪些适合K8s部署?"
  │  └─ 回答:Milvus(有Helm Chart)、Chroma(轻量容器化)
  │
  ├─ 子问题3"Milvus vs Chroma 在K8s上的运维差异?"
  │  └─ 回答:Milvus适合大规模、Chroma适合小规模
  │
  └─ 最终答案:大规模选Milvus,小规模选Chroma
/**
 * Self-Ask 范式实现
 * 核心思想:将多跳推理问题分解为单跳子问题
 */
@Service
public class SelfAskAgent {

    private final ChatLanguageModel model;
    private final SearchTool searchTool;

    public String execute(String query) {
        List<String> qaHistory = new ArrayList<>();

        for (int i = 0; i < 5; i++) {
            String context = qaHistory.isEmpty()
                ? "暂无" : String.join("\n", qaHistory);

            // 问LLM:需要先回答什么子问题?还是可以直接回答了?
            String response = model.generate("""
                原始问题:%s
                已知信息:
                %s
                请判断:
                - 如果需要先回答一个子问题,输出:Follow up: <子问题>
                - 如果已经可以回答原始问题,输出:Final Answer: <最终答案>
                """.formatted(query, context));

            if (response.contains("Final Answer:")) {
                return response.split("Final Answer:")[1].trim();
            }

            // 提取子问题,用搜索工具回答
            String subQuestion = response.split("Follow up:")[1].trim();
            String subAnswer = searchTool.search(subQuestion);
            qaHistory.add("Q: " + subQuestion + "\nA: " + subAnswer);
            log.info("[Self-Ask] 子问题{}: {}", i + 1, subQuestion);
        }
        return "无法在限定步数内回答";
    }
}

适用场景:多跳推理("A的老板的公司的CEO是谁?")、知识密集型问答、与搜索引擎结合的问答系统。


范式五:LATS(语言智能体树搜索)

本质:像下棋一样,同时探索多条行动路径,评估打分后选最优路径继续深入。借鉴了蒙特卡洛树搜索(MCTS)。

                 问题
                  │
        ┌─────────┼─────────┐
        │         │         │
      行动A     行动B     行动C     ← 同时生成多种行动
        │         │         │
      评分:7    评分:9    评分:5LLM评估每条路径
        │         │
        ×      选择B ✅            ← 剪枝,只走最优
                  │
            ┌─────┼─────┐
          行动B1  行动B2  行动B3    ← 继续分支探索
            │      │
          评分:6  评分:8 ✅
                   │
                 最终答案

适用场景:编程竞赛(探索多种算法解法)、数学证明(多条推导路径)、需要找最优解的复杂决策。


范式六:Multi-Agent(多智能体协作)

本质:多个Agent角色分工,各司其职协作完成任务。

模式A - 辩论式:Agent正方 ◄──► Agent反方 → 辩论出更好的答案
模式B - 流水线:Agent研究 → Agent写作 → Agent审核 → Agent优化
模式C - 主从式:协调者Agent → 分派任务给多个Worker Agent

详细实现见 [[2019-多智能体协作和复杂推理]]。


范式选择决策树

你的任务是什么?
│
├─ 简单工具调用
│  └─→ ReAct ✅(最通用,LangChain4J默认支持)
│
├─ 复杂多步任务
│  ├─ 需要省钱? → REWOO ✅(只需2次LLM调用)
│  └─ 需要全局规划? → Plan-and-Execute ✅
│
├─ 需要高准确性(代码生成、推理)
│  └─→ Reflexion ✅(自我纠错,迭代改进)
│
├─ 多跳知识问答
│  └─→ Self-Ask ✅(递归分解子问题)
│
├─ 需要探索多种解法
│  └─→ LATS ✅(树搜索找最优)
│
└─ 一个Agent搞不定
   └─→ Multi-Agent ✅(角色分工协作)

本质上,所有范式都在回答同一个问题:LLM的思考、行动、观察三者之间,应该如何编排?

  • ReAct:交替进行 | Plan-Execute:思考先集中做完 | Reflexion:多加一步回顾
  • REWOO:行动先集中做完 | Self-Ask:思考递归分解 | LATS:并行探索多条路径

2️⃣ Tool定义:给Agent装备工具

基础Tool定义

/**
 * 使用@Tool注解定义工具
 * LLM会根据方法名和描述来决定何时调用
 */
public class CodeAnalysisTools {

    @Tool("分析Java代码的结构,包括类、方法、字段的数量和复杂度")
    public String analyzeCodeStructure(
            @P("要分析的Java源代码文本") String code) {
        int classCount = countPattern(code, "class\\s+\\w+");
        int methodCount = countPattern(code, "(public|private|protected)\\s+\\w+\\s+\\w+\\s*\\(");
        int fieldCount = countPattern(code, "(private|public|protected)\\s+\\w+\\s+\\w+\\s*;");

        return String.format("代码结构分析:%d个类,%d个方法,%d个字段",
            classCount, methodCount, fieldCount);
    }

    @Tool("检查代码中的安全漏洞,如SQL注入、XSS等")
    public String checkSecurity(
            @P("要检查的Java源代码") String code) {
        List<String> issues = new ArrayList<>();

        if (code.contains("Statement") && !code.contains("PreparedStatement")) {
            issues.add("发现SQL注入风险:使用了Statement而非PreparedStatement");
        }
        if (code.contains("innerHTML") || code.contains("document.write")) {
            issues.add("发现XSS风险:直接操作DOM");
        }

        return issues.isEmpty() ? "未发现安全漏洞" : String.join("\n", issues);
    }

    @Tool("检查代码的性能问题")
    public String checkPerformance(
            @P("要检查的Java源代码") String code) {
        List<String> issues = new ArrayList<>();

        if (code.contains("for") && code.contains("for")) {
            issues.add("可能存在嵌套循环,注意时间复杂度");
        }
        if (code.contains("synchronized")) {
            issues.add("使用了synchronized,注意死锁和性能影响");
        }

        return issues.isEmpty() ? "未发现明显性能问题" : String.join("\n", issues);
    }

    private int countPattern(String text, String pattern) {
        return (int) Pattern.compile(pattern).matcher(text).results().count();
    }
}

@Tool注解详解

public class ToolAnnotationExamples {

    // 1. 基本用法 - 方法名作为工具名
    @Tool("获取当前时间")
    public String getCurrentTime() {
        return LocalDateTime.now().toString();
    }

    // 2. 带参数描述
    @Tool("计算两个数字的和")
    public int add(
            @P("第一个数字") int a,
            @P("第二个数字") int b) {
        return a + b;
    }

    // 3. 返回复杂对象(会被序列化为JSON)
    @Tool("查询用户信息")
    public UserInfo queryUser(@P("用户ID") String userId) {
        return userService.findById(userId);
    }

    // 4. 可选参数
    @Tool("搜索代码中的特定模式")
    public String searchCode(
            @P("要搜索的代码") String code,
            @P("搜索的模式(正则表达式)") String pattern) {
        Matcher matcher = Pattern.compile(pattern).matcher(code);
        List<String> matches = new ArrayList<>();
        while (matcher.find()) {
            matches.add(matcher.group());
        }
        return "找到 " + matches.size() + " 个匹配:" + matches;
    }

    // 5. 枚举参数
    @Tool("根据严重程度过滤问题")
    public List<String> filterIssues(
            @P("严重程度:HIGH, MEDIUM, LOW") String severity) {
        Severity level = Severity.valueOf(severity);
        return issueService.findBySeverity(level);
    }
}

3️⃣ AiServices模式:声明式Agent创建

定义Agent接口

/**
 * 使用AiServices创建Agent
 * 接口定义 → 框架自动实现 → 包含Tool调用能力
 */
public interface CodeReviewAgent {

    @SystemMessage("""
        你是一个专业的代码审查助手。
        你可以使用工具来分析代码的结构、安全性和性能。
        请根据分析结果给出综合的代码审查建议。

        审查流程:
        1. 先分析代码结构
        2. 检查安全问题
        3. 检查性能问题
        4. 综合给出建议
        """)
    String reviewCode(@UserMessage String codeDescription);
}

创建和使用Agent

@Configuration
public class AgentConfig {

    @Bean
    public CodeReviewAgent codeReviewAgent(ChatLanguageModel model) {
        // 创建工具实例
        CodeAnalysisTools tools = new CodeAnalysisTools();

        // 使用AiServices构建Agent
        return AiServices.builder(CodeReviewAgent.class)
                .chatLanguageModel(model)
                .tools(tools)  // 注册工具
                .chatMemory(MessageWindowChatMemory.withMaxMessages(20))
                .build();
    }
}

// 使用Agent
@Service
public class CodeReviewService {
    @Autowired
    private CodeReviewAgent agent;

    public String review(String code) {
        return agent.reviewCode("请审查以下代码:\n" + code);
    }
}

AiServices的工作原理

AiServices 是 LangChain4J 实现 Agent 的核心机制。理解它的内部原理,才能真正掌握 Agent。

第一层:JDK 动态代理 — Agent的"壳"
// 你写的代码:
CodeReviewAgent agent = AiServices.builder(CodeReviewAgent.class)
    .chatLanguageModel(model)
    .tools(new CodeAnalysisTools())
    .build();

// LangChain4J内部做了什么?
// ↓↓↓ 等价于 ↓↓↓

CodeReviewAgent agent = (CodeReviewAgent) Proxy.newProxyInstance(
    CodeReviewAgent.class.getClassLoader(),
    new Class[]{CodeReviewAgent.class},
    new AiServiceInvocationHandler(model, tools, memory, ...)  // 核心!
);
AiServices.build() 的内部过程:

1. 扫描接口上的注解
   ├─ @SystemMessage → 提取系统提示词
   ├─ @UserMessage  → 标记用户输入参数
   └─ @V            → 模板变量

2. 扫描工具对象上的 @Tool 注解
   ├─ 方法名 → 工具名
   ├─ @Tool("描述") → 工具描述(给LLM看的)
   ├─ @P("参数描述") → 参数描述
   └─ 生成 List<ToolSpecification>(JSON Schema格式)

3. 创建 JDK 动态代理
   └─ 所有方法调用都被 InvocationHandler 拦截
第二层:@Tool → ToolSpecification — 让LLM"看懂"工具
// 你定义的工具:
public class CodeAnalysisTools {
    @Tool("分析Java代码的结构,返回类数、方法数")
    public String analyzeStructure(@P("Java源代码") String code) { ... }
}

// LangChain4J 扫描后转换成的 ToolSpecification(发给LLM的JSON):
// ↓↓↓ 等价于 ↓↓↓
ToolSpecification.builder()
    .name("analyzeStructure")                          // 方法名
    .description("分析Java代码的结构,返回类数、方法数")   // @Tool的值
    .addParameter("code", JsonSchemaProperty.STRING,    // 参数类型
        description("Java源代码"))                       // @P的值
    .build();

// 最终发给 OpenAI API 的格式:
// {
//   "type": "function",
//   "function": {
//     "name": "analyzeStructure",
//     "description": "分析Java代码的结构,返回类数、方法数",
//     "parameters": {
//       "type": "object",
//       "properties": {
//         "code": { "type": "string", "description": "Java源代码" }
//       },
//       "required": ["code"]
//     }
//   }
// }
关键理解:
@Tool 注解的描述 = LLM 决定"用不用这个工具"的唯一依据!

LLM 收到的信息:
┌───────────────────────────────────────┐
│ 你有以下工具可用:                       │
│                                       │
│ 1. analyzeStructure                   │
│    描述:"分析Java代码的结构,返回类数、方法数"│
│    参数:code (string) - "Java源代码"    │
│                                       │
│ 2. checkSecurity                      │
│    描述:"检查代码中的安全漏洞"             │
│    参数:code (string) - "Java源代码"    │
│                                       │
│ 你可以选择调用工具,也可以直接回答。        │
└───────────────────────────────────────┘
第三层:InvocationHandler — Agent循环的核心引擎

当你调用 agent.reviewCode("审查这段代码") 时,InvocationHandler 内部执行的完整流程:

/**
 * 伪代码:AiServices 内部的 InvocationHandler
 * 这就是 LangChain4J Agent 的"心脏"
 */
class AiServiceInvocationHandler implements InvocationHandler {

    private final ChatLanguageModel model;
    private final List<ToolSpecification> toolSpecs;   // 工具定义列表
    private final Map<String, ToolExecutor> toolExecutors; // 工具执行器
    private final ChatMemory memory;                   // 对话记忆

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {

        // ===== Step 1: 构建消息 =====
        // 从注解提取 SystemMessage
        String systemPrompt = method.getAnnotation(SystemMessage.class).value();
        memory.add(SystemMessage.from(systemPrompt));

        // 从参数提取 UserMessage
        String userInput = (String) args[0];  // @UserMessage 标注的参数
        memory.add(UserMessage.from(userInput));

        // ===== Step 2: Agent 循环(ReAct 的核心!)=====
        int maxIterations = 10;  // 防止死循环

        for (int i = 0; i < maxIterations; i++) {

            // 2a. 调用 LLM(带工具定义)
            Response<AiMessage> response = model.generate(
                memory.messages(),   // 完整的消息历史
                toolSpecs            // 所有可用工具的定义
            );

            AiMessage aiMessage = response.content();
            memory.add(aiMessage);

            // 2b. 判断:LLM 是否要调用工具?
            if (!aiMessage.hasToolExecutionRequests()) {
                // ══════════════════════════════════════
                // LLM 没有调用工具 → 循环结束,返回结果
                // 这就是 ReAct 中的"够了吗?→ 是"
                // ══════════════════════════════════════
                return aiMessage.text();
            }

            // 2c. LLM 决定调用工具 → 执行
            for (ToolExecutionRequest req : aiMessage.toolExecutionRequests()) {
                // 找到对应的工具执行器
                ToolExecutor executor = toolExecutors.get(req.name());

                // 执行工具(调用你的 @Tool 方法)
                // 内部:JSON参数 → 反序列化 → 反射调用方法 → 结果序列化
                String result = executor.execute(req, memoryId);

                // 把工具结果放回消息历史
                memory.add(ToolExecutionResultMessage.from(req, result));
            }

            // → 回到循环顶部,LLM 基于工具结果继续思考
        }

        throw new RuntimeException("Agent达到最大迭代次数");
    }
}
第四层:完整调用链时序图
你的代码               AiServices 内部                   LLM API
  │                      │                                │
  │ agent.reviewCode()   │                                │
  │─────────────────────>│                                │
  │                      │                                │
  │                      │ Step 1: 构建消息                │
  │                      │ ┌─────────────────────┐        │
  │                      │ │ SystemMsg: "你是审查专家"│        │
  │                      │ │ UserMsg: "审查这段代码" │        │
  │                      │ │ Tools: [analyze, check]│        │
  │                      │ └─────────────────────┘        │
  │                      │                                │
  │                      │ ──── 第1轮循环 ────             │
  │                      │                                │
  │                      │ generate(messages, tools)      │
  │                      │ ──────────────────────────────>│
  │                      │                                │
  │                      │    AiMessage: 调用analyzeStructure
  │                      │ <──────────────────────────────│
  │                      │                                │
  │                      │ 反射调用你的 @Tool 方法          │
  │                      │ tools.analyzeStructure(code)   │
  │                      │ → 结果: "3个类,10个方法"        │
  │                      │                                │
  │                      │ 把结果加入消息历史               │
  │                      │                                │
  │                      │ ──── 第2轮循环 ────             │
  │                      │                                │
  │                      │ generate(messages, tools)      │
  │                      │ ──────────────────────────────>│
  │                      │                                │
  │                      │    AiMessage: 调用checkSecurity │
  │                      │ <──────────────────────────────│
  │                      │                                │
  │                      │ tools.checkSecurity(code)      │
  │                      │ → 结果: "发现SQL注入风险"        │
  │                      │                                │
  │                      │ ──── 第3轮循环 ────             │
  │                      │                                │
  │                      │ generate(messages, tools)      │
  │                      │ ──────────────────────────────>│
  │                      │                                │
  │                      │    AiMessage: 不调用工具,给出文本
  │                      │    "综合审查结果:发现1个SQL注入..."
  │                      │ <──────────────────────────────│
  │                      │                                │
  │                      │ hasToolExecutionRequests = false│
  │                      │ → 循环结束!                    │
  │                      │                                │
  │ return "综合审查结果..." │                              │
  │<─────────────────────│                                │
第五层:ToolExecutor 内部 — 从JSON到方法调用
/**
 * 伪代码:ToolExecutor 如何执行你的 @Tool 方法
 *
 * LLM返回的是 JSON:{"name":"checkSecurity", "arguments":"{\"code\":\"...\"}"}
 * ToolExecutor 需要把 JSON 转换为 Java 方法调用
 */
class DefaultToolExecutor implements ToolExecutor {

    private final Object toolObject;    // 你的工具类实例(如 CodeAnalysisTools)
    private final Method method;        // @Tool标注的方法(如 checkSecurity)

    @Override
    public String execute(ToolExecutionRequest request, Object memoryId) {
        // 1. 解析LLM返回的JSON参数
        String jsonArgs = request.arguments();  // {"code":"public class Foo {...}"}
        Map<String, Object> args = JsonParser.parse(jsonArgs);

        // 2. 将JSON参数映射到Java方法参数
        Object[] methodArgs = new Object[method.getParameterCount()];
        Parameter[] params = method.getParameters();
        for (int i = 0; i < params.length; i++) {
            String paramName = params[i].getAnnotation(P.class) != null
                ? params[i].getName() : params[i].getName();
            methodArgs[i] = convertType(args.get(paramName), params[i].getType());
        }

        // 3. 反射调用你的方法
        Object result = method.invoke(toolObject, methodArgs);

        // 4. 结果序列化为字符串返回给LLM
        return result.toString();
    }
}
总结:三句话理解 LangChain4J Agent
1. 外壳:JDK动态代理 — 你调接口方法,它调LLM
2. 引擎:while循环 — LLM返回工具调用就执行,返回文本就结束
3. 桥梁:ToolExecutorJSON参数 → 反射调用 → 结果字符串

整个 Agent 的本质 = 动态代理 + while(hasToolCalls) + 反射

💡 关键洞察:LangChain4J 的 Agent 并没有什么"魔法"。它只是把 LLM 的 Function Calling 能力 + Java 的动态代理 + 一个 while 循环组合在一起。理解了这三点,你就理解了整个 Agent 实现。

4️⃣ 手动实现Agent Loop

/**
 * 手动实现Agent循环
 * 完全控制每一步的执行过程
 */
@Service
public class ManualAgentLoop {
    private static final Logger log = LoggerFactory.getLogger(ManualAgentLoop.class);
    private static final int MAX_ITERATIONS = 10;

    private final ChatLanguageModel model;
    private final Map<String, ToolExecutor> toolExecutors;
    private final List<ToolSpecification> toolSpecs;

    public ManualAgentLoop(ChatLanguageModel model) {
        this.model = model;

        // 注册工具
        CodeAnalysisTools tools = new CodeAnalysisTools();
        this.toolSpecs = ToolSpecifications.toolSpecificationsFrom(tools);
        this.toolExecutors = new HashMap<>();
        for (ToolSpecification spec : toolSpecs) {
            toolExecutors.put(spec.name(),
                new DefaultToolExecutor(tools, spec));
        }
    }

    /**
     * 执行Agent循环
     */
    public String execute(String userQuery) {
        List<ChatMessage> messages = new ArrayList<>();
        messages.add(SystemMessage.from(
            "你是代码审查助手。使用可用的工具来分析代码。"));
        messages.add(UserMessage.from(userQuery));

        for (int iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
            log.info("[Agent] 第{}轮迭代,消息数:{}", iteration + 1, messages.size());

            // 步骤1:调用LLM(带工具定义)
            Response<AiMessage> response = model.generate(messages, toolSpecs);
            AiMessage aiMessage = response.content();
            messages.add(aiMessage);

            // 步骤2:检查是否有工具调用
            if (!aiMessage.hasToolExecutionRequests()) {
                // 没有工具调用 = LLM认为任务完成
                log.info("[Agent] 任务完成,共{}轮迭代", iteration + 1);
                return aiMessage.text();
            }

            // 步骤3:执行所有工具调用
            for (ToolExecutionRequest toolRequest : aiMessage.toolExecutionRequests()) {
                String toolName = toolRequest.name();
                String toolArgs = toolRequest.arguments();

                log.info("[Agent] 调用工具:{} 参数:{}", toolName, toolArgs);

                // 执行工具
                ToolExecutor executor = toolExecutors.get(toolName);
                if (executor == null) {
                    String errorMsg = "未知工具:" + toolName;
                    log.error("[Agent] {}", errorMsg);
                    messages.add(ToolExecutionResultMessage.from(
                        toolRequest, errorMsg));
                    continue;
                }

                String result = executor.execute(toolRequest, null);
                log.info("[Agent] 工具结果:{}", result);

                // 把工具结果加入消息历史
                messages.add(ToolExecutionResultMessage.from(
                    toolRequest, result));
            }
        }

        log.warn("[Agent] 达到最大迭代次数 {}", MAX_ITERATIONS);
        return "抱歉,我无法在规定步骤内完成任务。";
    }
}

5️⃣ 错误处理和超时控制

@Service
public class RobustAgent {
    private static final Logger log = LoggerFactory.getLogger(RobustAgent.class);
    private static final int MAX_ITERATIONS = 10;
    private static final long TOOL_TIMEOUT_MS = 30000;  // 工具调用超时30秒
    private static final long TOTAL_TIMEOUT_MS = 120000; // 总超时2分钟

    public String execute(String query) {
        long startTime = System.currentTimeMillis();
        List<ChatMessage> messages = new ArrayList<>();
        messages.add(SystemMessage.from("你是代码审查助手。"));
        messages.add(UserMessage.from(query));

        for (int i = 0; i < MAX_ITERATIONS; i++) {
            // 检查总超时
            if (System.currentTimeMillis() - startTime > TOTAL_TIMEOUT_MS) {
                log.error("[Agent] 总执行时间超时");
                return "执行超时,已部分完成的分析结果:" + getPartialResult(messages);
            }

            try {
                Response<AiMessage> response = model.generate(messages, toolSpecs);
                AiMessage aiMessage = response.content();
                messages.add(aiMessage);

                if (!aiMessage.hasToolExecutionRequests()) {
                    return aiMessage.text();
                }

                // 执行工具(带超时)
                for (ToolExecutionRequest request : aiMessage.toolExecutionRequests()) {
                    String result = executeToolWithTimeout(request);
                    messages.add(ToolExecutionResultMessage.from(request, result));
                }

            } catch (Exception e) {
                log.error("[Agent] 第{}轮出错:{}", i + 1, e.getMessage());
                messages.add(UserMessage.from(
                    "工具调用出错:" + e.getMessage() + ",请尝试其他方法"));
            }
        }

        return "达到最大迭代次数,部分结果:" + getPartialResult(messages);
    }

    private String executeToolWithTimeout(ToolExecutionRequest request) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        try {
            Future<String> future = executor.submit(() -> {
                ToolExecutor toolExec = toolExecutors.get(request.name());
                return toolExec.execute(request, null);
            });
            return future.get(TOOL_TIMEOUT_MS, TimeUnit.MILLISECONDS);
        } catch (TimeoutException e) {
            log.warn("[Tool] {} 执行超时", request.name());
            return "工具执行超时,请使用其他方法";
        } catch (Exception e) {
            log.error("[Tool] {} 执行失败:{}", request.name(), e.getMessage());
            return "工具执行失败:" + e.getMessage();
        } finally {
            executor.shutdownNow();
        }
    }

    private String getPartialResult(List<ChatMessage> messages) {
        // 从消息历史中提取已完成的工具结果
        return messages.stream()
            .filter(m -> m instanceof ToolExecutionResultMessage)
            .map(m -> ((ToolExecutionResultMessage) m).text())
            .collect(Collectors.joining("\n"));
    }
}

6️⃣ 监控和调试Agent行为

@Service
public class MonitoredAgent {
    private static final Logger log = LoggerFactory.getLogger(MonitoredAgent.class);

    // 使用Micrometer记录指标
    private final MeterRegistry meterRegistry;
    private final Counter iterationCounter;
    private final Counter toolCallCounter;
    private final Timer agentTimer;

    public MonitoredAgent(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        this.iterationCounter = Counter.builder("agent.iterations")
            .description("Agent迭代次数").register(meterRegistry);
        this.toolCallCounter = Counter.builder("agent.tool_calls")
            .description("工具调用次数").register(meterRegistry);
        this.agentTimer = Timer.builder("agent.execution_time")
            .description("Agent执行时间").register(meterRegistry);
    }

    public String execute(String query) {
        return agentTimer.record(() -> {
            List<ChatMessage> messages = buildMessages(query);

            for (int i = 0; i < MAX_ITERATIONS; i++) {
                iterationCounter.increment();

                Response<AiMessage> response = model.generate(messages, toolSpecs);
                AiMessage aiMessage = response.content();

                // 详细日志
                log.info("[Agent] 迭代={} finishReason={} hasTools={} tokenUsage={}",
                    i + 1,
                    response.finishReason(),
                    aiMessage.hasToolExecutionRequests(),
                    response.tokenUsage());

                messages.add(aiMessage);

                if (!aiMessage.hasToolExecutionRequests()) {
                    log.info("[Agent] 完成!共{}轮", i + 1);
                    return aiMessage.text();
                }

                for (ToolExecutionRequest req : aiMessage.toolExecutionRequests()) {
                    toolCallCounter.increment();
                    log.info("[Tool] 调用: name={} args={}", req.name(), req.arguments());

                    Timer.Sample sample = Timer.start();
                    String result = executeTool(req);
                    sample.stop(Timer.builder("agent.tool_duration")
                        .tag("tool", req.name())
                        .register(meterRegistry));

                    log.info("[Tool] 结果: {}",
                        result.length() > 200 ? result.substring(0, 200) + "..." : result);
                    messages.add(ToolExecutionResultMessage.from(req, result));
                }
            }
            return "达到最大迭代次数";
        });
    }
}

💻 实战:完整的代码审查Agent

/**
 * 生产级代码审查Agent
 * 包含:多工具、错误处理、监控、缓存
 */

// 1. 定义Agent接口
public interface ProductionCodeReviewAgent {

    @SystemMessage("""
        你是一位资深的Java代码审查专家。

        审查时请遵循以下流程:
        1. 首先分析代码结构(类、方法、字段)
        2. 检查是否存在安全漏洞
        3. 评估性能问题
        4. 检查代码风格
        5. 给出综合评分和改进建议

        评分标准:
        - 安全性(30%)
        - 性能(25%)
        - 可读性(25%)
        - 最佳实践(20%)
        """)
    String reviewCode(@UserMessage String request);
}

// 2. 定义工具类
public class ProductionCodeTools {

    @Tool("分析Java代码结构,返回类数量、方法数量、代码行数等")
    public String analyzeStructure(@P("Java源代码") String code) {
        String[] lines = code.split("\n");
        int codeLines = (int) Arrays.stream(lines)
            .filter(l -> !l.trim().isEmpty() && !l.trim().startsWith("//"))
            .count();
        int commentLines = (int) Arrays.stream(lines)
            .filter(l -> l.trim().startsWith("//") || l.trim().startsWith("*"))
            .count();
        int methodCount = countMatches(code, "(public|private|protected)\\s+\\w+\\s+\\w+\\s*\\(");

        return String.format(
            "代码行数:%d(代码%d行,注释%d行),方法数:%d,注释率:%.1f%%",
            lines.length, codeLines, commentLines, methodCount,
            commentLines * 100.0 / lines.length);
    }

    @Tool("检查代码中的安全漏洞")
    public String securityScan(@P("Java源代码") String code) {
        List<String> vulnerabilities = new ArrayList<>();

        if (code.contains("Runtime.getRuntime().exec")) {
            vulnerabilities.add("[严重] 命令注入风险:使用了Runtime.exec()");
        }
        if (code.matches("(?s).*Statement.*execute.*\\+.*")) {
            vulnerabilities.add("[严重] SQL注入风险:字符串拼接SQL");
        }
        if (code.contains("new File(") && code.contains("request.getParameter")) {
            vulnerabilities.add("[高] 路径遍历风险:用户输入直接用于文件路径");
        }
        if (!code.contains("@Valid") && code.contains("@RequestBody")) {
            vulnerabilities.add("[中] 缺少参数校验:RequestBody没有@Valid");
        }

        return vulnerabilities.isEmpty()
            ? "安全扫描通过,未发现漏洞"
            : "发现 " + vulnerabilities.size() + " 个安全问题:\n" +
              String.join("\n", vulnerabilities);
    }

    @Tool("分析代码性能瓶颈")
    public String performanceAnalysis(@P("Java源代码") String code) {
        List<String> issues = new ArrayList<>();

        if (code.contains("for") && code.contains("for")) {
            issues.add("[性能] 嵌套循环,时间复杂度可能为O(n²)");
        }
        if (code.contains(".stream()") && code.contains(".collect(")) {
            issues.add("[建议] Stream操作较多,考虑是否需要并行流");
        }
        if (code.contains("new ArrayList") && !code.contains("initialCapacity")) {
            issues.add("[建议] ArrayList未指定初始容量");
        }

        return issues.isEmpty()
            ? "性能分析通过"
            : String.join("\n", issues);
    }

    @Tool("检查代码风格和最佳实践")
    public String checkStyle(@P("Java源代码") String code) {
        List<String> suggestions = new ArrayList<>();

        if (code.contains("System.out.println")) {
            suggestions.add("[风格] 使用Logger替代System.out.println");
        }
        if (code.contains("catch (Exception e)") && code.contains("e.printStackTrace()")) {
            suggestions.add("[风格] 使用Logger记录异常,不要用printStackTrace");
        }
        if (!code.contains("final ") && code.contains("private ")) {
            suggestions.add("[建议] 考虑使用final修饰不变的字段");
        }

        return suggestions.isEmpty()
            ? "代码风格良好"
            : String.join("\n", suggestions);
    }

    private int countMatches(String text, String regex) {
        return (int) Pattern.compile(regex).matcher(text).results().count();
    }
}

// 3. 配置和使用
@Configuration
public class AgentConfiguration {

    @Bean
    public ProductionCodeReviewAgent codeReviewAgent(
            ChatLanguageModel model) {
        return AiServices.builder(ProductionCodeReviewAgent.class)
                .chatLanguageModel(model)
                .tools(new ProductionCodeTools())
                .chatMemory(MessageWindowChatMemory.withMaxMessages(30))
                .build();
    }
}

// 4. 服务层调用
@Service
public class CodeReviewService {
    private static final Logger log = LoggerFactory.getLogger(CodeReviewService.class);

    @Autowired
    private ProductionCodeReviewAgent agent;

    @Cacheable(value = "codeReviews", key = "#code.hashCode()")
    public String reviewCode(String code) {
        log.info("[审查] 开始审查,代码长度:{}", code.length());
        long start = System.currentTimeMillis();

        try {
            String result = agent.reviewCode("请审查以下Java代码:\n```java\n" + code + "\n```");
            long duration = System.currentTimeMillis() - start;
            log.info("[审查] 完成,耗时:{}ms", duration);
            return result;
        } catch (Exception e) {
            log.error("[审查] 失败", e);
            throw new RuntimeException("代码审查失败:" + e.getMessage(), e);
        }
    }
}

Agent调用时序图

用户                  Agent(LLM)           Tools
 │                      │                    │
 │ "审查这段代码"       │                    │
 │─────────────────────>│                    │
 │                      │                    │
 │                      │ 思考:需要先分析结构  │
 │                      │──analyzeStructure──>│
 │                      │<──结果:3个方法───── │
 │                      │                    │
 │                      │ 思考:检查安全       │
 │                      │──securityScan──────>│
 │                      │<──结果:发现SQL注入── │
 │                      │                    │
 │                      │ 思考:检查性能       │
 │                      │──performanceAnalysis>│
 │                      │<──结果:嵌套循环───── │
 │                      │                    │
 │                      │ 思考:已足够,生成报告 │
 │ "综合审查结果..."    │                    │
 │<─────────────────────│                    │

🔧 最佳实践

✅ 好的Agent设计

// 1. 工具描述要清晰
@Tool("分析Java代码结构,返回类数、方法数、行数等统计信息")
public String analyze(@P("完整的Java源代码文本") String code) { }

// 2. 工具返回结构化结果
@Tool("检查安全漏洞")
public String checkSecurity(@P("Java源代码") String code) {
    return "发现2个问题:\n1. [严重] SQL注入\n2. [中等] 缺少校验";
    // 而不是返回 "有问题"
}

// 3. 设置合理的迭代上限
AiServices.builder(Agent.class)
    .chatLanguageModel(model)
    .tools(tools)
    .build();
// 框架默认有迭代上限

// 4. SystemMessage要提供清晰的指导
@SystemMessage("""
    你是代码审查专家。
    审查流程:1.结构 2.安全 3.性能 4.风格
    每个工具只调用一次,避免重复。
    """)

❌ 坏的Agent设计

// 1. 工具描述模糊
@Tool("分析代码")  // LLM不知道具体做什么
public String analyze(String code) { }

// 2. 工具返回不明确
@Tool("检查安全")
public boolean checkSecurity(String code) {
    return true;  // LLM无法从boolean理解细节
}

// 3. 没有迭代限制(可能死循环)

// 4. SystemMessage太笼统
@SystemMessage("你是助手")  // LLM不知道要做什么

学习成果检查

  • 能解释Agent的本质和ReAct循环
  • 能区分七大范式并根据场景选型
  • 能使用@Tool和@P定义工具
  • 能用AiServices创建Agent
  • 能手动实现Agent Loop
  • 能为Agent添加错误处理和监控

下一步:学习组件综合对比,掌握何时用ChatModel、Chain、Agent的选择策略。