尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于Spring Boot与LangChain Agent构建智能业务系统实战

基于Spring Boot与LangChain Agent构建智能业务系统实战 在实际企业级应用开发中将AI能力与传统业务系统深度融合正从概念验证走向生产落地。一个典型的场景是如何利用大语言模型LLM的推理和规划能力为传统业务流程注入智能决策和自然语言交互能力。本文将以一个“AI无人机租赁系统”为蓝本探讨如何结合Java Spring Boot后端、LangChain框架以及Agent智能体技术构建一个具备智能客服、任务规划和自动化执行能力的业务系统。这个项目不仅适用于学习LangChain Agent的集成其架构思路也完全可用于毕业设计、课程设计或作为面试中展示复杂系统设计能力的案例。我们将从零开始构建一个模拟的无人机租赁平台。用户可以通过自然语言如“我想租一架能航拍4K视频的无人机明天下午在西湖区使用3小时”发起请求系统背后的AI Agent将理解用户意图自动查询库存、计算费用、生成订单甚至处理一些简单的异常协商。整个过程我们将重点放在如何将Spring Boot的稳健性与LangChain Agent的灵活性结合起来并解释每一步的设计考量与潜在陷阱。1. 理解核心组件LangChain与Agent为何能驱动业务系统在开始编码之前必须厘清几个核心概念以及它们在这个项目中的角色。很多初学者直接上手代码遇到问题后才发现对基础组件的理解有偏差。1.1 LangChain不只是调用大模型的SDKLangChain是一个用于开发由语言模型驱动的应用程序的框架。它的核心价值在于提供了丰富的“链”Chains和“代理”Agents抽象帮助开发者将LLM与外部工具、数据源和记忆系统连接起来。在我们的无人机租赁系统中LangChain扮演着“智能中枢”的角色。它负责模板化提示词将用户查询、业务规则、库存数据等动态填充到给LLM的指令中。工具调用定义一系列Java方法作为“工具”如queryDrones、calculatePrice、createOrder并让LLM学会在合适的时候调用它们。控制流管理通过Agent决定是先查库存还是先算价格或者当库存不足时是建议更换机型还是修改时间。简单地将LangChain视为一个LLM API封装库是片面的。它的设计哲学是构建可执行的、多步骤的推理应用。1.2 Agent具备规划和执行能力的智能体Agent是LangChain中的高级抽象可以理解为“一个能使用工具的LLM”。与简单的链式调用不同Agent可以根据LLM的推理自主决定下一步该执行哪个工具并循环执行直到任务完成或无法继续。在我们的场景中一个RentalAgent需要完成以下任务理解意图解析用户自然语言请求提取关键实体设备类型、时间、地点、规格。制定计划决定需要调用哪些工具以及调用顺序。执行与观察调用工具如查询数据库并将工具返回的结果结构化数据作为新的上下文反馈给LLM。决策与输出根据所有工具执行结果生成最终的自然语言回复或结构化动作如创建订单。1.3 系统架构总览Spring Boot与AI层的协作整个系统采用分层架构确保业务逻辑与AI逻辑解耦。[用户界面/API] - [Spring Boot Controller] - [Agent服务层] - [工具层/业务服务层] - [数据库/外部API] ^ | [LangChain LLM (如OpenAI, 本地模型)]Spring Boot层提供RESTful API、用户认证、订单持久化、库存管理等标准企业级功能。它是系统的主体和事实来源。AI服务层一个独立的Spring Service内部封装了LangChain的Agent实例。它接收来自Controller的文本请求协调Agent执行并返回结果。工具层一系列实现了Tool接口的Spring Bean。这些工具本质上是代理了Spring Boot业务服务如DroneService,OrderService的方法使Agent能够安全地操作业务数据。这种设计的优势在于AI层是“可插拔”的。如果未来需要更换LLM提供商或调整Agent逻辑只需修改AI服务层而不会影响核心业务代码。2. 环境准备与项目初始化我们将使用Spring Boot 3.x和LangChain4J一个优秀的Java版LangChain实现进行开发。选择LangChain4J是因为它能与Spring生态无缝集成。2.1 开发环境与依赖清单首先确保本地环境符合以下要求组件版本要求说明JDK17 或 21Spring Boot 3.x 的长期支持版本Maven3.6项目管理与构建工具IDEIntelliJ IDEA 或 Eclipse推荐使用IDEA以获得更好的框架支持LLM 接入OpenAI GPT 或 本地模型需准备相应的API Key或模型文件创建一个标准的Spring Boot项目。以下是pom.xml中需要关注的核心依赖?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.2.5/version !-- 使用稳定版本 -- relativePath/ /parent groupIdcom.example/groupId artifactIdai-drone-rental/artifactId version0.0.1-SNAPSHOT/version nameai-drone-rental/name descriptionAI-Powered Drone Rental System/description properties java.version17/java.version langchain4j.version0.30.0/langchain4j.version !-- 确认使用最新稳定版 -- /properties dependencies !-- Spring Boot 基础 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-jpa/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-validation/artifactId /dependency !-- 数据库 (以H2内存数据库为例便于演示) -- dependency groupIdcom.h2database/groupId artifactIdh2/artifactId scoperuntime/scope /dependency !-- LangChain4J 核心 -- dependency groupIddev.langchain4j/groupId artifactIdlangchain4j/artifactId version${langchain4j.version}/version /dependency !-- LangChain4J 与 Spring Boot 集成 -- dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-spring-boot-starter/artifactId version${langchain4j.version}/version /dependency !-- 使用OpenAI作为LLM (也可替换为ollama等) -- dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-open-ai/artifactId version${langchain4j.version}/version /dependency !-- 工具类 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId configuration excludes exclude groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /exclude /excludes /configuration /plugin /plugins /build /project2.2 关键配置连接LLM与定义Agent行为在application.yml中我们需要配置LLM连接和Agent的基本参数。这里以OpenAI为例# application.yml spring: datasource: url: jdbc:h2:mem:testdb driver-class-name: org.h2.Driver username: sa password: jpa: hibernate: ddl-auto: update show-sql: true # LangChain4J 与 OpenAI 配置 langchain4j: open-ai: chat-model: api-key: ${OPENAI_API_KEY:your-api-key-here} # 强烈建议通过环境变量注入 model-name: gpt-3.5-turbo # 或 gpt-4 temperature: 0.2 # 较低的温度使输出更确定适合工具调用 max-tokens: 1000 timeout: 60s streaming: false # 演示阶段关闭流式简化处理 # 自定义Agent配置 ai: agent: system-prompt: | 你是一个专业的无人机租赁助手。你的职责是帮助用户查询可租赁的无人机、计算租赁费用、创建订单。 你必须严格遵守以下规则 1. 在回答用户任何关于库存、价格、订单的问题前必须先调用相应的工具获取准确数据。 2. 用户可能会提供不完整的信息如只说了“想租无人机”你必须通过对话引导用户提供必要信息租赁开始时间、结束时间、大致用途如航拍、测绘。 3. 如果用户没有指定机型你可以根据用途推荐。 4. 所有金额必须以人民币(CNY)为单位明确告知用户。 5. 订单创建后必须向用户提供订单号。 你的回复应友好、专业且简洁。注意api-key务必通过环境变量OPENAI_API_KEY传入不要将密钥硬编码在配置文件中提交到代码仓库。对于本地模型如通过Ollama部署则需要配置不同的langchain4j.ollama属性。3. 构建业务基础实体、仓库与服务在引入AI之前必须先搭建好坚实的业务基础。这是一个标准的Spring Boot三层架构实现。3.1 定义核心领域模型首先创建无人机、订单等实体类。// Drone.java package com.example.airdrone.entity; import jakarta.persistence.*; import lombok.Data; import java.math.BigDecimal; Entity Data Table(name drones) public class Drone { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; private String model; // 型号如 DJI Air 3 private String type; // 类型如 CONSUMER, PROFESSIONAL private String capability; // 能力描述如 4K航拍 热成像 private BigDecimal hourlyRate; // 每小时租金 private Integer stock; // 库存数量 private Boolean isActive true; // 是否可租 }// RentalOrder.java package com.example.airdrone.entity; import jakarta.persistence.*; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; Entity Data Table(name rental_orders) public class RentalOrder { Id private String orderId; // 自定义订单号如 ORD20240520001 ManyToOne JoinColumn(name drone_id) private Drone drone; private String customerName; private String customerContact; private LocalDateTime startTime; private LocalDateTime endTime; private BigDecimal totalAmount; private String status; // CREATED, CONFIRMED, CANCELLED, COMPLETED private LocalDateTime createdAt; }3.2 实现数据访问与业务服务创建Spring Data JPA仓库和对应的服务类。// DroneRepository.java package com.example.airdrone.repository; import com.example.airdrone.entity.Drone; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import java.util.List; public interface DroneRepository extends JpaRepositoryDrone, Long { ListDrone findByIsActiveTrue(); ListDrone findByCapabilityContainingIgnoreCaseAndIsActiveTrue(String capability); ListDrone findByTypeAndIsActiveTrue(String type); }// DroneService.java package com.example.airdrone.service; import com.example.airdrone.entity.Drone; import com.example.airdrone.repository.DroneRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.util.List; Service RequiredArgsConstructor public class DroneService { private final DroneRepository droneRepository; public ListDrone getAllAvailableDrones() { return droneRepository.findByIsActiveTrue(); } public ListDrone findDronesByCapability(String capability) { return droneRepository.findByCapabilityContainingIgnoreCaseAndIsActiveTrue(capability); } public Drone getDroneById(Long id) { return droneRepository.findById(id).orElseThrow(() - new RuntimeException(Drone not found)); } // 检查库存是否充足 public boolean checkStock(Long droneId, Integer required) { Drone drone getDroneById(droneId); return drone.getStock() required; } }订单服务类OrderService包含创建订单、计算费用的逻辑代码类似此处省略。关键在于这些服务将是后续暴露给AI Agent的“工具”的实际执行者。4. 集成LangChain4J定义工具与构建Agent这是本项目的核心环节。我们将把上一步创建的业务服务包装成LangChain4J的Tool然后组装成一个可用的Agent。4.1 将业务服务封装为AI工具LangChain4J的Tool注解允许我们将任何Spring Bean的方法暴露给AI调用。工具方法的描述至关重要它直接决定了LLM是否能正确理解和使用该工具。// RentalTools.java package com.example.airdrone.ai.tools; import com.example.airdrone.entity.Drone; import com.example.airdrone.service.DroneService; import com.example.airdrone.service.OrderService; import dev.langchain4j.agent.tool.Tool; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.List; import java.util.stream.Collectors; Component RequiredArgsConstructor public class RentalTools { private final DroneService droneService; private final OrderService orderService; /** * 工具1查询所有可用无人机 * LLM会根据用户对机型、功能的模糊描述决定是否调用此工具获取列表。 */ Tool(查询所有可租赁的无人机列表返回型号、类型、能力和每小时租金。) public String queryAllAvailableDrones() { ListDrone drones droneService.getAllAvailableDrones(); if (drones.isEmpty()) { return 当前没有可租赁的无人机。; } return drones.stream() .map(d - String.format(型号: %s, 类型: %s, 功能: %s, 时租: %.2f元, 库存: %d, d.getModel(), d.getType(), d.getCapability(), d.getHourlyRate(), d.getStock())) .collect(Collectors.joining(\n)); } /** * 工具2根据功能关键词查询无人机 * 这是更精准的查询工具。 */ Tool(根据功能描述例如4K、热成像、长续航查询符合条件的无人机。) public String queryDronesByCapability(String capabilityDescription) { ListDrone drones droneService.findDronesByCapability(capabilityDescription); if (drones.isEmpty()) { return String.format(没有找到功能包含%s的无人机。, capabilityDescription); } return drones.stream() .map(d - String.format(型号: %s, 功能: %s, 时租: %.2f元, d.getModel(), d.getCapability(), d.getHourlyRate())) .collect(Collectors.joining(\n)); } /** * 工具3计算租赁费用 * LLM需要从对话中提取出droneId, startTime, endTime等参数来调用此工具。 * 注意工具方法参数名应清晰LangChain会将其传递给LLM。 */ Tool(计算租赁费用。需要提供无人机型号ID、租赁开始时间和结束时间。) public String calculateRentalCost(Long droneId, LocalDateTime startTime, LocalDateTime endTime) { // 参数校验 if (startTime.isAfter(endTime)) { return 错误租赁开始时间不能晚于结束时间。; } if (startTime.isBefore(LocalDateTime.now())) { return 错误租赁开始时间不能是过去的时间。; } // 调用业务服务计算 try { BigDecimal cost orderService.calculateCost(droneId, startTime, endTime); return String.format(租赁费用计算成功。总计%.2f元。, cost); } catch (RuntimeException e) { return 计算费用时出错 e.getMessage(); } } /** * 工具4创建租赁订单 * 这是最终的执行工具。 */ Tool(创建租赁订单。需要提供无人机型号ID、客户姓名、联系方式、租赁开始和结束时间。) public String createRentalOrder(Long droneId, String customerName, String customerContact, LocalDateTime startTime, LocalDateTime endTime) { try { String orderId orderService.createOrder(droneId, customerName, customerContact, startTime, endTime); return String.format(订单创建成功订单号%s。请妥善保管。, orderId); } catch (RuntimeException e) { return 创建订单失败 e.getMessage(); } } }关键点解释Tool注解其中的字符串描述是给LLM看的“说明书”必须清晰、准确说明工具的用途和所需参数。参数设计工具方法的参数应使用明确的类型如Long,LocalDateTime,String这有助于LangChain进行类型转换和参数提取。返回值工具应返回一个字符串结果这个结果会被反馈给LLM作为下一步推理的上下文。结果应信息充分且格式友好。4.2 配置与装配AI Agent服务接下来我们创建一个Spring Service来组装这些工具并构建一个可用的Agent。// DroneRentalAgentService.java package com.example.airdrone.ai; import dev.langchain4j.agent.tool.ToolSpecification; import dev.langchain4j.memory.ChatMemory; import dev.langchain4j.memory.chat.MessageWindowChatMemory; import dev.langchain4j.model.chat.ChatLanguageModel; import dev.langchain4j.service.AiServices; import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.List; public interface Assistant { String chat(String userMessage); } Service Slf4j RequiredArgsConstructor public class DroneRentalAgentService { private final ChatLanguageModel chatLanguageModel; // 由LangChain4J自动注入配置的模型 private final RentalTools rentalTools; // 我们之前定义的工具Bean private Assistant assistant; Value(${ai.agent.system-prompt}) private String systemPrompt; PostConstruct public void init() { // 1. 构建聊天记忆保留最近10轮对话使Agent有上下文能力 ChatMemory chatMemory MessageWindowChatMemory.withMaxMessages(10); // 2. 使用AiServices.builder()创建Agent this.assistant AiServices.builder(Assistant.class) .chatLanguageModel(chatLanguageModel) .tools(rentalTools) // 注入工具 .chatMemory(chatMemory) // 注入记忆 .systemPrompt(systemPrompt) // 注入系统指令 .build(); log.info(无人机租赁AI助手初始化完成。); } public String chat(String userMessage) { try { // 3. 调用Agent处理用户消息 String response assistant.chat(userMessage); log.info(用户输入: {}, AI回复: {}, userMessage, response); return response; } catch (Exception e) { log.error(AI助手处理消息时出错: {}, userMessage, e); return 抱歉系统处理您的请求时出现了一些问题请稍后再试或联系客服。; } } }代码解析Assistant接口这是一个“代理接口”。AiServices会动态生成此接口的实现将方法调用路由给LLM和工具。这里我们只定义了一个chat方法。PostConstruct在Spring Bean初始化完成后自动构建Agent。确保所有依赖如模型、工具都已就绪。AiServices.builder()这是LangChain4J的核心API。我们指定了LLM模型、工具列表、记忆系统和系统提示词从而创建了一个具备规划与执行能力的Agent。异常处理在chat方法中捕获异常至关重要。LLM API可能不稳定工具执行也可能出错必须给用户一个友好的回退响应。5. 暴露API与运行验证现在我们将Agent服务通过REST API暴露出来并准备一些测试数据完成端到端的验证。5.1 创建控制器// RentalAgentController.java package com.example.airdrone.controller; import com.example.airdrone.ai.DroneRentalAgentService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; RestController RequestMapping(/api/ai-rental) RequiredArgsConstructor public class RentalAgentController { private final DroneRentalAgentService agentService; PostMapping(/chat) public String handleUserQuery(RequestBody ChatRequest request) { if (request.getMessage() null || request.getMessage().trim().isEmpty()) { return 请输入您的需求。; } return agentService.chat(request.getMessage()); } // 简单的请求体 public static class ChatRequest { private String message; // getter and setter public String getMessage() { return message; } public void setMessage(String message) { this.message message; } } }5.2 准备初始数据与启动应用在src/main/resources下创建data.sql让应用启动时自动插入一些测试无人机数据。-- data.sql INSERT INTO drones (model, type, capability, hourly_rate, stock, is_active) VALUES (DJI Air 3, CONSUMER, 4K高清航拍全向避障长续航, 150.00, 5, true), (DJI Mavic 3 Pro, PROFESSIONAL, 4/3 CMOS哈苏相机28倍混合变焦专业航拍, 380.00, 3, true), (Autel EVO Nano, CONSUMER, 轻便型4K 50fps三向避障, 120.00, 4, true), (DJI Matrice 350 RTK, INDUSTRIAL, 测绘、巡检RTK精准定位热成像, 800.00, 2, true), (FreeFly Alta X, INDUSTRIAL, 重型负载电影级拍摄抗风性强, 1200.00, 1, true);现在启动Spring Boot应用。cd ai-drone-rental mvn spring-boot:run看到类似以下的日志表示启动成功Started AiDroneRentalApplication in 5.234 seconds 无人机租赁AI助手初始化完成。5.3 进行端到端测试使用curl或Postman等工具测试API。以下是一个完整的交互示例请求1用户模糊查询curl -X POST http://localhost:8080/api/ai-rental/chat \ -H Content-Type: application/json \ -d {message: 你好我想租一台能拍4K视频的无人机。}预期Agent行为LLM理解用户需要“4K”能力的无人机。决定调用queryDronesByCapability工具参数为“4K”。工具返回符合条件的无人机列表。LLM将列表组织成友好回复。可能回复找到几款支持4K航拍的无人机 1. 型号: DJI Air 3, 功能: 4K高清航拍全向避障长续航, 时租: 150.00元 2. 型号: DJI Mavic 3 Pro, 功能: 4/3 CMOS哈苏相机28倍混合变焦专业航拍, 时租: 380.00元 3. 型号: Autel EVO Nano, 功能: 轻便型4K 50fps三向避障, 时租: 120.00元 请问您对哪款感兴趣或者能告诉我您的具体使用时间和用途吗请求2用户进一步询问并下单curl -X POST http://localhost:8080/api/ai-rental/chat \ -H Content-Type: application/json \ -d {message: 我选DJI Air 3明天下午2点到5点租3个小时。我叫张三电话13800138000。}预期Agent行为LLM从上下文中知道DJI Air 3并提取出租赁时间需要解析为LocalDateTime和用户信息。可能先调用calculateRentalCost计算费用。然后调用createRentalOrder创建订单。将订单结果返回给用户。可能回复费用计算成功。总计450.00元。 订单创建成功订单号ORD20240520001。请妥善保管。通过这个流程我们验证了Agent能够理解多轮对话上下文、正确选择工具、提取参数并执行业务流程。6. 核心机制剖析与高级配置项目跑通后我们需要深入理解其工作机制并进行优化配置使其更稳定、更可控。6.1 Agent的推理与执行循环LangChain4J的AiServices默认使用ReAct模式。其内部循环大致如下思考LLM根据当前对话历史和系统提示思考下一步该做什么调用工具还是直接回答。行动如果决定调用工具则输出一个结构化的工具调用请求包含工具名和参数。观察框架执行对应的Java工具方法获取结果字符串。再思考LLM将工具执行结果作为新的上下文再次思考决定是继续调用工具还是给出最终答案。这个循环会一直进行直到LLM认为任务完成或达到最大迭代次数。6.2 关键配置参数与调优在application.yml中我们可以对Agent行为进行更精细的控制langchain4j: open-ai: chat-model: # ... 其他配置 temperature: 0.2 # (关键) 低温度使输出更确定工具调用更准确。调高会更有创造性但可能出错。 max-tokens: 1000 # 以下是一些高级参数可通过 properties 设置 # top-p: 0.9 # frequency-penalty: 0.0 # presence-penalty: 0.0 # 可配置Agent执行策略 agent: max-iterations: 10 # 限制Agent最大思考-执行循环次数防止死循环在代码中也可以通过AiServices的Builder进行配置this.assistant AiServices.builder(Assistant.class) .chatLanguageModel(chatLanguageModel) .tools(rentalTools) .chatMemory(chatMemory) .systemPrompt(systemPrompt) .maxRetries(2) // 工具调用失败重试次数 .build();6.3 处理复杂参数与类型转换有时用户会说“明天下午两点”而工具方法需要LocalDateTime。LangChain4J内置了常见类型的转换器但复杂情况需要自定义。方案一在工具方法内进行解析Tool(计算租赁费用。需要提供无人机型号ID、租赁开始时间(如明天14:00)和结束时间。) public String calculateRentalCost(Long droneId, String startTimeStr, String endTimeStr) { LocalDateTime startTime parseDateTime(startTimeStr); // 自定义解析逻辑 LocalDateTime endTime parseDateTime(endTimeStr); // ... 后续计算 }方案二使用P注解提供更详细的参数描述public String calculateRentalCost(P(无人机在数据库中的唯一ID) Long droneId, P(租赁开始时间格式为YYYY-MM-DD HH:MM例如2024-05-21 14:00) LocalDateTime startTime, P(租赁结束时间格式同上) LocalDateTime endTime) { // ... }P注解的描述会帮助LLM更好地理解如何提供参数。7. 常见问题排查与调试技巧集成AI Agent的过程不会一帆风顺。以下是几个典型问题及其排查路径。7.1 问题一Agent不调用工具直接胡言乱语现象用户输入明确需求但Agent直接编造了一个库存列表或订单号没有调用工具。可能原因与排查系统提示词不明确检查system-prompt是否强制要求“必须先调用工具”。提示词需要清晰指令。工具描述不清检查Tool注解的描述是否准确说明了工具的功能和输入。描述太模糊会导致LLM无法匹配。LLM温度值过高尝试将temperature降至0.1-0.3降低随机性。上下文不足确认ChatMemory是否正常工作上一轮对话是否被正确传递。解决步骤首先开启LangChain4J的详细日志。logging: level: dev.langchain4j: DEBUG观察日志看LLM的思考过程Thought:和行动Action:输出。如果没有Action说明LLM认为不需要或不知道调用工具。优化提示词例如“你必须通过调用queryDronesByCapability工具来获取无人机信息严禁自行编造数据。”7.2 问题二工具调用参数错误或类型不匹配现象日志显示Agent尝试调用工具但参数错误如将字符串传给Long导致工具方法抛出异常。可能原因与排查LLM提取参数错误用户说“DJI Air 3”但工具需要Long类型的droneId。LLM无法从对话中直接获取ID。需要中间步骤应该先调用查询工具返回的列表中包含IDLLM在后续调用中才能使用这个ID。解决方案设计工具链。第一个工具返回包含ID的详细信息引导LLM在后续步骤中使用。或者修改工具方法使其能接受型号名称内部再转换为ID。Tool(根据无人机型号名称查询其ID和详细信息。) public String findDroneIdByName(String modelName) { // ... 查询数据库返回格式如 DJI Air 3 的ID是 1 }7.3 问题三多轮对话中上下文丢失或混乱现象用户在第一轮说了租赁时间第二轮询问价格时Agent又回头问时间。可能原因聊天记忆窗口太小MessageWindowChatMemory.withMaxMessages(10)只保留最近10条消息可能把关键信息挤出去了。记忆未持久化默认内存存储在服务重启后丢失。解决方案根据对话复杂度调整maxMessages。对于生产环境需要实现持久化的ChatMemoryStore将会话状态保存到数据库或Redis中。7.4 问题四性能与延迟问题现象API响应慢超过10秒。排查方向LLM API延迟检查网络和OpenAI API状态。考虑使用更快的模型如gpt-3.5-turbo或本地模型。工具执行慢检查DroneService、OrderService中的数据库查询是否优化是否有慢SQL。Agent循环过多检查max-iterations防止陷入无意义的循环思考。可以在日志中观察迭代次数。优化建议为耗时工具方法添加缓存。设置合理的超时时间。考虑将复杂的、多步骤的Agent任务拆分成更小的、可独立执行的子任务。8. 生产环境进阶考量与最佳实践将这样一个系统用于生产环境除了基本功能还需要考虑更多工程化问题。8.1 安全性加固风险点防护措施LLM API密钥泄露使用环境变量或密钥管理服务如Vault注入不在代码和配置文件中硬编码。用户输入攻击Prompt注入对用户输入进行基础清洗和长度限制。在系统提示词中明确指令边界例如“你只能回答与无人机租赁相关的问题”。工具滥用在工具方法内部进行严格的业务逻辑校验和权限检查例如验证用户是否有权创建订单。敏感信息泄露确保工具返回的结果不包含内部系统ID、异常堆栈等敏感信息。对输出进行过滤。8.2 可观测性与监控一个黑盒的Agent是运维的噩梦。必须建立监控体系。结构化日志记录每一次用户请求、LLM的完整思考过程、工具调用详情及结果、最终回复。// 在DroneRentalAgentService.chat方法中增加详细日志 log.info(AI Request - Session: {}, Input: {}, sessionId, userMessage); log.debug(AI Thought Process: {}, extractThoughtFromDebugInfo()); // 需要从底层获取 log.info(AI Tool Called - Name: {}, Args: {}, Result: {}, toolName, args, toolResult); log.info(AI Response - Session: {}, Output: {}, sessionId, response);关键指标监控请求量、平均响应时间、错误率。工具调用成功率、各工具平均耗时。Agent迭代次数分布用于发现循环异常。链路追踪集成OpenTelemetry等追踪一个用户请求在整个Agent思考链路中的耗时。8.3 测试策略AI系统的测试更具挑战性。单元测试工具方法确保每个Tool方法在各种边界条件下行为正确。集成测试Agent使用Mock的LLM如InProcessChatLanguageModel和固定的对话历史测试特定输入能否触发预期的工具调用序列。端到端测试准备一批涵盖典型、边界和异常场景的测试用例定期运行监控回复质量和工具调用准确性。金丝雀发布将新版本的Agent或提示词先对一小部分流量开放对比关键指标如订单转化率、用户满意度再全量发布。8.4 架构扩展方向当前是单体集成架构。随着复杂度提升可以考虑以下演进微服务化将DroneRentalAgentService及其工具独立为一个AI微服务通过RPC或消息队列与核心业务服务通信。降低耦合独立伸缩。多Agent协作引入LangGraph或类似框架设计多个专职Agent如“查询Agent”、“议价Agent”、“风控Agent”协同工作处理更复杂的租赁流程。RAG增强当需要回答基于最新文档如租赁条款、促销活动的问题时可以引入检索增强生成RAG让Agent能查询外部知识库。通过以上步骤我们完成了一个从零到一、从Demo到具备生产意识的“AI无人机租赁系统”核心模块。它清晰地展示了如何将Spring Boot的工程能力与LangChain Agent的智能能力相结合。真正的价值不在于Agent本身而在于你如何设计工具、编写提示词、处理异常并将这套流程无缝嵌入到现有的、严谨的业务系统中。
返回列表