
Call4Agents 发布工具:可复现 AI 智能体批准操作重复执行故障
来源标题:Show HN: Replay three AI agent approval failures in five seconds, in Python
Call4Agents 推出 call4agents 工具,能让 Python 智能体的操作在崩溃后可安全重试,避免已批准的操作被执行两次。该工具兼容 LangGraph、Pydantic AI、OpenAI Agents SDK 和 MCP server,并提供 crashtest 命令在每步崩溃重启后指出哪些操作重复运行。当前版本 0.6,仅依赖标准库,采用 Apache-2.0 许可。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
用 Call4Agents 让 Python agent 的动作可以安全重试。你不需要换掉现有的 agent:LangGraph、Pydantic AI、OpenAI Agents SDK、MCP server 或者纯 Python 都行,它不替代其中任何一个。
技术说明,2026 年 11 月 5 日:一句“是”并不等于恰好一次。一笔已批准的付款,紧接着一次崩溃,一次有记录的恢复:在 LangGraph、Pydantic AI 和 OpenAI Agents SDK 中各自产生了 2 笔付款。脚本和每次运行的数据都包含在内。
你的 agent 在崩溃后会重复执行某个动作吗?这个工具会在每一步杀掉进程、重启它,并告诉你哪个动作被执行了两次。你的 agent 不需要先接入我们的防护机制。
pip install call4agents call4agents crashtest --demo # 一个小 agent,分别在没有和有那一行修复的情况下运行 call4agents crashtest your_agent.py # 你的 agent(实验性;每个动作都会真的执行,所以请使用测试账号)
版本 0.6,早期版本。仅使用标准库,零依赖(多机部署时可选用 PostgreSQL)。Apache-2.0。
pip install call4agents
import call4agents as c4a c4a.init(".c4a/first.sqlite") def pay(amount, to): print(f"paying {amount} to {to}") return "paid" with c4a.run("order-42"): c4a.approve(pay, amount=10, to="alice") # 此人已同意这次确切的调用 print(pay(10, "alice")) # 会执行 print(pay(10, "alice")) # 重试:返回记录的结果,不会第二次付款 pay(9999, "mallory") # 未获批准:抛出异常,不会付款
paying 10 to alice paid paid call4agents.ApprovalRequired: main.pay needs approval for exactly {"amount":9999,"to":"mallory"}
再运行一次:pay 什么都不会打印,因为记录中已经保存了结果。
每个框架都有可运行代码的指南:salahmakboul.github.io/call4agents/guides。
每次变更都会测试(tests.yml)。我们只声明支持以下系统:在 Python 3.12 上,配合真实框架,覆盖全部三个系统:LangGraph(+ LangChain)、Pydantic AI、OpenAI Agents SDK 和 MCP Python SDK。CI 会安装每个框架的最新版本,每次运行都会用 call4agents doctor 打印确切的版本。
pip install call4agents call4agents incident
每个事故都在真实进程中运行,伴随真实崩溃,一次不启用本工具,一次启用。银行和 agent 循环都是小型的本地替代实现;下面的 call4agents quickstart 会展示真实框架中的崩溃。
pip install call4agents call4agents quickstart
quickstart 运行一个纯 Python 演示。然后,对于已安装的 LangGraph、Pydantic AI 和 OpenAI Agents SDK 中的每一个,它会在该框架中使用假模型运行一次真实的崩溃与恢复。每个框架都分别在不启用和启用 Call4Agents 的情况下各运行一次。我们机器上的输出(Windows 10、Python 3.12,三者均已安装):
纯 Python —— 在发送邮件后立即崩溃,然后恢复: 不使用运行记录 已发送邮件:2 使用运行记录(在工具执行后崩溃)已发送邮件:1 使用运行记录(在工具执行内部崩溃)已发送邮件:1(拒绝重发:状态存疑) 对 pay(10, alice) 回答“是”,但调用被改成 pay(9999, mallory):已拒绝;已批准的调用:已付款;付款次数:1 发现的框架:LangGraph、Pydantic AI、OpenAI Agents SDK LangGraph 在发送邮件后崩溃并恢复:不使用 call4agents 发送 2 封邮件,使用 call4agents 发送 1 封 Pydantic AI 在发送邮件后崩溃并恢复:不使用 call4agents 发送 2 封邮件,使用 call4agents 发送 1 封 OpenAI Agents SDK 在发送邮件后崩溃并恢复:不使用 call4agents 发送 2 封邮件,使用 call4agents 发送 1 封
如果未安装任何框架,只会运行纯 Python 部分(在我们机器上约 5 秒)。要看到框架相关的输出行,请先安装它们:pip install langgraph langgraph-checkpoint-sqlite pydantic-ai openai-agents(在全新的虚拟环境中约需 75 秒)。
call4agents selftest 会检查演示结果。在仓库检出根目录运行它,则会改为运行完整的离线测试套件(kit、production、stress 和幂等性检查)。
发现问题,或者觉得缺少了什么?call4agents report 会打印你的系统和框架版本,并附上一个已替你填好这些信息的 issue 表单链接。它不发送任何内容,也不打开任何东西:由你阅读后决定。没有任何形式的追踪。
你的 agent 会发送邮件、付款、创建工单或写数据库,而一次崩溃、一次超时重试或从检查点恢复,都可能让这些动作重复执行。 一个人批准了某个动作,但在它运行之前参数可能发生变化,例如通过编辑过的已保存状态,或者重启后重新询问模型。 一个人双击了“批准”,或者两个 worker 拿到了同一个已批准的任务。 你调用的 API 支持 Idempotency-Key(Stripe、Adyen 等),并且希望中途崩溃后能安全重试,而不需要人工介入。 你切换了模型或提供商,希望在发布前看到哪些工具调用发生了变化。 如果你的 agent 只读取数据,或者每个动作都已经运行在能提供这些保证的持久化工作流引擎中,那你可能不需要它。
import call4agents as c4a c4a.init() # 创建 .c4a/ledger.sqlite 和 .c4a/secret def send_email(to, body): ... def pay(amount, to): ... def charge(amount, to): return requests.post(URL, json={"amount": amount, "to": to}, headers=c4a.idempotency_headers()).json() def ask_model(prompt): ... with c4a.run("thread-42"): # 使用你的框架恢复时所用的 id send_email("bob", "hi") send_email("bob", "hi") # 同一动作:返回记录的结果,不发送任何内容 send_email("bob", "hi", c4a_key="second") # 有意为之的第二次相同动作 c4a.approve(pay, amount=10, to="alice") # 当此人同意他们所看到的内容时 pay(amount=10, to="alice")
开始前值得了解的规则: Pydantic AI、OpenAI Agents SDK、MCP。每个都有适配器。它会把框架的上下文参数(RunContext、RunContextWrapper、MCP 的 Context)排除在 key 之外,因为该对象每次调用都会变化,而普通的 @c4a.effect 会拒绝它。它还会替你找到 run id。框架自己的装饰器放在最上层: from call4agents.adapters import pydantic_ai as c4a_pai # run id:该 run 的 conversation_id
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。