LangChain4j数据库智能体开发实战

发布时间:2026/7/22 5:12:32
LangChain4j数据库智能体开发实战 1. 初识LangChain4j与数据库智能体第一次接触LangChain4j时我正为一个电商项目的数据查询接口发愁。每天要处理上百种SQL查询变体从简单的查找用户订单到复杂的统计某商品在不同地区的月销量趋势。传统做法要么写死SQL要么构建复杂的查询构建器——直到发现LangChain4j这个Java版的AI编排框架。LangChain4j是LangChain生态的Java实现专为Java开发者设计的大语言模型(LLM)集成工具。它最大的价值在于让Java应用能像Python生态那样轻松接入AI能力。最新0.35.0版本强化了对Gemini等模型的支持特别适合企业级应用开发。数据库智能体(Database Agent)是LangChain4j的典型应用场景。它本质上是一个能理解自然语言、自主操作数据库的AI程序。比如用户问帮我查查上周销售额最高的5个商品智能体会自动理解时间范围上周识别需要查询的销售额字段确定排序方式和限制条件生成并执行对应SQL以自然语言返回结果这种模式彻底改变了人机交互方式。根据我的实践在数据查询场景中智能体能减少80%的固定接口开发量特别适合需求多变的业务系统。2. 环境准备与基础配置2.1 开发环境搭建建议使用Java 17和Maven构建项目。在pom.xml中添加关键依赖dependencies !-- LangChain4j核心库 -- dependency groupIddev.langchain4j/groupId artifactIdlangchain4j/artifactId version0.35.0/version /dependency !-- MySQL连接器 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency !-- 可选Spring Boot集成 -- dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-spring-boot-starter/artifactId version0.35.0/version /dependency /dependencies2.2 数据库连接配置创建MySQL数据库连接池是智能体稳定运行的基础。推荐使用HikariCPHikariConfig config new HikariConfig(); config.setJdbcUrl(jdbc:mysql://localhost:3306/your_database); config.setUsername(username); config.setPassword(password); config.setMaximumPoolSize(10); config.setConnectionTimeout(30000); HikariDataSource dataSource new HikariDataSource(config);注意生产环境建议将密码等敏感信息放在配置中心或环境变量中不要硬编码在代码里。2.3 初始化LangChain4j组件核心需要配置两部分ChatModel选择使用的LLM模型ChatMemory管理对话上下文// 使用本地运行的Ollama模型 OpenAiChatModel model OpenAiChatModel.builder() .apiKey(your_api_key) .modelName(gpt-3.5-turbo) .temperature(0.3) // 控制创造性 .build(); // 对话记忆管理 ChatMemory chatMemory MessageWindowChatMemory.withMaxMessages(20);3. 构建MySQL数据库智能体3.1 定义智能体接口使用LangChain4j的Tool注解声明智能体能力public interface MySQLAgent { Tool(查询数据库中的用户信息) String queryUserInfo(P(用户ID) String userId); Tool(执行商品库存查询) String checkInventory( P(商品ID) String productId, P(仓库编号) String warehouseCode ); Tool(获取销售统计数据) String getSalesStatistics( P(开始日期) String startDate, P(结束日期) String endDate, P(统计维度) String dimension ); }3.2 实现工具方法每个Tool方法对应一个数据库操作public class MySQLAgentImpl implements MySQLAgent { private final DataSource dataSource; public String queryUserInfo(String userId) { try (Connection conn dataSource.getConnection()) { PreparedStatement stmt conn.prepareStatement( SELECT username, email, register_date FROM users WHERE user_id ?); stmt.setString(1, userId); ResultSet rs stmt.executeQuery(); if (rs.next()) { return String.format(用户%s: 邮箱%s, 注册日期%s, rs.getString(username), rs.getString(email), rs.getDate(register_date)); } return 未找到该用户; } catch (SQLException e) { return 查询失败: e.getMessage(); } } }3.3 组装智能体服务使用AiServices绑定接口与实现MySQLAgent agent AiServices.builder(MySQLAgent.class) .chatLanguageModel(model) .chatMemoryProvider(memoryId - chatMemory) .tools(new MySQLAgentImpl(dataSource)) .build();4. 高级功能实现4.1 动态SQL生成对于复杂查询可以让LLM生成SQL再执行Tool(根据自然语言描述查询数据) String naturalLanguageQuery(P(查询描述) String description) { String prompt 你是一个MySQL专家。根据以下描述生成SQL查询 数据库表products(id,name,price,stock) 用户描述%s 只输出SQL语句不要任何解释。确保语句安全避免SQL注入。 ; String sql model.generate(prompt.formatted(description)); // 执行SQL并返回结果 return executeSafeQuery(sql); }安全提示务必对生成的SQL进行校验和参数化处理防止SQL注入。4.2 事务处理智能体也可以管理事务Tool(下订单并扣减库存) String placeOrder( P(用户ID) String userId, P(商品ID) String productId, P(数量) int quantity ) { Connection conn null; try { conn dataSource.getConnection(); conn.setAutoCommit(false); // 1. 扣减库存 PreparedStatement stmt1 conn.prepareStatement( UPDATE products SET stock stock - ? WHERE id ? AND stock ?); stmt1.setInt(1, quantity); stmt1.setString(2, productId); stmt1.setInt(3, quantity); int updated stmt1.executeUpdate(); if (updated 0) { conn.rollback(); return 库存不足; } // 2. 创建订单 PreparedStatement stmt2 conn.prepareStatement( INSERT INTO orders(user_id, product_id, quantity) VALUES (?,?,?)); stmt2.setString(1, userId); stmt2.setString(2, productId); stmt2.setInt(3, quantity); stmt2.executeUpdate(); conn.commit(); return 订单创建成功; } catch (SQLException e) { if (conn ! null) try { conn.rollback(); } catch (SQLException ex) {} return 下单失败: e.getMessage(); } finally { if (conn ! null) try { conn.close(); } catch (SQLException e) {} } }4.3 结果格式化让LLM帮助美化查询结果Tool(获取商品列表) String listProducts(P(页数) int page, P(每页数量) int size) { ListMapString, Object products jdbcTemplate.queryForList( SELECT id, name, price FROM products LIMIT ? OFFSET ?, size, (page-1)*size); String prompt 将以下商品数据格式化为易读的Markdown表格 %s 要求 - 包含ID、名称和价格三列 - 价格显示为带两位小数的数字 - 表头使用中文 ; return model.generate(prompt.formatted(products.toString())); }5. 生产环境优化5.1 性能调优数据库智能体的性能瓶颈通常在两方面LLM响应时间数据库查询效率优化建议为常用查询添加缓存批量处理小查询限制单次查询返回的数据量// 带缓存的查询示例 Tool(获取商品详情) Cacheable(value productCache, key #productId) public String getProductDetails(P(商品ID) String productId) { // 数据库查询逻辑 }5.2 错误处理健壮的智能体需要处理各种异常情况public class SafeQueryExecutor { public static String execute(String sql) { try { // 1. SQL注入检查 if (sql.toLowerCase().contains(drop) || sql.toLowerCase().contains(delete)) { throw new SecurityException(危险操作被阻止); } // 2. 执行查询 // ... } catch (Exception e) { return 抱歉查询时出现问题。以下是技术细节 %s 请尝试重新表述您的请求或联系管理员。 .formatted(e.getMessage()); } } }5.3 监控与日志添加详细的日志帮助排查问题Aspect Component public class AgentLogger { Around(annotation(tool)) public Object logToolExecution(ProceedingJoinPoint pjp, Tool tool) throws Throwable { String methodName pjp.getSignature().getName(); Object[] args pjp.getArgs(); log.info(执行工具 {} 参数: {}, methodName, Arrays.toString(args)); try { Object result pjp.proceed(); log.info(工具 {} 执行成功, methodName); return result; } catch (Exception e) { log.error(工具 {} 执行失败: {}, methodName, e.getMessage()); throw e; } } }6. 实际应用案例6.1 电商客服系统我们为电商平台实现的客服智能体能处理如下请求用户12345最近下了哪些订单帮我查一下iPhone 15的库存情况统计上个月销售额最高的三个品类实现关键点建立领域专用的提示词模板设计合理的权限控制结果可视化处理6.2 内部数据看板市场团队使用的数据查询智能体显示本月华北区的销售趋势对比A产品和B产品过去半年的销量预测下季度可能缺货的商品特色功能自动生成图表描述支持数据导出定时报告推送6.3 跨库查询代理对于有多个数据库的系统智能体可以理解查询需求确定数据所在库执行分布式查询合并返回结果Tool(跨库查询用户完整信息) String queryUserAcrossSystems(P(用户ID) String userId) { // 1. 从CRM库获取基本信息 String basicInfo crmAgent.queryUserBasic(userId); // 2. 从订单库获取历史订单 String orders orderAgent.queryUserOrders(userId); // 3. 从日志库获取行为数据 String behaviors logAgent.queryUserBehaviors(userId); // 让LLM汇总结果 return model.generate( 请将以下用户信息整合成一段连贯的描述 基本信息 %s 历史订单 %s 行为数据 %s .formatted(basicInfo, orders, behaviors)); }7. 经验总结与避坑指南7.1 常见问题排查问题1SQL注入风险现象智能体生成的SQL包含危险操作解决方案使用参数化查询添加SQL关键字过滤限制数据库账号权限问题2性能低下现象复杂查询响应慢优化方法添加查询超时控制对大表查询添加限制条件使用EXPLAIN分析慢查询问题3结果不准确原因LLM误解了用户意图改进添加确认环节(您是要查询X吗)提供示例问题实现模糊匹配7.2 性能优化技巧连接池配置初始连接数5最大连接数CPU核心数*2空闲超时10分钟LLM调用优化OpenAiChatModel model OpenAiChatModel.builder() .apiKey(your_key) .modelName(gpt-4-turbo) // 更快的模型 .timeout(Duration.ofSeconds(30)) // 设置超时 .logRequests(true) // 记录请求日志 .logResponses(true) .build();批量处理 对于多个小查询可以合并为一个批量请求Tool(批量查询商品信息) String batchQueryProducts(P(商品ID列表) ListString productIds) { String sql SELECT id, name FROM products WHERE id IN (%s) .formatted(productIds.stream() .map(id - id ) .collect(Collectors.joining(,))); // 执行查询... }7.3 安全最佳实践权限控制为智能体创建专用数据库账号只授予必要的最小权限实现用户级别的访问控制敏感数据保护Tool(查询用户联系信息) PreAuthorize(hasRole(ADMIN)) String queryUserContact(P(用户ID) String userId) { // 仅管理员可访问 }审计日志 记录所有智能体操作Aspect Component public class AuditLogger { AfterReturning(annotation(tool)) public void logSuccess(Tool tool, Object result) { auditService.log(工具执行成功: tool.value()); } AfterThrowing(pointcutannotation(tool), throwingex) public void logFailure(Tool tool, Exception ex) { auditService.log(工具执行失败: tool.value()); } }8. 扩展与进阶8.1 集成向量搜索结合pgvector等扩展实现语义搜索Tool(语义搜索商品) String semanticSearchProduct(P(搜索描述) String query) { // 1. 将查询文本转换为向量 float[] embedding embeddingModel.embed(query).content(); // 2. 执行向量搜索 String sql SELECT id, name, description FROM products ORDER BY embedding ? LIMIT 5 ; // 3. 执行查询并返回结果 // ... }8.2 多模态扩展让智能体不仅能查数据还能生成图表Tool(生成销售图表) String generateSalesChart( P(开始日期) String start, P(结束日期) String end, P(图表类型) String chartType ) { // 1. 查询数据 ListSalesData data querySalesData(start, end); // 2. 让LLM生成Python绘图代码 String pythonCode model.generate( 根据以下数据生成%s图表 %s 使用matplotlib返回base64编码的PNG图像。 .formatted(chartType, data)); // 3. 执行Python代码返回图像 return executePythonCode(pythonCode); }8.3 自动化工作流将多个工具串联成工作流Tool(处理退货申请) String processReturn( P(订单号) String orderId, P(原因) String reason ) { // 1. 验证订单状态 String status checkOrderStatus(orderId); // 2. 根据规则判断是否可退 boolean approved model.generate( 根据我们的退货政策判断是否可以接受以下退货 订单状态%s 退货原因%s 只回答true或false。 .formatted(status, reason)) .equalsIgnoreCase(true); // 3. 执行退款或拒绝 if (approved) { return executeRefund(orderId); } else { return 抱歉您的退货申请未被批准; } }在实际项目中我发现最有效的智能体往往是那些专注于特定领域、功能明确的。一个试图做所有事情的通用智能体通常不如多个专门化的小智能体协作来得高效。建议从小的垂直场景开始逐步扩展能力边界。