ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Multi-Agent容错实战:从重试到Checkpoint与幂等性设计

Multi-Agent容错实战:从重试到Checkpoint与幂等性设计 1. 为什么“失败就重试”在 Multi-Agent 里是个陷阱1.1 单 Agent 时代的重试逻辑为什么能凑合用大部分人第一次接触 Agent 开发都是从单 Agent 起步的。一个 LLM 调用包一层try/except失败了就for i in range(3)重试三次再不行就抛异常。这套逻辑在单 Agent 场景下确实能跑通因为它的假设非常朴素失败是瞬时的、无状态的、可重复的。比如你调一个翻译接口超时了重试一次大概率能成功。因为翻译这个动作不依赖上一次调用的任何中间状态输入一样输出就一样。这就是典型的幂等操作——执行一次和执行十次对系统的影响是一样的。但 Multi-Agent 系统完全不是这个逻辑。我见过太多项目一个 Orchestrator 带着三五个 Worker Agent每个 Worker 有自己的工具调用、有自己的记忆、有自己的中间产物。这时候某个 Worker 挂了你直接重试会发生什么1.2 Multi-Agent 失败的真实代价状态污染与副作用叠加举个我实际踩过的坑。之前做一个文档分析的多 Agent 系统结构是这样的一个 Planner 负责拆任务一个 Retriever 负责检索一个 Summarizer 负责总结一个 Writer 负责成文。四个 Agent 串行协作中间通过共享的 Context 传递数据。有一次 Summarizer 在调用外部模型时超时了。当时的代码逻辑很简单捕获异常后直接重试。结果重试成功了但最终输出里出现了两份摘要——因为 Summarizer 在超时之前其实已经把第一份摘要写进了共享 Context只是返回响应的时候超时了。重试之后它又写了一份Context 里就有了重复数据Writer 拿到两份摘要输出直接乱掉。这就是 Multi-Agent 重试的第一个大坑副作用已经发生但调用方不知道。在分布式系统里这叫“部分失败”是经典难题。单 Agent 场景下Agent 本身没有持久化状态重试是干净的Multi-Agent 场景下每个 Agent 都可能是状态的持有者和修改者重试就是在脏状态上再叠一层。第二个坑更隐蔽重试会放大下游压力。假设你有 10 个 Worker Agent 并行跑其中一个因为下游限流失败了你重试。如果重试策略没做好退避10 个 Worker 同时重试下游瞬间被打爆本来只是偶发失败现在变成雪崩。这在 Agent 编排里特别常见因为 Agent 之间的调用链比普通微服务更长一个失败可能触发上游多个 Agent 的连锁重试。第三个坑是语义层面的不可重试。有些 Agent 的动作天然有副作用比如“发送邮件”“写入数据库”“调用支付接口”。这类操作失败了你根本不知道它到底执行没执行。盲目重试可能导致重复发送、重复扣款。这时候需要的不是重试而是幂等性设计和状态确认。所以标题说“只会重试就太初级了”不是危言耸听。重试只是最表层的容错手段真正成熟的 Multi-Agent 系统需要一整套围绕状态管理、幂等性、检查点、补偿的机制。下面我按自己实际做过的项目把这套东西拆开讲。2. Multi-Agent 容错的核心思路拆解2.1 先搞清楚失败的类型再决定怎么处理很多人一上来就写重试逻辑但根本没分类失败。我的经验是Multi-Agent 里的失败至少分四类每类的处理策略完全不同失败类型典型场景是否可重试推荐策略瞬时故障网络抖动、下游限流、模型超时可重试指数退避 抖动 最大次数状态不一致Agent 写了一半 Context 就挂了不可直接重试Checkpoint 回滚 重放语义副作用发邮件、写库、调支付不可盲目重试幂等键 状态查询逻辑错误Prompt 有问题、工具参数错重试无用快速失败 告警 人工介入这张表是我踩了无数坑之后总结的。核心观点是重试只对第一类有效。后面三类你重试一百次也没用甚至越重试越糟。举个具体例子。之前有个项目Writer Agent 调用一个内部 API 生成 PDF。这个 API 有副作用——每次调用都会在对象存储里生成一个文件。有一次调用超时了代码重试结果对象存储里出现了两个文件后续的下载链接指向了旧的那个用户拿到的是过期内容。这就是典型的“语义副作用 盲目重试”导致的 bug。后来我们的改法是给每次 PDF 生成请求带一个幂等键比如task_id versionAPI 端先查这个键有没有对应的文件有就直接返回没有才生成。这样重试就安全了。这个思路在分布式系统里叫幂等性设计是 Multi-Agent 容错的基础设施。2.2 Checkpoint 机制让 Agent 可以“存档读档”如果说幂等性是防重复那 Checkpoint 就是防丢失。Multi-Agent 系统跑一个长任务可能涉及几十次 Agent 调用、上百次工具调用中间任何一步失败如果从头再来成本极高。这时候就需要 Checkpoint。Checkpoint 的本质很简单在关键节点把整个系统的状态序列化存下来。这个状态包括每个 Agent 的输入输出、共享 Context 的内容、已经执行到哪一步、哪些工具调用已经完成。失败之后从最近的 Checkpoint 恢复而不是从零开始。我在一个数据分析的多 Agent 项目里用过这套机制。整个流程是数据清洗 Agent → 特征工程 Agent → 建模 Agent → 报告 Agent。每个 Agent 跑完就把当前状态写到一个 JSON 文件里同时记录一个step_id。如果建模 Agent 挂了重启后直接读step_id2的 Checkpoint从特征工程的结果继续前面的清洗和特征工程不用重跑。这里有个关键细节Checkpoint 的粒度。粒度太粗恢复时浪费算力粒度太细写 Checkpoint 本身的开销就很大。我的经验是按“Agent 调用”为粒度比较合适因为 Agent 调用通常耗时较长几秒到几十秒写一次 Checkpoint 的开销可以接受。如果 Agent 内部有多个工具调用可以在工具调用前后也加轻量级的 Checkpoint。还有一个坑Checkpoint 的版本兼容。你存的状态格式恢复的时候代码可能已经改了字段对不上。所以 Checkpoint 里一定要带 schema 版本号恢复时做兼容处理或者拒绝恢复。这个在快速迭代的项目里特别容易出问题。2.3 幂等性不是可选项是必选项幂等性这个词听起来很学术其实用生活类比很好理解电梯按钮。你按一次和按十次电梯都只来一趟。这就是幂等。Multi-Agent 系统里每个有副作用的操作都应该设计成幂等的。实现幂等性有几个层次从简单到复杂第一层天然幂等。查询类操作天然幂等比如“读取文件内容”“查询数据库”。这类操作重试无副作用随便重试。第二层幂等键去重。给每个操作分配一个唯一 ID服务端记录已处理的 ID重复请求直接返回缓存结果。这是最常用的方案。幂等键的生成要保证全局唯一通常用task_id agent_id step_id组合。第三层状态机约束。把操作设计成状态机只有特定状态才能执行特定动作。比如订单 Agent只有pending状态才能paypaid状态再调pay直接拒绝。这样即使重试也不会重复扣款。第四层补偿事务。对于无法幂等的操作设计一个反向操作来抵消。比如“扣款”失败了但不确定是否成功就查一下账户余额如果扣了就走退款流程。这就是 Saga 模式的思路。我在实际项目里第二层和第三层用得最多。幂等键去重适合工具调用状态机约束适合 Agent 之间的协作流程。两者结合基本能覆盖 90% 的场景。2.4 重试策略本身也要讲究退避、抖动、熔断就算确定了某个失败可以重试重试的方式也很关键。我见过最粗暴的写法是while True: try: ... except: continue这简直是灾难。正确的重试策略至少包含三个要素指数退避第一次等 1 秒第二次等 2 秒第三次等 4 秒以此类推。目的是给下游恢复的时间避免持续施压。抖动Jitter在退避时间上加一个随机量比如sleep base * 2^n random(0, 1)。目的是避免多个 Agent 同时重试造成“惊群效应”。这个在并行 Agent 场景下特别重要。熔断如果某个下游连续失败 N 次直接熔断不再重试快速失败。等一段时间后再半开试探。这个能防止一个坏掉的下游拖垮整个系统。我用 Python 写过一个通用的重试装饰器核心逻辑大概是这样import time import random from functools import wraps def retry_with_backoff(max_retries3, base_delay1, max_delay30, jitterTrue): def decorator(func): wraps(func) def wrapper(*args, **kwargs): for attempt in range(max_retries 1): try: return func(*args, **kwargs) except RetryableError as e: if attempt max_retries: raise delay min(base_delay * (2 ** attempt), max_delay) if jitter: delay random.uniform(0, delay * 0.5) time.sleep(delay) except NonRetryableError: raise return wrapper return decorator注意这里区分了RetryableError和NonRetryableError。这个区分非常重要前面说的四类失败只有第一类应该抛RetryableError其他三类直接抛NonRetryableError快速失败。很多项目就是没做这个区分所有异常都重试结果逻辑错误也重试白白浪费时间。3. 核心细节解析与实操要点3.1 Checkpoint 存什么、存哪里、怎么恢复Checkpoint 的设计是 Multi-Agent 容错的核心我把它拆成三个问题存什么、存哪里、怎么恢复。存什么一个完整的 Checkpoint 至少包含以下字段{ checkpoint_id: ckpt_20240101_001, schema_version: 1.2, task_id: task_abc123, step_id: 3, timestamp: 1704067200, agent_states: { planner: {status: done, output: {...}}, retriever: {status: done, output: {...}}, summarizer: {status: running, partial_output: {...}} }, shared_context: {...}, completed_tool_calls: [call_1, call_2], pending_tool_calls: [call_3] }这里的关键是completed_tool_calls和pending_tool_calls。恢复的时候已完成的工具调用直接跳过用缓存结果未完成的重新执行。这样既避免了重复副作用又不会丢失进度。存哪里小项目直接写本地文件就行JSON 或 pickle 都可以。但生产环境建议用对象存储比如 S3 兼容的存储或者数据库。我一般用 Redis 存热数据最近几个 Checkpoint用对象存储存冷数据历史 Checkpoint。Redis 的好处是读写快恢复延迟低对象存储的好处是容量大、成本低。怎么恢复恢复逻辑要处理三种情况Checkpoint 完整且 schema 兼容直接加载从step_id继续。Checkpoint 存在但 schema 不兼容尝试迁移迁移不了就回退到更早的 Checkpoint或者从头开始。Checkpoint 损坏校验和失败回退到上一个可用 Checkpoint。这里有个实操心得Checkpoint 一定要做校验和。我遇到过磁盘写入中断导致 Checkpoint 文件半截的情况恢复的时候 JSON 解析失败整个任务卡死。后来加了 CRC32 校验损坏的 Checkpoint 直接跳过回退到上一个问题就解决了。3.2 幂等键的设计与生成规则幂等键的设计看似简单其实有很多细节。核心原则是同一个逻辑操作无论重试多少次幂等键必须相同不同的逻辑操作幂等键必须不同。我常用的生成规则是idempotency_key hash(task_id agent_id step_id operation_name input_hash)逐个解释task_id整个任务的唯一标识保证不同任务之间不冲突。agent_id哪个 Agent 发起的操作同一任务里不同 Agent 的操作要区分。step_id第几步同一 Agent 的不同步骤要区分。operation_name操作名称比如send_email、write_db。input_hash输入参数的哈希保证相同输入才复用结果。这里有个坑input_hash 不能包含时间戳、随机数等易变字段。我见过有人把timestamp放进输入里算哈希结果每次重试哈希都不一样幂等键失效去重完全没用。所以输入哈希之前要把易变字段剔除。另一个坑幂等键的存储要有 TTL。不能无限期存着否则存储会爆。TTL 的设置要大于任务的最大可能重试时间窗口。我一般设 24 小时对于长任务设 7 天。幂等键的存储用 Redis 最合适因为需要高性能的读写和 TTL 支持。用SET key value NX EX ttl一条命令就能实现“不存在才写入 过期时间”天然适合幂等去重。3.3 Agent 之间的状态同步共享 Context 的并发问题Multi-Agent 系统里Agent 之间通常通过共享 Context 传递数据。这个 Context 在并行场景下就是并发写热点处理不好会出现数据覆盖、丢失更新。我遇到过最典型的问题两个 Worker Agent 同时往 Context 的一个列表里 append 数据结果其中一个的写入被覆盖了。原因是读-改-写不是原子的。解决方案有几个方案一加锁。用分布式锁比如 Redis 的 Redlock保护 Context 的写操作。简单有效但性能差Agent 多了会排队。方案二CASCompare-And-Swap。每次写 Context 带一个版本号写入时检查版本号是否变化变了就重试。这个比锁性能好但实现复杂。方案三事件溯源。不直接改 Context而是把每个 Agent 的输出作为事件追加到事件日志里最终状态由事件重放得到。这个最优雅但改造成本高。我在实际项目里小规模用方案一大规模用方案三。方案二用得少因为 CAS 的重试逻辑容易写错调试困难。这里还有个细节Context 的 schema 要严格定义。我见过项目用裸 dict 当 Context不同 Agent 往里塞各种字段最后字段冲突、类型不一致排查起来极其痛苦。后来改成 Pydantic 模型每个字段有明确类型和默认值问题少了很多。3.4 失败分类器的实现怎么判断该不该重试前面说了失败分四类但实际代码里怎么判断我的做法是写一个失败分类器根据异常类型、错误码、错误信息来判断。class FailureClassifier: RETRYABLE_CODES {408, 429, 500, 502, 503, 504} NON_RETRYABLE_CODES {400, 401, 403, 404, 422} staticmethod def classify(exception): if isinstance(exception, TimeoutError): return FailureType.TRANSIENT if isinstance(exception, ConnectionError): return FailureType.TRANSIENT if isinstance(exception, HTTPError): if exception.status_code in FailureClassifier.RETRYABLE_CODES: return FailureType.TRANSIENT if exception.status_code in FailureClassifier.NON_RETRYABLE_CODES: return FailureType.LOGIC if isinstance(exception, StateInconsistencyError): return FailureType.STATE if isinstance(exception, SideEffectError): return FailureType.SIDE_EFFECT return FailureType.UNKNOWN分类之后不同类别走不同处理路径TRANSIENT走重试STATE走 Checkpoint 回滚SIDE_EFFECT走幂等查询LOGIC直接告警。这个分类器不是一次写完的是随着项目跑不断补充规则。我建议一开始就搭好框架后面遇到新的失败类型往里加规则就行。4. 实操过程与核心环节实现4.1 搭建一个带 Checkpoint 的 Multi-Agent 骨架下面我用 Python 写一个最小可用的 Multi-Agent 骨架包含 Checkpoint、幂等、重试三个核心机制。代码不追求生产级完备但逻辑是完整的可以直接参考。先定义状态和 Checkpoint 的数据结构from pydantic import BaseModel, Field from typing import Dict, List, Optional, Any import json import hashlib import time class AgentState(BaseModel): agent_id: str status: str # pending, running, done, failed output: Optional[Dict[str, Any]] None error: Optional[str] None class Checkpoint(BaseModel): checkpoint_id: str schema_version: str 1.0 task_id: str step_id: int timestamp: float agent_states: Dict[str, AgentState] shared_context: Dict[str, Any] completed_tool_calls: List[str] Field(default_factorylist) checksum: Optional[str] None def compute_checksum(self): data self.model_dump(exclude{checksum}) raw json.dumps(data, sort_keysTrue).encode() return hashlib.sha256(raw).hexdigest()[:16]然后是 Checkpoint 的存储层我用本地文件模拟生产环境换成 Redis 或对象存储import os class CheckpointStore: def __init__(self, base_dir./checkpoints): self.base_dir base_dir os.makedirs(base_dir, exist_okTrue) def save(self, ckpt: Checkpoint): ckpt.checksum ckpt.compute_checksum() path os.path.join(self.base_dir, f{ckpt.task_id}_{ckpt.step_id}.json) tmp_path path .tmp with open(tmp_path, w) as f: f.write(ckpt.model_dump_json()) os.replace(tmp_path, path) # 原子替换避免半截文件 def load_latest(self, task_id: str) - Optional[Checkpoint]: files [f for f in os.listdir(self.base_dir) if f.startswith(task_id)] if not files: return None files.sort(keylambda f: int(f.split(_)[-1].split(.)[0])) for f in reversed(files): path os.path.join(self.base_dir, f) try: with open(path) as fp: ckpt Checkpoint.model_validate_json(fp.read()) if ckpt.checksum ckpt.compute_checksum(): return ckpt except Exception: continue return None注意os.replace这个细节它是原子操作保证不会出现半截文件。还有load_latest里的校验和检查损坏的 Checkpoint 直接跳过。4.2 幂等工具调用的实现接下来是幂等工具调用的封装。核心思路是调用前先查幂等键有缓存直接返回没有才真正执行执行完写缓存。import redis import json class IdempotentToolExecutor: def __init__(self, redis_client, ttl86400): self.redis redis_client self.ttl ttl def _make_key(self, task_id, agent_id, step_id, op_name, params): # 剔除易变字段 stable_params {k: v for k, v in params.items() if k not in (timestamp, nonce, request_id)} raw f{task_id}:{agent_id}:{step_id}:{op_name}:{json.dumps(stable_params, sort_keysTrue)} return idem: hashlib.sha256(raw.encode()).hexdigest() def execute(self, task_id, agent_id, step_id, op_name, params, func): key self._make_key(task_id, agent_id, step_id, op_name, params) # 先查缓存 cached self.redis.get(key) if cached: return json.loads(cached) # 用 SET NX 占位防止并发重复执行 lock_key key :lock acquired self.redis.set(lock_key, 1, nxTrue, ex60) if not acquired: # 其他进程正在执行等待结果 for _ in range(30): time.sleep(0.5) cached self.redis.get(key) if cached: return json.loads(cached) raise TimeoutError(等待幂等结果超时) try: result func(**params) self.redis.set(key, json.dumps(result), exself.ttl) return result finally: self.redis.delete(lock_key)这里有两个关键点一是SET NX占位锁防止并发重复执行二是执行完写结果缓存后续重试直接命中。这个模式在分布式系统里叫“幂等执行器”是处理有副作用操作的标准方案。4.3 带退避和熔断的重试执行器重试执行器我前面给了装饰器版本这里给一个更完整的、带熔断的版本class CircuitBreaker: def __init__(self, failure_threshold5, recovery_timeout60): self.failure_threshold failure_threshold self.recovery_timeout recovery_timeout self.failures 0 self.last_failure_time 0 self.state closed # closed, open, half_open def call(self, func, *args, **kwargs): if self.state open: if time.time() - self.last_failure_time self.recovery_timeout: self.state half_open else: raise CircuitOpenError(熔断器打开快速失败) try: result func(*args, **kwargs) if self.state half_open: self.state closed self.failures 0 return result except Exception as e: self.failures 1 self.last_failure_time time.time() if self.failures self.failure_threshold: self.state open raise熔断器的三个状态closed正常放行open直接拒绝half_open试探性放行。这个模式能有效防止一个坏掉的下游拖垮整个系统。把重试、熔断、幂等组合起来一个完整的工具调用流程是检查熔断器状态open直接失败。检查幂等缓存命中直接返回。执行实际调用失败则分类。可重试的失败走退避重试。重试仍失败记录熔断计数。不可重试的失败直接抛出。4.4 一个完整的失败恢复流程演示假设我们有一个三 Agent 的流程Planner → Worker → Writer。Worker 在调用外部 API 时失败了。完整的恢复流程是这样的第一步失败捕获与分类。Worker 捕获到TimeoutError分类器判定为TRANSIENT可重试。第二步检查幂等缓存。用幂等键查 Redis发现没有缓存说明是首次执行。第三步重试。按指数退避重试三次如果都失败进入下一步。第四步保存 Checkpoint。把当前状态Planner 已完成、Worker 失败、Writer 未开始存成 Checkpointstep_id2。第五步告警与人工介入。如果配置了自动恢复可以等一段时间后从 Checkpoint 恢复否则告警人工决定是否恢复。第六步恢复执行。从step_id2的 Checkpoint 加载Worker 重新执行。这次因为幂等键相同如果之前有部分副作用会被去重。这个流程看起来步骤多但每一步都是必要的。少了任何一步都可能出问题。比如少了幂等检查恢复时可能重复副作用少了 Checkpoint恢复时要从头跑。5. 常见问题与排查技巧实录5.1 重试导致重复副作用的排查症状任务重试后下游出现了重复数据比如重复的邮件、重复的文件、重复的数据库记录。排查思路先确认副作用操作有没有幂等键。没有的话这是根因。有幂等键的话检查幂等键的生成规则是不是包含了易变字段。检查幂等键的存储是不是 TTL 太短重试时缓存已经过期。检查并发场景是不是两个请求同时执行都没命中缓存。解决方案按前面说的幂等执行器模式改造确保幂等键稳定、TTL 足够、并发有锁。5.2 Checkpoint 恢复后状态错乱的排查症状从 Checkpoint 恢复后Agent 的行为异常比如重复处理已经处理过的数据或者跳过了某些步骤。排查思路检查 Checkpoint 里的completed_tool_calls和pending_tool_calls是否正确。检查恢复逻辑有没有正确跳过已完成的步骤。检查 schema 版本是不是恢复时代码已经改了字段对不上。检查 Checkpoint 的写入时机是不是在副作用发生之前就写了。解决方案Checkpoint 的写入时机很关键要在“副作用完成之后、下一步开始之前”写。这样恢复时已完成的副作用不会重复未开始的步骤会重新执行。5.3 并行 Agent 的惊群效应排查症状下游服务偶发失败后突然收到大量重试请求导致雪崩。排查思路检查重试策略有没有加抖动。没有抖动的话多个 Agent 会同时重试。检查重试的退避曲线是不是退避时间太短。检查有没有熔断机制失败多了应该快速失败而不是继续重试。解决方案加抖动、加长退避、加熔断。三个一起上基本能解决。5.4 常见问题速查表问题可能原因快速排查解决方案重复副作用无幂等键或幂等键不稳定查幂等键生成逻辑稳定幂等键 Redis 去重状态错乱Checkpoint 时机不对查 Checkpoint 写入点副作用后写 Checkpoint雪崩重试无抖动无熔断查重试策略退避 抖动 熔断恢复失败Checkpoint 损坏或 schema 不兼容查校验和和版本号校验和 schema 迁移并发覆盖Context 读改写非原子查并发写逻辑加锁或事件溯源重试无效逻辑错误被当瞬时故障查失败分类器区分可重试与不可重试5.5 几个我踩过的坑和独家心得坑一幂等键用了 UUID。UUID 每次生成都不一样幂等键就失效了。幂等键必须是确定性的由输入参数计算得出不能用随机数。坑二Checkpoint 存了不可序列化的对象。比如存了一个数据库连接、一个文件句柄恢复的时候直接报错。Checkpoint 里只能存可序列化的纯数据连接这类资源要重新建立。坑三重试次数设太多。有人设max_retries10结果一个失败要等好几分钟才最终失败。我的经验是 3 次足够超过 3 次还失败说明不是瞬时故障重试也没用。坑四忘了清理旧的 Checkpoint。任务跑多了Checkpoint 文件堆满磁盘。要加定期清理只保留最近 N 个或者最近 M 天的。坑五幂等缓存和实际状态不一致。幂等缓存说操作成功了但实际数据库里没有。这种情况通常是缓存写入和实际写入不在一个事务里。解决方案是缓存写入放在实际写入之后或者用两阶段提交。这些坑文档里不会写但实际项目里一定会遇到。我的建议是一开始就把幂等、Checkpoint、重试这三件事的框架搭好后面遇到问题往里填规则比事后补救省事得多。6. 从“会重试”到“会容错”的思维转变写到这里我想聊聊思维层面的东西。很多人做 Agent 开发脑子里只有“调用-失败-重试”这个循环这是单机时代的思维。Multi-Agent 系统本质上是分布式的分布式系统的容错是一整套体系重试只是其中最基础的一环。我自己的转变是从做第一个多 Agent 项目开始的。当时一个任务跑了半小时最后一步失败了从头再来又是半小时效率极低。后来加了 Checkpoint失败后从中间恢复时间缩短到几分钟。再后来遇到重复副作用的问题加了幂等。再后来遇到雪崩加了熔断。每一步都是被问题逼出来的。现在回头看如果一开始就有这套体系的设计意识能少走很多弯路。所以我的建议是做 Multi-Agent 项目先把容错框架搭起来再写业务逻辑。框架包括失败分类器、重试执行器、幂等执行器、Checkpoint 存储、熔断器。这五个组件搭好后面写 Agent 就是往里填逻辑容错自动生效。最后分享一个我常用的调试技巧给每个 Agent 调用打上 trace_id所有日志、Checkpoint、幂等键都带上这个 trace_id。出问题的时候用 trace_id 一搜整个调用链一目了然。这个在 Multi-Agent 场景下特别有用因为调用链长、Agent 多没有 trace_id 根本理不清。这套东西不是一天建成的我也是在项目里一点点磨出来的。但只要你开始往这个方向想从“失败就重试”升级到“失败有分类、状态有检查点、操作有幂等、系统有熔断”你的 Multi-Agent 系统就上了一个台阶。
返回列表