尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

使用 Java、Spring Boot 和 Spring AI 开发符合 A2A 标准的 AI 智能体

使用 Java、Spring Boot 和 Spring AI 开发符合 A2A 标准的 AI 智能体
📅 发布时间:2026/6/19 18:49:56

AI 智能体指的是一种软件实体,它能够利用自然语言处理、机器学习或推理系统等人工智能技术,自主感知、推理和行动,以实现特定目标。

我为 Telex 开发了一个 AI 智能体,该智能体接收一个正则表达式模式,并就该模式所匹配的字符串类型提供易于理解的解释。开发此智能体的灵感源于我在此之前开发的一个 API(您可以在此处查看该项目),在该 API 中我必须使用正则表达式进行一些自然语言处理。尽管我之前学习过正则表达式,但感觉像是第一次见到它。正则表达式就是这样。因此,当 Telex 为其平台寻求更多 AI 智能体时,我决定开发这个智能体。

以下是我使用 Java、Spring AI 和 Spring Boot 实现它的过程。

初始设置

1. Spring Boot 项目初始化

我使用 Spring 提供的初始化工具来初始化项目。请注意,我在依赖项中包含了 Spring Web 和 Open AI。

初始化 Spring 项目

2. 设置 API 凭证

在我的 application.properties 文件中,我设置了 Spring AI 以使用我的 API 凭证(我的 API 密钥)。我通过 Google AI Studio 获得了一个免费的 Google Gemini API 密钥。我的 application.properties 文件设置如下:

spring.config.import=classpath:AI.propertiesspring.application.name=regexplainspring.ai.openai.api-key = ${GEMINI_API_KEY}
spring.ai.openai.base-url https://generativelanguage.googleapis.com/v1beta/openai
spring.ai.openai.chat.completions-path = /chat/completions
spring.ai.openai.chat.options.model = gemini-2.5-pro

第一行导入了包含我 API 密钥的文件。重要的是不要将您的 API 密钥暴露给公众。该文件与 application.properties 位于同一文件夹中。

3. 首次项目运行

使用我的包管理器(Maven),我安装了所需的依赖项。然后我运行了我的主类,以确保一切正常。如果您到目前为止一切都做对了,您的项目应该可以无错误运行。如果遇到任何错误,请在 Google 上查找解决方法。

A2A 请求和响应模型

在深入实现之前,让我们先谈谈符合 A2A 标准的请求和响应的结构。A2A 协议遵循标准的 JSON-RPC 2.0 结构来处理请求和响应。

所有方法调用都封装在一个请求对象中,其结构如下:

{"jsonrpc": "2.0","method": "String","id": "String | Integer","params": "Message"
}

响应对象有些类似:

{"jsonrpc": "2.0","id": "String | Integer | null","result?": "Task | Message | null","error?": "JSONRPCError"
}

响应中的 ID 必须与请求中的 ID 相同。

有关 A2A 协议的更多信息,请查阅 A2A 协议文档。

以上就是请求和响应的通用结构。我开发这个智能体是为了在 Telex 平台上使用,因此我的部分实现可能特定于 Telex。

现在进入实现部分。我创建了一个名为 model 的文件夹,用于存储我的模型。请求模型类 A2ARequest 如下所示:

public class A2ARequest {private String id;private RequestParamsProperty params;public A2ARequest(String id, RequestParamsProperty params) {this.id = id;this.params = params;}// getters and setters
}

RequestParamsProperty 类代表了 params 中包含信息的结构。它如下所示:

public class RequestParamsProperty {private HistoryMessage message;private String messageId;public RequestParamsProperty(HistoryMessage message, String messageId) {this.message = message;this.messageId = messageId;}// getters and setter
}

HistoryMessage 类如下所示:

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class HistoryMessage {private String kind;private String role;private List<MessagePart> parts;private String messageId;private String taskId;public HistoryMessage() {}public HistoryMessage(String role, List<MessagePart> parts, String messageId, String taskId) {this.kind = "message";this.role = role;this.parts = parts;this.messageId = messageId;this.taskId = taskId;}// getters and setters
}

注解的作用是让 Spring 知道在请求和响应的 JSON 表示中包含什么。如果请求中不存在某个属性,它应该忽略它并在类中将其设置为 null。如果某个属性设置为 null,则不应将其包含在响应中。

MessagePart 类如下所示:

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MessagePart {private String kind;private String text;private List<MessagePart> data;public MessagePart(String kind, String text, List<MessagePart> data) {this.kind = kind;this.text = text;this.data = data;}// getters and setters
}

以上就是表示从 Telex 接收的请求结构所需的所有类。现在需要为我的响应创建一个模型,以及表示响应所需的所有支持类。

A2AResponse 类:

@JsonInclude(JsonInclude.Include.NON_NULL)
public class A2AResponse {private final String jsonrpc;@JsonInclude(JsonInclude.Include.ALWAYS)private String id;private Result result;private CustomError error;public A2AResponse() {this.jsonrpc = "2.0";}public A2AResponse(String id, Result result, CustomError error) {this.jsonrpc = "2.0";this.id = id;this.result = result;this.error = error;}//getters and setters
}

Result 类:

public class Result {private String id;private String contextId;private TaskStatus status;private List<Artifact> artifacts;private List<HistoryMessage> history;private String kind;public Result() {}public Result(String id, String contextId, TaskStatus status, List<Artifact> artifacts, List<HistoryMessage> history, String task) {this.id = id;this.contextId = contextId;this.status = status;this.artifacts = artifacts;this.history = history;this.kind = task;}// getters and setters
}

CustomError 类:

public class CustomError {private int code;private String message;private Map<String, String> data;public CustomError(int code, String message, Map<String, String> data) {this.code = code;this.message = message;this.data = data;}// getters and setters
}

TaskStatus 类:

@JsonInclude(JsonInclude.Include.NON_NULL)
public class TaskStatus {private String state;private Instant timestamp;private HistoryMessage message;public TaskStatus() {}public TaskStatus(String state, Instant timestamp, HistoryMessage message) {this.state = state;this.timestamp = timestamp;this.message = message;}// getters and setters
}

Artifact 类:

public class Artifact {private String artifactId;private String name;private List<MessagePart> parts; // 稍后复查此类型public Artifact() {}public Artifact(String artifactId, String name, List<MessagePart> parts) {this.artifactId = artifactId;this.name = name;this.parts = parts;}// getters and setters
}

A2A 协议还包含一个称为"智能体卡片"的东西。我也为它创建了一个模型。

public class AgentCard {private String name;private String description;private String url;private Map<String, String> provider;private String version;private Map<String, Boolean> capabilities;private List<String> defaultInputModes;private List<String> defaultOutputModes;private List<Map<String, Object>> skills;public AgentCard() {this.provider = new HashMap<>();this.capabilities = new HashMap<>();this.skills = new ArrayList<>();}// getters and setters
}

模型部分就这些了。继续...

服务类

我的智能体的作用是获取一个正则表达式字符串,然后使用预定义的提示词将其发送到 OpenAI 的 API。服务类负责与 OpenAI 通信,发送提示词并接收响应。我创建了另一个名为 service 的文件夹,我的服务类就放在这里。我是这样编写我的服务类的:

@Service
public class RegExPlainService {private ChatClient chatClient;RegExPlainService(ChatClient.Builder chatClientBuilder) {this.chatClient = chatClientBuilder.build();}@Tool(name = "regexplain", description = "An agent that explains what type of string a regex pattern matches")public String generateResponse(String regex) {return chatClient.prompt("Give me a simple explanation of the type of string matched by this regex pattern: %s. No validating statements from you. Just straight to the point".formatted(regex)).call().content();}
}

@Service 注解允许 Spring Boot 将服务注入到您的控制器中。@Tool 注解将该方法标记为一个智能体工具,如果将来要扩展该智能体以包含该功能,它可以被自主调用。不过目前并不需要它。

控制器

控制器通过 REST API 暴露该智能体。在这个案例中,我有两个端点,一个 GET 端点和一个 POST 端点。我在一个名为 controller 的文件夹中创建了我的控制器。实现如下:

@RestController
public class RegExPlainController {private final RegExPlainService regexplainService;@AutowiredRegExPlainController (RegExPlainService regexplainService) {this.regexplainService = regexplainService;}@GetMapping("/a2a/agent/regexplain/.well-known/agent.json")public ResponseEntity<AgentCard> getAgentCard () {AgentCard agentCard = new AgentCard();agentCard.setName("regexplain");agentCard.setDescription("An agent that provides a simple explanation of the type of string a regex pattern matches");agentCard.setUrl("regexplain-production.up.railway.app/api");agentCard.setProvider("Bituan", null); // 假设 setProvider 处理 Map 的填充agentCard.setVersion("1.0");agentCard.setCapabilities(false, false, false); // 假设 setCapabilities 处理 Map 的填充agentCard.setDefaultInputModes(List.of("text/plain"));agentCard.setDefaultOutputModes(List.of("application/json", "text/plain"));agentCard.setSkill("skill-001", "Explain Regex", "Provides a simple explanation of the type of string a regex pattern matches",List.of("text/plain"), List.of("text/plain"), List.of());return ResponseEntity.ok(agentCard);}@PostMapping("/a2a/agent/regexplain")public ResponseEntity<A2AResponse> explainRegex (@RequestBody A2ARequest request) {String regexRequest;String responseText;// 如果参数无效,返回 403try {regexRequest = request.getParams().getMessage().getParts().get(0).getText();} catch (Exception e) {CustomError error = new CustomError(-32603, "Invalid Parameter", Map.of("details", e.getMessage()));A2AResponse errorResponse = new A2AResponse(null, null,  error);return ResponseEntity.status(HttpStatusCode.valueOf(403)).body(errorResponse);}// 如果调用服务失败,返回错误 500try {responseText = regexplainService.generateResponse(regexRequest);} catch (Exception e) {CustomError error = new CustomError(-32603, "Internal Error", Map.of("details", e.getMessage()));A2AResponse errorResponse = new A2AResponse(null, null,  error);return ResponseEntity.internalServerError().body(errorResponse);}// 构建响应A2AResponse response = new A2AResponse();response.setId(request.getId());// 构建响应 -> 构建结果Result result = new Result();result.setId(UUID.randomUUID().toString());result.setContextId(UUID.randomUUID().toString());result.setKind("task");// 构建响应 -> 构建结果 -> 构建状态TaskStatus status = new TaskStatus();status.setState("completed");status.setTimestamp(Instant.now());// 构建响应 -> 构建结果 -> 构建状态 -> 构建消息HistoryMessage message = new HistoryMessage();message.setRole("agent");message.setParts(List.of(new MessagePart("text", responseText, null)));message.setKind("message");message.setMessageId(UUID.randomUUID().toString());// 构建响应 -> 构建结果 -> 构建状态 (续)status.setMessage(message);// 构建响应 -> 构建结果 -> 构建工件List<Artifact> artifacts = new ArrayList<>();Artifact artifact = new Artifact();artifact.setArtifactId(UUID.randomUUID().toString());artifact.setName("regexplainerResponse");artifact.setParts(List.of(new MessagePart("text", responseText, null)));artifacts.add(artifact);// 构建响应 -> 构建结果 -> 构建历史记录List<HistoryMessage> history = new ArrayList<>();// 构建响应 -> 构建结果 (续)result.setStatus(status);result.setArtifacts(artifacts);result.setHistory(history);// 构建响应 (续)response.setResult(result);return ResponseEntity.ok(response);}
}
  • GET 端点使用的路由路径是 A2A 协议标准中用于获取智能体卡片的部分。智能体卡片是对智能体及其功能的描述。
  • POST 端点接收一个符合 A2A 标准的请求,执行智能体,然后返回适当的响应。

结论

就是这样。这就是我编写 Regexplain 的过程。

通过这个示例,您可以从头开始构建您的 AI 智能体并使其符合 A2A 标准。或者,至少我希望这能让您对如何使用 Java 开发符合 A2A 标准的 AI 智能体有所了解。


【注】本文译自:Developing an A2A-compliant AI Agent with Java, Spring Boot and Spring AI - DEV Community

相关新闻

  • 2025年口碑好的装配式轻钢龙骨热门厂家推荐榜单
  • 2025年评价高的三层式恒温恒湿试验箱用户口碑最好的厂家榜
  • 2025年11月远程控制软件推荐:主流排行榜与口碑评价对比指南

最新新闻

  • 5步掌握FitGirl游戏启动器:高效管理压缩游戏的终极工具
  • 2026年西安评价高的玻璃门生产厂家哪家强 - 品牌鉴赏官2026
  • 江门报名 CPPM 注册采购经理哪家靠谱?机构选择避坑指南 - 众智商学院课程中心
  • 如何在OBS直播中添加实时语音识别字幕:免费开源插件终极指南
  • 如何快速掌握跨设备控制:终极多平台键鼠共享方案
  • 2026年台州市PMP培训机构哪家好?官方授权R.E.P.报考指南 - 众智商学院课程中心

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号