SpringAI 搭建智能体(二):搭建客服系统智能体
在现代人工智能应用中,智能体(Agent) 是一个重要的概念,它的核心能力是自主性与灵活性。一个智能体不仅能够理解用户的需求,还能拆解任务、调用工具完成具体操作,并在复杂场景中高效运行。在本篇博客中,我们将围绕一个基于 Spring AI 的智能体实现,深入探讨智能体的概念、构建流程以及实际应用场景。
1. 什么是智能体?
智能体是一种能够根据目标自主执行任务的系统。与传统的 AI 模型生成内容的模式不同,智能体通过整合语义理解、任务分解和工具调用等功能,具备以下特征:
- 目标驱动:智能体能够根据输入指令明确任务目标。
- 任务拆解:将复杂任务分解为多个子任务。
- 工具调用:根据任务需求动态选择并调用工具。
- 自适应性:根据上下文调整行为,处理动态变化的环境。
智能体 vs 传统 AI
传统 AI 通常专注于单一功能(如文本生成、分类任务等),而智能体是一个更高层次的概念,它整合了多个功能模块,能够在复杂场景中完成多步骤任务。
2. 智能体的核心功能
在一个智能体系统中,核心功能包括:
- 语义解析:理解用户输入,明确任务目标。
- 工具管理:维护一组工具及其描述,供智能体调用。
- 任务执行:动态调用工具完成任务,并整合结果。
- 结果生成:将工具返回的结果组合成易于理解的输出。
3. 基于 Spring AI 的智能体架构
我们基于 Spring AI 实现了一个完整的智能体系统,其架构如下:
3.1 核心组件
-
工具接口(Tool Interface)
每个工具都实现一个统一的接口,包含名称、描述、支持状态和执行逻辑等。 -
工具管理器(Tool Manager)
用于维护工具列表并提供工具调用的功能。 -
语义分析模块(Semantic Analysis)
调用 ChatGPT 等语言模型,解析任务并生成格式化的任务步骤。 -
智能体核心(Agent Core)
负责任务拆解、工具调用和结果整合,是智能体的“大脑”。
3.2 智能体执行流程
-
用户输入:
用户通过系统输入任务描述,例如:查询北京的天气,并获取推荐的景点信息。 -
工具列表生成:
系统将工具的名称、描述和支持状态提供给语义分析模块。 -
任务解析:
语义分析模块(基于 ChatGPT)解析任务,并生成 JSON 格式的任务步骤,例如:[{"toolName": "weather", "input": "Beijing"},{"toolName": "tourism", "input": "Beijing"} ] -
工具调用:
智能体根据任务步骤依次调用对应工具,并获取结果。 -
结果整合:
将工具返回的结果整合成最终输出,返回给用户。
4. 实际应用场景
4.1 智能客服
智能体可以根据用户问题调用多个工具完成复杂的客服任务。
- 示例:用户输入:
查询上海今天的天气,并推荐适合的活动。- 工具调用:
WeatherTool查询天气。ActivityRecommendationTool提供活动推荐。
- 输出结果:
上海今天晴天,气温 26°C。推荐的活动有:游览外滩、参观上海博物馆。
- 工具调用:
4.2 数据处理与分析
在数据处理场景中,智能体可以调用数据清洗、分析和可视化工具,完成复杂的数据管道任务。
- 示例:用户输入:
对销售数据进行清洗,然后计算过去一年的月度增长率。- 工具调用:
DataCleaningTool处理数据。GrowthAnalysisTool计算增长率。
- 输出结果:
数据已清洗。过去 12 个月的月度增长率为:10%、12%、8%...
- 工具调用:
4.3 自动化运维
在运维场景中,智能体可以调用状态检查、日志分析和自动化脚本执行工具。
- 示例:用户输入:
检查所有服务器的状态,如果有异常,重新启动服务。- 工具调用:
HealthCheckTool检查服务器状态。RestartServiceTool重新启动异常服务。
- 输出结果:
检查完成。服务器 2 和 5 状态异常,已成功重启服务。
- 工具调用:
5. 智能体的优势
5.1 灵活性
通过语义解析和动态工具调用,智能体能够灵活处理多样化的任务。
5.2 可扩展性
新增工具只需实现工具接口并注册到工具管理器,无需改动核心逻辑。
5.3 可解释性
每个工具调用和结果整合过程都清晰透明,便于调试和改进。
6. 示例代码
以下是客服智能体实现的核心代码示例:
工具接口与实现
public interface Tool {String getName();String getDescription();boolean isSupported();String execute(String input);
}@Component
public class WeatherTool implements Tool {@Overridepublic String getName() {return "weather";}@Overridepublic String getDescription() {return "查询指定城市的天气";}@Overridepublic boolean isSupported() {return true;}@Overridepublic String execute(String input) {return "The weather in " + input + " is sunny and 25°C.";}
}
语义分析模块
@Component
public class ChatGPTService {// 调用 ChatGPT API 的逻辑public String analyze(String task, String toolsList) {// 调用 OpenAI 接口返回任务步骤return "[{\"toolName\": \"weather\", \"input\": \"Beijing\"}]";}
}
智能体核心逻辑
@Component
public class Agent {private final ToolManager toolManager;private final ChatGPTService chatGPTService;@Autowiredpublic Agent(ToolManager toolManager, ChatGPTService chatGPTService) {this.toolManager = toolManager;this.chatGPTService = chatGPTService;}public String execute(String task) {String toolsList = toolManager.getToolsDescription();String stepsJson = chatGPTService.analyze(task, toolsList);List<TaskStep> steps = parseSteps(stepsJson);List<String> results = new ArrayList<>();for (TaskStep step : steps) {results.add(toolManager.executeTool(step.getToolName(), step.getInput()));}return String.join("\n", results);}
}
代码实现
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;import java.util.ArrayList;
import java.util.List;@Component
public class AdvancedSemanticAgent {private final ToolManager toolManager;private final ChatGPTService chatGPTService;@Autowiredpublic AdvancedSemanticAgent(ToolManager toolManager, ChatGPTService chatGPTService) {this.toolManager = toolManager;this.chatGPTService = chatGPTService;}// 核心执行逻辑public String execute(String task) {// 使用 ChatGPT 进行语义解析,生成任务步骤List<TaskStep> steps = parseTaskWithChatGPT(task);// 执行每一步任务List<String> results = new ArrayList<>();for (TaskStep step : steps) {String result = toolManager.executeTool(step.getToolName(), step.getInput());results.add(result);}// 整合结果return combineResults(results);}// 使用 ChatGPT 解析任务private List<TaskStep> parseTaskWithChatGPT(String task) {String toolList = generateToolListDescription();String prompt = "以下是可用工具列表及其描述,请根据任务选择合适的工具并生成任务步骤。" +"返回结果为 JSON 数组,每个对象包含工具名称(toolName)和输入参数(input)。" +"忽略工具列表中标注为不支持的工具。\n\n" +"任务描述:" + task + "\n\n" +"工具列表:" + toolList;String response = chatGPTService.generateResponse(prompt);// 解析 ChatGPT 返回的 JSONreturn parseStepsFromResponse(response);}// 生成工具列表的描述private String generateToolListDescription() {List<Tool> tools = toolManager.getAvailableTools();StringBuilder toolListBuilder = new StringBuilder();for (Tool tool : tools) {toolListBuilder.append("- 工具名称: ").append(tool.getName()).append(", 描述: ").append(tool.getDescription()).append(", 示例入参: ").append(tool.getExampleInput()).append(", 是否支持: ").append(tool.isSupported() ? "支持" : "不支持").append("\n");}return toolListBuilder.toString();}// 解析 ChatGPT 返回的 JSONprivate List<TaskStep> parseStepsFromResponse(String response) {List<TaskStep> steps = new ArrayList<>();try {ObjectMapper mapper = new ObjectMapper();steps = mapper.readValue(response, new TypeReference<List<TaskStep>>() {});} catch (Exception e) {throw new RuntimeException("解析任务步骤失败:" + e.getMessage(), e);}return steps;}// 整合结果private String combineResults(List<String> results) {return String.join("\n", results);}// 定义子任务步骤static class TaskStep {private String toolName;private String input;// Getters 和 Setterspublic String getToolName() {return toolName;}public void setToolName(String toolName) {this.toolName = toolName;}public String getInput() {return input;}public void setInput(String input) {this.input = input;}}
}
工具接口与管理器
工具接口扩展
扩展工具接口,增加工具描述和支持状态。
public interface Tool {String getName();String getDescription(); // 返回工具的描述String getExampleInput(); // 返回工具的示例入参boolean isSupported(); // 工具是否被支持String execute(String input);
}
工具实现示例
假设我们有三个工具:WeatherTool(支持)、DatabaseTool(支持)、UnsupportedTool(不支持)。
WeatherTool
@Component
public class WeatherTool implements Tool {@Overridepublic String getName() {return "weather";}@Overridepublic String getDescription() {return "查询指定城市的天气信息";}@Overridepublic String getExampleInput() {return "城市名称,例如 'New York'";}@Overridepublic boolean isSupported() {return true;}@Overridepublic String execute(String input) {return "The weather in " + input + " is sunny and 25°C.";}
}
DatabaseTool
@Component
public class DatabaseTool implements Tool {@Overridepublic String getName() {return "database";}@Overridepublic String getDescription() {return "查询数据库中的相关记录";}@Overridepublic String getExampleInput() {return "查询条件,例如 'customer:12345'";}@Overridepublic boolean isSupported() {return true;}@Overridepublic String execute(String input) {return "Query result for input [" + input + "]: {id: 1, name: 'Spring AI'}";}
}
UnsupportedTool
@Component
public class UnsupportedTool implements Tool {@Overridepublic String getName() {return "unsupported";}@Overridepublic String getDescription() {return "这是一个不支持的工具";}@Overridepublic String getExampleInput() {return "无";}@Overridepublic boolean isSupported() {return false;}@Overridepublic String execute(String input) {throw new UnsupportedOperationException("This tool is not supported.");}
}
工具管理器扩展
@Component
public class ToolManager {private final List<Tool> tools;@Autowiredpublic ToolManager(List<Tool> toolList) {this.tools = toolList;}public List<Tool> getAvailableTools() {return tools;}public String executeTool(String toolName, String input) {return tools.stream().filter(tool -> tool.getName().equals(toolName)).findFirst().orElseThrow(() -> new IllegalArgumentException("Tool not found: " + toolName)).execute(input);}
}
示例执行流程
工具列表
通过工具管理器提供给 ChatGPT 的工具列表如下:
工具列表:
- 工具名称: weather, 描述: 查询指定城市的天气信息, 示例入参: 城市名称,例如 'New York', 是否支持: 支持
- 工具名称: database, 描述: 查询数据库中的相关记录, 示例入参: 查询条件,例如 'customer:12345', 是否支持: 支持
- 工具名称: unsupported, 描述: 这是一个不支持的工具, 示例入参: 无, 是否支持: 不支持
输入任务
用户输入任务:
获取纽约的天气,并查询与天气相关的数据库记录。
ChatGPT 返回的结果
[{"toolName": "weather", "input": "New York"},{"toolName": "database", "input": "weather:New York"}
]
工具调用结果
智能体调用工具并返回结果:
The weather in New York is sunny and 25°C.
Query result for input [weather:New York]: {id: 1, name: 'Spring AI'}
7. 未来展望
随着 AI 模型和工具生态的不断发展,智能体将进一步扩展到以下领域:
- 多模态任务:支持文本、图像、语音等多种输入与输出。
- 学习与优化:通过强化学习优化任务拆解和工具调用策略。
- 全局规划:在任务间建立依赖关系,优化多任务执行流程。
智能体是 AI 应用发展的重要方向,其灵活性和扩展性为解决复杂问题提供了强大的工具。
8. 总结
通过引入智能体的概念和实践,我们展示了如何构建一个灵活、高效的系统,完成复杂任务。智能体结合 Spring AI 提供的工具管理和语义分析能力,成为连接用户需求和执行逻辑的桥梁。未来,智能体将在更多场景中展现其强大的应用潜力,为智能化发展注入新动力。
相关文章:
SpringAI 搭建智能体(二):搭建客服系统智能体
在现代人工智能应用中,智能体(Agent) 是一个重要的概念,它的核心能力是自主性与灵活性。一个智能体不仅能够理解用户的需求,还能拆解任务、调用工具完成具体操作,并在复杂场景中高效运行。在本篇博客中&…...
豆包MarsCode:前缀和计算问题
问题描述 思路分析 问题理解 小S的任务是计算一个整数数组 nums 的前缀和。前缀和是指从数组开始到某个位置的所有元素的累加值,形成一个新数组。例如: 输入数组:nums [4, 5, 1, 6]前缀和数组:[4, 9, 10, 16] 4 49 4 510 …...
【16届蓝桥杯寒假刷题营】第2期DAY5
2.最大公因数 - 蓝桥云课 问题描述 给你2个正整数N,M。 你需要构造一个有N个数的正整数序列a,满足以下条件: ∑i1NaiM。 求gcd(a),可能的最大值。 输入描述 输入一行两个正整数N,M,表示数组的长…...
Python 合并 Excel 单元格
合并 Excel 单元格是 Excel 数据处理和表格设计中的一项常用操作。例如,在制作表格标题时,经常会将多个单元格合并,使标题能够跨列显示,更加醒目和美观。此外,当对数据进行分类时,为了使同一类别的数据在视…...
[EAI-023] FAST: Efficient Action Tokenization for Vision-Language-Action Models
Paper Card 论文标题:FAST: Efficient Action Tokenization for Vision-Language-Action Models 论文作者:Karl Pertsch, Kyle Stachowicz, Brian Ichter, Danny Driess, Suraj Nair, Quan Vuong, Oier Mees, Chelsea Finn, Sergey Levine 论文链接&…...
解锁微服务:五大进阶业务场景深度剖析
目录 医疗行业:智能诊疗的加速引擎 电商领域:数据依赖的破局之道 金融行业:运维可观测性的提升之路 物流行业:智慧物流的创新架构 综合业务:服务依赖的优化策略 医疗行业:智能诊疗的加速引擎 在医疗行业迈…...
java入门笔记基础语法篇(4)
变量 在Java中,每个变量都有一个类型(type)。在声明变量时,变量的类型位于变量 名之前。例如: int days; double salary; long earthPopulation; boolean done; 在Java中,每个声明以分号结束。变量名必须…...
java语法学习
目录 一、基础语法 1.注释 2.关键字 3.字面量 4.变量 定义与使用 存储 5.数据类型 6.标识符 7.集成环境 二、运算符 1.概念 2.种类 算术运算符 除法与取模 转化规则 自增减 赋值运算符 关系运算符 逻辑运算符 短路运算符 三元运算符 其它运算符 三、流…...
装饰SpringMVC的适配器实现响应自动包装
文章目录 1.common-tool-starter1.目录结构2.ResultWrapper.java 2.common-web-starter1.目录结构2.IgnoredResultWrapper.java 自定义注解,忽略对返回结果的自动包装3.ReturnValueHandlersDecorator.java 对适配器进行扩展的装饰器4.WebAutoConfiguration.java 将装…...
【Rust自学】15.4. Drop trait:告别手动清理,释放即安全
喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 15.4.1. Drop trait的意义 类型如果实现了Drop trait,就可以让程序员自定义当值…...
【算法】【归并排序】AcWing 算法基础 788. 逆序对的数量
题目 给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。 逆序对的定义如下:对于数列的第 i个和第 j 个元素,如果满足 i<j且 a[i]>a[j],则其为一个逆序对;否则不是。 输入格式 第一行包含整数 n&#…...
一个局域网通过NAT访问另一个地址重叠的局域网(IP方式访问)
正文共:1335 字 7 图,预估阅读时间:4 分钟 现在,我们已经可以通过调整两台设备的组合配置(地址重叠时,用户如何通过NAT访问对端IP网络?)或仅调整一台设备的配置(仅操作一…...
05-机器学习-数据标注
一、学习数据标注的核心目标 数据标注不仅是“打标签”,而是理解数据与AI模型之间的桥梁。需要掌握: 标注技术:不同任务类型的标注方法(如分割、实体识别)。标注工具:高效使用专业工具(如CVAT…...
LQ1052 Fibonacci斐波那契数列
题目描述 Fibonacci斐波那契数列也称为兔子数列,它的递推公式为:FnFn-1Fn-2,其中F1F21。 当n比较大时,Fn也非常大,现在小蓝想知道,Fn除以10007的余数是多少,请你编程告诉她。 输入 输入包含一…...
AWTK 骨骼动画控件发布
Spine 是一款广泛使用的 2D 骨骼动画工具,专为游戏开发和动态图形设计设计。它通过基于骨骼的动画系统,帮助开发者创建流畅、高效的角色动画。本项目是基于 Spine 实现的 AWTK 骨骼动画控件。 代码:https://gitee.com/zlgopen/awtk-widget-s…...
分库分表后如何进行join操作
在分库分表后的系统中,进行表之间的 JOIN 操作比在单一数据库表中复杂得多,因为涉及的数据可能位于不同的物理节点或分片中。此时,传统的 SQL JOIN 语句不能直接用于不同分片的数据,以下是几种处理这样的跨分片 JOIN 操作的方法&a…...
arkui-x 前端布局编码模板
build() {Column() {Row() {// 上侧页面布局实现}// 下侧页面布局实现}.width(Const.THOUSANDTH_1000).height(Const.THOUSANDTH_1000).justifyContent(FlexAlign.SpaceBetween).backgroundImage($r(app.media.background_xxx)).backgroundImageSize(ImageSize.Cover).backgrou…...
宝塔面板SSL加密访问设置教程
参考:https://www.bt.cn/bbs/thread-117246-1-1.html 如何快速使用证书加密访问面板 因早期默认未开启https访问所以没有相关的风险提醒,现面板默认已开启https加密访问、提升安全性 由于采用的是服务器内部本身签发证书,不被公网浏览器信任请参考以下步…...
c++ set/multiset 容器
1. set 基本概念 简介: 所有元素都会在插入时自动排序本质: set/multiset属于关联式容器,底层结构是用二叉树实现。set 和 multiset 区别: set容器不允许有重复的元素。 multiset允许有重复的元素。2. set 构造和赋值 构造&a…...
前部分知识复习02
一、物体的屏幕UV坐标 float2 ScreenUV i.pos.xy / _ScreenParams.xy; 二、抓取屏幕图像 GrabPass{" _A "} //_A为贴图图像名称 之后需在Pass中声明该贴图才能在Pass中引用此贴图 三、屏幕抓取并制作热效应代码 Shader"unity/HeatDistort 07" {Pr…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...
