Nodejs也能写Agent - 23.LangGraph篇 - 可靠性与容错
上一篇我们管住了上下文窗口该 trim 的 trim该摘要的摘要RAG 也不再一股脑乱塞。窗口干净了Agent 就稳了吗并没有。生产里 LLM 会超时、会 429、Ollama 会挂、ReAct 会空转烧光额度——喂对了内容照样可能直接崩给你看。本篇管「挂了怎么办」——重试、Fallback、防死循环让异常变成优雅降级而不是用户脸上的 stack trace。老规矩本文以官网最新文档核对过Fault tolerance、Prebuilt middleware、Agents。入口继续createAgent——别再抄createReactAgent。重试 / Fallback / 调用上限优先挂官方中间件别先上手写一整套invokeWithRetry。一、生产里 Agent 怎么死先认清「会死在哪」再谈怎么救。场景典型原因表现超时模型负载高、网络慢、prompt 过长挂起后 timeout429 限流API 配额用尽、并发过高Rate limit exceeded模型不可用Ollama 没起、模型没 pull、服务宕机ECONNREFUSED、model not found上下文超限messages RAG 超窗400 / context length exceeded失控循环模型一直吐tool_calls烧 token、拖超时最后 recursive 爆官网把错误按「谁来修」分得更清楚——不同错误不该用同一招错误类型谁来修策略官方手段瞬时故障网络、限流系统自动指数退避重试modelRetryMiddleware/toolRetryMiddlewareLLM 可恢复工具失败、解析翻车模型错误进ToolMessage让模型改主意工具返回错误串JS 尚无ToolErrorMiddleware用户可修复缺信息、指令不清人暂停等人interrupt/ HITL供应商宕机系统自动换备选模型modelFallbackMiddleware失控循环系统自动封顶调用次数modelCallLimitMiddleware/toolCallLimitMiddlewarerecursionLimit未知异常开发者往上抛别瞎 catch无中间件硬吞工具失败时把错误信息回给模型它往往能自己换招。官网 JS 侧ToolErrorMiddleware尚未提供——继续走「错误内容进 ToolMessage」即可别等一个还不存在的 API。瞬时供应商挂工具可恢复失控循环未知错误发生错误类型?Retry 退避Fallback 模型错误进 ToolMessageCallLimit / recursionLimit向上抛出二、瞬时故障重试网络抖一下、偶发 429立刻失败只会逼用户狂点刷新。策略上策略说明固定间隔每次等一样久简单但 429 时可能越重试越堵指数退避第 n 次等initialDelayMs * backoffFactor^n给服务喘息时间maxRetries一般 23 次封顶别无限重试Chat 模型自身也可能有maxRetries但挂在 Agent 上时官网主路径是中间件——模型调用和工具调用各管各的import{createAgent,modelRetryMiddleware,toolRetryMiddleware,}fromlangchain;import{ChatOllama}fromlangchain/ollama;import{tool}fromlangchain/core/tools;import*aszfromzod;constsearchWebtool(async({q}:{q:string})搜索结果${q},{name:search_web,description:搜索网页外部 API值得重试,schema:z.object({q:z.string()}),});constllmnewChatOllama({model:qwen2.5:7b,temperature:0});constagentcreateAgent({model:llm,tools:[searchWeb],systemPrompt:需要外部信息时调用 search_web。,middleware:[// 模型超时 / 限流 / 5xx 类瞬时错误modelRetryMiddleware({maxRetries:3,backoffFactor:2.0,initialDelayMs:1000,}),// 工具只重试会抖的外部调用本地 read 别无脑重试toolRetryMiddleware({maxRetries:2,tools:[search_web],backoffFactor:2.0,initialDelayMs:500,}),],});要点默认就是指数退避backoffFactor: 0才退回固定间隔。toolRetryMiddleware用tools: [...]收窄范围——官网原话文件系统read失败多半重试也没用网页搜索超时才值得再试。onFailure: continue时重试用尽可返回带错误说明的AIMessage让 Agent 有机会收尾而不是整段炸穿。手写forsleep也能懂原理生产别重复造轮子中间件已经把退避、jitter、失败策略打包好了。三、主模型挂了Fallback重试用尽、或者主模型整机不可用时换备选继续服务主模型 qwen2.5:7b 失败 → 备选 llama3.1:8b或其它已 pull 的模型import{createAgent,modelFallbackMiddleware}fromlangchain;import{ChatOllama}fromlangchain/ollama;constprimarynewChatOllama({model:qwen2.5:7b,temperature:0});constfallbacknewChatOllama({model:llama3.1:8b,temperature:0});constagentcreateAgent({model:primary,tools:[],middleware:[// 主模型失败后按顺序尝试备选可传多个modelFallbackMiddleware(fallback),],});注意备选能力可能不同——回答风格、工具遵从度都会变。日志或 UI 最好标一句「已切换备选模型」别假装什么都没发生。Fallback 解决的是「模型/供应商挂了」解决不了「问题本身无解」。盯 fallback 触发率太高说明主路径在持续抽风。四、防死循环recursionLimit Call LimitReAct 环里模型若一直返回tool_calls而不给最终答案就会空转import{GraphRecursionError}fromlangchain/langgraph;try{awaitagent.invoke({messages:[{role:user,content:帮我做一件超复杂的事}]},{recursionLimit:15}// 生产可配环境变量默认别太大);}catch(err){if(errinstanceofGraphRecursionError){// 别把 stack 甩给用户return任务步骤过多请简化问题后再试。;}throwerr;}但要分清两层闸门闸门数的是什么超限表现recursionLimitLangGraphsuper-step调度滴答不是「模型调用次数」抛GraphRecursionErrormodelCallLimitMiddleware/toolCallLimitMiddleware业务语义上的模型/工具调用次数可exitBehavior: end优雅收束挂了beforeModel/afterModel这类会编译成独立节点的中间件会多占 super-stepwrapModelCall包在原节点里一般不另计。所以recursionLimit要留余量真正「最多调几次模型」交给 Call Limit 更直观。import{createAgent,modelCallLimitMiddleware,toolCallLimitMiddleware,}fromlangchain;import{ChatOllama}fromlangchain/ollama;constagentcreateAgent({model:newChatOllama({model:qwen2.5:7b,temperature:0}),tools:[/* ... */],middleware:[modelCallLimitMiddleware({runLimit:15,// 单次 invoke 内最多 15 次模型调用exitBehavior:end,// 到顶优雅结束而不是甩异常}),toolCallLimitMiddleware({runLimit:30,// 单次 invoke 内工具调用封顶}),],});runLimit一次用户请求内计数下轮重置。threadLimit整条会话累计需要 Checkpointer。两道闸一起上Call Limit 管业务预算recursionLimit防图调度层面真失控。五、缓存与熔断轻量中间件解决「这次调用怎么扛」缓存和熔断解决「别把下游打爆 / 别重复烧钱」。精确缓存 vs 语义缓存类型命中条件MVP 思路精确缓存问题字符串完全一致可 hash内存Map TTL语义缓存embedding 相似度过阈值向量库本篇不展开typeCacheEntry{value:string;expiresAt:number};constexactCachenewMapstring,CacheEntry();constTTL_MS5*60*1000;functioncacheKey(question:string){returnquestion.trim().toLowerCase();}functiongetCached(question:string):string|undefined{consthitexactCache.get(cacheKey(question));if(!hit)returnundefined;if(Date.now()hit.expiresAt){exactCache.delete(cacheKey(question));returnundefined;}returnhit.value;}functionsetCached(question:string,value:string){exactCache.set(cacheKey(question),{value,expiresAt:Date.now()TTL_MS,});}// 「现在几点」「今天天气」——实时题别进缓存注意不同用户 / 不同thread_id是否共享缓存要想清楚带隐私或个性化的回答默认不要全局共享。Circuit Breaker 简述连续失败时与其每次都去撞已经挂掉的 Ollama不如短暂拒绝关闭 → 失败累积 → 打开直接拒→ 冷却后 → 半开放一枪试探→ 成功则关闭classSimpleBreaker{privatefailures0;privateopenUntil0;constructor(privatethreshold5,privatecoolDownMs30_000){}getisOpen(){returnDate.now()this.openUntil;}beforeCall(){if(this.isOpen){thrownewError(服务暂时不可用请稍后重试熔断开启);}}onSuccess(){this.failures0;this.openUntil0;}onFailure(){this.failures1;if(this.failuresthis.threshold){this.openUntilDate.now()this.coolDownMs;this.failures0;}}}constbreakernewSimpleBreaker();asyncfunctioninvokeWithBreaker(run:()Promiseunknown){breaker.beforeCall();try{constresultawaitrun();breaker.onSuccess();returnresult;}catch(e){breaker.onFailure();throwe;}}这是教学级 MVP。完整半开态、按依赖隔离可后续对标 resilience4j 一类库本篇目标是建立心智不是重造运维平台。六、组合生产最小可靠骨架把前面几招叠在一颗createAgent上import{createAgent,modelRetryMiddleware,toolRetryMiddleware,modelFallbackMiddleware,modelCallLimitMiddleware,toolCallLimitMiddleware,}fromlangchain;import{ChatOllama}fromlangchain/ollama;import{GraphRecursionError}fromlangchain/langgraph;import{tool}fromlangchain/core/tools;import*aszfromzod;constgetWeathertool(async({city}:{city:string})${city}晴25°C,{name:get_weather,description:查询城市天气,schema:z.object({city:z.string()}),});constprimarynewChatOllama({model:qwen2.5:7b,temperature:0});constfallbacknewChatOllama({model:llama3.1:8b,temperature:0});constagentcreateAgent({model:primary,tools:[getWeather],systemPrompt:需要天气时调用 get_weather。,middleware:[modelRetryMiddleware({maxRetries:2,backoffFactor:2.0,initialDelayMs:1000,}),toolRetryMiddleware({maxRetries:2,tools:[get_weather],}),modelFallbackMiddleware(fallback),modelCallLimitMiddleware({runLimit:15,exitBehavior:end}),toolCallLimitMiddleware({runLimit:30}),],});exportasyncfunctionsafeInvoke(userText:string){try{returnawaitagent.invoke({messages:[{role:user,content:userText}]},{recursionLimit:25}// 比 callLimit 留余量);}catch(err){if(errinstanceofGraphRecursionError){return{messages:[{role:assistant,content:任务步骤过多请简化问题后再试。,},],};}throwerr;}}retry / fallback / 触顶时你才能在 LangSmith 里看见「到底换过几次、卡在哪」。可靠性没有可观测就是盲修。常见坑无重试直接失败偶发抖动逼用户狂点至少模型侧maxRetries: 2。重试无退避429 时立刻重试只会更堵用指数退避。工具无脑全量重试本地/确定性失败不值得重试tools: [...]收窄。只有recursionLimit、没有 Call Limitsuper-step ≠ 业务调用次数两道闸一起上更稳。Fallback 不告知备选质量不同日志/UI 应标注。缓存误用天气、时间、用户私有回答不该进全局精确缓存。熔断阈值乱调太敏感则误杀太钝则雪崩。瞎 catch 未知异常官网建议处理不了的往上抛方便调试。

相关新闻

VMware与VirtualBox虚拟机与主机双向复制粘贴配置与排错指南

VMware与VirtualBox虚拟机与主机双向复制粘贴配置与排错指南

1. 从“隔阂”到“丝滑”:为什么虚拟机与主机的复制粘贴如此重要如果你和我一样,经常在Windows主机上跑一个Linux虚拟机(比如Ubuntu、CentOS)做开发、测试或者学习,那你一定遇到过这个让人抓狂的场景:在虚拟…

2026/10/26 11:21:30 阅读更多 →
SpringBoot数据库操作方案对比与实战优化

SpringBoot数据库操作方案对比与实战优化

1. SpringBoot数据库操作的核心价值SpringBoot作为Java生态中最流行的应用框架之一,其数据库操作能力直接决定了企业级应用的开发效率。我在实际项目中发现,合理的数据库访问层设计能让后续维护成本降低40%以上。SpringBoot通过自动配置和starter机制&am…

2026/10/24 7:01:47 阅读更多 →
算力的隐形代价:当AI的“水足迹”成为下一个技术瓶颈

算力的隐形代价:当AI的“水足迹”成为下一个技术瓶颈

算力的隐形代价:当AI的“水足迹”成为下一个技术瓶颈 最近,一条关于“2030年AI耗水量够13亿人用一年”的消息冲上了热搜榜。乍一看,这个数字似乎有些耸人听闻,甚至让人觉得又是哪个环保组织的夸张宣传。但作为身处技术一线的开发者…

2026/10/24 7:17:26 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/26 12:00:21 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/25 22:36:10 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/26 4:52:12 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/26 12:00:21 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/26 5:00:37 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/26 3:16:46 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/26 12:00:19 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/25 13:21:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/26 8:34:37 阅读更多 →