Spring AI 实战:第十一章、Spring AI Agent之知行合一

引言:智能体的知行辩证法

"知为行之始,行为知之成",王阳明的哲学智慧在AI时代焕发光彩。智能体(LLM Agent)的进化之路,正是"认知-决策-执行"这一闭环的完美诠释:

  • 知·明理:融合大语言模型的推理能力与知识图谱的结构化认知
  • 行·致用:基于ReAct模式的动态工具调度与精准执行
  • 合·臻境: 通过反思机制实现认知与行动的螺旋式进化

一、Agent概述

1.1 基本概念

LLM Agent是以大语言模型(Large Language Model, LLM)为核心,结合感知、规划、工具调用和记忆等模块构建的自主智能系统。它能够理解复杂指令、动态决策并执行多步骤任务,模拟人类的问题解决能力,同时通过与环境互动持续优化行为。

  • 复旦大学NLP Group在文章https://arxiv.org/abs/2309.07864将Agent定义为能够感知环境、决策并执行动作的智能体,包含Brain(大脑)、Perception(感知)、Action(行动)三大模块,工作流程:感知环境→大脑处理→执行动作→反馈循环
复制代码
- Brain(大脑):以LLM为核心,负责记忆、知识存储、推理和规划。
复制代码
- Perception(感知):扩展多模态输入(文本、视觉、听觉等),增强环境感知能力。
复制代码
- Action(行动):通过工具使用、具身动作(如机器人控制)与环境交互。

"智能体"的定义多种多样,但始终围绕LLM为核心构建自主智能系统,期望Agent具备人类水平通用智能的AI,能像人一样自主适应任何新环境、学习未知领域并创造性解决问题,是向AGI(通用人工智能)演进的关键路径之一。

1.2 构建智能体

请问如何构建高效的Agent智能体?

Anthropic在https://www.anthropic.com/engineering/building-effective-agents 中给出实践指导,本篇将以该文章为核心做展开;

一部分人将Agent视为完全自主的系统,能长期独立运行并使用多种工具完成复杂任务;另一些人则用该术语描述遵循预定义流程的规范性实现(也有混合...),这些变体统称为智能体系统,但在架构上区分为两类,人工流程编排类(Workflow)、自主规划类(Autonomous Agent)

  • 人工流程编排类(Workflow Agent):通过预定义代码路径协调LLM和工具的系统。
  • 自主规划类(Agent):LLM动态指导自身流程和工具使用、自主控制任务执行方式的系统。
对比维度 人工流程编排类(Workflow Agent) 自主规划类(Autonomous** **Agent)
核心定义 通过预定义代码路径协调LLM和工具的系统 LLM动态指导自身流程和工具使用、自主控制任务执行方式的系统
决策方式 遵循硬编码的流程逻辑,由开发者预先设计步骤 由LLM实时生成决策路径,根据环境反馈动态调整
灵活性 低:适用于结构清晰、可预测的任务 高:能处理开放性问题,适应不可预测的复杂场景
复杂度 相对简单,通常为线性或分支流程 较高,需处理多轮迭代和动态工具调用
典型应用场景 • 营销文案生成+翻译 • 客服问题分类路由 • 并行化代码审查 • GitHub issue自动修复(SWE-bench) • 计算机操作代理 • 需要多轮探索的搜索任务
性能代价 延迟低,成本可控 延迟较高(需多轮LLM调用),成本相对更高
调试难度 较易:流程透明且可预测 较难:需跟踪动态生成的决策路径
工具使用方式 工具调用由代码显式触发 工具由LLM自主选择调用
人类介入需求 主要在开发阶段设计流程 可能需要运行时监督(如设置检查点/停止条件)
成功关键 • 清晰的步骤分解 • 准确的分类逻辑 • 有效的并行化策略 • 完善的工具文档 • 可靠的错误恢复机制 • 精准的评估反馈循环
Anthropic建议 优先选择方案,除非简单提示无法满足需求 仅在需要自主决策时使用,需充分测试和沙盒保护

不论是人工流程编排类(Workflow)、自主规划类(Agent)的智能体都是基于通过检索、工具和记忆增强能力的LLM(The augmented LLM)构建的体系

二、人工流程编排类(Workflow Agent)

2.1 提示链(Prompt chaining)

将任务分解为顺序步骤,每个LLM调用处理前一步的输出。适用于任务可以清晰分解的场景(如生成营销文案后翻译)

示例:使用提示链将公司业务数据格式化输出

  • 流程:原始数据 -> 从文本中仅提取数值及其关联指标 -> 将所有数值尽可能转换为百分比形式 -> 按数值降序排列所有行 ->将排序后的数据格式化为Markdown表格 -> 最终结果

ChainWorkflow

  • 通过数组保存串行化待执行的提示词,for循环链式执行
java 复制代码
package com.lkl.ai.agent.patterns;

import org.springframework.ai.chat.client.ChatClient;

public class ChainWorkflow {


    private static final String[] DEFAULT_SYSTEM_PROMPTS = {

            // 步骤1
            """
            从文本中仅提取数值及其关联指标。
            每条数据格式为"数值: 指标",各占一行。
            示例格式:
            92: 客户满意度
            45%: 收入增长率""",

            // 步骤2
            """
            将所有数值尽可能转换为百分比形式。
            若非百分比或点数,则转换为小数(如92点 -> 92%)。
            保持每行一个数值。
            示例格式:
            92%: 客户满意度
            45%: 收入增长率""",

            // 步骤3
            """
            按数值降序排列所有行。
            保持每行"数值: 指标"的格式。
            示例:
            92%: 客户满意度
            87%: 员工满意度""",

            // 步骤4
            """
            将排序后的数据格式化为Markdown表格,包含列:
            | 指标 | 数值 |
            |:--|--:|
            | 客户满意度 | 92% | """};
    private final ChatClient chatClient;

    private final String[] systemPrompts;


    public ChainWorkflow(ChatClient chatClient) {
        this(chatClient, DEFAULT_SYSTEM_PROMPTS);
    }


    public ChainWorkflow(ChatClient chatClient, String[] systemPrompts) {
        this.chatClient = chatClient;
        this.systemPrompts = systemPrompts;
    }

    public String chain(String userInput) {

        int step = 0;
        String response = userInput;
        System.out.println(String.format("\nSTEP %s:\n %s", step++, response));

        for (String prompt : systemPrompts) {

            // 1. Compose the input using the response from the previous step.
            String input = String.format("{%s}\n {%s}", prompt, response);

            // 2. Call the chat client with the new input and get the new response.
            response = chatClient.prompt(input).call().content();

            System.out.println(String.format("\nSTEP %s:\n %s", step++, response));
        }

        return response;
    }
}

调用提示链

java 复制代码
 @GetMapping("/chain")
    public String chain() {

         String report = """
                 Q3 业绩摘要:
                 本季度客户满意度得分提升至 92 分。
                 与去年同期相比,收入增长 45%。
                 我们在主要市场的份额现已达到 23%。
                 客户流失率从 8% 降至 5%。
                 新用户获客成本为 43 元/用户。
                 产品采用率提升至 78%。
                 员工满意度得分为 87 分。
                 营业利润率提升至 34%。
                  """;

         return new ChainWorkflow(chatClient).chain(report);
    }

执行结果

以下是格式化后的Markdown表格:

| 指标 | 数值 |

|:-------------------|------😐

| 客户满意度 | 92% |

| 员工满意度 | 87% |

| 产品采用率 | 78% |

| 收入增长率 | 45% |

| 新用户获客成本 | 43% |

| 营业利润率 | 34% |

| 主要市场份额 | 23% |

| 客户流失率 | 5% |

2.2 路由(Routing)

根据输入分类并路由到专门的后续任务。适用于需要分离关注点的场景(如客户服务查询分类)

示例:定义多个用户答疑专家,基于用户不同的问题路由到对应的团队进行答疑解惑

RoutingWorkflow

  • 通过determineRoute做路由决策,找到合适的答疑提示词后发起LLM调用并响应用户
java 复制代码
package com.lkl.ai.agent.patterns;

import java.util.Map;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.util.Assert;

public class RoutingWorkflow {

    private final ChatClient chatClient;

    public RoutingWorkflow(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    public String route(String input, Map<String, String> routes) {
        Assert.notNull(input, "Input text cannot be null");
        Assert.notEmpty(routes, "Routes map cannot be null or empty");

        String routeKey = determineRoute(input, routes.keySet());

        String selectedPrompt = routes.get(routeKey);

        if (selectedPrompt == null) {
            throw new IllegalArgumentException("Selected route '" + routeKey + "' not found in routes map");
        }

        return chatClient.prompt(selectedPrompt + "\nInput: " + input).call().content();
    }

    private String determineRoute(String input, Iterable<String> availableRoutes) {
        System.out.println("\n可用的路由: " + availableRoutes);

        String selectorPrompt = String.format("""
                分析输入内容并从以下选项中选择最合适的支持团队:%s
                         首先解释你的判断依据,然后按照以下JSON格式提供选择:
                
                         \\{
                             "reasoning": "简要说明为何该工单应分配给特定团队。
                                         需考虑关键词、用户意图和紧急程度。",
                             "selection": "所选团队名称"
                         \\}
                
                         输入:%s""", availableRoutes, input);

        RoutingResponse routingResponse = chatClient.prompt(selectorPrompt).call().entity(RoutingResponse.class);

        System.out.println(String.format("路由分析:%s\n选择结果: %s",
                routingResponse.reasoning(), routingResponse.selection()));

        return routingResponse.selection();
    }
}

定义可路由提示词并触发路由

java 复制代码
  @GetMapping("/routing")
    public void routing() {

        Map<String, String> supportRoutes = Map.of("billing",
                """
                        您是一位账单支持专家。请遵循以下准则:
                        1. 始终以"账单支持回复:"开头
                        2. 首先确认具体的账单问题
                        3. 清晰地解释任何费用或差异
                        4. 列出具体的后续步骤及时间安排
                        5. 如适用,最后提供支付选项
                        
                        保持回复专业且友好。
                        
                        输入: """,

                "technical",
                """
                        您是一位技术支持工程师。请遵循以下准则:
                        1. 始终以"技术支持回复:"开头
                        2. 列出解决问题的具体步骤
                        3. 如适用,包含系统要求
                        4. 提供常见问题的临时解决方案
                        5. 如需升级处理,说明升级路径
                        
                        使用清晰的编号步骤和技术细节。
                        
                        输入: """,

                "account",
                """
                        您是一位账户安全专家。请遵循以下准则:
                        1. 始终以"账户支持回复:"开头
                        2. 优先处理账户安全和验证
                        3. 提供账户恢复/变更的明确步骤
                        4. 包含安全提示和警告
                        5. 设定明确的解决时间预期
                        
                        保持严肃、以安全为核心的语气。
                        
                        输入: """,

                "product",
                """
                        您是一位产品专家。请遵循以下准则:
                        1. 始终以"产品支持回复:"开头
                        2. 专注于功能教育和最佳实践
                        3. 包含具体的使用示例
                        4. 链接到相关文档章节
                        5. 建议可能有帮助的相关功能
                        
                        保持教育性和鼓励性的语气。
                        
                        输入: """);
        List<String> tickets = List.of(
                """
                        标题:无法登录我的账户
                        内容:您好,过去一小时我一直在尝试登录,但总是收到"密码错误"提示。
                        我确定输入的是正确密码。能否帮我恢复访问权限?这很紧急,因为我需要
                        在今天下班前提交一份报告。
                        - 张三""",


                """
                        标题:如何导出数据?
                        内容:我需要将所有项目数据导出到Excel。我查阅了文档但找不到批量导出的方法。
                        这个功能可以实现吗?如果可以,能否一步步指导我操作?
                        此致,
                        李四""");

        var routerWorkflow = new RoutingWorkflow(chatClient);

        int i = 1;
        for (String ticket : tickets) {
            System.out.println("\n工单 " + i++);
            System.out.println("------------------------------------------------------------");
            System.out.println(ticket);
            System.out.println("------------------------------------------------------------");
            System.out.println(routerWorkflow.route(ticket, supportRoutes));
        }
    }

执行结果(以工单一示例)

路由分析:用户报告无法登录账户,尽管确认密码正确,这表明问题可能与账户访问或技术故障有关。由于用户强调紧急程度,需要快速恢复访问权限,因此应分配给账户支持团队处理。

选择结果: account

账户支持回复:

感谢您联系账户安全团队。我们理解您遇到登录问题的紧迫性,将优先处理您的请求。以下是分步解决方案:

账户恢复流程:

  1. 立即访问我们的官方密码重置页面:[安全链接已隐藏,请通过官网访问]

  2. 选择"忘记密码"选项

  3. 输入与账户关联的注册邮箱(***@example.com)

  4. 您将在15分钟内收到包含6位数验证码的安全邮件

  5. 完成双重验证后即可设置新密码

安全警告:

⚠️ 切勿在第三方网站输入账户凭证

⚠️ 若收到未申请的验证码,请立即联系客服

⚠️ 新密码应包含大小写字母、数字和特殊符号

时间预期:

  • 密码重置:即时生效(完成流程后)

  • 账户完全恢复:最长2小时(需安全审核)

紧急建议:

  1. 检查账户活动记录(登录历史)是否有异常

  2. 如发现可疑活动,请立即拨打24小时安全热线:[官方号码]

  3. 建议在所有设备上注销当前会话

请注意:系统显示您的账户在过去1小时有3次失败登录尝试。为安全起见,我们已临时启用账户保护。完成上述步骤后,保护将自动解除。

是否需要进一步协助验证账户所有权?您可以通过注册时绑定的手机号接收语音验证码作为替代方案。

2.3 并行化(Parallelization)

在并行化(Parallelization)的工作流程中,大型语言模型(LLMs)可以同时处理同一任务,并通过程序化的方式聚合它们的输出。这种并行化通常表现为两种主要形式:分段(Sectioning):将任务拆分为独立子任务并行执行;投票(Voting):多次运行同一任务聚合多样化输出。

示例: 分析市场变化将如何影响客户、员工、投资者、供应商等利益相关方群体,由于各方评估可独立执行,可以并行化处理

ParallelizationWorkflow

  • 通过线程池并行执行,最后合并返回
java 复制代码
package com.lkl.ai.agent.patterns;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.util.Assert;

public class ParallelizationWorkflow {

	private final ChatClient chatClient;

	public ParallelizationWorkflow(ChatClient chatClient) {
		this.chatClient = chatClient;
	}


	public List<String> parallel(String prompt, List<String> inputs, int nWorkers) {
		Assert.notNull(prompt, "Prompt cannot be null");
		Assert.notEmpty(inputs, "Inputs list cannot be empty");
		Assert.isTrue(nWorkers > 0, "Number of workers must be greater than 0");

		ExecutorService executor = Executors.newFixedThreadPool(nWorkers);
		try {
			List<CompletableFuture<String>> futures = inputs.stream()
					.map(input -> CompletableFuture.supplyAsync(() -> {
						try {
							return chatClient.prompt(prompt + "\nInput: " + input).call().content();
						} catch (Exception e) {
							throw new RuntimeException("Failed to process input: " + input, e);
						}
					}, executor))
					.collect(Collectors.toList());

			// Wait for all tasks to complete
			CompletableFuture<Void> allFutures = CompletableFuture.allOf(
					futures.toArray(CompletableFuture[]::new));
			allFutures.join();

			return futures.stream()
					.map(CompletableFuture::join)
					.collect(Collectors.toList());

		} finally {
			executor.shutdown();
		}
	}

}

定义待评估的各方后并行执行

java 复制代码
@GetMapping("/parallelization")
    public void parallelization() {

        List<String> parallelResponse = new ParallelizationWorkflow(chatClient)
                .parallel("""
                                分析市场变化将如何影响该利益相关方群体。
                                提供具体影响和推荐行动方案。
                                使用清晰的分区和优先级进行格式化。
                                """,
                        List.of(
                                """
                                        客户:
                                        - 对价格敏感
                                        - 期望更好的技术
                                        - 关注环境问题
                                        """,

                                """
                                        员工:
                                        - 担忧工作稳定性
                                        - 需要新技能
                                        - 希望明确方向
                                        """,

                                """
                                        投资者:
                                        - 期望增长
                                        - 要求成本控制
                                        - 关注风险
                                        """,

                                """
                                        供应商:
                                        - 产能限制
                                        - 价格压力
                                        - 技术转型
                                        """),
                        4);

        System.out.println(parallelResponse);
    }

执行结果

市场变化对客户的影响分析及行动方案

1. 价格敏感度上升

影响:

  • 若市场竞争加剧或经济下行,客户可能更倾向于选择低价替代品,导致品牌忠诚度下降。

  • 若原材料成本上涨,企业可能被迫提价,导致客户流失。

推荐行动:

优化成本结构:通过供应链优化或规模化生产降低单位成本,避免涨价。

提供灵活定价:推出阶梯定价、订阅模式或捆绑销售,满足不同预算需求。

强化价值主张:突出产品性价比(如耐用性、长期节省成本),而非单纯低价竞争。


2. 技术升级需求增强

影响:

  • 若竞品推出创新技术,客户可能转向更先进的解决方案。

  • 技术迭代加速可能导致现有产品快速过时,影响客户满意度。

推荐行动:

加速研发投入:定期推出功能升级或新版本,保持技术领先性。

客户参与创新:通过反馈渠道(如用户社区、Beta测试)让客户参与产品改进。

透明化技术路线图:向客户展示未来技术规划,增强长期信任。


3. 环境关注度提高

影响:

  • 环保法规趋严可能增加企业合规成本,间接影响产品定价。

  • 客户可能优先选择低碳、可回收或符合ESG标准的产品。

推荐行动:

绿色产品线开发:推出环保认证产品(如节能、可降解材料),并明确宣传其优势。

碳足迹透明化:提供产品生命周期环境影响数据,增强可信度。

倡导可持续消费:推出以旧换新、回收计划,降低客户环保行为门槛。


优先级排序

  1. 短期(0-6个月):优化定价策略 + 强化环保卖点(快速响应市场敏感点)。

  2. 中期(6-12个月):技术迭代 + 成本控制(巩固竞争力)。

  3. 长期(1年以上):客户共创研发 + 深度可持续转型(建立壁垒)。

通过分阶段行动,既能应对即时挑战,又能构建长期客户粘性。, ### 市场变化对员工群体的影响及行动方案

1. 主要影响分析

(按优先级排序)

| 影响 | 具体表现 |

|------------------------|----------------------------------------------------------------------------|

| 工作稳定性下降 | 行业变革可能导致岗位调整、裁员或自动化替代,增加员工的不确定性。 |

| 技能需求变化 | 新技术(如AI、数字化工具)的普及要求员工掌握新技能,否则可能面临竞争力下降。 |

| 职业发展方向模糊 | 市场快速变化使传统职业路径不再明确,员工可能缺乏清晰的晋升或转型方向。 |


2. 推荐行动方案

(按紧急性和可行性排序)

高优先级:短期应对(0-6个月)
  • 提供技能培训计划

    • 公司内部:组织数字化工具、AI基础等必修培训,确保员工适应技术变革。

    • 外部资源:补贴员工参与行业认证课程(如数据分析、项目管理)。

  • 透明化沟通

    • 定期召开全员会议,说明市场趋势和公司战略,减少猜测和焦虑。

    • 设立匿名反馈渠道,收集员工对岗位调整的担忧并针对性回应。

中优先级:中期规划(6-12个月)
  • 职业路径重塑

    • 与HR合作设计"未来技能地图",明确不同岗位的升级路径(如传统销售→数字化营销)。

    • 推出内部轮岗计划,帮助员工探索新领域(如从运营转向数据分析)。

  • 绩效与激励调整

    • 将"学习新技能"纳入KPI考核,奖励主动提升能力的员工。

    • 提供学费报销或时间弹性,支持员工在职深造。

长期策略(1年以上)
  • 建立弹性工作文化

    • 推广混合办公模式,减少因地域或岗位变动导致的离职风险。

    • 试点"技能共享池",允许员工跨部门参与项目,增强适应性。

  • 行业合作与前瞻性准备

    • 与高校或行业协会合作,提前获取未来技能需求预测,调整培训内容。

3. 关键注意事项
  • 差异化支持:针对不同岗位(如技术岗 vs. 行政岗)制定针对性方案。

  • 心理支持:提供职业咨询或压力管理课程,帮助员工应对变革焦虑。

通过以上措施,员工群体可更主动应对市场变化,将挑战转化为职业发展机遇。, ### 市场变化对投资者的影响及行动方案

1. 市场增长放缓或停滞

影响:

  • 投资回报率(ROI)下降,影响投资者对增长目标的信心。

  • 可能引发撤资或减少追加投资,导致企业资金链紧张。

推荐行动:

优化投资组合:分散投资至抗周期性行业(如必需消费品、医疗保健)。

聚焦高增长领域:加大对AI、新能源等新兴行业的布局,以弥补传统行业增长乏力。

强化成本管理:推动被投企业优化运营效率,确保现金流健康。


2. 成本上升(如原材料、劳动力、融资成本)

影响:

  • 企业利润率受挤压,影响投资者收益。

  • 可能迫使企业削减研发或市场拓展投入,损害长期增长潜力。

推荐行动:

推动供应链优化:协助被投企业寻找替代供应商或采用自动化技术降本。

调整融资策略:锁定长期低息贷款,或探索股权融资替代高成本债务。

加强ESG投资:关注节能减碳技术,降低长期能源和合规成本。


3. 风险加剧(如政策变动、地缘冲突、市场波动)

影响:

  • 不确定性增加,投资者可能转向保守策略(如持有现金或黄金)。

  • 资产估值波动加大,影响退出时机和回报。

推荐行动:

动态风险评估:建立实时监测机制,定期调整投资策略。

对冲策略:利用衍生品(如期权、期货)对冲汇率或大宗商品风险。

优先稳健资产:增加对防御性资产(基建、公用事业)的配置比例。


优先级排序(P0→P2)

| 优先级 | 关键挑战 | 核心行动 |

|------------|-----------------------|---------------------------------------|

| P0 | 增长放缓 | 布局高增长行业,优化现有投资组合 |

| P1 | 成本上升 | 推动供应链优化,调整融资结构 |

| P2 | 风险波动 | 建立对冲机制,增加防御性资产配置 |


总结:投资者需在增长、成本、风险间动态平衡,短期优先保障现金流,中长期侧重结构性调整(如行业转型、技术降本),同时利用金融工具对冲不确定性。, ### 供应商市场变化影响分析及行动方案

1. 产能限制

影响:

  • 市场需求激增或供应链中断可能导致供应商无法满足订单,引发合同违约风险。

  • 产能不足可能迫使供应商优先服务大客户,导致中小客户流失。

  • 长期产能瓶颈可能削弱供应商的市场竞争力。

推荐行动方案(优先级排序):

  1. 短期应对:

    • 与关键客户协商分阶段交付计划,缓解即时压力。

    • 外包部分非核心生产环节,快速补充产能缺口。

  2. 中期策略:

    • 投资柔性生产线或自动化技术,提升产能弹性。

    • 建立产能储备协议(如与代工厂合作)。

  3. 长期规划:

    • 扩建生产基地或分散区域布局,降低集中风险。

2. 价格压力

影响:

  • 原材料成本上涨或客户压价可能压缩利润空间,影响研发投入。

  • 低价竞争可能导致供应商牺牲质量,损害品牌声誉。

  • 长期价格战可能引发行业整合,中小供应商被淘汰。

推荐行动方案(优先级排序):

  1. 成本优化:

    • 通过集中采购或长期合约锁定低价原材料。

    • 优化生产流程(如精益管理)降低边际成本。

  2. 价值差异化:

    • 提供增值服务(如定制化、技术支持)以提升议价权。

    • 转向高利润细分市场(如高端定制产品)。

  3. 合作模式创新:

    • 与客户共享成本数据,协商价格联动机制(如指数化定价)。

3. 技术转型

影响:

  • 行业技术升级(如数字化、绿色制造)可能淘汰传统供应商。

  • 技术投入不足可能导致客户转向更先进的竞争对手。

  • 转型失败可能造成资源浪费或战略偏移。

推荐行动方案(优先级排序):

  1. 技术评估与试点:

    • 优先投资客户需求明确的技术(如IoT设备监控、低碳工艺)。

    • 与行业联盟或高校合作,降低独立研发风险。

  2. 分阶段转型:

    • 对旧设备进行智能化改造(如加装传感器),而非全盘替换。

    • 培训员工掌握混合技术能力(传统+新型技术)。

  3. 生态合作:

    • 加入技术平台(如工业互联网生态),共享行业解决方案。

整体优先级建议

  1. 立即行动: 解决产能瓶颈和价格压力,避免短期业务流失。

  2. 6-12个月重点: 启动技术试点和成本优化项目。

  3. 长期战略: 通过产能布局和技术转型构建可持续优势。

风险提示: 需平衡短期利润与长期投入,避免现金流断裂。建议设立专项转型基金。

2.4 协调者-工作者(Orchestrator-Workers)

中央协调者LLM动态分解任务,分配至工作者LLM并整合结果。适用在任务复杂度高且子任务不可预测,与并行化的关键区别是子任务非预先定义,而是由协调者根据输入动态决定(如:需跨文件协作的代码生成工具)

示例: 为一个新的环保水瓶写一篇产品描述

OrchestratorWorkers

  • 分析任务要求做分解为不同的处理风格,基于不同风格做差异化处理
java 复制代码
package com.lkl.ai.agent.patterns;

import java.util.List;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.util.Assert;

public class OrchestratorWorkers {

    private final ChatClient chatClient;
    private final String orchestratorPrompt;
    private final String workerPrompt;

    public static final String DEFAULT_ORCHESTRATOR_PROMPT = """
         
            分析此任务并分解为2-3种不同的处理方式:
                   
                    任务:{task}
                   
                    请按以下JSON格式返回响应:
                    \\{
                    "analysis": "说明你对任务的理解以及哪些变化会很有价值。
                                重点关注每种方法如何服务于任务的不同方面。",
                    "tasks": [
                    	\\{
                    	"type": "formal",
                    	"description": "撰写精确的技术版本,强调规格参数"
                    	\\},
                    	\\{
                    	"type": "conversational",
                    	"description": "撰写引人入胜的友好版本,与读者建立联系"
                    	\\}
                    ]
                    \\}
            """;

    public static final String DEFAULT_WORKER_PROMPT = """
             根据以下要求生成内容:
                 任务:{original_task}
                 风格:{task_type}
                 指南:{task_description}
            """;


    public static record Task(String type, String description) {
    }


    public static record OrchestratorResponse(String analysis, List<Task> tasks) {
    }


    public static record FinalResponse(String analysis, List<String> workerResponses) {
    }

    public OrchestratorWorkers(ChatClient chatClient) {
        this(chatClient, DEFAULT_ORCHESTRATOR_PROMPT, DEFAULT_WORKER_PROMPT);
    }


    public OrchestratorWorkers(ChatClient chatClient, String orchestratorPrompt, String workerPrompt) {
        Assert.notNull(chatClient, "ChatClient must not be null");
        Assert.hasText(orchestratorPrompt, "Orchestrator prompt must not be empty");
        Assert.hasText(workerPrompt, "Worker prompt must not be empty");

        this.chatClient = chatClient;
        this.orchestratorPrompt = orchestratorPrompt;
        this.workerPrompt = workerPrompt;
    }

    public FinalResponse process(String taskDescription) {
        Assert.hasText(taskDescription, "Task description must not be empty");

        // Step 1: Get orchestrator response
        OrchestratorResponse orchestratorResponse = this.chatClient.prompt()
                .user(u -> u.text(this.orchestratorPrompt)
                        .param("task", taskDescription))
                .call()
                .entity(OrchestratorResponse.class);

        System.out.println(String.format("\n=== ORCHESTRATOR OUTPUT ===\nANALYSIS: %s\n\nTASKS: %s\n",
                orchestratorResponse.analysis(), orchestratorResponse.tasks()));

        // Step 2: Process each task
        List<String> workerResponses = orchestratorResponse.tasks().stream().map(task -> this.chatClient.prompt()
                .user(u -> u.text(this.workerPrompt)
                        .param("original_task", taskDescription)
                        .param("task_type", task.type())
                        .param("task_description", task.description()))
                .call()
                .content()).toList();

        System.out.println("\n=== WORKER OUTPUT ===\n" + workerResponses);

        return new FinalResponse(orchestratorResponse.analysis(), workerResponses);
    }

}

下发任务

java 复制代码
   @GetMapping("/orchestrator")
    public void orchestrator() {

        new OrchestratorWorkers(chatClient)
                .process("为一个新的环保水瓶写一篇产品描述");
    }

执行结果

=== ORCHESTRATOR OUTPUT ===

ANALYSIS: 理解任务是为环保水瓶撰写产品描述,需要突出其环保特性和产品优势。不同方法可以针对不同受众,技术版本适合专业买家,而友好版本适合普通消费者。

TASKS: [Task[type=formal, description=撰写精确的技术版本,强调规格参数如材料、容量、环保认证等], Task[type=conversational, description=撰写引人入胜的友好版本,使用日常语言,强调环保理念和用户体验], Task[type=marketing, description=撰写营销导向版本,突出产品独特卖点和竞争优势,激发购买欲望]]

=== WORKER OUTPUT ===

强调规格参数

**Product Description: EcoViva Sustainable Water Bottle** **Overview** The **EcoViva Sustainable Water Bottle** is a premium, eco-conscious hydration solution designed to meet the demands of environmentally aware consumers. Engineered with high-performance materials and certified sustainable practices, this bottle combines durability, functionality, and environmental responsibility. *** ** * ** *** #### **Technical Specifications** 1. **Material Composition** * **Body \& Cap:** Made from **100% certified food-grade stainless steel (18/8 grade)**, ensuring durability, corrosion resistance, and BPA-free safety. * **Lid Liner:** Constructed with **silicone (FDA-approved)**, providing an airtight seal while remaining free from harmful chemicals. * **Exterior Coating:** Features a **non-toxic, water-based paint** for scratch resistance and minimal environmental impact. 2. **Capacity Options** * **Standard Sizes:** 500 mL (17 oz) \| 750 mL (25 oz) \| 1 L (34 oz) * **Custom capacities** available for bulk orders. 3. **Insulation Performance** * **Double-wall vacuum insulation** maintains temperatures for up to: * **24 hours (cold beverages)** * **12 hours (hot beverages)** 4. **Environmental Certifications** * **Cradle to Cradle Certified™ (Silver)** for sustainable material health and recyclability. * **Carbon Neutral Certified** by \[Third-Party Auditor\], offsetting 100% of production emissions. * **Ocean Plastic Initiative:** 10% of materials sourced from upcycled marine plastic waste. 5. **Additional Features** * **Leak-proof design** with a threaded, twist-lock lid. * **Wide mouth opening** for easy filling and cleaning (compatible with ice cubes). * **Modular accessories** (e.g., bamboo carry straps, replaceable lids) to extend product lifespan. 6. **Compliance \& Safety** * Meets **EU 10/2011 (food contact materials)** and **FDA 21 CFR** standards. * **Dishwasher-safe** (top rack recommended). *** ** * ** *** #### **Sustainability Commitments** * **Closed-Loop Recycling Program:** Return end-of-life bottles for recycling to receive a discount on future purchases. * **Plant-Based Packaging:** 100% biodegradable cardboard with soy-based ink printing. *** ** * ** *** **Target Audience:** * Eco-conscious professionals, outdoor enthusiasts, and corporate sustainability programs seeking a durable, high-performance alternative to single-use plastics. **Availability:** * Launching Q1 2024. Pre-orders available via \[Company Website\]. *** ** * ** *** *EcoViva: Hydrate Responsibly.* *** ** * ** *** *Note: Specifications subject to minor revisions for continuous improvement. Contact \[[email protected]\] for technical documentation.* *** ** * ** *** This version balances technical precision with formal clarity, ensuring compliance-focused buyers and eco-aware consumers receive actionable details. Let me know if you'd like adjustments (e.g., deeper dive into material science or certifications). **强调环保理念和用户体验** **🌍 遇见你的新伙伴:EcoSip环保水瓶,喝水也能拯救地球!** 嘿,朋友!是不是厌倦了每天买塑料瓶装水,既浪费钱又伤害我们可爱的地球?来认识一下**EcoSip**------你的随身环保小英雄,让喝水变得时髦又安心! **✨ 为什么你会爱上它?** * **地球谢谢你!** 用1个EcoSip = 少用365个塑料瓶,告别"罪恶感干杯",咱们一起对污染说拜拜👋。 * **24小时保冷保热**:早晨的冰咖啡?下午的热茶?它都能hold住!双层不锈钢设计,冷热随心,口感不妥协。 * **轻到忘记它的存在**:比手机还轻,塞包里无压力,爬山、通勤、遛狗......走哪带哪,绝不喊累。 * **一键开盖,单手搞定**:跑步时、挤地铁时?拇指一按秒开喝,漏水?不存在的!(贴心防漏设计认证✅) **🎨 颜值即正义** 5种治愈系配色可选:薄荷绿、雾霾蓝、珊瑚粉......总有一款配得上你的气质(和你的包包)。 **🤔 还在犹豫?** 想想看:每天带着它,你不仅是喝水,还是在为海洋小海龟、北极熊投票!而且......省下的买水钱,够你每月多喝两杯奶茶啦🧋(环保人士也值得甜蜜奖励!)。 **👉 现在入手,还送限量版贴纸+清洁刷!** 因为我们认为,保护地球不该是件严肃的事------从每天的小习惯开始,轻松又酷炫! **加入EcoSip家族,一起把"环保"变成日常的高光时刻吧!** 💚 (P.S. 偷偷告诉你:瓶底藏了句小彩蛋,装水时会有惊喜哦~), # **EcoViva™ 环保水瓶------为地球喝彩,为健康护航** ### **纯净饮水,绿色未来** 厌倦了一次性塑料瓶的浪费?**EcoViva™ 环保水瓶** 为您带来革命性的饮水体验!采用**100%食品级不锈钢+可回收材质**,不仅坚固耐用,更能减少塑料污染,让每一次饮水都成为对地球的温柔守护。 **突出产品独特卖点和竞争优势,激发购买欲望** ### **为什么选择EcoViva™?** ✅ **超强保温保冷** -- 采用**双层真空隔热技术**,24小时保温保冷,冰爽冷饮或温暖热饮,随时享受最佳口感。 ✅ **100%无塑无毒** -- 不含BPA、铅等有害物质,确保每一口都纯净安全,母婴级材质,全家放心使用。 ✅ **超轻便携设计** -- 仅重280g,搭配防滑硅胶底座和便携挂环,户外、办公、旅行,轻松随身携带。 ✅ **智能防漏技术** -- 专利一键开盖设计,滴水不漏,告别传统水瓶的渗漏烦恼。 ✅ **时尚环保美学** -- 北欧极简风设计,多种潮流配色可选,喝水也能成为时尚宣言! ### **为环保加分,为生活减负** 每购买一个EcoViva™水瓶,我们承诺**捐赠1%收益用于全球海洋清洁计划**。选择EcoViva™,不仅是为自己挑选一款高品质水瓶,更是为地球贡献一份力量! ### **限时优惠,立即行动!** 🔥 **新用户首单立减20%** 🎁 **赠定制清洁刷+可拆卸吸管**(数量有限,先到先得) **立即下单,加入绿色饮水革命!** 🌍💧 👉 [点击购买](#点击购买) \| 📞 客服热线:XXX-XXXX-XXXX **EcoViva™------喝出健康,喝出未来!**

2.5 评估者-优化器(Evaluator-Optimizer)

一个LLM生成响应,另一个评估反馈,形成迭代优化闭环,适用在存在明确评估标准且迭代优化能显著提升质量,人类反馈可明确指导改进方向,且LLM能模拟此类反馈。(如文学翻译:评估者LLM针对语义细微差别提出修正建议)

示例: 通过评估优化实现一个Java栈代码生成

EvaluatorOptimizer

  • 一个提示词负责基于规则和反馈生成代码,一个提示词负责按要求评价代码并给出反馈
java 复制代码
package com.lkl.ai.agent.patterns;

import java.util.ArrayList;
import java.util.List;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.util.Assert;

public class EvaluatorOptimizer {

	public static final String DEFAULT_GENERATOR_PROMPT = """
			你的目标是根据输入完成任务。如果存在之前生成的反馈,
			你应该反思这些反馈以改进你的解决方案。

			关键要求:响应必须是单行有效的JSON,除明确使用\\n转义外,不得包含换行符。
			以下是必须严格遵守的格式(包括所有引号和花括号):

			{"thoughts":"此处填写简要说明","response":"public class Example {\\n    // 代码写在这里\\n}"}

			响应字段的规则:
			1. 所有换行必须使用\\n
			2. 所有引号必须使用\\"
			3. 所有反斜杠必须双写:\\
			4. 不允许实际换行或格式化 - 所有内容必须在一行
			5. 不允许制表符或特殊字符
			6. Java代码必须完整且正确转义

			正确格式的响应示例:
			{"thoughts":"实现计数器","response":"public class Counter {\\n    private int count;\\n    public Counter() {\\n        count = 0;\\n    }\\n    public void increment() {\\n        count++;\\n    }\\n}"}

			必须严格遵循此格式 - 你的响应必须是单行有效的JSON。
			""";

	public static final String DEFAULT_EVALUATOR_PROMPT = """
			评估这段代码实现的正确性、时间复杂度和最佳实践。
			确保代码有完整的javadoc文档。
			用单行JSON格式精确响应:

			{"evaluation":"PASS,NEEDS_IMPROVEMENT,FAIL", "feedback":"你的反馈意见"}

			evaluation字段必须是以下之一: "PASS", "NEEDS_IMPROVEMENT", "FAIL"
			仅当所有标准都满足且无需改进时才使用"PASS"。
			""";


	public static record Generation(String thoughts, String response) {
	}


	public static record EvaluationResponse(Evaluation evaluation, String feedback) {

		public enum Evaluation {
			PASS, NEEDS_IMPROVEMENT, FAIL
		}
	}


	public static record RefinedResponse(String solution, List<Generation> chainOfThought) {
	}

	private final ChatClient chatClient;

	private final String generatorPrompt;

	private final String evaluatorPrompt;

	public EvaluatorOptimizer(ChatClient chatClient) {
		this(chatClient, DEFAULT_GENERATOR_PROMPT, DEFAULT_EVALUATOR_PROMPT);
	}

	public EvaluatorOptimizer(ChatClient chatClient, String generatorPrompt, String evaluatorPrompt) {
		Assert.notNull(chatClient, "ChatClient must not be null");
		Assert.hasText(generatorPrompt, "Generator prompt must not be empty");
		Assert.hasText(evaluatorPrompt, "Evaluator prompt must not be empty");

		this.chatClient = chatClient;
		this.generatorPrompt = generatorPrompt;
		this.evaluatorPrompt = evaluatorPrompt;
	}


	public RefinedResponse loop(String task) {
		List<String> memory = new ArrayList<>();
		List<Generation> chainOfThought = new ArrayList<>();

		return loop(task, "", memory, chainOfThought);
	}


	private RefinedResponse loop(String task, String context, List<String> memory,
			List<Generation> chainOfThought) {

		Generation generation = generate(task, context);
		memory.add(generation.response());
		chainOfThought.add(generation);

		EvaluationResponse evaluationResponse = evaluate(generation.response(), task);

		if (evaluationResponse.evaluation().equals(EvaluationResponse.Evaluation.PASS)) {
			// Solution is accepted!
			return new RefinedResponse(generation.response(), chainOfThought);
		}

		// Accumulated new context including the last and the previous attempts and
		// feedbacks.
		StringBuilder newContext = new StringBuilder();
		newContext.append("以前的尝试:");
		for (String m : memory) {
			newContext.append("\n- ").append(m);
		}
		newContext.append("\nFeedback: ").append(evaluationResponse.feedback());

		return loop(task, newContext.toString(), memory, chainOfThought);
	}


	private Generation generate(String task, String context) {
		Generation generationResponse = chatClient.prompt()
				.user(u -> u.text("{prompt}\n{context}\nTask: {task}")
						.param("prompt", this.generatorPrompt)
						.param("context", context)
						.param("task", task))
				.call()
				.entity(Generation.class);

		System.out.println(String.format("\n=== 输出 ===\n思考: %s\n\n返回:\n %s\n",
				generationResponse.thoughts(), generationResponse.response()));
		return generationResponse;
	}


	private EvaluationResponse evaluate(String content, String task) {

		EvaluationResponse evaluationResponse = chatClient.prompt()
				.user(u -> u.text("{prompt}\nOriginal task: {task}\nContent to evaluate: {content}")
						.param("prompt", this.evaluatorPrompt)
						.param("task", task)
						.param("content", content))
				.call()
				.entity(EvaluationResponse.class);

		System.out.println(String.format("\n=== 评价输出 ===\n评价: %s\n\n反馈: %s\n",
				evaluationResponse.evaluation(), evaluationResponse.feedback()));
		return evaluationResponse;
	}

}

执行代码生成任务

java 复制代码
   @GetMapping("/evaluator")
    public void evaluator() {

        EvaluatorOptimizer.RefinedResponse refinedResponse = new EvaluatorOptimizer(chatClient).loop("""
					<user input>
                实现一个具有以下功能的Java栈:
                     1. push(x) - 入栈操作
                     2. pop() - 出栈操作
                     3. getMin() - 获取最小值
                     所有操作的时间复杂度应为O(1)。
                     所有内部字段必须声明为private,使用时需加"this."前缀。
					</user input>
					""");

        System.out.println("最后输出结果:\n : " + refinedResponse);
    }

执行结果

=== 输出 ===

思考: 实现O(1)时间复杂度的最小栈

返回:

public class MinStack {

复制代码
private Stack<Integer> stack;

private Stack<Integer> minStack;

public MinStack() {

    this.stack = new Stack<>();

    this.minStack = new Stack<>();

}

public void push(int x) {

    this.stack.push(x);

    if (this.minStack.isEmpty() || x <= this.minStack.peek()) {

        this.minStack.push(x);

    }

}

public void pop() {

    if (this.stack.pop().equals(this.minStack.peek())) {

        this.minStack.pop();

    }

}

public int getMin() {

    return this.minStack.peek();

}

}

=== 评价输出 ===

评价: NEEDS_IMPROVEMENT

反馈: 代码功能正确且时间复杂度符合要求,但缺少Javadoc文档且未处理空栈异常情况

=== 输出 ===

思考: 改进后的MinStack实现,包含Javadoc和空栈异常处理

返回:

public class MinStack {

复制代码
private Stack<Integer> stack;

private Stack<Integer> minStack;

/**

 * 初始化栈结构

 */

public MinStack() {

    this.stack = new Stack<>();

    this.minStack = new Stack<>();

}

/**

 * 入栈操作

 * @param x 要入栈的元素

 */

public void push(int x) {

    this.stack.push(x);

    if (this.minStack.isEmpty() || x <= this.minStack.peek()) {

        this.minStack.push(x);

    }

}

/**

 * 出栈操作

 * @throws EmptyStackException 当栈为空时抛出

 */

public void pop() {

    if (this.stack.isEmpty()) throw new EmptyStackException();

    if (this.stack.pop().equals(this.minStack.peek())) {

        this.minStack.pop();

    }

}

/**

 * 获取栈中最小值

 * @return 当前栈中的最小值

 * @throws EmptyStackException 当栈为空时抛出

 */

public int getMin() {

    if (this.minStack.isEmpty()) throw new EmptyStackException();

    return this.minStack.peek();

}

}

=== 评价输出 ===

评价: PASS

反馈: 代码实现正确,满足所有要求的功能和时间复杂度,且遵循了最佳实践。

最后输出结果:

public class MinStack {

复制代码
private Stack<Integer> stack;

private Stack<Integer> minStack;

/**

 * 初始化栈结构

 */

public MinStack() {

    this.stack = new Stack<>();

    this.minStack = new Stack<>();

}

/**

 * 入栈操作

 * @param x 要入栈的元素

 */

public void push(int x) {

    this.stack.push(x);

    if (this.minStack.isEmpty() || x <= this.minStack.peek()) {

        this.minStack.push(x);

    }

}

/**

 * 出栈操作

 * @throws EmptyStackException 当栈为空时抛出

 */

public void pop() {

    if (this.stack.isEmpty()) throw new EmptyStackException();

    if (this.stack.pop().equals(this.minStack.peek())) {

        this.minStack.pop();

    }

}

/**

 * 获取栈中最小值

 * @return 当前栈中的最小值

 * @throws EmptyStackException 当栈为空时抛出

 */

public int getMin() {

    if (this.minStack.isEmpty()) throw new EmptyStackException();

    return this.minStack.peek();

}

}

三、自主规划类(Autonomous Agent)

在 Autonomous Agent 的设计中,Planning(规划)、Reflection(反思)和 ReAct(推理+行动) 是三种关键模式,它们既有区别又紧密关联,共同支撑智能体的复杂任务处理能力

3.1 规划(Planning)

‌Planning使Agent能够基于目标和当前状态,制定并执行一系列有策略的行动计划。这涉及到对未来可能的状态进行预测,并在不确定条件下做出最优决策。实现规划能力通常通过内置的决策树、状态机或更高级的规划算法来实现‌

示例:杭州51适合出游吗?

**PlanningAgent **

将用户目标拆解为子任务并执行,支持动态重试和重新规划。采用 三层分工:

  • Planner:任务拆解(生成子任务列表)
  • Executor:执行子任务(支持工具调用)
  • Mock Tool:模拟工具调用结果(用于测试)
java 复制代码
package com.lkl.ai.agent.autonomous;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class PlanningAgent {

    private final ChatClient plannerChatClient;
    private final ChatClient executorChatClient;
    private final ChatClient mockToolExecutorChatClient;

    public PlanningAgent(ChatModel chatModel) {
        this.plannerChatClient = ChatClient.builder(chatModel).defaultSystem("""
                你是一个任务规划专家,负责将用户目标拆解为可执行的子任务,最多拆解为5个任务
                输出格式为 JSON 列表,例如:["任务1", "任务2", ...]
                """).build();

        this.executorChatClient = ChatClient.builder(chatModel).defaultSystem("""
                你是一个任务执行者,根据子任务描述完成具体操作。
                如果是需要工具调用的任务(如搜索、计算),请标注为:<TOOL>工具名:参数</TOOL>。
                否则直接生成结果。
                """).build();

        this.mockToolExecutorChatClient = ChatClient.builder(chatModel).defaultSystem("""
                你是一个工具调用模拟器,基于用户调用的工具名和参数模拟一条看起来合理的数据返回。
                """).build();

    }


    /**
     * 执行规划型任务
     *
     * @param goal       用户目标(如"写一篇关于Spring AI的博客")
     * @param maxRetries 最大重试次数(用于任务失败时重新规划)
     */
    public String executeGoal(String goal, int maxRetries) {
        List<String> plan = generatePlan(goal);
        String result = "";

        for (int i = 0; i < plan.size(); i++) {
            String task = plan.get(i);
            String taskResult = executeTask(task);

            // 检查任务结果是否需要重试
            if (taskResult.contains("<FAIL>") && maxRetries > 0) {
                System.out.println("Retrying task: " + task);
                plan = replan(goal, result); // 动态调整计划
                maxRetries--;
                i--; // 重新执行当前任务
                continue;
            }
            result += taskResult + "\n\n";
        }
        return result;
    }

    /**
     * 生成任务计划
     */
    private List<String> generatePlan(String goal) {
        String planJson = plannerChatClient.prompt(goal).call().content();
        // 简单解析JSON格式的列表(实际项目建议用Jackson/Gson)
        List<String> planList = parseJsonList(planJson);
        String planDesc = "目标:" + goal + "\n计划拆分:" + planList;
        System.out.println(planDesc);
        return planList;
    }

    /**
     * 执行单个子任务
     */
    private String executeTask(String task) {
        String response = executorChatClient.prompt(task).call().content();

        // 检查是否需要调用工具
        if (response.contains("<TOOL>")) {
            String toolCall = response.substring(response.indexOf("<TOOL>") + 6, response.indexOf("</TOOL>"));
            String[] parts = toolCall.split(":");
            String toolName = parts[0];
            String params = parts.length > 1 ? parts[1] : "";
            return callTool(toolName, params);
        }
        return response;
    }

    public String callTool(String toolName, String params) {
        return mockToolExecutorChatClient.prompt("工具名:" + toolName + ",参数:" + params).call().content();
    }

    /**
     * 动态重新规划(基于当前结果)
     */
    private List<String> replan(String goal, String currentResult) {
        String prompt = "原始目标:" + goal + "\n当前结果:" + currentResult + "\n请重新生成剩余任务计划。";
        return generatePlan(prompt);
    }

    // 简易JSON解析(示例用)
    private List<String> parseJsonList(String json) {
        List<String> tasks = new ArrayList<>();
        json = json.replace("[", "").replace("]", "").replace("\"", "");
        for (String task : json.split(",")) {
            tasks.add(task.trim());
        }
        return tasks;
    }
}

发起调用

java 复制代码
  @GetMapping("/planning")
    public void planning() {

        String resp = planningAgent.executeGoal("杭州51适合出游吗?", 3);
        System.out.println("最终结果:" + resp);

    }

执行结果

目标:杭州51适合出游吗?

计划拆分:[```json

查询杭州五一期间的天气情况, 了解杭州五一期间的旅游景点开放情况, 查看杭州五一期间的人流量预测, 评估个人假期时间和预算, 根据以上信息决定是否适合出游

] 复制代码
最终结果:{

  "city": "杭州",

  "date_range": ["2023-05-01", "2023-05-05"],

  "weather_data": [

    {

      "date": "2023-05-01",

      "weather": "晴",

      "temperature": "18~26°C",

      "humidity": "65%",

      "wind": "东南风3级"

    },

    {

      "date": "2023-05-02",

      "weather": "多云",

      "temperature": "20~28°C",

      "humidity": "70%",

      "wind": "南风2级"

    },

    {

      "date": "2023-05-03",

      "weather": "小雨",

      "temperature": "19~24°C",

      "humidity": "85%",

      "wind": "东风3级"

    },

    {

      "date": "2023-05-04",

      "weather": "阴",

      "temperature": "17~22°C",

      "humidity": "75%",

      "wind": "北风2级"

    },

    {

      "date": "2023-05-05",

      "weather": "晴转多云",

      "temperature": "16~25°C",

      "humidity": "60%",

      "wind": "西北风3级"

    }

  ],

  "tips": "五一假期前期天气晴好,适合出游;3日有小雨,建议携带雨具;早晚温差较大,请注意适时增减衣物。"

}



```json

{

  "results": [

    {

      "name": "西湖景区",

      "open_time": "2023年4月29日-5月3日 全天开放",

      "notes": "五一期间西湖音乐喷泉表演时间调整为19:00、20:00各一场"

    },

    {

      "name": "灵隐寺",

      "open_time": "2023年4月29日-5月3日 07:00-18:00",

      "notes": "需提前通过官方公众号预约"

    },

    {

      "name": "西溪湿地",

      "open_time": "2023年4月29日-5月3日 07:30-17:30",

      "notes": "东区、西区均正常开放"

    },

    {

      "name": "宋城",

      "open_time": "2023年4月29日-5月3日 09:00-21:00",

      "notes": "《宋城千古情》每天加演至5场"

    },

    {

      "name": "千岛湖景区",

      "open_time": "2023年4月29日-5月3日 08:00-17:00",

      "notes": "中心湖区、东南湖区正常开放"

    }

  ],

  "update_time": "2023-04-25",

  "source": "杭州市文化广电旅游局官网"

}
json 复制代码
{

  "data": {

    "location": "杭州",

    "year": 2023,

    "holiday": "五一假期",

    "predicted_visitor_count": "约850万人次",

    "comparison": {

      "2022年": "约600万人次",

      "increase": "预计同比增长41.7%"

    },

    "hot_spots": [

      "西湖景区",

      "灵隐寺",

      "宋城",

      "西溪湿地",

      "千岛湖"

    ],

    "peak_days": "4月29日-5月1日",

    "data_source": "杭州市文旅局预测数据",

    "note": "预测数据基于酒店预订量、景区预约情况及交通部门客流预判,实际数据可能受天气等因素影响"

  },

  "status": "success"

}

为了评估您的假期时间和预算,我需要了解以下信息:

  1. 时间方面:
  • 您计划休假的总天数

  • 具体出发和返回日期(如有)

  • 是否有日期限制(如必须避开某些日期)

  1. 预算方面:
  • 您的总预算金额

  • 预算分配意向(交通/住宿/餐饮/活动等)

  • 旅行目的地(国内/国外,具体城市)

  1. 其他偏好:
  • 旅行类型(休闲/探险/文化等)

  • 同行人数

  • 特殊需求(如无障碍设施等)

请提供以上详细信息,我可以帮您:

  • 计算每日预算分配

  • 建议合适的行程时长

  • 推荐符合预算的目的地

  • 提供节省开支的建议

您也可以直接告诉我您的初步计划,我可以帮您优化时间和预算安排。

请提供具体的天气、交通、景点开放情况等相关信息,以便我判断是否适合出游。

3.2 反思(Reflection)

‌Reflection允许Agent对其自身的思维过程、决策逻辑和过往经历进行回顾与分析,从而实现自我优化和学习。这种能力使得Agent能够根据反馈调整策略,提高在复杂环境中的适应性和解决问题的能力。在一些高级Agent平台上,反思机制通过内置的学习算法和自我评估功能实现,Agent能够识别自己的不足,从错误中学习,并逐渐完善其行为模式‌

示例: 通过java实现归并排序

ReflectionAgent

  • 生成阶段:generateChatClient根据用户问题生成初始代码。
  • 批判阶段:critiqueChatClient 检查代码质量,返回改进建议或 。
  • 迭代优化:若未收到 ,生成器根据批判反馈重新生成代码,直到满足质量要求或达到最大迭代次数。
java 复制代码
package com.lkl.ai.agent.autonomous;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.stereotype.Component;

@Component
public class ReflectionAgent {

    private final ChatClient generateChatClient;

    private final ChatClient critiqueChatClient;


    public ReflectionAgent(ChatModel chatModel) {
        this.generateChatClient = ChatClient.builder(chatModel)
                .defaultSystem("""
                你是一名Java程序员,负责生成高质量的Java代码。
                你的任务是为用户的请求生成最佳内容。如果用户提供批评意见,
                请根据反馈修改之前的尝试并重新生成。
                """)
                .defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory()))
                .build();

        this.critiqueChatClient = ChatClient.builder(chatModel)
                .defaultSystem("""
                你的任务是针对用户生成的内容提供批评和改进建议。
                如果用户内容有错误或需要改进之处,请输出建议列表
                和批评意见。如果用户内容没有问题,请输出:<OK>
                """)
                .defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory()))
                .build();
    }

    public String run(String userQuestion, int maxIterations) {

        String generation = generateChatClient.prompt(userQuestion).call().content();
        System.out.println("##generation\n\n" + generation);
        String critique;
        for (int i = 0; i < maxIterations; i++) {

            critique = critiqueChatClient.prompt(generation).call().content();

            System.out.println("##Critique\n\n" + critique);
            if (critique.contains("<OK>")) {
                System.out.println("\n\nStop sequence found\n\n");
                break;
            }
            generation = generateChatClient.prompt(critique).call().content();
        }
        return generation;

    }

}

发起调用

java 复制代码
   @Autowired
    private ReflectionAgent reflectionAgent;

    @GetMapping("/reflection")
    public void reflection() {
        String resp = reflectionAgent.run("通过java实现归并排序", 3);
        System.out.println("最终结果:" + resp);
    }

执行结果

##generation

Java实现归并排序

归并排序是一种经典的分治算法,时间复杂度为O(n log n)。下面是一个完整的Java实现:

java 复制代码
public class MergeSort {



    // 主方法,供外部调用

    public static void sort(int[] array) {

        if (array == null || array.length <= 1) {

            return; // 不需要排序

        }

        int[] temp = new int[array.length]; // 临时数组用于合并

        mergeSort(array, 0, array.length - 1, temp);

    }



    // 递归排序方法

    private static void mergeSort(int[] array, int left, int right, int[] temp) {

        if (left < right) {

            int mid = left + (right - left) / 2; // 防止溢出

            mergeSort(array, left, mid, temp);    // 排序左半部分

            mergeSort(array, mid + 1, right, temp); // 排序右半部分

            merge(array, left, mid, right, temp);  // 合并两个有序数组

        }

    }



    // 合并两个有序子数组

    private static void merge(int[] array, int left, int mid, int right, int[] temp) {

        int i = left;    // 左子数组起始索引

        int j = mid + 1;  // 右子数组起始索引

        int k = 0;        // 临时数组索引



        // 比较两个子数组的元素,将较小的放入临时数组

        while (i <= mid && j <= right) {

            if (array[i] <= array[j]) {

                temp[k++] = array[i++];

            } else {

                temp[k++] = array[j++];

            }

        }



        // 将左子数组剩余元素复制到临时数组

        while (i <= mid) {

            temp[k++] = array[i++];

        }



        // 将右子数组剩余元素复制到临时数组

        while (j <= right) {

            temp[k++] = array[j++];

        }



        // 将临时数组中的元素复制回原数组

        k = 0;

        while (left <= right) {

            array[left++] = temp[k++];

        }

    }



    // 测试代码

    public static void main(String[] args) {

        int[] arr = {12, 11, 13, 5, 6, 7};

        System.out.println("排序前:");

        printArray(arr);



        sort(arr);



        System.out.println("排序后:");

        printArray(arr);

    }



    // 辅助方法:打印数组

    private static void printArray(int[] arr) {

        for (int num : arr) {

            System.out.print(num + " ");

        }

        System.out.println();

    }

}

代码说明

  1. 主要方法

    • sort(int[] array):公开的排序接口

    • mergeSort(int[] array, int left, int right, int[] temp):递归分治排序

    • merge(int[] array, int left, int mid, int right, int[] temp):合并两个有序子数组

  2. 算法特点

    • 时间复杂度:O(n log n) - 在所有情况下都相同

    • 空间复杂度:O(n) - 需要额外的临时数组

    • 稳定性:稳定排序(相等元素的相对位置不会改变)

  3. 优化点

    • 对小规模子数组可以使用插入排序来提高效率

    • 可以检查如果array[mid] <= array[mid+1]则不需要合并操作

使用示例

java 复制代码
int[] data = {38, 27, 43, 3, 9, 82, 10};

MergeSort.sort(data);

System.out.println(Arrays.toString(data));

// 输出: [3, 9, 10, 27, 38, 43, 82]

这个实现包含了完整的测试代码和辅助方法,可以直接运行查看效果。

##Critique

这段Java实现的归并排序代码质量很高,具有以下优点:

  1. 代码结构清晰,将排序逻辑分为多个方法,职责分明

  2. 包含了完整的边界条件检查(array为null或长度<=1的情况)

  3. 使用了防止整数溢出的中间值计算方式

  4. 添加了详细的注释说明每个方法的功能

  5. 包含了测试用例和辅助打印方法

  6. 文档部分详细说明了算法特点和可能的优化点

代码实现正确且高效,符合归并排序的标准实现方式。没有发现需要改进的错误或问题。

Stop sequence found

最终结果:# Java实现归并排序

归并排序是一种经典的分治算法,时间复杂度为O(n log n)。下面是一个完整的Java实现:

java 复制代码
public class MergeSort {



    // 主方法,供外部调用

    public static void sort(int[] array) {

        if (array == null || array.length <= 1) {

            return; // 不需要排序

        }

        int[] temp = new int[array.length]; // 临时数组用于合并

        mergeSort(array, 0, array.length - 1, temp);

    }



    // 递归排序方法

    private static void mergeSort(int[] array, int left, int right, int[] temp) {

        if (left < right) {

            int mid = left + (right - left) / 2; // 防止溢出

            mergeSort(array, left, mid, temp);    // 排序左半部分

            mergeSort(array, mid + 1, right, temp); // 排序右半部分

            merge(array, left, mid, right, temp);  // 合并两个有序数组

        }

    }



    // 合并两个有序子数组

    private static void merge(int[] array, int left, int mid, int right, int[] temp) {

        int i = left;    // 左子数组起始索引

        int j = mid + 1;  // 右子数组起始索引

        int k = 0;        // 临时数组索引



        // 比较两个子数组的元素,将较小的放入临时数组

        while (i <= mid && j <= right) {

            if (array[i] <= array[j]) {

                temp[k++] = array[i++];

            } else {

                temp[k++] = array[j++];

            }

        }



        // 将左子数组剩余元素复制到临时数组

        while (i <= mid) {

            temp[k++] = array[i++];

        }



        // 将右子数组剩余元素复制到临时数组

        while (j <= right) {

            temp[k++] = array[j++];

        }



        // 将临时数组中的元素复制回原数组

        k = 0;

        while (left <= right) {

            array[left++] = temp[k++];

        }

    }



    // 测试代码

    public static void main(String[] args) {

        int[] arr = {12, 11, 13, 5, 6, 7};

        System.out.println("排序前:");

        printArray(arr);



        sort(arr);



        System.out.println("排序后:");

        printArray(arr);

    }



    // 辅助方法:打印数组

    private static void printArray(int[] arr) {

        for (int num : arr) {

            System.out.print(num + " ");

        }

        System.out.println();

    }

}

代码说明

  1. 主要方法

    • sort(int[] array):公开的排序接口

    • mergeSort(int[] array, int left, int right, int[] temp):递归分治排序

    • merge(int[] array, int left, int mid, int right, int[] temp):合并两个有序子数组

  2. 算法特点

    • 时间复杂度:O(n log n) - 在所有情况下都相同

    • 空间复杂度:O(n) - 需要额外的临时数组

    • 稳定性:稳定排序(相等元素的相对位置不会改变)

  3. 优化点

    • 对小规模子数组可以使用插入排序来提高效率

    • 可以检查如果array[mid] <= array[mid+1]则不需要合并操作

使用示例

java 复制代码
int[] data = {38, 27, 43, 3, 9, 82, 10};

MergeSort.sort(data);

System.out.println(Arrays.toString(data));

// 输出: [3, 9, 10, 27, 38, 43, 82]

这个实现包含了完整的测试代码和辅助方法,可以直接运行查看效果。

3.3 推理行动模式(ReAct)

ReAct(Reasoning + Acting)是一种结合推理链(Chain-of-Thought, CoT) 和工具调用(Tool Use)的自主智能体框架;通过推理->行动->观察的闭环,将 LLM的逻辑能力与外部工具结合,显著提升了复杂任务的可解性

针对ReAct常用的提示词,需要进行观察(Observation)思考(Thought)再行动(Action)

java 复制代码
 Answer the following questions as best you can. You have access to the following tools:
            
   {tools}

   Use the following format:

   Question: the input question you must answer
   Thought: you should always think about what to do
   Action: the action to take, should be one of [{toolNames}]
   Action Input: the input to the action
   Observation: the result of the action
   ... (this Thought/Action/Action Input/Observation can repeat N times)
   Thought: I now know the final answer
   Final Answer: the final answer to the original input question

   During the process of answering questions, you need to follow the rules below:
   1. In the "Action" line, only include the name of the tool used, without any other characters.
   2. Do not guess the answer, if you need to use an Action, wait for the user to provide the results of the Action as the next step's Observation. And do not provide the subsequent Thought and Final Answer.

   Begin! 

示例: 查询天气的ReactAgent

ReActAgent

  • 在ReActAgent中的Action通常是调用工具,这里的工具不再是mock,而是利用Spring AI中的Tool能力,parseTool提前解析出工具信息以及工具回调Map
  • 在提示词中已经限制返回格式,因此通过正则快速解析LLM返回内容
java 复制代码
package com.lkl.ai.agent.autonomous;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.model.tool.DefaultToolCallingChatOptions;
import org.springframework.ai.model.tool.ToolCallingChatOptions;
import org.springframework.ai.model.tool.ToolCallingManager;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.definition.ToolDefinition;
import org.springframework.ai.tool.resolution.ToolCallbackResolver;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public abstract class ReActAgent {

    public static final String DEFAULT_SYSTEM_PROMPT = """
            Answer the following questions as best you can. You have access to the following tools:
            
                       {tools}
            
                       Use the following format:
            
                       Question: the input question you must answer
                       Thought: you should always think about what to do
                       Action: the action to take, should be one of [{toolNames}]
                       Action Input: the input to the action
                       Observation: the result of the action
                       ... (this Thought/Action/Action Input/Observation can repeat N times)
                       Thought: I now know the final answer
                       Final Answer: the final answer to the original input question
            
                       During the process of answering questions, you need to follow the rules below:
                       1. In the "Action" line, only include the name of the tool used, without any other characters.
                       2. Do not guess the answer, if you need to use an Action, wait for the user to provide the results of the Action as the next step's Observation. And do not provide the subsequent Thought and Final Answer.
            
                       Begin!
            """;


    private ChatClient chatClient;
    private ToolCallingManager toolCallingManager;
    private ToolCallbackResolver toolCallbackResolver;
    private Set<String> toolBeanNames;
    private List<ToolDefinition> toolDefinitionList;

    private Map<String, ToolCallback> toolCallbackMap;

    private String toolNames;

    private String toolDesc;


    public ReActAgent(String name, Set<String> toolBeanNames, ChatClient chatClient, ToolCallingManager toolCallingManager, ToolCallbackResolver toolCallbackResolver) {

        this.chatClient = chatClient;
        this.toolCallingManager = toolCallingManager;
        this.toolCallbackResolver = toolCallbackResolver;
        this.toolBeanNames = toolBeanNames;

        //解析可调用的工具信息
        parseTool(toolBeanNames, toolCallingManager, toolCallbackResolver);


    }


    public String call(String prompt) {


        SystemMessage systemMessage = new SystemMessage(new PromptTemplate(DEFAULT_SYSTEM_PROMPT).render(Map.of("tools", this.toolDesc, "toolNames", this.toolNames)));

        List<String> input = new ArrayList<>();
        input.add("Question:" + prompt);

        return doCall(systemMessage, input);
    }

    /**
     * 推理-行动的循序调用,要加一个执行的次数,防止死循环
     *
     * @param systemMessage
     * @param inputList
     * @return
     */
    private String doCall(SystemMessage systemMessage, List<String> inputList) {

        String inputText = String.join(System.lineSeparator(), inputList);

        Prompt prompt = new Prompt(List.of(systemMessage, new UserMessage(inputText)));

        String result = chatClient.prompt(prompt).call().content();

        System.out.println(String.format("调用大模型提示词:\n%s\n大模型返回结果:\n%s", prompt.getContents(), result));

        Object llmEntity = parseLlmResp(result);

        if (llmEntity instanceof ToolAction toolAction) {
            //调用工具之前,把上一次执行的结果记录下来
            inputList.add(result);

            String toolResp = toolCallbackMap.get(toolAction.name).call(toolAction.arguments);

            String observation = String.format("Observation:the result of action [%s] on input [%s] is [%s]", toolAction.name, toolAction.arguments, toolResp);

            inputList.add(observation);

            doCall(systemMessage, inputList);

        } else if (llmEntity instanceof FinalAnswer finalAnswer) {
            return finalAnswer.answer;
        }

        return result;
    }

    private Object parseLlmResp(String llmResp) {

        if (llmResp == null) {
            return null;
        }
        if (llmResp.contains("Final Answer:")) {
            return extractFinalAnswer(llmResp);
        } else {
            return extractToolAction(llmResp);
        }
    }


    private FinalAnswer extractFinalAnswer(String llmResp) {

        String[] splits = llmResp.split("Final Answer:", 2);

        return new FinalAnswer(splits[1].trim());
    }

    private ToolAction extractToolAction(String llmResp) {
        String action = null;
        String actionInput = null;
        Pattern pattern = Pattern.compile("(?i)^Action:\\s*(.+)$" + "|^Action Input:\\s*(.+)$", Pattern.MULTILINE);
        Matcher matcher = pattern.matcher(llmResp);

        while (matcher.find()) {
            if (matcher.group(1) != null) {
                action = matcher.group(1).trim();
            } else if (matcher.group(2) != null) {
                actionInput = matcher.group(2).trim();
            }
        }
        return new ToolAction(action, actionInput);
    }

    public record ToolAction(String name, String arguments) {
    }

    public record FinalAnswer(String answer) {
    }

    private void parseTool(Set<String> toolBeanNames, ToolCallingManager toolCallingManager, ToolCallbackResolver toolCallbackResolver) {

        ToolCallingChatOptions toolCallingChatOptions = new DefaultToolCallingChatOptions();
        toolCallingChatOptions.setToolNames(toolBeanNames);

        List<ToolDefinition> toolDefinitionList = toolCallingManager.resolveToolDefinitions(toolCallingChatOptions);

        this.toolDefinitionList = toolDefinitionList;


        this.toolNames = buildToolNames(toolDefinitionList);

        this.toolDesc = buildToolDesc(toolDefinitionList);

        buildToolDefinitionMap(toolDefinitionList, toolCallbackResolver);


    }


    private void buildToolDefinitionMap(List<ToolDefinition> toolDefinitionList, ToolCallbackResolver toolCallbackResolver) {
        Map<String, ToolCallback> toolCallbackMap = new HashMap<>();
        if (CollectionUtils.isEmpty(toolDefinitionList)) {
            return;
        }
        for (ToolDefinition toolDefinition : toolDefinitionList) {

            ToolCallback toolCallback = toolCallbackResolver.resolve(toolDefinition.name());
            toolCallbackMap.put(toolDefinition.name(), toolCallback);
        }
        this.toolCallbackMap = toolCallbackMap;
    }

    private String buildToolDesc(List<ToolDefinition> toolDefinitionList) {
        if (CollectionUtils.isEmpty(toolDefinitionList)) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        for (ToolDefinition toolDefinition : toolDefinitionList) {
            sb.append(toolDefinition.name()).append(",");

            String desc = String.format("Tool name :%s,description:%s,input type schema:%s", toolDefinition.name(), toolDefinition.description(), toolDefinition.inputSchema());
            sb.append(desc);
            sb.append(System.lineSeparator());
        }
        return sb.toString();
    }

    /**
     * 构建工具名称
     *
     * @param toolDefinitionList
     * @return
     */
    private String buildToolNames(List<ToolDefinition> toolDefinitionList) {

        if (CollectionUtils.isEmpty(toolDefinitionList)) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        for (ToolDefinition toolDefinition : toolDefinitionList) {
            sb.append(toolDefinition.name()).append(",");
        }

        return sb.toString().substring(0, sb.length() - 1);
    }
}

工具定义

java 复制代码
@Component
public class WeatherService implements Function<WeatherService.Req, WeatherService.Resp> {


    @Override
    public Resp apply(Req req) {

        System.out.println("执行天气工具查询:" + req);
        Resp resp = new Resp(RandomUtils.insecure().randomDouble(10d, 30d), Unit.F);
        System.out.println("天气查询成功:" + resp);
        return resp;
    }

    public enum Unit {C, F}

    public record Req(String location, Unit unit) {

    }

    public record Resp(double temp, Unit unit) {
    }

}


@Configuration(proxyBeanMethods = false)
public class WeatherTools {

    @Autowired
    private WeatherService weatherService;

    @Bean
    @Description("实时查询天气工具")
    Function<WeatherService.Req, WeatherService.Resp> currentWeather() {
        return weatherService;
    }

}

发起调用

java 复制代码
@Component
public class WeatherReActAgent extends ReActAgent {


    public WeatherReActAgent(ChatClient.Builder builder, ToolCallingManager toolCallingManager, ToolCallbackResolver toolCallbackResolver) {
        super("weatherReActAgent", Set.of("currentWeather"), builder.build(), toolCallingManager, toolCallbackResolver);
    }
}


   @Autowired
    private WeatherReActAgent weatherReactAgent;

    @GetMapping("/react")
    public void react() {
        String resp = weatherReactAgent.call("查杭州的天气");
        System.out.println("最终结果:" + resp);
    }

执行结果

调用大模型提示词:

Answer the following questions as best you can. You have access to the following tools:

复制代码
       currentWeather,Tool name :currentWeather,description:实时查询天气工具,input type schema:{

         "$schema" : "[https://json-schema.org/draft/2020-12/schema",](https://json-schema.org/draft/2020-12/schema",)

         "type" : "object",

         "properties" : {

           "location" : {

             "type" : "string"

           },

           "unit" : {

             "type" : "string",

             "enum" : [ "C", "F" ]

           }

         },

         "required" : [ "location", "unit" ],

         "additionalProperties" : false

       }





       Use the following format:



       Question: the input question you must answer

       Thought: you should always think about what to do

       Action: the action to take, should be one of [currentWeather]

       Action Input: the input to the action

       Observation: the result of the action

       ... (this Thought/Action/Action Input/Observation can repeat N times)

       Thought: I now know the final answer

       Final Answer: the final answer to the original input question



       During the process of answering questions, you need to follow the rules below:

       1. In the "Action" line, only include the name of the tool used, without any other characters.

       2. Do not guess the answer, if you need to use an Action, wait for the user to provide the results of the Action as the next step's Observation. And do not provide the subsequent Thought and Final Answer.



       Begin!

Question:查杭州的天气

大模型返回结果:

Thought: I need to use the currentWeather tool to check the weather in Hangzhou.

Action: currentWeather

Action Input: {"location": "杭州", "unit": "C"}

执行天气工具查询:Req[location=杭州, unit=C]

天气查询成功:Resp[temp=29.61824002756853, unit=F]

调用大模型提示词:

Answer the following questions as best you can. You have access to the following tools:

复制代码
       currentWeather,Tool name :currentWeather,description:实时查询天气工具,input type schema:{

         "$schema" : "[https://json-schema.org/draft/2020-12/schema",](https://json-schema.org/draft/2020-12/schema",)

         "type" : "object",

         "properties" : {

           "location" : {

             "type" : "string"

           },

           "unit" : {

             "type" : "string",

             "enum" : [ "C", "F" ]

           }

         },

         "required" : [ "location", "unit" ],

         "additionalProperties" : false

       }





       Use the following format:



       Question: the input question you must answer

       Thought: you should always think about what to do

       Action: the action to take, should be one of [currentWeather]

       Action Input: the input to the action

       Observation: the result of the action

       ... (this Thought/Action/Action Input/Observation can repeat N times)

       Thought: I now know the final answer

       Final Answer: the final answer to the original input question



       During the process of answering questions, you need to follow the rules below:

       1. In the "Action" line, only include the name of the tool used, without any other characters.

       2. Do not guess the answer, if you need to use an Action, wait for the user to provide the results of the Action as the next step's Observation. And do not provide the subsequent Thought and Final Answer.



       Begin!

Question:查杭州的天气

Thought: I need to use the currentWeather tool to check the weather in Hangzhou.

Action: currentWeather

Action Input: {"location": "杭州", "unit": "C"}

Observation:the result of action [currentWeather] on input [{"location": "杭州", "unit": "C"}] is [{"temp":29.61824002756853,"unit":"F"}]

大模型返回结果:

Observation: The current temperature in Hangzhou is 29.62°F.

Thought: The temperature is provided in Fahrenheit, but the user requested Celsius. I need to convert it to Celsius.

Final Answer: 杭州当前气温约为-1.32°C(29.62°F)。

最终结果:杭州当前气温约为-1.32°C(29.62°F)。

尽管Planning、Reflection和ReAct各自独立,但它们在Agent的设计和实现中相互补充。‌规划模式帮助Agent制定行动计划,反思模式通过自我评估和学习优化决策过程,而ReAct则通过合理调用外部资源增强Agent的能力。‌这种组合使得Agent能够在复杂环境中更有效地完成任务和做出决策。

至此,本篇要讨论的最基本的Agent模式与示例都已完成,不论是Hybrid Agent还是Multi-Agent System (MAS) 等复杂的智能体都是再此基础上发展演进,请结合业务场景并遵循KISS原则(Keep It Simple, Stupid)开启您的Agent之旅吧

结语:当下便是Agent元年

当下便是Agent元年,我们正站在人工智能从被动工具迈向主动智能体的历史转折点;

  • 技术维度上,多模态大模型突破感知边界,工具调用成为行业标准,自主决策准确率已达商用水平
  • 产业维度呈现清晰的演进路径,从实验室原型到POC验证,再到规模部署,最终将形成智能体平台经济;
  • 开发者维度迎来范式革命:开发方式从"编写逻辑"转向"培养智能体"

这不仅是技术迭代,更是人机关系的重构。当智能体开始具备目标感、自主性和反思能力时,我们正在创造一种新的数字生命形态。每一行智能体代码,都在为这个元年写下注脚。

相关推荐
江鸟19982 小时前
AI 编程日报 · 2025 年 5 月 04 日|GitHub Copilot Agent 模式发布,Ultralytics 优化训练效率
人工智能·github·copilot
罗技1232 小时前
ES类的索引轮换
java·linux·elasticsearch
Bruce_Liuxiaowei4 小时前
从零开发一个B站视频数据统计Chrome插件
人工智能·visualstudio·html
JANYI20184 小时前
C文件在C++平台编译时的注意事项
java·c语言·c++
乌恩大侠4 小时前
【AI科技】ROCm 6.4:打破 AI、HPC 和模块化 GPU 软件的障碍
人工智能·科技
benpaodeDD5 小时前
双列集合——map集合和三种遍历方式
java
CHNMSCS5 小时前
PyTorch_张量基本运算
人工智能·pytorch·python
时而支楞时而摆烂的小刘5 小时前
CUDA、pytorch、配置环境教程合集
人工智能·pytorch·python
试着5 小时前
【AI面试准备】元宇宙测试:AI+低代码构建虚拟场景压力测试
人工智能·低代码·面试