Error Handling#error-handling这里的Error Handling指的是当大模型调用 Tool 时如果 Tool 执行出错了LangChain4j 应该怎么处理这个错误。因为 Tool 本质上就是你的 Java 方法所以它可能会出现各种异常参数为空 参数格式不对 订单不存在 用户无权限 数据库异常 第三方接口超时 空指针 业务状态不允许操作Error Handling就是告诉你Tool 出错时不要让整个 AI 调用莫名其妙失败而是要把错误处理成模型能理解、用户能接受、系统可控的结果。1. 为什么 Tool 需要错误处理比如你有一个查询订单的 ToolTool(根据订单号查询订单状态)publicStringgetOrderStatus(P(订单号)StringorderId){returnorderService.getStatus(orderId);}用户问帮我查一下订单10001正常情况下没问题。但如果出现这些情况呢orderId 为空 orderId 格式不对 订单不存在 数据库连接失败 orderService 抛异常如果你不处理可能会导致AI Service 方法直接抛异常 用户看到 500 错误 模型无法继续回答 日志里一堆异常所以需要 Error Handling。2. Tool 出错时有两种处理思路LangChain4j 里的 Tool 错误处理大体可以分成两层1. Tool 方法内部自己处理 2. 配置全局 ToolExecutionExceptionHandler3. 方式一Tool 方法内部自己处理这是最推荐、最基础的方式。你在 Tool 方法里自己判断参数、业务状态然后返回模型能理解的错误信息。例如ComponentpublicclassOrderTools{privatefinalOrderServiceorderService;publicOrderTools(OrderServiceorderService){this.orderServiceorderService;}Tool(根据订单号查询订单状态)publicStringgetOrderStatus(P(订单号例如 10001)StringorderId){if(orderIdnull||orderId.isBlank()){return订单号不能为空请让用户提供订单号。;}if(!orderId.matches(\\d)){return订单号格式不正确订单号应该是数字。;}OrderorderorderService.findByOrderId(orderId);if(ordernull){return没有找到订单orderId请确认订单号是否正确。;}return 订单号%s 当前状态%s 预计送达%s .formatted(order.getOrderId(),order.getStatus(),order.getEstimatedDeliveryTime());}}这种方式的好处是错误信息可控 模型能理解 用户体验好 不会轻易抛 5004. 为什么建议 Tool 自己先处理业务错误因为很多错误其实不是“系统异常”而是“业务结果”。比如订单不存在 订单已取消 余额不足 库存不足 当前用户无权限 参数缺失这些最好不要直接抛异常给 LangChain4j而是返回清楚的业务信息。比如不推荐thrownewRuntimeException(Order not found);更推荐return没有找到该订单请确认订单号是否正确。;因为 Tool 的返回值会交给大模型大模型可以继续组织回答没有查到订单 10001请你确认一下订单号是否正确。5. 方式二配置 ToolExecutionExceptionHandler如果 Tool 方法里真的抛异常了可以通过ToolExecutionExceptionHandler统一处理。它的作用是捕获 Tool 执行过程中抛出的异常然后返回一个字符串作为 Tool 执行结果。大概配置方式是ConfigurationpublicclassAiConfig{BeanpublicOrderAssistantorderAssistant(ChatLanguageModelchatLanguageModel,OrderToolsorderTools){returnAiServices.builder(OrderAssistant.class).chatLanguageModel(chatLanguageModel).tools(orderTools).toolExecutionExceptionHandler((exception,context)-{return工具执行失败请稍后再试。;}).build();}}不同 LangChain4j 版本里lambda 参数可能略有差异有的版本可能是.toolExecutionExceptionHandler(exception-{return工具执行失败请稍后再试。;})或者带上 tool request/context 信息。但核心思想一样Tool 抛异常 ↓ ToolExecutionExceptionHandler 捕获 ↓ 返回一个错误信息字符串 ↓ 这个字符串作为 Tool 执行结果交给模型6. ToolExecutionExceptionHandler 的作用流程假设 Tool 是这样的Tool(根据订单号查询订单状态)publicStringgetOrderStatus(StringorderId){thrownewRuntimeException(数据库连接失败);}用户问查一下订单10001流程可能是1. 大模型决定调用 getOrderStatus 2. LangChain4j 执行 Tool 3. Tool 抛异常 4. ToolExecutionExceptionHandler 捕获异常 5. Handler 返回“系统暂时无法查询订单请稍后再试。” 6. 这个结果交给模型 7. 模型回答用户 抱歉当前系统暂时无法查询订单请稍后再试。7. 一个更真实的异常处理配置你可以根据不同异常类型返回不同信息。ConfigurationpublicclassAiConfig{BeanpublicOrderAssistantorderAssistant(ChatLanguageModelchatLanguageModel,OrderToolsorderTools){returnAiServices.builder(OrderAssistant.class).chatLanguageModel(chatLanguageModel).tools(orderTools).toolExecutionExceptionHandler((exception,context)-{Throwablecauseexception.getCause();if(causeinstanceofIllegalArgumentException){return参数不合法请检查后重新提供。;}if(causeinstanceofAccessDeniedException){return当前用户没有权限执行该操作。;}if(causeinstanceofOrderNotFoundException){return没有找到对应订单请确认订单号是否正确。;}return系统暂时无法完成该操作请稍后再试。;}).build();}}如果你当前版本的 handler 只有一个参数可以写成类似.toolExecutionExceptionHandler(exception-{Throwablecauseexception.getCause();if(causeinstanceofIllegalArgumentException){return参数不合法请检查后重新提供。;}return工具执行失败请稍后再试。;})8. Error Handling 返回的字符串会去哪这点很重要。如果你使用的是普通 Tool 调用模式Handler 返回的字符串一般会作为 Tool 执行结果交给大模型。比如 Handler 返回没有找到订单请确认订单号是否正确。然后大模型可能最终回答我没有查到这个订单请你确认一下订单号是否正确。也就是说异常信息 → Handler 转成可理解文本 → 交给模型 → 模型回复用户9. 如果是立即返回 Tool 呢你前面问过returnBehavior IMMEDIATE。如果 Tool 是立即返回类型Tool(value生成支付链接,returnBehaviorIMMEDIATE)publicStringcreatePaymentUrl(StringorderId){...}或者 ToolProvider 中.returnBehavior(IMMEDIATE)那么 Tool 执行失败时Handler 返回的错误信息可能会直接作为最终结果返回。所以立即返回类型的 Tool错误信息更要写得适合直接给用户看。例如return生成支付链接失败请稍后再试。;不要返回returnNullPointerException at PaymentService.java:35;10. ToolProvider 里怎么处理 Error Handling如果你使用ToolProvider手动写ToolExecutor有两种方式。10.1 在 ToolExecutor 里自己 try-catch这是最直接的方式。privateToolExecutorcreatePaymentUrlExecutor(){return(request,memoryId)-{try{JsonNodejsonobjectMapper.readTree(request.arguments());StringorderIdjson.get(orderId).asText();if(orderIdnull||orderId.isBlank()){return订单号不能为空。;}StringuserIdString.valueOf(memoryId);if(!paymentService.canPay(userId,orderId)){return你无权支付该订单。;}returnpaymentService.createPaymentUrl(userId,orderId);}catch(Exceptione){return生成支付链接失败请稍后再试。;}};}这种写法适合你想对某个 Tool 单独处理异常。10.2 抛出去让全局 ToolExecutionExceptionHandler 处理也可以不 catch让异常往外抛privateToolExecutorcreatePaymentUrlExecutor(){return(request,memoryId)-{JsonNodejsonobjectMapper.readTree(request.arguments());StringorderIdjson.get(orderId).asText();StringuserIdString.valueOf(memoryId);returnpaymentService.createPaymentUrl(userId,orderId);};}然后在AiServices.builder里统一处理.toolExecutionExceptionHandler((exception,context)-{return工具执行失败请稍后再试。;})11. 实战建议业务异常自己处理系统异常统一处理推荐你按这个原则来业务可预期错误Tool 内部处理并返回 系统不可预期异常交给 ToolExecutionExceptionHandler 统一兜底例如Tool 内处理订单不存在 订单号为空 用户无权限 订单状态不允许取消 余额不足 库存不足全局 Handler 处理数据库连接失败 第三方接口超时 空指针 JSON 解析异常 未知 RuntimeException12. 完整示例Spring Boot 查询订单12.1 AssistantpublicinterfaceOrderAssistant{Stringchat(Stringmessage);}12.2 ToolComponentpublicclassOrderTools{privatefinalOrderServiceorderService;publicOrderTools(OrderServiceorderService){this.orderServiceorderService;}Tool(根据订单号查询订单状态)publicStringgetOrderStatus(P(订单号例如 10001)StringorderId){if(orderIdnull||orderId.isBlank()){return订单号不能为空请让用户提供订单号。;}if(!orderId.matches(\\d)){return订单号格式不正确请提供纯数字订单号。;}OrderorderorderService.findByOrderId(orderId);if(ordernull){return没有找到订单orderId;}return 订单号%s 状态%s 预计送达%s .formatted(order.getOrderId(),order.getStatus(),order.getEstimatedDeliveryTime());}Tool(取消订单)publicStringcancelOrder(P(订单号)StringorderId){if(orderIdnull||orderId.isBlank()){return订单号不能为空。;}OrderorderorderService.findByOrderId(orderId);if(ordernull){return订单不存在。;}if(!order.canCancel()){return该订单当前状态不允许取消。;}orderService.cancel(orderId);return订单 orderId 已取消。;}}12.3 配置全局异常处理ConfigurationpublicclassAiConfig{BeanpublicOrderAssistantorderAssistant(ChatLanguageModelchatLanguageModel,OrderToolsorderTools){returnAiServices.builder(OrderAssistant.class).chatLanguageModel(chatLanguageModel).tools(orderTools).toolExecutionExceptionHandler((exception,context)-{// 这里建议记录完整日志// log.error(Tool execution failed, exception);Throwablecauseexception.getCause();if(causeinstanceofTimeoutException){return系统查询超时请稍后再试。;}if(causeinstanceofAccessDeniedException){return当前用户没有权限执行该操作。;}return系统暂时无法完成该操作请稍后再试。;}).build();}}13. 不要把异常堆栈直接返回给用户不推荐.toolExecutionExceptionHandler((exception,context)-{returnexception.getMessage();})因为异常信息里可能有数据库表名 SQL 服务器路径 内部类名 第三方接口地址 token 用户隐私信息 堆栈信息比如com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure这种东西不应该暴露给用户也不应该直接交给模型。推荐return系统暂时无法完成该操作请稍后再试。;同时你在服务端日志里记录详细异常log.error(Tool execution failed,exception);14. 参数错误也算 Error Handling大模型传参不一定稳定。比如 Tool 需要{orderId:10001}但模型可能传{orderId:订单10001}或者{orderId:}甚至参数缺失。所以每个 Tool 最好都做参数校验if(orderIdnull||orderId.isBlank()){return订单号不能为空请让用户提供订单号。;}不要因为参数不对就直接空指针。15. 高风险 Tool 更要严格处理错误比如这些 Tool退款 取消订单 转账 删除数据 冻结账户 发送短信 修改权限错误处理不能随便。例如退款 ToolTool(给订单发起退款)publicStringrefund(ToolMemoryIdStringuserId,P(订单号)StringorderId,P(退款原因)Stringreason){if(!permissionService.canRefund(userId)){return当前用户没有退款权限。;}if(orderIdnull||orderId.isBlank()){return订单号不能为空。;}if(reasonnull||reason.isBlank()){return退款原因不能为空。;}RefundResultresultrefundService.refund(orderId,reason);if(!result.success()){return退款失败原因result.message();}return退款已提交退款单号result.refundNo();}不要让异常随便抛出去更不要返回内部错误。16. Error Handling 和 Accessing Executed Tools 可以配合你前面学过Accessing Executed Tools。如果 Tool 出错了你可以通过工具执行记录看到调用了哪个 Tool 传了什么参数 返回了什么错误结果比如ResultStringresultassistant.chat(帮我查订单abc);result.toolExecutions().forEach(toolExecution-{System.out.println(toolExecution.request().name());System.out.println(toolExecution.request().arguments());System.out.println(toolExecution.result());});可能输出getOrderStatus {orderId:abc} 订单号格式不正确请提供纯数字订单号。这对调试非常有用。17. Error Handling 和 ToolProvider 的关系如果你用ToolProviderError Handling 也一样重要。区别只是使用方式错误处理位置Tool注解Tool 方法内部处理或全局 ToolExecutionExceptionHandlerToolProviderToolExecutor 内部处理或全局 ToolExecutionExceptionHandler简单说Tool 方式错误可能出现在 Java 方法里 ToolProvider 方式错误可能出现在 ToolExecutor 里但本质一样都是 Tool 执行失败。18. 最佳实践总结错误类型推荐处理方式参数为空Tool 内部返回友好提示参数格式错误Tool 内部返回格式说明业务数据不存在Tool 内部返回业务提示用户无权限Tool 内部返回无权限提示并记录日志业务状态不允许Tool 内部返回原因第三方接口失败Tool 内部或全局 Handler 返回稍后再试数据库异常全局 Handler 兜底日志记录未知异常全局 Handler 兜底隐藏技术细节19. 一句话总结Error Handling的作用就是当大模型调用 Tool 时如果 Tool 参数错误、业务失败或代码抛异常你可以把这些错误处理成可控、友好、安全的结果而不是让 AI 调用直接崩掉。实际使用建议1. Tool 内部处理可预期业务错误 2. AiServices.builder 配置 toolExecutionExceptionHandler 兜底未知异常 3. 不要把技术异常、堆栈、SQL、token 暴露给模型或用户 4. 高风险 Tool 必须做参数校验、权限校验、审计日志
企业数字化 ERP 产品动态
相关推荐
大小鼠抓力测定仪 一、产品介绍:
MedLab-Z605大小鼠抓力测定仪是评估啮齿类动物神经肌肉功能与肌力的经典设备,核心由高精度拉力传感器、可替换抓具(网格/T型杆)及数据采集系统组成。适配大小鼠前肢/后肢测试。利用动物本能抓握反应,拉动… · 2026/11/14 11:22:12
Flutter开发Android TV应用实践指南 1. Flutter开发Android TV应用的优势与挑战 Flutter作为跨平台开发框架,在移动端已经证明了自己的价值。但很多人不知道的是,它同样适用于Android TV应用的开发。我最近用Flutter完成了一个Android TV项目,发现整个过程比预想的要简单得多。 … · 2026/10/28 6:12:55
AI 编程工具 Qoder 的工程化实践:从模型竞争到任务交付 AI 编程工具 Qoder 的工程化实践:从模型竞争到任务交付
先说结论Qoder 的核心优势不在于模型本身,而在于 Task Runtime 任务运行时,它让 AI 编程从一次性对话变成可观测、可恢复的工程流水线。知识引擎(Memory Repo Wiki… · 2026/11/2 9:13:32
外省电工证能转过来吗?考电工证网上模拟试题帮你搞懂全国通用规则 外省电工证能转过来吗?考电工证网上模拟试题帮你搞懂全国通用规则 之前考的证在外省能不能转过来?这是很多人在报考电工证时最关心的问题。特别是在河南安阳,不少工人是从外地来打工,拿到的电工证是外省发的,担心回老家或者换工作时会被卡住。其实,… · 2026/11/14 11:21:47
美的电工证重新注册考试真题与备考技巧 电工证过期了不知道怎么重新注册?怎么报名流程全在这里了 你是不是也遇到过这种情况,电工证眼看就要到期了,却不知道怎么重新注册?别慌,今天就来给你讲讲, 美的电工证重新注册 到底是怎么回事, 怎么报名… · 2026/11/14 11:21:47
电工证怎么向人社?实操考试心里没底怕挂科?看济源市政工怎么办 电工证怎么向人社?实操考试心里没底怕挂科?看济源市政工怎么办 实操考试心里没底怕挂科,这几乎是每个准备考电工证的学员都有的想法。尤其是像济源市的市政工程从业者,天天和电打交道,但一到考试,手心冒汗是常态。你是不是也担心自己操作不熟练,考不过… · 2026/11/14 11:21:47
电工证在手才有饭吃?四川高低压电工证网上查询全攻略 电工证在手才有饭吃?四川高低压电工证网上查询全攻略 急需特种作业证才能上岗找工作,这几乎是所有工程类毕业生、转行人员、自由职业者的真实写照。特别是在四川地区,低压电工证和高压电工证几乎是进入建筑、电力、制造业等相关岗位的“通行证”。很多人在… · 2026/11/14 11:21:47
澳洲认可的电工证怎么查网上查询?实操考试心里没底怕挂科 澳洲认可的电工证怎么查网上查询?实操考试心里没底怕挂科 实操考试心里没底怕挂科,尤其是准备报考澳洲认可的电工证的新手,担心自己操作不规范、流程不熟悉、考试不过关。其实很多人在第一次参加特种作业实操考试时都会有这种焦虑,关键是要提前了解流程、… · 2026/11/14 11:21:47
中人考电工证多久拿证 外省证书怎么转过来 中人考电工证多久拿证 外省证书怎么转过来 之前考的证在外省能不能转过来?这是很多电工同行最关心的问题。尤其像我们南阳卧龙区从事市政公用工程的电工,经常因为项目跨区域,证件办理和使用都成了难题。今天我们就来聊聊【中人考电工证】多久拿证、外省证… · 2026/11/14 11:20:47
电工证丢失还能补吗?千万别踩坑,丢了证等于失业 电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。… · 2026/11/13 22:30:50
电力电缆作业证直播报名入口与办理流程良心建议 电力电缆作业证直播报名入口与办理流程良心建议 你是不是也担心学历不高报不了名?别急,今天就给你讲讲 电力电缆作业证直播 的报名流程和那些你必须知道的干货, 良心建议 在这里,别错过。 电力电缆作业证直播报名需要什么条件?… · 2026/11/13 5:40:45
英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 怕考不过白交培训费?英德电工证报考费多少钱,你真的了解吗?现在市面上培训机构五花八门,价格参差不齐,很多人一不小心就花了冤枉钱,结果还考不过。别急,今天就来给你说清楚英德电工证的… · 2026/11/12 23:27:43
有初级电工证怎么工作 2026河南最新政策怎么应对 有初级电工证怎么工作 2026河南最新政策怎么应对 之前考的证在外省能不能转过来?这个问题我每天被问上百次。2026年河南最新政策对证书跨省转移有了明确说明,特别是南阳市的从业者,需要特别关注。… · 2026/11/14 0:00:31
电工证过期了不知道怎么复审?考电工证自学书+官方报名入口全攻略 电工证过期了不知道怎么复审?考电工证自学书+官方报名入口全攻略 证书过期了不知道怎么复审延期?很多人遇到这种情况,要么是工作太忙没时间处理,要么是不知道具体流程,导致证书失效,影响工作和项目进展。其实复审并不难,关键是要找准官方报名入口,掌… · 2026/11/14 0:00:31
为什么要低压电工证实操考试考什么 为什么低压电工证值不值得考?别再被中介骗了 你是不是也经常看到网上有人在问“低压电工证到底值不值得考”?或者在找报名点时,担心被中间人骗钱?这些问题,我懂,我也经历过。作为一名在应急管理行业摸爬滚打多年的从业者,我深知低压电工证不仅是一个从… · 2026/11/14 0:00:31
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/13 6:12:21
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/13 6:11:51
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/13 22:31:30