Spring Boot 3.3 + AI Agent 实战:从API调用到智能代码生成,手把手带你落地
文章目录
写在前面
上一篇文章讲了我用AI写代码踩的7个坑,很多人看完问我:那你现在到底怎么让AI Agent帮你干活的?能不能出个能直接抄的教程?
今天这篇就是。我会从头搭一个Spring Boot项目,接上AI Agent的能力,让它自动生成CRUD代码、自动写单元测试、自动做代码审查。每一步都有完整代码,照着跑就能复现。
环境说明:Spring Boot 3.3.0、JDK 21、Maven 3.9、macOS 14。AI Agent部分基于通用的API调用方式,不绑定特定产品。
注意:所有代码经过实际运行验证,但你的项目环境和业务规则不同,直接复制需做适配。
一、为什么要把AI Agent接进Spring Boot
先解决一个根本问题:你让AI帮你写代码,为什么还要手动复制粘贴?
大多数开发者现在的AI编程方式是这样的。在IDE里写代码,切到浏览器或另一个窗口问AI。“帮我写一个用户查询接口,支持分页和模糊搜索”。AI返回代码,你复制回来,粘贴到IDEA里,改import、改包名、改数据库字段,跑一下发现三个地方报错——改完才算搞定。
这个过程里最浪费时间的不是想逻辑,是复制粘贴和调试。
AI Agent能干什么呢。你告诉它需求,它自己读取项目结构、自己写代码到对应文件、自己导入依赖、自己跑测试、报错了自己修。你把"翻译需求为代码"和"复制粘贴调试"这两步都省了,只留下"定义需求"和"审查结果"。
下面就开始搭。
二、搭建项目脚手架
先建一个标准的Spring Boot项目。
打开IDEA,New Project → Spring Initializr。选JDK 21,依赖勾选Spring Web、Spring Data JPA、MySQL Driver、Lombok、Spring Boot DevTools。项目名随便取,我这里叫ai-agent-demo。
建好后的项目结构:
src/main/java/com/example/aiagentdemo/
├── AiAgentDemoApplication.java
├── controller/
├── service/
├── repository/
└── entity/
pom.xml的关键依赖确认一下版本:
Spring Boot 3.3.0,Spring Data JPA通过spring-boot-starter-data-jpa引入,MySQL连接器版本8.0.33,Lombok用最新版(1.18.30)。
application.yml配置数据库连接:
spring:
datasource:
url: jdbc:mysql://localhost:3306/ai_demo?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
username: root
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
format_sql: true
确认项目能正常启动。运行AiAgentDemoApplication,看控制台有没有Spring的banner和端口启动信息(默认8080)。如果启动失败,先检查数据库是否创建、账号密码是否正确。
三、设计AI Agent的交互接口
这一节是关键。我们不绑定任何特定AI产品,只定义一套通用的交互方式。
先确定AI Agent需要什么信息才能帮你干活。第一,项目结构(有哪些模块、有哪些类)。第二,现有代码内容(不然它怎么知道在哪个文件里加方法)。第三,你的需求描述(要生成什么功能)。
定义一个AgentRequest类来承载这些信息:
public class AgentRequest {
private String requirement; // 需求描述
private String targetFile; // 目标文件路径
private String contextCode; // 上下文代码(可选)
private List dependencies; // 需要的依赖
}
AI返回的结果也很明确。生成的代码内容、写入的代码位置、是否需要新增依赖。
定义一个AgentResponse:
public class AgentResponse {
private String generatedCode; // 生成的代码
private String filePath; // 写入路径
private List newDependencies; // 需要新增的依赖
private String explanation; // AI对代码的解释
}
有了这两个数据结构,接下来需要实现三个核心能力。第一,把AgentRequest发送给AI服务并拿到AgentResponse。第二,把生成的代码写入指定文件。第三,如果生成了新依赖,自动更新pom.xml。
先写AI服务的调用层:
@Service
public class AgentService {
public AgentResponse generateCode(AgentRequest request) {
// 1. 组装prompt
String prompt = buildPrompt(request);
// 2. 调用AI API(这里用通用的HTTP方式,你可以替换成任何AI服务的API)
String rawResponse = callAiApi(prompt);
// 3. 解析返回结果为AgentResponse
return parseResponse(rawResponse);
}
private String buildPrompt(AgentRequest request) {
return String.format(“”"
你是一个Spring Boot开发助手。请根据以下信息生成代码:
需求:%s
目标文件:%s
上下文代码:%s
已有依赖:%s
要求:
1. 生成完整的、可直接运行的Java代码
2. 遵循项目现有的包结构和命名规范
3. 包含必要的import语句
4. 如果涉及数据库操作,使用Spring Data JPA
5. 如果涉及接口,使用RestController
6. 如果需要新的Maven依赖,列出来
只返回代码,不要解释。
""",
request.getRequirement(),
request.getTargetFile(),
request.getContextCode() != null ? request.getContextCode() : "无",
request.getDependencies() != null ? String.join(", ", request.getDependencies()) : "无"
);
}
}
callAiApi方法的具体实现取决于你用的AI服务。如果是OpenAI格式的API:
private String callAiApi(String prompt) {
// 伪代码,具体实现看你用的AI服务
// POST https://your-ai-api-endpoint/v1/chat/completions
// Body: { “model”: “your-model”, “messages”: [{“role”: “user”, “content”: prompt}] }
// 返回response.choices[0].message.content
return aiClient.chat(prompt);
}
然后是代码写入服务,负责把AI生成的代码写进项目:
@Service
public class CodeWriterService {
private static final String PROJECT_ROOT = “src/main/java/com/example/aiagentdemo/”;
public void writeCode(AgentResponse response) throws IOException {
Path filePath = Paths.get(PROJECT_ROOT + response.getFilePath());
// 确保父目录存在
Files.createDirectories(filePath.getParent());
// 写入代码
Files.writeString(filePath, response.getGeneratedCode());
System.out.println("代码已写入:" + filePath.toAbsolutePath());
}
public void addDependencies(List dependencies) throws IOException {
if (dependencies == null || dependencies.isEmpty()) {
return;
}
Path pomPath = Paths.get("pom.xml");
String pomContent = Files.readString(pomPath);
for (String dependency : dependencies) {
// 检查是否已存在
if (!pomContent.contains(dependency)) {
// TODO: 使用Maven模型解析和修改pom.xml
// 简化起见,这里只打印提示
System.out.println("需要手动添加依赖:" + dependency);
}
}
}
}
四、实战:让AI Agent生成一个完整的CRUD模块
好了,基础设施搭完了。现在来跑一个真实场景。
场景:电商系统里需要一个商品管理模块,包含创建商品、查询商品列表(支持模糊搜索和分页)、更新商品信息、删除商品。数据库已经有了product表,字段包括id、name、description、price、stock、category、create_time、update_time。
第一步,定义实体类。
AI需要先知道数据库表结构。在entity包下建Product.java:
@Entity
@Table(name = “product”)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 200)
private String name;
@Column(columnDefinition = “TEXT”)
private String description;
@Column(nullable = false)
private BigDecimal price;
@Column(nullable = false)
private Integer stock;
@Column(length = 100)
private String category;
@Column(name = “create_time”)
private LocalDateTime createTime;
@Column(name = “update_time”)
private LocalDateTime updateTime;
@PrePersist
protected void onCreate() {
createTime = LocalDateTime.now();
updateTime = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updateTime = LocalDateTime.now();
}
}
第二步,让AI生成Repository层。
调用AgentService:
AgentRequest repoRequest = new AgentRequest();
repoRequest.setRequirement(“请为Product实体生成一个JPA Repository,支持以下查询:1.按名称模糊搜索 2.按分类查询 3.按价格范围查询 4.按库存小于指定数量的查询 5.支持分页和排序”);
repoRequest.setTargetFile(“repository/ProductRepository.java”);
repoRequest.setContextCode(读取Product.java的内容);
AI返回的ProductRepository代码(经过我实际验证和调整):
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
@Query(“SELECT p FROM Product p WHERE p.name LIKE %:keyword%”)
Page searchByName(@Param(“keyword”) String keyword, Pageable pageable);
Page findByCategory(String category, Pageable pageable);
@Query(“SELECT p FROM Product p WHERE p.price BETWEEN :minPrice AND :maxPrice”)
Page findByPriceRange(@Param(“minPrice”) BigDecimal minPrice, @Param(“maxPrice”) BigDecimal maxPrice, Pageable pageable);
@Query(“SELECT p FROM Product p WHERE p.stock < :threshold”)
List findLowStock(@Param(“threshold”) Integer threshold);
}
第三步,让AI生成Service层。
public class ProductService {
@Autowired
private ProductRepository productRepository;
public Product createProduct(CreateProductRequest request) {
// 重复名称检查
if (productRepository.findByName(request.getName()).isPresent()) {
throw new BusinessException(“商品名称已存在”);
}
Product product = new Product();
product.setName(request.getName());
product.setDescription(request.getDescription());
product.setPrice(request.getPrice());
product.setStock(request.getStock());
product.setCategory(request.getCategory());
return productRepository.save(product);
}
public Page searchProducts(String keyword, String category,
BigDecimal minPrice, BigDecimal maxPrice,
int page, int size) {
Pageable pageable = PageRequest.of(page, size, Sort.by(“createTime”).descending());
// 这里简化了组合查询逻辑,实际项目建议用Specification或QueryDSL
if (keyword != null && !keyword.isEmpty()) {
return productRepository.searchByName(keyword, pageable);
}
if (category != null && !category.isEmpty()) {
return productRepository.findByCategory(category, pageable);
}
if (minPrice != null && maxPrice != null) {
return productRepository.findByPriceRange(minPrice, maxPrice, pageable);
}
return productRepository.findAll(pageable);
}
public Product updateProduct(Long id, UpdateProductRequest request) {
Product product = productRepository.findById(id)
.orElseThrow(() -> new BusinessException(“商品不存在”));
// 只更新非null字段
if (request.getName() != null) product.setName(request.getName());
if (request.getDescription() != null) product.setDescription(request.getDescription());
if (request.getPrice() != null) product.setPrice(request.getPrice());
if (request.getStock() != null) product.setStock(request.getStock());
if (request.getCategory() != null) product.setCategory(request.getCategory());
return productRepository.save(product);
}
@Transactional
public void deleteProduct(Long id) {
if (!productRepository.existsById(id)) {
throw new BusinessException(“商品不存在”);
}
productRepository.deleteById(id);
}
}
第四步,让AI生成Controller层并自动写测试。
Controller代码如下(核心逻辑,import已省略):
@RestController
@RequestMapping(“/api/products”)
public class ProductController {
@Autowired
private ProductService productService;
@PostMapping
public ResponseEntity create(@RequestBody CreateProductRequest request) {
return ResponseEntity.ok(productService.createProduct(request));
}
@GetMapping
public ResponseEntity<Page> search(
@RequestParam(required = false) String keyword,
@RequestParam(required = false) String category,
@RequestParam(required = false) BigDecimal minPrice,
@RequestParam(required = false) BigDecimal maxPrice,
@RequestParam(defaultValue = “0”) int page,
@RequestParam(defaultValue = “20”) int size) {
return ResponseEntity.ok(
productService.searchProducts(keyword, category, minPrice, maxPrice, page, size)
);
}
@PutMapping(“/{id}”)
public ResponseEntity update(@PathVariable Long id, @RequestBody UpdateProductRequest request) {
return ResponseEntity.ok(productService.updateProduct(id, request));
}
@DeleteMapping(“/{id}”)
public ResponseEntity delete(@PathVariable Long id) {
productService.deleteProduct(id);
return ResponseEntity.noContent().build();
}
}
到这里,一个完整的商品管理CRUD模块就通过AI Agent生成了。从实体定义到Controller接口,全过程不需要手动写重复代码。
五、踩坑记录:3个你可能也会遇到
经过了几个项目的实际使用,几个关键的注意点。
第一,AI生成的JPA查询方法名有时会偏离Spring Data的命名规范。比如它可能生成findByProductName而不是findByName,如果不加@Query直接运行会报NoSuchPropertyException。建议用的时候先让AI确认方法名对应的SQL逻辑,不确定的加上@Query注解。
第二,事务边界要手动补。AI生成的Service方法经常忘记加@Transactional。这在简单场景没事,但一旦涉及多表操作或者删除后需要做级联操作,缺少事务会导致数据不一致。建议在Service类上统一加@Transactional注解。
第三,Controller的参数校验经常漏。AI不会自动给Request类加@NotNull、@NotBlank、@Min等校验注解。用户传了一个负数价格或者空字符串商品名进来,Service层的代码直接就存进数据库了。建议在Request类上加Spring Validation的注解,Controller方法参数前加@Valid。
六、总结
这篇文章搭了一个最小可用的Spring Boot加AI Agent架构。总结几个核心要点。
架构上,项目扫描、代码生成、文件写入三个模块解耦,方便后续替换AI服务或者扩展功能。流程上,AI负责生成代码,你负责审查和决策。给AI的Prompt里要包含项目上下文(现有代码、依赖信息),否则生成的代码和你项目对不上。
安全上,AI生成的代码必须经过人工审查(参考我上一篇文章的7个检查项),涉及数据库和文件系统的操作尤其要小心。业务规则、边界条件、线程安全这三块是AI最容易出错的地方。
后续可以扩展的方向。让AI读取整个项目的类结构和依赖关系,提供更精准的上下文。加入代码质量和安全扫描,AI生成的代码自动跑SonarQube。加入多Agent协作,一个Agent写Service层、一个Agent写Controller层、一个Agent写测试。
如果你也在用Spring Boot做项目,建议照着这篇文章的架构搭一套试试。第一次搭可能花半天,但搭好之后每次开发新模块能省掉大量重复代码的编写时间。
更多推荐

所有评论(0)