mcpField
S
SafeAgent — Execution Guard for AI Agents

SafeAgent — Execution Guard for AI Agents

本地服务
github.com/azender1AI 与智能体83 周前更新

关于 SafeAgent — Execution Guard for AI Agents

SafeAgent 是面向 AI Agent 的执行保护层,可在重试时抑制重复副作用。它通过持久化声明记录未决操作,并在核实结果前阻止再次执行。

主要功能

  1. 01使用稳定 request_id 声明操作
  2. 02抑制并发及重复操作
  3. 03未决状态阻止不确定的重试
  4. 04按操作结果结算声明
  5. 05支持筛选的声明审计记录

适用场景

  1. 01防止超时后重复扣款
  2. 02去重重试的邮件和 Webhook 操作
  3. 03阻止重复交易或资源配置
  4. 04排查崩溃后的未决操作

MCP 相关

SafeAgent 通过 stdio 暴露 safeagent_claim 和 safeagent_settle 两个 MCP 工具,供 MCP 客户端声明操作并结算结果。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"SafeAgent": {
"command": "uvx",
"args": [
"safeagent-exec-guard"
]
}
}
}
启动命令uvx safeagent-exec-guard

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypisafeagent-exec-guard0.1.22

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

SafeAgent — AI Agent 执行防护

Mycelium 提供方

POST /claim · safeagent-production.up.railway.app
控制面板:safeagent-dashboard-2.vercel.app

# Claim an action — free, no payment header required
curl -s -X POST https://safeagent-production.up.railway.app/claim \
  -H "Content-Type: application/json" \
  -d '{"request_id":"order:TQQQ:buy:6:2026-05-19T13:31:00-04:00","action":"order"}'
# → {"status":"PROCEED","request_id":"..."}

# Settle after the action fires
curl -s -X POST https://safeagent-production.up.railway.app/settle/order:TQQQ:buy:6:2026-05-19T13:31:00-04:00 \
  -H "Content-Type: application/json" \
  -d '{"result":{"status":"completed"}}'
# → {"status":"committed","request_id":"..."}

# Retry with the same request_id — returns SKIP
curl -s -X POST https://safeagent-production.up.railway.app/claim \
  -H "Content-Type: application/json" \
  -d '{"request_id":"order:TQQQ:buy:6:2026-05-19T13:31:00-04:00","action":"order"}'
# → {"status":"SKIP","request_id":"...","existing":{...}}

# Free test endpoint — same logic, limited to 10 calls per IP
curl -s -X POST https://safeagent-production.up.railway.app/claim/test \
  -H "Content-Type: application/json" \
  -d '{"agent_id":"bot-1","action_type":"order","scope":"TQQQ:buy:bar:2026-05-19T13:31:00-04:00"}'
# → {"status":"PROCEED","request_id":"...","test":true,"calls_remaining":9}

已在 Bazaar 编入索引。

CrewAI 重试 A/B 实测

一项无需凭据的实验,测试了 CrewAI 1.15.21 在同一进程中实际执行的 `ToolUsage._use` 重试,以及 SafeAgent 0.1.23。在 30 次执行效果后、确认前的试验中,未受保护的路径每个逻辑操作记录了两次效果;SafeAgent 路径记录了一次效果,并保留了 `PENDING` 声明以供协调。

**范围:**使用脚本化确定性 LLM,并通过进程外、能力隔离的账本记录无害效果。本实验未验证进程终止、新工作进程恢复、真实外部提供方或 SafeAgent Control 协调。

方法、源码、测试、哈希值和 180 次试验的证据

SafeAgent Control 创始试点

现向外部运营方开放两个范围受限的只读协调试点。只有当 SafeAgent Control 发现此前未知且可复现、并经运营方同意确属可操作的问题时,才会收取费用。

范围及基于结果的条款



Mycelium Trails

此实现是一个 Mycelium 提供方。 每个已完成的操作都会向 ARGENTUM 提交一条 trail,其中包含内容寻址的 action_ref (基于四个原像字段计算的 JCS+SHA-256)。返回的 mycelium_trail_id 会包含在 每张回执中,以供独立验证。


已在 Soma 上验证

SafeAgent 是 Soma(Mycelium Agent 目录)中首个通过验证的外部集成方。每次生产执行都会通过 Mycelium Trails 锚定到链上,并且无需经由运营方即可独立验证。


功能

SafeAgent 是一款持久化执行声明防护工具。它会抑制使用相同稳定 request_id 的并发和重复尝试,并保留尚未解决的尝试以供协调处理,而不是悄然重试。

每项操作都会根据其逻辑操作生成一个稳定的 request_id。新键返回 PROCEED;已结算的键返回 SKIP,并附带存储的结果。超时或崩溃后仍处于 PENDING 状态的键会继续被阻止,因为仅凭本地状态无法证明提供商是否已接受该操作。只有在检查提供商证据或使用提供商原生幂等机制后,才能恢复处理。

状态机: CLAIMABLE → PENDING → COMMITTED;后续声明会看到 PENDING 或 SKIP。

SafeAgent 可防止的常见故障模式:

场景不使用 SafeAgent使用 SafeAgent
Stripe 受理扣款后请求超时重试可能导致重复扣款同一键会保持 PENDING,直到与提供商协调确认
用户注册时重试发送欢迎邮件用户会收到两封欢迎邮件第二次发送返回 SKIP
Webhook 被重复投递(Stripe/GitHub/Twilio 保证至少投递一次)事件被处理两次第二次处理返回 SKIP
重试时配置工作区创建两个工作区第二次配置返回 SKIP
AI Agent 在崩溃后重试工具调用产生重复副作用同一键会继续被阻止;结果明确标记为尚未解决

保证边界: SafeAgent 能证明本地声明状态,但不能证明外部结果。COMMITTED 表示调用方已结算一份回执。PENDING 表示尚未解决——既不代表失败,也不代表已确认成功。要实现端到端的恰好一次效果,必须使用提供商原生幂等机制,和/或与提供商的权威记录进行协调核对。


技术栈

SafeAgent 是 Agent 执行完整性技术栈中的持久化声明与重复抑制层:

Polaris (commit-gated authorization)
└── AgentGraph safety verdict (pre-execution safety gate)
    └── SafeAgent (durable claim guard)  ← you are here
        └── Mycelium Trails (on-chain anchor)

每一层均由独立主体编写,并可独立验证。各层之间互不信任。


API

POST /claim

为操作设置门控。首次调用返回 PROCEED,任何重复调用均返回 SKIP。

请求正文:

{
  "request_id": "order:TQQQ:buy:6:2026-05-19T13:31:00-04:00",
  "action": "order"
}
  • request_id — 根据 Agent 正在执行的操作生成的稳定标识符。相同输入 = 相同键。
  • action — 设置门控的操作类型(例如 payment.send、email、trade、order)

响应:

{ "status": "PROCEED", "request_id": "order:TQQQ:buy:6:2026-05-19T13:31:00-04:00" }

使用相同的负载重试:

{ "status": "SKIP", "request_id": "order:TQQQ:buy:6:2026-05-19T13:31:00-04:00", "existing": {...} }
POST /settle/{request_id}

操作执行后结算声明。将状态从 PENDING 推进到 COMMITTED。

curl -s -X POST https://safeagent-production.up.railway.app/settle/order:TQQQ:buy:6:2026-05-19T13:31:00-04:00 \
  -H "Content-Type: application/json" \
  -d '{"result":{"status":"completed","txid":"abc123"}}'
{ "status": "committed", "request_id": "..." }
POST /claim/test

免费测试端点——逻辑相同,无需付款。每个 IP 总共最多调用 10 次。

curl -s -X POST https://safeagent-production.up.railway.app/claim/test \
  -H "Content-Type: application/json" \
  -d '{"agent_id":"bot-1","action_type":"order","scope":"TQQQ:buy:6:bar:2026-05-19T13:31:00-04:00"}'
{ "status": "PROCEED", "request_id": "...", "test": true, "calls_remaining": 9 }
GET /audit

完整的声明历史。可按 agent_id、action、status 或时间戳范围筛选。

curl "https://safeagent-production.up.railway.app/audit?agent_id=bot-1&status=COMMITTED"
{"items": [...], "total": 5, "limit": 100, "offset": 0}

参数:agent_id、action、status、from_ts、to_ts、limit(最大值为 1000)、offset。


集成

Python
import requests

def claim(request_id: str, action: str) -> dict:
    r = requests.post(
        "https://safeagent-production.up.railway.app/claim",
        headers={"Content-Type": "application/json"},
        json={"request_id": request_id, "action": action}
    )
    return r.json()  # {"status": "PROCEED"|"SKIP", "request_id": "..."}

def settle(request_id: str, result: dict) -> dict:
    r = requests.post(
        f"https://safeagent-production.up.railway.app/settle/{request_id}",
        headers={"Content-Type": "application/json"},
        json={"result": result}
    )
    return r.json()

# Usage
response = claim("payment:customer-123:invoice-456", "payment.send")
if response["status"] == "PROCEED":
    result = send_payment(...)
    settle("payment:customer-123:invoice-456", {"status": "completed"})
elif response["status"] == "SKIP":
    print("Already executed, skipping")
SaaS(Stripe/邮件/Webhook)

对于生产环境中的 Stripe PaymentIntents,请使用文档中介绍的、由许可凭证门控的适配器: SafeAgent Boundary。 它会将 Stripe 凭证保留在 Agent 之外,将已消费的许可凭证 ID 作为原生幂等键传递给 Stripe,持久化提供商关联信息,验证 Webhook 签名,并支持权威回读。下面的简单声明/结算代码片段仅用于说明通用 API;它不是提供商适配器。

请运行范围受限的测试模式示例: examples/stripe_payment_intent_guard.py。 验证记录记录了观察到的端到端结果:一个成功创建的 Stripe 沙盒 PaymentIntent、在分发到提供商之前被阻止的完全相同重放请求,以及通过 retrieve 进行的权威协调核对。

import requests

def safe_stripe_charge(customer_id, amount, idempotency_key):
    request_id = f"stripe:charge:{customer_id}:{idempotency_key}"

    response = requests.post(
        "https://safeagent-production.up.railway.app/claim",
        headers={"Content-Type": "application/json"},
        json={"request_id": request_id, "action": "stripe_charge"}
    ).json()

    if response["status"] == "SKIP":
        return response.get("existing")

    charge = stripe.PaymentIntent.create(
        amount=amount,
        currency="usd",
        customer=customer_id,
        idempotency_key=request_id,
    )
    requests.post(
        f"https://safeagent-production.up.railway.app/settle/{request_id}",
        headers={"Content-Type": "application/json"},
        json={"result": {"charge_id": charge.id}}
    )
    return charge

Webhook 去重 — 稳定的事件 ID 可在结果结算后抑制重复处理;尚未解决的 PENDING 事件会继续被阻止,以便进行调查:

def handle_stripe_webhook(event):
    response = requests.post(
        "https://safeagent-production.up.railway.app/claim",
        headers={"Content-Type": "application/json"},
        json={"request_id": event["id"], "action": "stripe_event"}
    ).json()

    if response["status"] == "SKIP":
        return {"ok": True}

    provision_subscription(event)
    requests.post(
        f"https://safeagent-production.up.railway.app/settle/{event['id']}",
        headers={"Content-Type": "application/json"},
        json={"result": {"processed": True}}
    )
CrewAI
from crewai import Agent
import sqlite3

guard_con = sqlite3.connect("safeagent_orders.db", check_same_thread=False)
# ... same guard pattern, keyed on tool_name + input hash + session_id

PR crewAIInc/crewAI#5822 添加了可插拔的幂等性后端。SafeAgent 的 SQLite 架构与其兼容。

WisePick

WisePick 是面向 Agent 运行时的确定性路由层。此集成将能力选择与持久化、幂等执行拆分开来——WisePick 决定做什么以及使用哪个提供方,SafeAgent 则判断这项逻辑工作是否已执行过。

技术栈:

WisePick /v1/decide → DashClaw → SafeAgent → Mycelium Trails → Base/Arbitrum

本地防护(嵌入式 SQLite)

无需网络调用,即可实现相同的持久化声明行为。将以下代码放入任意 Python Agent 中:

import json
import sqlite3

_SA_DB = "safeagent_orders.db"
_sa_con = sqlite3.connect(_SA_DB, check_same_thread=False)
_sa_con.execute("""CREATE TABLE IF NOT EXISTS orders (
    request_id TEXT PRIMARY KEY,
    result     TEXT,
    status     TEXT DEFAULT 'PENDING',
    created_at TEXT DEFAULT (datetime('now'))
)""")
_sa_con.commit()

def place_order_with_guard(symbol, qty, side, bar_ts):
    request_id = f"order:{symbol}:{side}:{qty}:{bar_ts}"

    cur = _sa_con.execute(
        "INSERT OR IGNORE INTO orders (request_id, status) VALUES (?, 'PENDING')",
        (request_id,)
    )
    _sa_con.commit()

    if cur.rowcount == 0:
        row = _sa_con.execute(
            "SELECT status, result FROM orders WHERE request_id = ?",
            (request_id,)
        ).fetchone()
        if row and row[0] == 'COMMITTED':
            print(f"SAFEAGENT SKIP: {request_id}")
            return row[1]
        raise RuntimeError(
            f"SAFEAGENT BLOCKED: unresolved PENDING claim for {request_id}"
        )

    result = place_order(symbol, qty, side)

    _sa_con.execute(
        "UPDATE orders SET status='COMMITTED', result=? WHERE request_id=?",
        (json.dumps(str(result)), request_id)
    )
    _sa_con.commit()
    return result

案例研究:防止崩溃重试导致重复操作

一个交易机器人发出市价单,买入 6 股 TQQQ。经纪商接受了订单。机器人在更新状态前崩溃。重启后——信号相同,K 线相同——机器人再次发出订单。经纪商成交了两次。Agent 现在持有 12 股,而它原本只打算持有 6 股。

这并非纸上谈兵。在提交订单与持久化状态之间发生任何未处理的异常时,都可能出现这种情况。

SafeAgent 会在联系经纪商前生成稳定的键:

request_id = "order:TQQQ:buy:6:2026-05-19T13:31:00-04:00"

首次调用:PROCEED。触发副作用。settle 写入 COMMITTED。
崩溃并重试:SKIP。不再联系经纪商。


案例研究:实时阻止重复操作——2026 年 5 月 21 日

完整技术栈在实时会话中确认了 6 次 SKIP 事件:DashClaw、SafeAgent、Mycelium Trails、Base/Arbitrum、经纪商 Alpaca。

  • 0942 ET:阻止重复买入 TQQQ,数量=6,$452
  • 0947 ET:阻止重复加仓 TQQQ,数量=6,$452
  • 0949 ET:反转时阻止重复卖出 TQQQ,数量=12,$902
  • 1000 ET:阻止重复买入 TQQQ,数量=6,$454
  • 1014 ET:V20 反转时阻止重复卖出 TQQQ,数量=18,$1,350
  • 1106 ET:分批建仓期间阻止重复加仓 SQQQ,$43

完整会话数据:https://gist.github.com/azender1/b9112b6519c935df4a75cb05cd250e26


一致性验证

SafeAgent 参与了 A2A 跨实现一致性验证语料库。四个独立实现的夹具均通过字节级验证:

  • kenneives (agentgraph) — verifier-attestation-v0:30/30 ✓
  • evidai (LemonCake) — gated-preflight-v1:33/33 ✓
  • haroldmalikfrimpong-ops (agentid) — 独立验证器 ✓
  • SafeAgent — claim-lifecycle conformance v1.1 ✓

A2A #1920 已关闭。四个实现均满足新鲜度和重放要求。


规范的 action_ref 派生

JCS (RFC 8785),与 argentum-core、Nobulex 和 APS 保持一致:

import hashlib
import rfc8785

def compute_action_ref(
    agent_id: str,
    action_type: str,
    scope: str,
    timestamp: str,  # RFC 3339 UTC, 3-digit ms: "2026-05-15T10:00:00.123Z"
) -> str:
    payload = {
        "agent_id": agent_id,
        "action_type": action_type,
        "scope": scope,
        "timestamp": timestamp,
    }
    canonical = rfc8785.dumps(payload)
    return hashlib.sha256(canonical).hexdigest()

timestamp 是 RFC 3339 UTC 字符串,且必须恰有 3 位毫秒数字。末尾的 Z 为必填项。

一致性验证夹具:giskard09/argentum-core tag action-ref-v1.0


部署

Railway · Serverless OFF · 始终运行
PyPI:pip install safeagent-exec-guard
npm:npm install n8n-nodes-safeagent
MCP Registry:io.github.azender1/safeagent
仪表板:safeagent-dashboard-2.vercel.app


许可证

Apache-2.0

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。