燃爆啦!Spring AI 五大智能体开发模式震撼登场
智能体系统的基础构建模块是一个经过增强的 LLM,这种增强体现在它集成了**检索**、**工具**和**记忆**等功能。我们当前的模型能够主动利用这些能力——生成自己的搜索查询、选择合适的工具,并决定保留哪些信息。
1. 简介
智能体系统的基础构建模块是一个经过增强的 LLM,这种增强体现在它集成了检索、工具和记忆等功能。我们当前的模型能够主动利用这些能力——生成自己的搜索查询、选择合适的工具,并决定保留哪些信息。
Anthropic公司将不同 “智能体” 定义(有些人认为智能体是能够长期独立运行、使用各种工具完成复杂任务的全自主系统;而另一些人则将其视为遵循预定义工作流的实现方案)都归类为智能体系统,但在架构上对工作流和智能体进行了区分:
- 工作流:它是一个系统,通过预定义的代码路径来协调大型语言模型(LLM)和工具,即按照既定的流程和规则来执行任务。
- 智能体:它强调大型语言模型能够动态指导自身处理流程和工具使用,具有自主性,能够根据实际情况自主控制如何完成任务。
接下来,将介绍在生产环境中观察到的智能体系统的常见模式。我们将从基础构建模块——增强型大型语言模型(augmented LLM)开始,然后逐步增加复杂性,从简单的组合式工作流到自主智能体。
1.1 链式工作流(Chain Workflow)
链式工作流模式体现了将复杂任务分解为更简单、更易管理的步骤的原则。如下图所示:
使用场景:
- 任务具有清晰的顺序步骤时
- 当您愿意以增加延迟为代价换取更高准确性时
- 当每个步骤都基于前一步骤的输出时
1.2 并行化工作流(Parallelization Workflow)
大型语言模型(LLMs)可以同时处理任务,并通过编程方式聚合它们的输出。如下图所示:
使用场景:
- 处理大量相似但相互独立的事项时
- 需要多个独立视角来完成的任务时
- 当处理时间至关重要且任务可并行化时
1.3 路由工作流(Routing Workflow)
路由模式实现了智能的任务分配,能够对不同类型的输入进行专门处理。如下图所示:
使用场景:
- 处理具有不同输入类别的复杂任务时
- 当不同输入需要专门的处理方式时
- 当能够准确进行分类处理时
1.4 协调器-工作者工作流(Orchestrator-workers)
在协调器-工作者工作流中,一个中央的大型语言模型(LLM)会动态地分解任务,将其分配给工作者LLM,并综合它们的处理结果。如下图所示:
使用场景:
- 在那些子任务无法提前预测的复杂任务中
- 在需要采用不同方法或视角来完成的任务中
- 在需要自适应解决问题的情境中
1.5 评估器-优化器工作流(Evaluator-optimizer)
在评估器-优化器工作流中,一个大型语言模型(LLM)调用生成响应,而另一个模型则在循环中提供评估和反馈。如下图所示:
使用场景:
- 当存在明确的评估标准时
- 当迭代优化能带来可衡量的价值时
- 当任务能从多轮评审中受益时
1.6 智能体(Agents)
智能体随LLMs成熟在生产中兴起,能处理复杂任务。它们从人类用户获取指令后独立规划操作,执行时从环境获取反馈以评估进展,可暂停等待人类反馈。任务完成后终止,常设停止条件。如下图所示:
使用场景:
智能体适用于解决开放式问题,即那些难以或无法预测所需步骤数量,且无法预先设定固定路径的问题。大型语言模型(LLM)可能会进行多轮操作,因此你必须对其决策能力有一定程度的信任。智能体的自主性使其非常适合在受信任的环境中扩展任务规模。
注意:智能体的自主性也意味着更高的成本以及错误累积的潜在风险。我们建议在沙盒环境中进行广泛的测试,并设置适当的防护措施。
接下来,我们将通过案例的方式演示上面的3种工作流模式。
2.实战案例
*环境准备*
<dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-starter</artifactId> <version>1.0.0-M6.1</version></dependency>
我们使用阿里的大模型。
*配置文件*
spring: ai: dashscope: api-key: sk-xxxooo base-url: https://dashscope.aliyuncs.com/compatible-mode/v1 chat: options: stream: true model: qwen-turbo
*2.1* *链式工作流*
@Componentpublic class ChainWorkflow { // 一系列系统提示(system prompts),这些提示定义了链式处理中的转换步骤。每个提示都充当一个关卡(gate),在进入下一步之前对输出进行验证和转换。 public static final String[] DEFAULT_SYSTEM_PROMPTS = { // Step 1 """ 从文本中仅提取数值及其对应的指标。 将每个数值和指标按照“数值: 指标”的格式逐行列出。 示例格式: 92: 客户满意度 45%: 收入增长率""", // Step 2 """ 将所有数值尽可能转换为百分比形式。 若数值并非百分比或点数形式,则将其转换为小数形式后再以百分比呈现(例如,92 点 → 92%)。 每行只保留一个数值。 示例格式: 92%:客户满意度 45%:收入增长率""", // Step 3 """ 将所有行按照数值大小进行降序排序。 每行保持“数值: 指标”的格式。 示例: 92%: 客户满意度 87%: 员工满意度""", // Step 4 """ 将排序后的数据格式化为以下带有“指标”和“数值”两列的 Markdown 表格: | 指标 | 数值 | |:--|--:| | 客户满意度 | 92% | """ }; private final ChatClient chatClient; public ChainWorkflow(ChatClient chatClient) { this.chatClient = chatClient ; } public String chain(String userInput, String[] systemPrompts) { int step = 0; String response = userInput; System.out.println(String.format("\nSTEP %s:\n %s", step++, response)); for (String prompt : systemPrompts) { // 1. 使用上一步的响应来构建输入内容。 String input = String.format("{%s}\n {%s}", prompt, response); // 2. 使用新的输入内容调用聊天客户端,并获取新的响应。 response = chatClient.prompt(input).call().content(); System.out.println(String.format("\nSTEP %s:\n %s", step++, response)); } return response; }}
*测试接口*
@GetMapping("")public ResponseEntity<String> chain() { String[] prompts = ChainWorkflow.DEFAULT_SYSTEM_PROMPTS ; String userInput = """ 第三季度绩效总结: 本季度我们的客户满意度得分提升至92分。 与去年相比,收入增长了45%。 在我们的主要市场中,市场份额现已达到23%。 客户流失率从8%下降至5%。 新用户获取成本为每用户43美元。 产品采用率提升至78%。 员工满意度得分为87分。 营业利润率提高至34%。 """; ; return ResponseEntity.ok(this.chainWorkflow.chain(userInput, prompts)) ;}
*运行结果*
控制台
接口输出
*2.2* *并行化工作流*
@Componentpublic class ParalleWorkflow { private final ChatClient chatClient; public ParalleWorkflow(ChatClient chatClient) { this.chatClient = chatClient; } /** * 使用固定线程池和相同的提示模板并发处理多个输入。此方法会保持结果顺序与输入顺序一致。 * * @param prompt 用于每个输入的提示模板。输入将被追加到此提示后。不能为null。示例:"Translate the following text to French:" * @param inputs 待处理的输入字符串列表。每个输入将独立并行处理。不能为null或空。示例:["Hello", "World", "Good morning"](["你好", "世界", "早上好"] * @param nWorkers 要使用的并发工作线程数。这控制着同时进行的最大LLM API调用次数。必须大于0。在设置此值时,请考虑API的速率限制。 * @return 与输入顺序相同的处理结果列表。每个结果包含LLM对相应输入的响应。 */ public List<String> parallel(String prompt, List<String> inputs, int nWorkers) { 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()); // 等待所有任务完成 CompletableFuture<Void> allFutures = CompletableFuture.allOf( futures.toArray(CompletableFuture[]::new)); allFutures.join(); return futures.stream() .map(CompletableFuture::join) .collect(Collectors.toList()); } finally { executor.shutdown(); } }}
*测试接口*
@GetMapping("")public ResponseEntity<?> index() { List<String> response = this.paralleWorkflow.parallel(""" 分析市场变化将如何影响该利益相关者群体。 提供具体影响及建议措施。 格式应清晰划分章节,并明确优先级。 """, List.of(""" 客户群体: - 对价格敏感 - 追求更先进的技术 - 关注环境问题 """, """ 员工群体: - 对工作保障的担忧 - 需要新技能 - 希望获得明确的方向指引 """, """ 投资者: - 期望增长 - 希望控制成本 - 关注风险问题 """, """ 供应商: - 产能限制 - 价格压力 - 技术转型 """), 4); System.err.println(response) ; return ResponseEntity.ok(response);}
*2.3* *路由工作流*
public class RoutingWorkflow { private final ChatClient chatClient; public RoutingWorkflow(ChatClient chatClient) { this.chatClient = chatClient; } public String route(String input, Map<String, String> routes) { 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": "所选团队的名称" \\} Input: %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(); }}
测试代码
运行结果
如何学习大模型 AI ?
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】
更多推荐
所有评论(0)