LongGuard:为LangGraph装上熔断器,终结Agent失控循环

如果你在生产环境中运行AI Agent,很可能亲眼见过它们「实时烧钱」的场景:一个模糊的工具返回(比如「Access Denied」或「Item not found」)就足以让Agent陷入认知死循环,反复调用同一个工具二十几次,直到LangGraph抛出GraphRecursionError崩溃为止。等到它真正挂掉时,你已经烧掉了5万token、丢失了对话状态,还向用户返回了一个未处理的异常。
AI Agent与LangGraph技术背景
AI Agent是指能够自主感知环境、做出决策并执行行动的智能系统。在生产环境中,Agent通常需要调用多种外部工具(如搜索API、数据库查询、文件操作等)来完成复杂任务。LangGraph是LangChain生态系统中的一个核心组件,它提供了一种基于状态图(StateGraph)的编程范式来构建这类多步骤的Agent应用。
LangGraph采用的状态图(StateGraph)编程范式是对传统链式调用的重大改进。在早期的LangChain中,Agent的执行流程是线性的链式结构,难以处理分支、循环和条件跳转等复杂逻辑。状态图将Agent的执行过程建模为有向图:每个节点代表一个操作或状态(如「调用工具」、「生成回复」、「检查条件」),边则定义了状态之间的转换规则(可以是确定性的函数或基于LLM输出的动态路由)。这种范式的优势在于能够清晰表达复杂的决策流程,支持循环重试、并行执行和条件分支。但其代价是引入了新的复杂性:开发者需要显式管理状态传递、防止意外的无限循环,并处理图执行过程中的异常。正是在这种范式下,当Agent的决策逻辑出现偏差时,它可能会在状态图中不断循环,既无法完成任务,也无法自行退出,最终导致资源耗尽。
针对这一痛点,EnDevSols团队开源了他们内部使用的中间件——LongGuard,一个专为LangGraph设计的「熔断器」(Circuit Breaker)。它的目标很明确:动态捕获并从这些失控循环中恢复,而不是简单地让程序崩溃。
熔断器模式在分布式系统中的应用
熔断器(Circuit Breaker)是一种源自电气工程的设计模式,在软件工程特别是微服务架构中被广泛采用。其核心思想是:当系统检测到某个服务或操作持续失败时,主动切断对该服务的调用,防止故障级联传播。这一模式最早由Michael Nygard在2007年的经典著作《Release It!》中系统性地引入软件领域,随后被Netflix的Hystrix库推广到全行业。经典的熔断器通常有三种状态:关闭(CLOSED,正常工作,所有请求正常通过)、开启(OPEN,阻断请求,直接返回错误或降级响应)、半开(HALF_OPEN,允许少量请求通过以尝试恢复)。在AI Agent场景中应用这一模式极具创新性:传统熔断器保护的是网络调用和服务间通信,防止的是基础设施层面的级联故障;而LongGuard保护的是Agent的认知循环,防止的是推理层面的失控。当Agent陷入无效推理时,熔断器能够识别这种「认知故障」,并通过注入反思提示来尝试「修复」Agent的思维路径,这比简单地终止进程要智能得多,也开创了将分布式系统可靠性模式应用于AI系统的新方向。

为什么内置的recursion_limit不够用
LangGraph本身提供了recursion_limit来防止无限循环,但这只是一个「粗暴的撞车护栏」(blunt crash barrier)。它能阻止程序永远跑下去,却做不到以下几件事:
- 无法区分Agent是在做有意义的多步推理,还是在原地打转;
- 无法在崩溃之前介入并尝试纠正;
- 崩溃后不保存状态,直接把异常甩给用户;
- 无法控制成本——等到触发limit时,钱早就花出去了。
Token与大语言模型计费机制
在大语言模型(LLM)的使用中,Token是计费和计量的基本单位。一个Token大约对应3/4个英文单词或半个中文字。不同模型使用不同的分词器(Tokenizer),例如OpenAI的GPT系列使用的是基于BPE(Byte Pair Encoding)的tiktoken,它将文本分割为子词单元。主流模型如GPT-4的定价通常分为输入Token和输出Token两部分,且输出Token的单价往往是输入的2-4倍。例如GPT-4o的定价约为每百万输入Token $2.50,每百万输出Token $10.00;而更强大的Claude 3.5 Sonnet则为每百万输入Token $3.00,每百万输出Token $15.00。
在AI Agent的失控循环中,成本增长往往不是线性的,而是呈现复合效应。每次循环不仅会重新发送历史对话上下文(消耗输入Token),还会生成新的推理输出(消耗输出Token)。更隐蔽的是,许多Agent框架会在每次迭代时携带完整的工具调用历史和中间状态,导致上下文长度像滚雪球一样增长。例如,第1次调用消耗2000 Token,第5次可能因为累积的上下文已经膨胀到8000 Token,第10次甚至达到15000 Token。这种超线性增长在触发recursion_limit之前,可能已经产生数十万Token的消耗。对于使用GPT-4等高成本模型的团队,一个周末的失控Agent可能烧掉数千美元预算。更严重的是,一些Agent部署在自动化流水线中,没有人工监控,失控可能持续数小时才被发现。这也是为什么实时熔断机制在商业部署中不可或缺。
换句话说,recursion_limit只是最后一道死亡线,而生产环境真正需要的是一套能提前感知、主动干预的机制。这正是LongGuard试图填补的空白。
四种失控模式的实时检测
LongGuard的核心是嵌入到你的StateGraph中,在Agent的每一步都以亚毫秒级速度评估四种失败模式:
1. 相同工具调用(Identical tool calls)
通过对工具参数进行快速的SHA-256哈希,在滑动窗口内捕获参数完全一致的重复调用。这种确定性哈希方式万无一失,且几乎没有延迟开销。
SHA-256是一种密码学哈希函数,属于SHA-2(Secure Hash Algorithm 2)家族,由美国国家安全局(NSA)设计。它能够将任意长度的输入数据映射为固定的256位(32字节)输出,通常表示为64个十六进制字符。其核心特性包括三点:单向性(无法从哈希值反推原始数据)、雪崩效应(输入哪怕只变化一个比特,输出也会面目全非)和确定性(相同输入必定产生相同输出)。LongGuard利用SHA-256的确定性特性来检测完全相同的工具调用:将工具名称和参数序列化(通常是JSON字符串化后排序键值)后计算哈希值,若在滑动窗口内出现相同哈希,即可断定发生了精确重复。这种方法的优势在于计算成本极低(现代CPU上每秒可处理数GB数据,Python中hashlib的SHA-256实现也足够高效)且准确率100%,不存在误判也不存在漏判。相比之下,基于字符串比较的方法容易受到参数顺序差异、空白字符和格式差异的干扰,而SHA-256在标准化序列化后的输出完美规避了这些问题。滑动窗口机制则确保系统只关注近期的调用模式,不会因为历史上的合理重复而误触发。
2. 语义震荡(Semantic oscillation)
更隐蔽的情况是,LLM换了措辞但本质上还卡在同一个思维循环里。LongGuard通过分析embedding的方差来识别这种「换汤不换药」的死循环。
Embedding(嵌入)是将文本、图像等高维离散数据映射到低维连续向量空间的技术,是现代深度学习的基石之一。在自然语言处理中,文本Embedding通过神经网络(如Transformer架构的编码器)将句子或段落编码为固定维度的稠密向量(常见维度为384、768或1536),使得语义相近的文本在向量空间中距离较近。例如,「搜索天气信息」和「查询气象数据」虽然措辞完全不同,但其Embedding向量的余弦相似度可能高达0.9以上。LongGuard利用这一特性来检测「语义震荡」:即使Agent每次换了不同的表述方式,只要其思维本质未变,对应的Embedding就会在高维空间中形成紧密的聚类。通过计算滑动窗口内连续Embedding向量的方差(variance),系统可以量化Agent思维的「扩散程度」——方差过低意味着向量高度聚集,Agent很可能在语义层面「原地踏步」。这种方法比简单的文本匹配智能得多,能捕获同义改写、语序调整等表层变化背后的实质重复。但它也有局限性:Embedding模型的质量直接影响检测精度,且方差阈值的合理设定需要根据具体场景调校——过低的阈值可能将正常的聚焦深度思考误判为循环,而过高的阈值则可能放过真正的语义震荡。
3. 死胡同漂移(Dead-end drift)
如果Agent连续走了5步以上却没有发现任何新的观察结果(用Jaccard相似度衡量),说明它可能已经陷入了无效探索,熔断器会被触发。
Jaccard相似度(Jaccard Similarity,又称Jaccard系数或IoU)是衡量两个集合相似程度的经典指标,定义为两集合交集大小与并集大小的比值:J(A,B) = |A∩B| / |A∪B|,取值范围为[0,1],其中0表示完全不相交,1表示完全相同。这一指标由瑞士植物学家Paul Jaccard于1901年提出,最初用于比较生态群落的物种组成,如今在信息检索、推荐系统和自然语言处理中广泛应用。在LongGuard的「死胡同漂移」检测中,系统将Agent每一步的观察结果(如工具返回的关键词、实体、数据字段等)进行分词或实体提取后视为集合,然后计算连续步骤间的Jaccard相似度。如果连续5步的相似度都超过某个高阈值(例如0.8),说明Agent虽然在「行动」,但实际上没有获取到实质性的新信息,陷入了无效探索。这种方法巧妙地将信息论中「信息增益」的概念转化为可计算的集合运算。相比直接比较输出文本,Jaccard方法更关注实质性的新发现,能够容忍措辞和格式的变化,但仍能捕获「原地打转」的本质特征。其计算复杂度为O(n)(n为集合元素数量),对实时系统几乎没有性能负担。
4. Token速率(Token velocity)
追踪每一步滚动的token消耗量,用来捕获指数级膨胀的「独白」——那种越写越长、越陷越深的自我对话。Token速率监控的原理是:正常的Agent推理通常表现出相对稳定的token消耗节奏,而失控的Agent往往会出现token消耗的急剧膨胀,因为它不断将之前失败的尝试纳入上下文,试图通过更长的推理来解决问题,结果却是越写越偏。通过设置token速率的增长阈值,系统可以在这种膨胀变得不可控之前发出预警。
这四种模式覆盖了从最明显的重复调用到最隐蔽的语义卡顿,形成了一张相对完整的Agent失控检测网。
检测性能的工程权衡
将监控逻辑嵌入到Agent的执行循环中是一把双刃剑。LongGuard在设计上追求「亚毫秒级」的检测延迟,这意味着其监控逻辑必须极其高效。SHA-256哈希计算在现代CPU上确实快如闪电(单核每秒可处理数百MB数据),Jaccard相似度的集合运算同样轻量。但embedding计算就完全不同了:即使使用轻量级模型如sentence-transformers的all-MiniLM-L6-v2(仅22M参数),每次推理在CPU上也需要10-50毫秒,在GPU上约1-5毫秒;若使用更精确的大型embedding模型(如OpenAI的text-embedding-3-large)则涉及网络请求,延迟可能达到数百毫秒。对于高频调用的Agent——特别是那些每秒可能执行多步的快速推理Agent——这种延迟可能累积成可观的性能开销。
LongGuard的策略是让用户在配置中权衡:对延迟敏感的场景可以只启用确定性检测(哈希和Jaccard),这些检测几乎是零成本的;而对成本更敏感的场景则可以接受轻微的性能损失来换取更全面的语义监控。此外,embedding计算可以采用异步执行或批量处理来降低对主流程的阻塞。这种模块化设计体现了工程中「没有银弹」的现实——每种检测方法都有其最佳适用场景,而最优配置取决于具体的业务需求和资源约束。
反思与转向:不是简单地杀掉进程
LongGuard最有意思的设计在于它的恢复机制。它没有在检测到循环时立刻终止运行,而是采用了一个比标准熔断器更精细的四态状态机:CLOSED → REFLECTING → HALF_OPEN → OPEN。
这个四态模型比经典的三态熔断器更加精细,专门为AI Agent的特性而设计。CLOSED状态表示正常监控,系统持续收集各项指标(哈希记录、embedding向量、Jaccard值、token计数)但不干预Agent的执行;当检测到潜在循环模式时进入REFLECTING状态,此时会向Agent注入反思提示但继续允许执行,给Agent一次自我纠正的机会——这是与传统熔断器最大的区别;如果Agent成功调整策略(表现为工具调用模式的改变、Jaccard相似度下降或新信息的获取),系统回到CLOSED状态;若Agent忽视提示继续重复,则进入HALF_OPEN状态进行最后一轮验证;确认无法恢复后才转入OPEN状态彻底熔断。
这种「渐进式干预」设计体现了对AI系统不确定性的深刻理解:与确定性程序不同,LLM驱动的Agent具有一定的随机性和自适应能力,同样的提示在不同上下文中可能产生截然不同的行为。过早熔断可能错失其自我恢复的机会(LLM有时只需要一个小小的提示就能跳出思维定势),而过晚干预又会造成不可挽回的资源浪费。在REFLECTING和HALF_OPEN之间留出的观察窗口,正是为这种不确定性预留的缓冲空间,这也是LongGuard区别于简单计数器或固定阈值方案的核心价值所在。
当检测到循环时,它会向Agent注入一个针对性的系统提示,例如:
"Stop calling search. You've attempted this 3 times with zero new information. Change your strategy."(停止调用搜索,你已经尝试了3次且没有任何新信息,请改变策略。)
这一「Reflect & Pivot」(反思与转向)的思路很关键:
- 如果Agent据此调整了策略(pivot),熔断器就会重置,让流程继续;
- 如果Agent依然固执地重复,熔断器会干净地终止运行,保存状态,并输出一份结构化的审计报告。
这种「先劝、再断」的两段式设计,比一刀切的崩溃要优雅得多,也更贴合真实生产场景的容错需求。
结构化审计报告的可观测性价值
LongGuard在熔断时生成的结构化审计报告是一个容易被忽视但极具价值的功能。在现代软件工程中,「可观测性」(Observability)已经成为生产系统的基础设施标配,其三大支柱是日志(Logs)、指标(Metrics)和追踪(Traces)。然而在AI Agent领域,可观测性仍处于早期阶段——大多数团队对Agent的内部推理过程缺乏系统性的监控和分析能力。
LongGuard的审计报告不仅记录了触发熔断的直接原因(如「连续5次相同工具调用」或「语义方差降至0.02以下」),还包含完整的执行轨迹:每一步的工具调用参数及返回结果、Token消耗的逐步变化、各项检测指标的时序曲线、状态机的状态转换记录等。这些数据对于生产环境的持续改进具有多重价值:如果审计日志显示Agent反复因「Access Denied」而卡住,可能说明权限管理策略有缺陷或系统提示词中缺少错误处理指导;如果语义震荡频繁出现在特定任务类型(如复杂的多步搜索),可能说明该任务的分解策略需要重新设计;如果Token速率经常在第4-5步开始飙升,可能说明上下文管理策略需要优化(例如引入摘要机制或截断早期历史)。这种数据驱动的Agent优化循环,是从「构建Agent」到「运营Agent」的关键跨越。
硬性预算上限:告别账单惊吓
除了循环检测,LongGuard还内置了一个覆盖40多个模型的定价引擎,允许你为每次运行设置硬性的美元预算上限:
GuardConfig(model="gpt-4o", max_cost_usd=0.50)
一旦某次运行的成本达到上限,熔断器就会跳闸。内置的定价引擎意味着用户不需要自己维护各模型的价格表——随着OpenAI、Anthropic等厂商频繁调价,这种自动化的成本追踪能力节省了大量的维护负担。对于成本敏感的生产部署来说,这是一个非常实用的安全阀,彻底避免因Agent卡住而产生的意外账单。
集成方式也极为简洁,只需一行包装即可:
from langgraph.graph import StateGraph
from longguard.integrations.langgraph import add_guard_to_graph
from longguard import GuardConfig
workflow = StateGraph(AgentState)
# ... 你的标准节点和边 ...
# 一行代码包装推理节点:
workflow = add_guard_to_graph(
workflow,
GuardConfig(model="gpt-4o", max_cost_usd=0.50)
)
app = workflow.compile()
这种极简的集成方式降低了采用门槛——团队可以在不重构现有Agent代码的前提下,快速为已有系统添加熔断保护。add_guard_to_graph函数在底层所做的是将监控节点插入到StateGraph的关键路径上,拦截每次状态转换以执行检测逻辑,同时保持原有图结构的语义不变。
权衡与局限:语义检测可能过度敏感
值得一提的是,作者坦诚地指出了工具的权衡取舍:
- 确定性哈希(相同工具调用检测):万无一失,零延迟,可以放心使用;
- 语义震荡检测器:这是需要注意的部分。如果你的Agent正在执行一个真正复杂的多步推理路径,但在评估器看来「像是重复」,语义检测器可能会过于激进地误判。此时需要针对具体场景调整默认阈值。
这种误判风险在某些特定场景下尤为突出。例如,一个负责代码调试的Agent可能需要反复审视同一段代码的不同方面,其推理内容在embedding空间中天然聚集;又如,一个进行深度研究的Agent可能需要对同一主题的多个来源进行交叉验证,每次搜索的语义都很接近但实际上是在做有意义的信息综合。在这些场景下,过低的方差阈值会频繁触发误报,打断正常的深度推理流程。因此,LongGuard并非开箱即用的万能方案,对于推理链本身就长而复杂的Agent,使用者需要投入一定的调优成本——包括分析审计日志中的误触发记录、逐步放宽特定检测器的阈值、甚至为不同任务类型配置不同的检测策略。
工程实践上的加分项
从工程角度看,LongGuard在依赖管理和代码质量上做得比较克制:
- MIT许可证:商用友好,集成无法律顾虑。MIT许可证是最宽松的开源许可之一,允许任何人在任何项目中免费使用、修改和分发代码,唯一要求是保留原始版权声明。这意味着企业可以将LongGuard集成到商业产品中而无需开源自己的代码,也不存在GPL等许可证的「传染性」风险;
- 完全类型标注(fully typed):对IDE和大型代码库友好。Python从3.5版本开始引入了类型提示(Type Hints)机制,允许开发者通过标注来显式声明变量、函数参数和返回值的类型(如
def process(data: List[str]) -> Dict[str, int])。完全类型标注的代码库意味着所有公共API都带有明确的类型声明,这使得IDE(如PyCharm、VS Code)可以提供精确的自动补全、参数提示和实时错误检查,静态分析工具(如mypy、pyright)能在代码运行前发现类型不匹配的潜在bug。对于像LongGuard这样被集成到其他项目中的中间件库来说,完全类型标注尤为重要:它让集成方可以更安全、更高效地使用API,大幅减少因参数类型错误导致的运行时崩溃,这在生产环境中意味着更少的线上事故和更低的调试成本; - 不强制引入重型ML依赖:不会因为一个熔断器就往你的技术栈里塞一堆机器学习包。这一点在实际部署中非常重要——许多ML库(如PyTorch、TensorFlow)体积庞大(数百MB到数GB),且可能与现有依赖产生版本冲突。LongGuard将embedding相关功能设计为可选依赖,核心的确定性检测功能保持轻量。
这些细节反映出团队对生产环境实际约束的理解——生产级工具的价值不仅在于功能本身,还在于它是否「轻量、可控、不添乱」。一个引入大量依赖或破坏现有构建流程的工具,无论功能多强大,在实际采用中都会面临巨大阻力。
小结
LongGuard解决的是一个非常具体但普遍存在的Agent工程痛点:失控循环导致的token浪费与账单失控。它的防护思路可以概括为三个层次:
- 多维度检测——从哈希级的精确匹配到embedding级的语义分析,覆盖四种常见失控模式;
- 主动恢复——通过注入提示引导Agent「反思与转向」,而非直接崩溃;
- 硬性成本兜底——用预算上限彻底堵住账单漏洞。
对于任何在生产环境中运行LangGraph Agent的团队来说,这是一个值得关注的开源方案。它填补了LangGraph原生recursion_limit和真正的生产级容错之间的空白,将分布式系统中成熟的熔断器模式创造性地应用于AI Agent的认知循环保护。当然,语义检测的阈值调优以及尚未覆盖到的边缘场景(如多Agent协作中的级联失控、跨会话的状态持久化等),仍需要在实际使用中逐步验证和完善。项目欢迎社区提交PR和Issue,共同完善这套熔断机制。
相关推荐

对抗AI代码腐化:规格、结果笔记与文件清单的实战方法
一位开发者用八个月、650次提交、4.3万行代码的实战,总结出防止AI智能体代码库腐化的方法:前置规格与验收标准、任务结果笔记、文件清单约束,以及用触发式钩子取代规则文件。核心洞察是——指令只是建议,机制才能在长会话中存活。

"Tokens Exhausted":一段机器人视频背后的AI焦虑
一段名为「Tokens Exhausted」的机器人视频在 Reddit 引发热议,网友已分不清它是否为波士顿动力真实作品。本文解析这段AI讽刺内容为何戳中神经,以及它折射出的合成媒体与LLM时代焦虑。

4千美元淘到全新DGX Spark:本地部署大模型的性价比之选
一位Reddit用户以4000美元在Craigslist淘到全新DGX Spark,用于本地托管AI模型。本文解析这笔交易背后的性价比、二手交易安全,以及本地部署大模型的兴起趋势。