[控场AI]
· 6 分钟阅读· 3,418 字

Cellaflow:为AI Agent加上步骤级幂等与协调

Cellaflow:为AI Agent加上步骤级幂等与协调

Cellaflow 在 Agent 侧用租约和日志实现步骤级幂等,避免重复执行不可逆操作。

Cellaflow 是一个开源项目,旨在解决 AI Agent 在重试或并发时重复执行不可逆操作的问题。它不要求下游系统支持幂等键,而是通过装饰器在 Agent 侧包裹工具函数,由 Rust 引擎记录执行结果并协调并发。核心机制是租约:第一个调用者获得租约并执行,后续重试或并发请求直接复用结果。引擎通过心跳、栅栏令牌和最大生命周期来区分持有者死亡与变慢,防止脑裂。状态以仅追加日志加 fsync 持久化,支持 RocksDB 或 Postgres。项目兼容 LangGraph、CrewAI 等主流框架,提供 Python 和 TypeScript SDK,引擎采用 BSL 1.1 许可证,可免费用于生产。社区认可其价值,但也指出引入独立引擎会增加架构复杂度。

AI Agent在自动化任务中常常面临一个棘手问题:重复执行不可逆操作。比如,一个负责下单的Agent在重试时可能重复扣款,或者两个并发的Worker同时抢到同一个任务,导致订单被重复提交。针对这一痛点,开源项目Cellaflow提出了一种无需将Agent迁移到工作流引擎的解决方案——在步骤级别实现幂等与跨Agent协调。

Cellaflow项目介绍

为什么需要步骤级幂等

传统的幂等机制通常依赖于被调用方提供幂等键,但现实是,许多操作根本不支持这种机制。作者在Reddit帖子中列举了典型场景:你让Agent点击的结算页面不接受幂等键;通过SMTP发送的邮件、通过电话提供商拨打的电话、通过遗留排程系统预订的约会,同样无法保证幂等。大多数内部API和ERP系统也存在同样的问题。

这意味着,当Agent因为超时或错误而重试时,重复操作的风险完全由Agent侧承担。Cellaflow的思路正是从Agent端入手,通过装饰器包裹“不可逆”的函数,由引擎来记录执行结果并处理并发。

幂等键(Idempotency Key) 是分布式系统中实现幂等操作的常见手段:调用方为每次请求生成一个唯一标识符,服务端记录该键与结果的映射,当相同键再次到达时直接返回之前的结果而不重复执行。Stripe 的支付 API 就是典型例子——客户端在请求头中携带 Idempotency-Key,服务端保证同一键最多扣款一次。然而,幂等键的前提是被调用方主动支持并实现这套逻辑,对于无法改造的遗留系统、第三方页面点击、SMTP 邮件等场景,调用方根本无权要求对方识别幂等键。Cellaflow 的价值在于把幂等责任从被调用方转移到 Agent 侧,由引擎在调用发生前就拦截重复请求,从而绕过了下游系统不支持幂等键的限制。

工作原理:租约与结果复用

Cellaflow的核心机制围绕“租约(lease)”展开。当Agent调用一个被@tool装饰的函数时,第一个调用者会获得租约并执行操作,引擎记录下结果。之后的重试,或者另一个Agent请求相同的操作,都会直接拿到之前的结果,而不会再次执行。

作者在开源Agent代码库上进行了测试,通过中途杀死进程和并发运行多个Worker来统计重复执行的情况。以Skyvern为例,两个Worker同时处理同一个结算任务时,原本会各自下单;加上租约和操作级幂等后,第二个Worker被拒绝,订单只提交一次。

引擎本身是一个Rust守护进程,通过gRPC通信,使用RocksDB或Postgres存储。每个会话运行在独立的actor中(一个带邮箱的Tokio任务),会话状态不在actor间共享。操作在引擎响应之前会写入仅追加日志并执行fsync,确保持久性。当会话空闲时,actor被驱逐,下次请求时从日志重建——同样的过程也用于崩溃恢复。

仅追加日志(Append-Only Log) 是一种持久化数据结构,所有状态变更以追加记录的方式写入,而不是原地修改。配合 fsync 系统调用将数据强制刷盘,可以保证即使在写入后立即断电,已确认的操作也不会丢失。Cellaflow 在响应调用者之前先写日志并 fsync,意味着“操作已执行”这一事实在返回结果前就已持久化,重试时可以从日志中重建结果。这种设计也让崩溃恢复变得简单:重启后重放日志即可还原会话状态,无需依赖内存中的易失数据。RocksDB 和 Postgres 都支持这种追加写入模式,前者适合单机高吞吐,后者便于多节点共享存储。

租约管理:心跳、栅栏令牌与超时

租约过期并不一定意味着持有者已经死亡,也可能只是速度慢。为了区分这两种情况,Cellaflow要求持有者发送心跳,并为每个租约分配一个栅栏令牌(fencing token)。如果一个旧的持有者在另一个Worker接管后醒来,引擎会拒绝它的提交,从而避免脑裂问题。

此外,引擎还设置了租约的最大生命周期,默认一小时,用于处理那些挂起且不退出进程的Worker。其他调用者会等待当前持有者完成并接收其结果;如果持有者始终不完成,等待者之一可以接管。

对于跨会话的协调,不同会话中的Agent可以通过传递相同的协调ID(coordination ID)来共享同一个操作。

栅栏令牌(Fencing Token) 源自分布式系统防止脑裂的经典方案:每次授予租约时,令牌单调递增,持有者在提交操作时必须携带该令牌。存储层或引擎会拒绝令牌小于当前已知最大值的提交,因为那意味着持有者已经过期、资源已被新持有者接管。即使旧持有者因 GC 停顿或网络分区而“复活”,它的提交也会因令牌过时而失败,从而避免两个 Worker 同时写入造成数据损坏。心跳机制则用于区分“持有者已死亡”与“持有者只是慢”:持有者定期续约,引擎在心跳超时后才允许其他调用者接管,减少了误判导致的频繁切换。

快速上手与生态支持

使用Cellaflow只需要三步:启动引擎、安装SDK、包装工具函数。以下是一个简单的Python示例:

from cellaflow import workflow, tool, IdempotencyScope

@tool(
    tool_name="charge_card",
    scope=IdempotencyScope.SCOPE_SHARED,
    shared_on=["order_id"],
)
def charge_card(order_id: str, amount_cents: int) -> dict:
    return payments.charge(order_id, amount_cents)

@workflow(version="1.0.0")
def checkout(order_id: str) -> dict:
    return charge_card(order_id, 2499)

两次调用checkout("order-88", _coordination_id="order-88")会使用相同的协调ID,从而保证只执行一次扣款。

Cellaflow声称兼容所有主流Agent框架,包括LangGraph、CrewAI、AutoGen和OpenAI SDK。SDK提供Python和TypeScript版本,采用Apache 2.0或MIT许可证;引擎采用BSL 1.1许可证,允许免费用于生产环境,并会在固定日期转换为Apache 2.0。

BSL 1.1(Business Source License 1.1) 是一种“延迟开源”许可证:它允许用户免费使用、修改和分发软件,甚至用于生产环境,但限制将软件作为托管服务对外提供(即与许可证持有者竞争)。许可证中会指定一个“变更日期”,到期后自动转换为完全开源许可证(如 Apache 2.0)。Cellaflow 引擎采用 BSL 1.1,意味着团队可以免费在生产中部署自用,但如果想基于它构建并出售托管的幂等服务,则需要获得商业授权。这种模式在基础设施类开源项目中较为常见(如 HashiCorp 的部分产品),兼顾了社区采用与商业可持续性。

社区反馈与潜在考量

该项目在Reddit上发布后,引发了对Agent可靠性的讨论。有开发者认为,步骤级幂等是构建生产级Agent的必备能力,尤其是在涉及支付、通信等副作用操作时。也有声音指出,引入一个独立的引擎会增加架构复杂度,需要权衡其带来的可靠性收益。

从设计上看,Cellaflow通过日志和租约机制,在Agent侧提供了一种通用的幂等层,而不要求改造下游系统。这对于那些无法修改的遗留系统尤其有价值。不过,其实际性能表现、在高并发下的延迟,以及长期维护的可持续性,仍有待更多生产案例验证。

对于正在构建多Agent协作或需要可靠重试机制的团队,Cellaflow提供了一个值得关注的开源选项。项目提供了快速入门文档和在线演示,开发者可以自行体验崩溃恢复和并发协调的效果。

分享:

相关推荐