Agent设计模式学习(基于langchain4j实现)(11) - PlanAndExecute
<p>上篇学习了ReACT,今天继续学习PlanAndExecute模式</p><p><img src="https://img2024.cnblogs.com/blog/27612/202601/27612-20260131224737662-1296939375.gif" alt="plan_and_execute_pattern" width="480" loading="lazy" style="border: 1px solid rgba(0, 0, 0, 1)"></p>
<p><strong>与ReACT模式的关键区别如下</strong>:</p>
<table border="1">
<thead>
<tr><th>对比维度</th><th>ReAct Agent</th><th>Plan-and-Execute Agent</th></tr>
</thead>
<tbody>
<tr>
<td>思考模式</td>
<td>单步思考-行动循环</td>
<td>两阶段分离:先规划后执行</td>
</tr>
<tr>
<td>执行流程</td>
<td>Thought → Action → Observation (循环)</td>
<td>Plan → Execute Step 1 → Execute Step 2 → ...</td>
</tr>
<tr>
<td>规划范围</td>
<td>只规划下一步</td>
<td>一次性规划完整执行路径</td>
</tr>
<tr>
<td>LLM调用</td>
<td>每次循环都需要LLM</td>
<td>规划时一次,执行时可能多次</td>
</tr>
</tbody>
</table>
<h3>优势:</h3>
<ul>
<li>
<p class="ds-markdown-paragraph">效率更高:减少重复的"思考"步骤</p>
</li>
<li>
<p class="ds-markdown-paragraph">可预测性:预先知道完整执行路径</p>
</li>
<li>
<p class="ds-markdown-paragraph">易于调试:每个步骤都有明确的状态</p>
</li>
<li>
<p class="ds-markdown-paragraph">适合复杂任务:结构化处理多步骤流程</p>
</li>
</ul>
<h3>适用场景:</h3>
<ul>
<li>
<p class="ds-markdown-paragraph">✅ 数据处理的ETL流程</p>
</li>
<li>
<p class="ds-markdown-paragraph">✅ 自动化工作流</p>
</li>
<li>
<p class="ds-markdown-paragraph">✅ 需要审计的合规任务</p>
</li>
<li>
<p class="ds-markdown-paragraph">✅ 批量处理任务</p>
</li>
<li>
<p class="ds-markdown-paragraph">❌ 探索性任务(路径不确定)</p>
</li>
<li>
<p class="ds-markdown-paragraph">❌ 需要实时交互的对话</p>
</li>
</ul>
<p> </p>
<p><strong>示例代码:</strong></p>
<p>定义规划器Planner</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_fbfaddd0-2406-4c67-aaa0-566498073dea" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_fbfaddd0-2406-4c67-aaa0-566498073dea" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_fbfaddd0-2406-4c67-aaa0-566498073dea" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> Planner {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> @SystemMessage(<span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 0, 1)"> 你是一个任务规划专家。请将用户的任务分解为详细的执行步骤。
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 0, 1)"> 输出格式必须是严格的JSON格式:
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> "plan_name": "任务名称"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> "steps"<span style="color: rgba(0, 0, 0, 1)">: [
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">11</span> "step_number": 1<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">12</span> "description": "步骤描述"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">13</span> "tool": "使用的工具名称"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">14</span> "parameters": {"参数名": "参数值"<span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 0, 1)"> ],
</span><span style="color: rgba(0, 128, 128, 1)">17</span> "expected_output": "预期输出"
<span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">19</span>
<span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 0, 1)"> 可用工具列表:
</span><span style="color: rgba(0, 128, 128, 1)">21</span> 1. add -<span style="color: rgba(0, 0, 0, 1)"> 两数相加
</span><span style="color: rgba(0, 128, 128, 1)">22</span> 2. getWeather -<span style="color: rgba(0, 0, 0, 1)"> 天气查询
</span><span style="color: rgba(0, 128, 128, 1)">23</span> 3. calculateCircleArea -<span style="color: rgba(0, 0, 0, 1)"> 计算圆的面积
</span><span style="color: rgba(0, 128, 128, 1)">24</span> 4. getCurrentDateTime -<span style="color: rgba(0, 0, 0, 1)"> 获取当前时间
</span><span style="color: rgba(0, 128, 128, 1)">25</span> 5. calculateCuboidVolume -<span style="color: rgba(0, 0, 0, 1)"> 计算长方体体积
</span><span style="color: rgba(0, 128, 128, 1)">26</span> 6. multiply -<span style="color: rgba(0, 0, 0, 1)"> 两数相乘
</span><span style="color: rgba(0, 128, 128, 1)">27</span> 7. divide -<span style="color: rgba(0, 0, 0, 1)"> 两数相除
</span><span style="color: rgba(0, 128, 128, 1)">28</span> 8. queryExpressOrder -<span style="color: rgba(0, 0, 0, 1)"> 查询快递单
</span><span style="color: rgba(0, 128, 128, 1)">29</span> 9. queryRefundProgress -<span style="color: rgba(0, 0, 0, 1)"> 查询退款进度
</span><span style="color: rgba(0, 128, 128, 1)">30</span> """)
<span style="color: rgba(0, 128, 128, 1)">31</span> @UserMessage("问:{{request}}"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">32</span> @Agent("基于用户提供的问题生成计划"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">33</span> String createPlan(@V("request"<span style="color: rgba(0, 0, 0, 1)">) String request);
</span><span style="color: rgba(0, 128, 128, 1)">34</span> }</pre>
</div>
<span class="cnblogs_code_collapse">Planner </span></div>
<p>注:20-29行硬编码的方式指定需要用到的工具列表,也可以去掉,在运行时,类似ReAct一样,一股脑把sampleTools全扔给Planner调用的LLM,从运行结果来看,一样能跑通,但是使用token量就会大很多。</p>
<p>定义执行器</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_353bb914-41c5-473a-86d5-48765c588d0f" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_353bb914-41c5-473a-86d5-48765c588d0f" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_353bb914-41c5-473a-86d5-48765c588d0f" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> Executor {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> @SystemMessage(<span style="color: rgba(0, 0, 0, 1)">"""
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 0, 1)"> 你是一个任务执行器。根据给定的步骤执行任务。
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 0, 1)"> 每次只执行一个步骤,然后等待下一个指令。
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)"> 执行完成后,报告结果和下一步建议。
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)"> 输出格式:
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)"> 步骤 {n}: [工具名称]
</span><span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)"> 输入: {参数}
</span><span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 0, 1)"> 输出: {结果}
</span><span style="color: rgba(0, 128, 128, 1)">13</span> 状态: [成功/<span style="color: rgba(0, 0, 0, 1)">失败]
</span><span style="color: rgba(0, 128, 128, 1)">14</span>
<span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)"> 如果步骤失败,请说明原因和建议。
</span><span style="color: rgba(0, 128, 128, 1)">16</span> """)
<span style="color: rgba(0, 128, 128, 1)">17</span> @UserMessage("{{step}}"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">18</span> @Agent("基于用户提供的问题生成计划"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">19</span> String executeStep(@V("step"<span style="color: rgba(0, 0, 0, 1)">) String step);
</span><span style="color: rgba(0, 128, 128, 1)">20</span> }</pre>
</div>
<span class="cnblogs_code_collapse">Executor</span></div>
<p>定义协调器</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_f67fdf8b-0a27-4d79-985f-dbcd0d63e02e" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_f67fdf8b-0a27-4d79-985f-dbcd0d63e02e" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_f67fdf8b-0a27-4d79-985f-dbcd0d63e02e" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 128, 0, 1)">/**</span>
<span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(0, 128, 0, 1)"> * </span><span style="color: rgba(128, 128, 128, 1)">@author</span><span style="color: rgba(0, 128, 0, 1)"> junmingyang
</span><span style="color: rgba(0, 128, 128, 1)">3</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 128, 128, 1)">4</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Coordinator {
</span><span style="color: rgba(0, 128, 128, 1)">5</span>
<span style="color: rgba(0, 128, 128, 1)">6</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> Planner planner;
</span><span style="color: rgba(0, 128, 128, 1)">7</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> Executor executor;
</span><span style="color: rgba(0, 128, 128, 1)">8</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span><span style="color: rgba(0, 0, 0, 1)"> SampleTools tools;
</span><span style="color: rgba(0, 128, 128, 1)">9</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">final</span> Map<String, Object><span style="color: rgba(0, 0, 0, 1)"> context;
</span><span style="color: rgba(0, 128, 128, 1)"> 10</span>
<span style="color: rgba(0, 128, 128, 1)"> 11</span>
<span style="color: rgba(0, 128, 128, 1)"> 12</span> <span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Coordinator(ChatModel model, SampleTools tools) {
</span><span style="color: rgba(0, 128, 128, 1)"> 13</span>
<span style="color: rgba(0, 128, 128, 1)"> 14</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.tools =<span style="color: rgba(0, 0, 0, 1)"> tools;
</span><span style="color: rgba(0, 128, 128, 1)"> 15</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.context = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap<><span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)"> 16</span>
<span style="color: rgba(0, 128, 128, 1)"> 17</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建规划器</span>
<span style="color: rgba(0, 128, 128, 1)"> 18</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.planner = AgenticServices.agentBuilder(Planner.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 19</span> <span style="color: rgba(0, 0, 0, 1)"> .chatModel(model)
</span><span style="color: rgba(0, 128, 128, 1)"> 20</span> .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(15<span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 128, 1)"> 21</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 如果明确知道工具的列表,可以显式提供,这里就无需再绑定,以减少token使用
</span><span style="color: rgba(0, 128, 128, 1)"> 22</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">.tools(this.tools)</span>
<span style="color: rgba(0, 128, 128, 1)"> 23</span> <span style="color: rgba(0, 0, 0, 1)"> .build();
</span><span style="color: rgba(0, 128, 128, 1)"> 24</span>
<span style="color: rgba(0, 128, 128, 1)"> 25</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建执行器</span>
<span style="color: rgba(0, 128, 128, 1)"> 26</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.executor = AgenticServices.agentBuilder(Executor.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 27</span> <span style="color: rgba(0, 0, 0, 1)"> .chatModel(model)
</span><span style="color: rgba(0, 128, 128, 1)"> 28</span> .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(15<span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 128, 1)"> 29</span> .tools(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.tools)
</span><span style="color: rgba(0, 128, 128, 1)"> 30</span> <span style="color: rgba(0, 0, 0, 1)"> .build();
</span><span style="color: rgba(0, 128, 128, 1)"> 31</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)"> 32</span>
<span style="color: rgba(0, 128, 128, 1)"> 33</span>
<span style="color: rgba(0, 128, 128, 1)"> 34</span> <span style="color: rgba(0, 0, 255, 1)">public</span> Map<String, Object><span style="color: rgba(0, 0, 0, 1)"> executeTask(String task) {
</span><span style="color: rgba(0, 128, 128, 1)"> 35</span> System.out.println("\n" + "=".repeat(80<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 128, 1)"> 36</span> System.out.println("🎯 任务: " +<span style="color: rgba(0, 0, 0, 1)"> task);
</span><span style="color: rgba(0, 128, 128, 1)"> 37</span> System.out.println("=".repeat(80<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 128, 1)"> 38</span>
<span style="color: rgba(0, 128, 128, 1)"> 39</span> Map<String, Object> result = <span style="color: rgba(0, 0, 255, 1)">new</span> LinkedHashMap<><span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)"> 40</span> result.put("task"<span style="color: rgba(0, 0, 0, 1)">, task);
</span><span style="color: rgba(0, 128, 128, 1)"> 41</span> result.put("start_time"<span style="color: rgba(0, 0, 0, 1)">, LocalDateTime.now().toString());
</span><span style="color: rgba(0, 128, 128, 1)"> 42</span>
<span style="color: rgba(0, 128, 128, 1)"> 43</span> <span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)"> 44</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 阶段1: 规划</span>
<span style="color: rgba(0, 128, 128, 1)"> 45</span> System.out.println("\n📋 阶段1: 任务规划"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 46</span> System.out.println("-".repeat(40<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 128, 1)"> 47</span> String planJson =<span style="color: rgba(0, 0, 0, 1)"> planner.createPlan(task);
</span><span style="color: rgba(0, 128, 128, 1)"> 48</span> System.out.println("生成的计划:\n" +<span style="color: rgba(0, 0, 0, 1)"> planJson);
</span><span style="color: rgba(0, 128, 128, 1)"> 49</span>
<span style="color: rgba(0, 128, 128, 1)"> 50</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 解析计划(简化版,实际应该使用JSON解析)</span>
<span style="color: rgba(0, 128, 128, 1)"> 51</span> List<Map<String, String>> steps =<span style="color: rgba(0, 0, 0, 1)"> parsePlan(planJson);
</span><span style="color: rgba(0, 128, 128, 1)"> 52</span> result.put("plan"<span style="color: rgba(0, 0, 0, 1)">, steps);
</span><span style="color: rgba(0, 128, 128, 1)"> 53</span>
<span style="color: rgba(0, 128, 128, 1)"> 54</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 阶段2: 执行</span>
<span style="color: rgba(0, 128, 128, 1)"> 55</span> System.out.println("\n⚡ 阶段2: 执行计划"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 56</span> System.out.println("-".repeat(40<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 128, 1)"> 57</span>
<span style="color: rgba(0, 128, 128, 1)"> 58</span> List<Map<String, Object>> executionResults = <span style="color: rgba(0, 0, 255, 1)">new</span> ArrayList<><span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)"> 59</span>
<span style="color: rgba(0, 128, 128, 1)"> 60</span> <span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i < steps.size(); i++<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 128, 1)"> 61</span> Map<String, String> step =<span style="color: rgba(0, 0, 0, 1)"> steps.get(i);
</span><span style="color: rgba(0, 128, 128, 1)"> 62</span> System.out.printf("\n📝 步骤 %d/%d: %s%n"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)"> 63</span> i + 1, steps.size(), step.get("description"<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 128, 1)"> 64</span>
<span style="color: rgba(0, 128, 128, 1)"> 65</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 构建步骤指令</span>
<span style="color: rgba(0, 128, 128, 1)"> 66</span> String stepInstruction =<span style="color: rgba(0, 0, 0, 1)"> buildStepInstruction(step);
</span><span style="color: rgba(0, 128, 128, 1)"> 67</span>
<span style="color: rgba(0, 128, 128, 1)"> 68</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 执行步骤</span>
<span style="color: rgba(0, 128, 128, 1)"> 69</span> String stepResult =<span style="color: rgba(0, 0, 0, 1)"> executor.executeStep(stepInstruction);
</span><span style="color: rgba(0, 128, 128, 1)"> 70</span> System.out.println("执行结果:\n" +<span style="color: rgba(0, 0, 0, 1)"> stepResult);
</span><span style="color: rgba(0, 128, 128, 1)"> 71</span>
<span style="color: rgba(0, 128, 128, 1)"> 72</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 保存结果</span>
<span style="color: rgba(0, 128, 128, 1)"> 73</span> Map<String, Object> stepResultMap = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap<><span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)"> 74</span> stepResultMap.put("step_number", i + 1<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 75</span> stepResultMap.put("description", step.get("description"<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 128, 1)"> 76</span> stepResultMap.put("tool", step.get("tool"<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 128, 1)"> 77</span> stepResultMap.put("result"<span style="color: rgba(0, 0, 0, 1)">, stepResult);
</span><span style="color: rgba(0, 128, 128, 1)"> 78</span> <span style="color: rgba(0, 0, 0, 1)"> executionResults.add(stepResultMap);
</span><span style="color: rgba(0, 128, 128, 1)"> 79</span>
<span style="color: rgba(0, 128, 128, 1)"> 80</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 更新上下文</span>
<span style="color: rgba(0, 128, 128, 1)"> 81</span> <span style="color: rgba(0, 0, 0, 1)"> updateContext(task, step, stepResult);
</span><span style="color: rgba(0, 128, 128, 1)"> 82</span>
<span style="color: rgba(0, 128, 128, 1)"> 83</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 短暂暂停,避免过快执行</span>
<span style="color: rgba(0, 128, 128, 1)"> 84</span> Thread.sleep(1000<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 85</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)"> 86</span>
<span style="color: rgba(0, 128, 128, 1)"> 87</span> result.put("execution_results"<span style="color: rgba(0, 0, 0, 1)">, executionResults);
</span><span style="color: rgba(0, 128, 128, 1)"> 88</span> result.put("status", "completed"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 89</span>
<span style="color: rgba(0, 128, 128, 1)"> 90</span> } <span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
</span><span style="color: rgba(0, 128, 128, 1)"> 91</span> System.err.println("❌ 任务执行失败: " +<span style="color: rgba(0, 0, 0, 1)"> e.getMessage());
</span><span style="color: rgba(0, 128, 128, 1)"> 92</span> result.put("status", "failed"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 93</span> result.put("error"<span style="color: rgba(0, 0, 0, 1)">, e.getMessage());
</span><span style="color: rgba(0, 128, 128, 1)"> 94</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)"> 95</span>
<span style="color: rgba(0, 128, 128, 1)"> 96</span> result.put("end_time"<span style="color: rgba(0, 0, 0, 1)">, LocalDateTime.now().toString());
</span><span style="color: rgba(0, 128, 128, 1)"> 97</span> <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result;
</span><span style="color: rgba(0, 128, 128, 1)"> 98</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)"> 99</span>
<span style="color: rgba(0, 128, 128, 1)">100</span> <span style="color: rgba(0, 0, 255, 1)">private</span> List<Map<String, String>><span style="color: rgba(0, 0, 0, 1)"> parsePlan(String planJson) {
</span><span style="color: rgba(0, 128, 128, 1)">101</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 简化的计划解析(实际应用中应该使用完整的JSON解析)</span>
<span style="color: rgba(0, 128, 128, 1)">102</span> List<Map<String, String>> steps = <span style="color: rgba(0, 0, 255, 1)">new</span> ArrayList<><span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)">103</span>
<span style="color: rgba(0, 128, 128, 1)">104</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 使用正则表达式提取步骤信息</span>
<span style="color: rgba(0, 128, 128, 1)">105</span> Pattern stepPattern =<span style="color: rgba(0, 0, 0, 1)"> Pattern.compile(
</span><span style="color: rgba(0, 128, 128, 1)">106</span> "\"step_number\":\\s*(\\d+).*?" +
<span style="color: rgba(0, 128, 128, 1)">107</span> "\"description\":\\s*\"([^\"]+)\".*?" +
<span style="color: rgba(0, 128, 128, 1)">108</span> "\"tool\":\\s*\"([^\"]+)\""<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">109</span> <span style="color: rgba(0, 0, 0, 1)"> Pattern.DOTALL
</span><span style="color: rgba(0, 128, 128, 1)">110</span> <span style="color: rgba(0, 0, 0, 1)"> );
</span><span style="color: rgba(0, 128, 128, 1)">111</span>
<span style="color: rgba(0, 128, 128, 1)">112</span> Matcher matcher =<span style="color: rgba(0, 0, 0, 1)"> stepPattern.matcher(planJson);
</span><span style="color: rgba(0, 128, 128, 1)">113</span> <span style="color: rgba(0, 0, 255, 1)">while</span><span style="color: rgba(0, 0, 0, 1)"> (matcher.find()) {
</span><span style="color: rgba(0, 128, 128, 1)">114</span> Map<String, String> step = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap<><span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)">115</span> step.put("step_number", matcher.group(1<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 128, 1)">116</span> step.put("description", matcher.group(2<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 128, 1)">117</span> step.put("tool", matcher.group(3<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 128, 1)">118</span> <span style="color: rgba(0, 0, 0, 1)"> steps.add(step);
</span><span style="color: rgba(0, 128, 128, 1)">119</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">120</span>
<span style="color: rgba(0, 128, 128, 1)">121</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 如果没有匹配到,创建默认步骤</span>
<span style="color: rgba(0, 128, 128, 1)">122</span> <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (steps.isEmpty()) {
</span><span style="color: rgba(0, 128, 128, 1)">123</span> Map<String, String> defaultStep = <span style="color: rgba(0, 0, 255, 1)">new</span> HashMap<><span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 128, 128, 1)">124</span> defaultStep.put("step_number", "1"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">125</span> defaultStep.put("description", "执行任务: " +<span style="color: rgba(0, 0, 0, 1)"> planJson);
</span><span style="color: rgba(0, 128, 128, 1)">126</span> defaultStep.put("tool", "analyzeText"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">127</span> <span style="color: rgba(0, 0, 0, 1)"> steps.add(defaultStep);
</span><span style="color: rgba(0, 128, 128, 1)">128</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">129</span>
<span style="color: rgba(0, 128, 128, 1)">130</span> <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> steps;
</span><span style="color: rgba(0, 128, 128, 1)">131</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">132</span>
<span style="color: rgba(0, 128, 128, 1)">133</span> <span style="color: rgba(0, 0, 255, 1)">private</span> String buildStepInstruction(Map<String, String><span style="color: rgba(0, 0, 0, 1)"> step) {
</span><span style="color: rgba(0, 128, 128, 1)">134</span> <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> String.format(
</span><span style="color: rgba(0, 128, 128, 1)">135</span> "执行步骤 %s:\n" +
<span style="color: rgba(0, 128, 128, 1)">136</span> "描述: %s\n" +
<span style="color: rgba(0, 128, 128, 1)">137</span> "工具: %s\n" +
<span style="color: rgba(0, 128, 128, 1)">138</span> "请使用指定工具完成此步骤。"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">139</span> step.get("step_number"<span style="color: rgba(0, 0, 0, 1)">),
</span><span style="color: rgba(0, 128, 128, 1)">140</span> step.get("description"<span style="color: rgba(0, 0, 0, 1)">),
</span><span style="color: rgba(0, 128, 128, 1)">141</span> step.get("tool"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">142</span> <span style="color: rgba(0, 0, 0, 1)"> );
</span><span style="color: rgba(0, 128, 128, 1)">143</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">144</span>
<span style="color: rgba(0, 128, 128, 1)">145</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span> updateContext(String task, Map<String, String><span style="color: rgba(0, 0, 0, 1)"> step, String result) {
</span><span style="color: rgba(0, 128, 128, 1)">146</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 将步骤结果存入上下文,供后续步骤使用(可选)</span>
<span style="color: rgba(0, 128, 128, 1)">147</span> String key = MurmurHash.murmur3_32Hash(task) + "_step_" + step.get("step_number") + "_result"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">148</span> <span style="color: rgba(0, 0, 0, 1)"> context.put(key, result);
</span><span style="color: rgba(0, 128, 128, 1)">149</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">150</span>
<span style="color: rgba(0, 128, 128, 1)">151</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> printContext() {
</span><span style="color: rgba(0, 128, 128, 1)">152</span> System.out.println("-".repeat(50) + "\n上下文: "<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">153</span> context.forEach((key, value) -> System.out.println(key + " => \n" + value + "\n" + "-".repeat(30<span style="color: rgba(0, 0, 0, 1)">)));
</span><span style="color: rgba(0, 128, 128, 1)">154</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">155</span> }</pre>
</div>
<span class="cnblogs_code_collapse">Coordinator</span></div>
<p>注:22行,由于在Planner中明确指定了工具列表,所以在协调器中,创建planner实例时,无需刻意绑定Tools.</p>
<p>完整示例:</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_b99e41b4-c310-40e9-bb92-a6420ade4ce9" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_b99e41b4-c310-40e9-bb92-a6420ade4ce9" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_b99e41b4-c310-40e9-bb92-a6420ade4ce9" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">@SpringBootApplication
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> PlanAndExecuteApplication {
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> main(String[] args) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> IOException {
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> ConfigurableApplicationContext context = SpringApplication.run(AgentDesignPatternApplication.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">, args);
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> ChatModel model = context.getBean("ollamaChatModel", ChatModel.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> SampleTools sampleTools = context.getBean("sampleTools", SampleTools.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span> String[] testTasks =<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">10</span> "计算 15 加上 27 等于多少?"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">11</span> "北京现在的天气怎么样?"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">12</span> "计算半径为5的圆的面积"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">13</span> "现在是几点?"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">14</span> "计算长方体的体积,长10,宽5,高3"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">15</span> "帮我算一下 (25 × 4) ÷ 2 等于多少?"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">16</span> "快递单123456,现在到哪了?"<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">17</span> "我的订单56789,退款到账了没?"
<span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(0, 0, 0, 1)"> };
</span><span style="color: rgba(0, 128, 128, 1)">19</span>
<span style="color: rgba(0, 128, 128, 1)">20</span> Coordinator coordinator = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Coordinator(model, sampleTools);
</span><span style="color: rgba(0, 128, 128, 1)">21</span>
<span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i < testTasks.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 128, 1)">23</span> System.out.printf("\n📦 测试用例 %d/%d%n", i + 1<span style="color: rgba(0, 0, 0, 1)">, testTasks.length);
</span><span style="color: rgba(0, 128, 128, 1)">24</span>
<span style="color: rgba(0, 128, 128, 1)">25</span> Map<String, Object> result =<span style="color: rgba(0, 0, 0, 1)"> coordinator.executeTask(testTasks);
</span><span style="color: rgba(0, 128, 128, 1)">26</span>
<span style="color: rgba(0, 128, 128, 1)">27</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 打印总结</span>
<span style="color: rgba(0, 128, 128, 1)">28</span> System.out.println("\n✅ 任务完成总结:"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">29</span> System.out.println("-".repeat(40<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 128, 1)">30</span> System.out.println("任务: " + result.get("task"<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 128, 1)">31</span> System.out.println("状态: " + result.get("status"<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 128, 1)">32</span> System.out.println("耗时: " +<span style="color: rgba(0, 0, 0, 1)"> calculateDuration(
</span><span style="color: rgba(0, 128, 128, 1)">33</span> (String) result.get("start_time"<span style="color: rgba(0, 0, 0, 1)">),
</span><span style="color: rgba(0, 128, 128, 1)">34</span> (String) result.get("end_time"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">35</span> <span style="color: rgba(0, 0, 0, 1)"> ));
</span><span style="color: rgba(0, 128, 128, 1)">36</span>
<span style="color: rgba(0, 128, 128, 1)">37</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (result.containsKey("execution_results"<span style="color: rgba(0, 0, 0, 1)">)) {
</span><span style="color: rgba(0, 128, 128, 1)">38</span> @SuppressWarnings("unchecked"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">39</span> List<Map<String, Object>> executions =
<span style="color: rgba(0, 128, 128, 1)">40</span> (List<Map<String, Object>>) result.get("execution_results"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">41</span> System.out.println("执行步骤数: " +<span style="color: rgba(0, 0, 0, 1)"> executions.size());
</span><span style="color: rgba(0, 128, 128, 1)">42</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">43</span>
<span style="color: rgba(0, 128, 128, 1)">44</span> System.out.println("=".repeat(60<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 128, 1)">45</span>
<span style="color: rgba(0, 128, 128, 1)">46</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 任务间暂停</span>
<span style="color: rgba(0, 128, 128, 1)">47</span> <span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">48</span> Thread.sleep(2000<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">49</span> } <span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (InterruptedException e) {
</span><span style="color: rgba(0, 128, 128, 1)">50</span> <span style="color: rgba(0, 0, 0, 1)"> Thread.currentThread().interrupt();
</span><span style="color: rgba(0, 128, 128, 1)">51</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">52</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">53</span>
<span style="color: rgba(0, 128, 128, 1)">54</span> <span style="color: rgba(0, 0, 0, 1)"> coordinator.printContext();
</span><span style="color: rgba(0, 128, 128, 1)">55</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">56</span>
<span style="color: rgba(0, 128, 128, 1)">57</span>
<span style="color: rgba(0, 128, 128, 1)">58</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> String calculateDuration(String start, String end) {
</span><span style="color: rgba(0, 128, 128, 1)">59</span> <span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">60</span> LocalDateTime startTime =<span style="color: rgba(0, 0, 0, 1)"> LocalDateTime.parse(start);
</span><span style="color: rgba(0, 128, 128, 1)">61</span> LocalDateTime endTime =<span style="color: rgba(0, 0, 0, 1)"> LocalDateTime.parse(end);
</span><span style="color: rgba(0, 128, 128, 1)">62</span> Duration duration =<span style="color: rgba(0, 0, 0, 1)"> Duration.between(startTime, endTime);
</span><span style="color: rgba(0, 128, 128, 1)">63</span> <span style="color: rgba(0, 0, 255, 1)">return</span> String.format("%d秒"<span style="color: rgba(0, 0, 0, 1)">, duration.getSeconds());
</span><span style="color: rgba(0, 128, 128, 1)">64</span> } <span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
</span><span style="color: rgba(0, 128, 128, 1)">65</span> <span style="color: rgba(0, 0, 255, 1)">return</span> "未知"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">66</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">67</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">68</span> }</pre>
</div>
<span class="cnblogs_code_collapse">PlanAndExecuteApplication</span></div>
<p>运行结果:</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_cb598133-214c-4756-8d77-7241b9623606" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_cb598133-214c-4756-8d77-7241b9623606" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_cb598133-214c-4756-8d77-7241b9623606" class="cnblogs_code_hide">
<pre>📦 测试用例 1/8
================================================================================
🎯 任务: 计算 15 加上 27 等于多少?
================================================================================
📋 阶段1: 任务规划
----------------------------------------
生成的计划:
```json
{
"plan_name": "加法计算",
"steps": [
{
"step_number": 1,
"description": "使用add工具计算15加27的结果",
"tool": "add",
"parameters": {"a": 15, "b": 27}
}
],
"expected_output": "42"
}
```
⚡ 阶段2: 执行计划
----------------------------------------
📝 步骤 1/1: 使用add工具计算15加27的结果
[工具调用] 加法: 15.00 + 27.00 = 42.00
执行结果:
步骤 1: add
输入: {"a": 15, "b": 27}
输出: 42.00
状态: 成功
计算完成!15加27的结果是42.00。
请提供下一步指令。
✅ 任务完成总结:
----------------------------------------
任务: 计算 15 加上 27 等于多少?
状态: completed
耗时: 5秒
执行步骤数: 1
============================================================
📦 测试用例 2/8
================================================================================
🎯 任务: 北京现在的天气怎么样?
================================================================================
📋 阶段1: 任务规划
----------------------------------------
生成的计划:
```json
{
"plan_name": "查询北京天气",
"steps": [
{
"step_number": 1,
"description": "使用getWeather工具查询北京当前的天气情况",
"tool": "getWeather",
"parameters": {"city": "北京"}
}
],
"expected_output": "北京当前的天气信息,包括温度、湿度、天气状况等"
}
```
⚡ 阶段2: 执行计划
----------------------------------------
📝 步骤 1/1: 使用getWeather工具查询北京当前的天气情况
[工具调用] 查询天气: 北京
执行结果:
步骤 1: getWeather
输入: {"city": "北京"}
输出: 北京的天气:晴转多云,温度22-28°C,湿度65%,东南风2级
状态: 成功
天气查询完成!北京当前天气为晴转多云,温度22-28°C,湿度65%,东南风2级。
请提供下一步指令。
✅ 任务完成总结:
----------------------------------------
任务: 北京现在的天气怎么样?
状态: completed
耗时: 4秒
执行步骤数: 1
============================================================
📦 测试用例 3/8
================================================================================
🎯 任务: 计算半径为5的圆的面积
================================================================================
📋 阶段1: 任务规划
----------------------------------------
生成的计划:
```json
{
"plan_name": "计算圆的面积",
"steps": [
{
"step_number": 1,
"description": "使用calculateCircleArea工具计算半径为5的圆的面积",
"tool": "calculateCircleArea",
"parameters": {"radius": 5}
}
],
"expected_output": "78.5"
}
```
⚡ 阶段2: 执行计划
----------------------------------------
📝 步骤 1/1: 使用calculateCircleArea工具计算半径为5的圆的面积
[工具调用] 圆面积计算: 半径=5.00, 面积=78.54
执行结果:
步骤 1: calculateCircleArea
输入: {"radius": 5}
输出: 半径为 5.00 的圆的面积是 78.54
状态: 成功
计算完成!半径为5的圆的面积是78.54。
请提供下一步指令。
✅ 任务完成总结:
----------------------------------------
任务: 计算半径为5的圆的面积
状态: completed
耗时: 5秒
执行步骤数: 1
============================================================
📦 测试用例 4/8
================================================================================
🎯 任务: 现在是几点?
================================================================================
📋 阶段1: 任务规划
----------------------------------------
生成的计划:
```json
{
"plan_name": "获取当前时间",
"steps": [
{
"step_number": 1,
"description": "使用getCurrentDateTime工具获取当前时间",
"tool": "getCurrentDateTime",
"parameters": {}
}
],
"expected_output": "当前的时间信息,包括年、月、日、小时、分钟、秒等"
}
```
⚡ 阶段2: 执行计划
----------------------------------------
📝 步骤 1/1: 使用getCurrentDateTime工具获取当前时间
[工具调用] 当前时间: 2026-02-01 13:43:35
执行结果:
步骤 1: getCurrentDateTime
输入: {}
输出: 2026-02-01 13:43:35
状态: 成功
时间获取完成!当前时间是2026-02-01 13:43:35。
请提供下一步指令。
✅ 任务完成总结:
----------------------------------------
任务: 现在是几点?
状态: completed
耗时: 5秒
执行步骤数: 1
============================================================
📦 测试用例 5/8
================================================================================
🎯 任务: 计算长方体的体积,长10,宽5,高3
================================================================================
📋 阶段1: 任务规划
----------------------------------------
生成的计划:
```json
{
"plan_name": "计算长方体体积",
"steps": [
{
"step_number": 1,
"description": "使用calculateCuboidVolume工具计算长方体的体积,长10,宽5,高3",
"tool": "calculateCuboidVolume",
"parameters": {"length": 10, "width": 5, "height": 3}
}
],
"expected_output": "150"
}
```
⚡ 阶段2: 执行计划
----------------------------------------
📝 步骤 1/1: 使用calculateCuboidVolume工具计算长方体的体积,长10,宽5,高3
[工具调用] 长方体体积: 10.00×5.00×3.00=150.00
执行结果:
步骤 1: calculateCuboidVolume
输入: {"length": 10, "width": 5, "height": 3}
输出: 长 10.00、宽 5.00、高 3.00 的长方体体积是 150.00
状态: 成功
计算完成!长10、宽5、高3的长方体体积是150.00。
请提供下一步指令。
✅ 任务完成总结:
----------------------------------------
任务: 计算长方体的体积,长10,宽5,高3
状态: completed
耗时: 5秒
执行步骤数: 1
============================================================
📦 测试用例 6/8
================================================================================
🎯 任务: 帮我算一下 (25 × 4) ÷ 2 等于多少?
================================================================================
📋 阶段1: 任务规划
----------------------------------------
生成的计划:
```json
{
"plan_name": "复合运算计算",
"steps": [
{
"step_number": 1,
"description": "使用multiply工具计算25乘以4的结果",
"tool": "multiply",
"parameters": {"a": 25, "b": 4}
},
{
"step_number": 2,
"description": "使用divide工具将上一步的结果除以2",
"tool": "divide",
"parameters": {"a": 100, "b": 2}
}
],
"expected_output": "50"
}
```
⚡ 阶段2: 执行计划
----------------------------------------
📝 步骤 1/2: 使用multiply工具计算25乘以4的结果
[工具调用] 乘法: 25.00 × 4.00 = 100.00
执行结果:
步骤 1: multiply
输入: {"a": 25, "b": 4}
输出: 25.00 × 4.00 = 100.00
状态: 成功
计算完成!25乘以4的结果是100.00。
请提供下一步指令。
📝 步骤 2/2: 使用divide工具将上一步的结果除以2
[工具调用] 除法: 100.00 ÷ 2.00 = 50.00
执行结果:
步骤 2: divide
输入: {"a": 100, "b": 2}
输出: 100.00 ÷ 2.00 = 50.00
状态: 成功
计算完成!100除以2的结果是50.00。
请提供下一步指令。
✅ 任务完成总结:
----------------------------------------
任务: 帮我算一下 (25 × 4) ÷ 2 等于多少?
状态: completed
耗时: 9秒
执行步骤数: 2
============================================================
📦 测试用例 7/8
================================================================================
🎯 任务: 快递单123456,现在到哪了?
================================================================================
📋 阶段1: 任务规划
----------------------------------------
生成的计划:
```json
{
"plan_name": "查询快递物流状态",
"steps": [
{
"step_number": 1,
"description": "使用queryExpressOrder工具查询快递单号123456的物流状态",
"tool": "queryExpressOrder",
"parameters": {"orderNumber": "123456"}
}
],
"expected_output": "快递单号123456的当前物流状态,包括位置、派送进度等信息"
}
```
⚡ 阶段2: 执行计划
----------------------------------------
📝 步骤 1/1: 使用queryExpressOrder工具查询快递单号123456的物流状态
[工具调用] 快递单: 123456,已经在运输途中,预订明天送达
执行结果:
步骤 1: queryExpressOrder
输入: {"expressOrderNo": "123456"}
输出: 快递单: 123456,已经在运输途中,预订明天送达
状态: 成功
查询完成!快递单号123456的物流状态显示:已经在运输途中,预订明天送达。
请提供下一步指令。
✅ 任务完成总结:
----------------------------------------
任务: 快递单123456,现在到哪了?
状态: completed
耗时: 4秒
执行步骤数: 1
============================================================
📦 测试用例 8/8
================================================================================
🎯 任务: 我的订单56789,退款到账了没?
================================================================================
📋 阶段1: 任务规划
----------------------------------------
生成的计划:
```json
{
"plan_name": "查询退款进度",
"steps": [
{
"step_number": 1,
"description": "使用queryRefundProgress工具查询订单56789的退款进度",
"tool": "queryRefundProgress",
"parameters": {"orderNumber": "56789"}
}
],
"expected_output": "订单56789的退款进度信息,包括退款状态、预计到账时间等"
}
```
⚡ 阶段2: 执行计划
----------------------------------------
📝 步骤 1/1: 使用queryRefundProgress工具查询订单56789的退款进度
[工具调用] 订单: 56789,退款已审批通过,预计1-3个工作日按原路退回
执行结果:
步骤 1: queryRefundProgress
输入: {"orderNo": "56789"}
输出: 订单: 56789,退款已审批通过,预计1-3个工作日按原路退回
状态: 成功
查询完成!订单56789的退款进度显示:退款已审批通过,预计1-3个工作日按原路退回。
请提供下一步指令。
✅ 任务完成总结:
----------------------------------------
任务: 我的订单56789,退款到账了没?
状态: completed
耗时: 4秒
执行步骤数: 1</pre>
</div>
<span class="cnblogs_code_collapse">运行结果</span></div>
<p> 时序图-AI生成</p>
<p><img src="https://img2024.cnblogs.com/blog/27612/202601/27612-20260131224928024-246667291.png" alt="plan_and_execute_simple" width="480" loading="lazy" style="border: 1px solid rgba(0, 0, 0, 1)"></p>
<p>文中示例代码:</p>
<p>https://github.com/yjmyzz/agentic_turoial_with_langchain4j<br></p>
<p> </p>
<p>参考:</p>
<p>Building Effective AI Agents \ Anthropic</p>
<p>[译] AI Workflow & AI Agent:架构、模式与工程建议(Anthropic,2024)</p>
<p>Agents and Agentic AI | LangChain4j</p>
</div>
<div id="MySignature" role="contentinfo">
<div style="padding:5px;background:#ff9;border:solid 1px #ccc">作者:菩提树下的杨过<br />
出处:http://yjmyzz.cnblogs.com
<br/>
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
</div><br><br>
来源:https://www.cnblogs.com/yjmyzz/p/19559350/agentic-patterns-using-langchain4j-11-plan-and-execute
頁:
[1]