关于 failecho
failecho 是面向 AI Agent 的跨 Agent 故障信息网络,可查询其他 Agent 遇到相同工具故障时的恢复结果。它依据标准化故障指纹和独立报告给出建议,证据不足时不猜测。
主要功能
- 01查询相同故障的恢复建议
- 02提交故障、成功与恢复结果
- 03标准化错误并生成指纹
- 04证据不足时返回数据不足
- 05仅存储故障元数据
适用场景
- 01工具调用失败后决定是否重试
- 02让多个 Agent 共享恢复经验
- 03汇总调用成败与恢复结果
MCP 相关
MCP 服务提供故障查询、故障报告、成功报告和恢复结果报告工具。Agent 可在重试前查询,也可提交观测结果。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://failecho.com/mcpclaude mcp add --transport http com-failecho-failecho https://failecho.com/mcp{"mcpServers":{"com-failecho-failecho":{"type":"http","url":"https://failecho.com/mcp"}}}在 Cursor 中打开{"servers":{"com-failecho-failecho":{"type":"http","url":"https://failecho.com/mcp"}}}在 VS Code 中打开{"mcpServers":{"com-failecho-failecho":{"type":"http","url":"https://failecho.com/mcp"}}}{"mcpServers":{"com-failecho-failecho":{"serverUrl":"https://failecho.com/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
工具
4| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| service | string | 是 | MCP 服务自身的名称(serverInfo.name)或 API 主机名,例如 'api.github.com'。不是客户端的本地别名。 |
| verbose | boolean | 否 | 完整记录(时间戳、速率、有效计数、所有操作)。默认:简要答案。 |
| version | string | 否 | 服务/工具版本(如果已知)。 |
| operation | string | 是 | 服务器命名的工具或端点,例如 `create_issue`,而不是 `mcp__github__create_issue`。 |
| error_code | string | 否 | 代码,例如 `422`、`ECONNRESET`。 |
| error_type | string | 否 | 故障类别,例如 `validation_error`、`timeout`、`rate_limit`、`auth_error`。 |
| reporter_id | string | 否 | 可选的稳定 Agent ID;经过哈希处理,绝不存储原始值。这样才能回答 from_other_agents。 |
| schema_hash | string | 否 | 所用工具架构的短哈希(用于区分“API 故障”和“架构过时”)。 |
| error_message | string | 否 | 仅限错误文本;由服务器端规范化,此调用不会存储原文。 |
详细介绍
FailEcho 是一个跨 Agent 的失败情报网络。当工具或模型调用失败时,它会告知你的 Agent,其他 Agent 是如何解决这一确切故障的——或者告诉它目前还没有解决办法,让它停止重试。 Agent 会共享失败的特征以及解决方法(仅限元数据,绝不包含提示词或数据);下一个遇到相同故障的 Agent 就能得到答案。开源,无需账户。
每一行都是真实输出:对实验室网络的实时查询、一对根据实验室记录重放的双生 Agent(9 月 24 日)、包装器的实际载荷,以及带有 p 值的实验室计分板。使用的是我们自己的 Agent;目前独立报告者:0。
我们测量了什么,以及尚未测量什么
我们的 Agent 在实验室中以双生组运行:任务相同、模型相同,其中一个会在重试前询问 FailEcho 并根据回答采取行动,另一个不会。测量时间为 2026 年 9 月 22 日至 24 日。**目前独立用户:0。**每个数字、对应样本及显著性检验:docs/claims.md;实时数据见:实验室计分板。
| 已测量(p < 0.05) | 使用 FailEcho | 未使用 FailEcho |
|---|---|---|
| 从模型提供商的速率限制故障中恢复(收到提示后切换模型) | 74.5% | 31.2% |
| 已完成的运行,同一组(每边 416 次) | 90.6% | 80.2% |
| 每次运行因不稳定 API 损失的秒数 | 12.2 | 19.4 |
| 收到“跳过”建议后仍重试并成功恢复的 Agent 数 | 404 次中 0 次 |
| 尚未展示 | 使用 FailEcho | 未使用 FailEcho |
|---|---|---|
| 已会谨慎重试的 Agent:每次运行损失的秒数 | 9.8 | 10.1 |
| 答案正确率(通过真实 API 检查) | 99.3% | 99.2% |
| 编码 Agent:已完成的运行 | 73.7% | 73.7% |
| 仅向模型展示建议,由模型自行决定:已完成的运行 | 100% | 100% |
| OpenAI 和 Anthropic | 尚未纳入实验室 |
目录
从这里开始
| 一分钟内完成连接 | 端点、插件、一行提示词 |
| 它的作用 | 理念,以及其中使用的术语 |
| 在本地查看网络效应 | 六个 Agent、一次故障,在你的机器上 |
连接到某个对象
| 连接 Agent | MCP、Python、框架、REST、Claude Code 插件 |
| MCP | 端点、stdio 服务、四个工具 |
| REST API | 每个端点及可运行示例 |
| Python 客户端 | 零依赖,仅使用标准库 |
工作原理
| 连接时需要你做什么 | 什么也不用:无需密钥、令牌或账户 |
| 隐私 | 哪些内容永远不会发送,哪些内容永远不会存储 |
| 如何得出这些数字 | Wilson 分数,以及为何不用模型 |
| 滥用防护底线(V1) | 速率限制、报告者权重,以及尚未解决的问题 |
| 数据保留与清理 | 原始数据保留 48 小时,之后保留每小时聚合数据 |
运行和运维
| 本地运行 | uv 或 venv,一条命令 |
| 项目布局 | 各项内容所在的位置 |
| 配置 | 所有设置,以及如何部署到小型 VPS 上 |
| 是否正常运行? | 用于确认状态的检查项 |
| MVP 的局限 | 直言当前尚不支持的功能 |
Agent A fails.
FailEcho learns.
Agent B encounters the same failure.
It sees what actually worked for other agents.
Agent B benefits from evidence it never generated itself.
一分钟内完成连接
最简单的方式:让 Agent 来配置。 将以下内容粘贴到你正在使用的工具中—— Claude Code、Claude Desktop、Cursor、Codex 或你自己的运行框架:
Read https://failecho.com/llms.txt and set yourself up to use FailEcho.
它会读取机器可读指南并自行完成配置。无需账户,无需 API 密钥,也无需注册。下文介绍的都是手动完成相同操作的方法。
将它接入工具调用链路,而不是工具列表。 如果模型必须选择调用某个工具,它大多时候就不会调用:在我们的实验室中,使用 FailEcho MCP 工具的 Agent 平均每五次运行才调用一次。有效的集成会在模型已经查找答案的位置提供答案,因此请按客户端选择:
| 你的 Agent 运行于 | 安装方式 | 建议的呈现位置 |
|---|---|---|
| Claude Code | 安装插件:/plugin marketplace add FailEcho/failecho,然后运行 /plugin install failecho@failecho | 每次 MCP 工具调用后,通过钩子提供 |
| OpenCode | 使用单个文件:.opencode/plugin/failecho.js(源码),或通过 npm 配置 "plugin": ["failecho-opencode"] | 每个工具的输出中,包括 bash 和 webfetch |
| Cursor、Claude Desktop、任何 MCP 客户端 | 在每个 MCP 服务前使用 failecho-mcp proxy -- <server command> | 出现在失败工具的错误信息中 |
| 你自己的代码 | 使用 failecho-autoreport,并设置 FAILECHO_ADVISE=1 | 出现在你已经处理的异常中 |
| 无法安装任何内容 | 使用下方的纯 MCP 端点 | 仅当模型记得主动询问时 |
这四种方式都能提供建议,而且都经过端到端测试。实验室测得的收益来自会采取行动的 Agent——收到 switch_model 指示时切换模型,收到 skip 指示时停止(使用包装器的三行代码);但这四种集成方式本身目前都没有可供引用的实验室对比结果。
纯 MCP 端点——最精简的选项,也是效果最差的选项
https://failecho.com/mcp
大多数 MCP 客户端都接受以下配置块:
{
"mcpServers": {
"failecho": { "type": "http", "url": "https://failecho.com/mcp" }
}
}
在 Claude Code 中,配置文件是 .mcp.json;Cursor 使用 .cursor/mcp.json,并省略 type;VS Code 使用 .vscode/mcp.json,顶层键名为 servers。端点始终不变。配置页面中列出了相关表格。
在 Claude Code 中,CLI 可以为你写入同一个文件:
claude mcp add --transport http --scope project failecho https://failecho.com/mcp
如果希望自动报告失败和成功情况,可以使用 Python:
from failecho import FailEcho
echo = FailEcho("https://failecho.com", reporter_id="my-agent-1")
outcome = await echo.observe_tool_call(
service="github-mcp",
operation="create_issue",
call=lambda: github.create_issue(**args),
)
if outcome.failed and outcome.decision.actionable:
do(outcome.decision.recommendation) # your code decides, never FailEcho
无需账户,无需 API 密钥。公开 MVP 期间免费。 完整集成指南:连接 Agent。
功能
查看其他 AI Agent 此刻是否也遇到了相同的工具故障,以及哪些恢复操作确实有效。FailEcho 提供一个 Model Context Protocol(MCP)端点,Agent 可在工具故障后查询,还提供 REST API。
| 工具 | Agent 调用时机 |
|---|---|
check_tool_failure | 工具发生故障时——重试之前 |
report_tool_failure | 提交故障信息 |
report_tool_success | 提交成功信息(分母) |
report_recovery_outcome | 说明修复是否奏效 |
FailEcho 会以确定性方式(不使用模型)将错误文本规范化为指纹,累积与之相关的恢复结果,并且仅在独立报告者达成一致时返回建议。证据不足时会返回 INSUFFICIENT_DATA,而不是猜测。置信度是 Wilson 分数下界,可根据其旁边返回的计数重新计算。
系统只存储故障元数据。没有用于提示词、工具参数、工具结果、请求或响应正文、标头或 Cookie 的字段,因此这些内容都无法存储。有一个字段是自由文本,即错误消息:在钩子和包装器中默认关闭,可选启用;发送时会先进行规范化——替换标识符、编辑符合凭据格式的字符串——然后丢弃原始文本。这种规范化是第二道防线,并非保证;准确的说法是仅存储元数据,错误文本默认关闭,启用时会进行规范化。
在线服务: https://failecho.com · /docs · /openapi.json · /llms.txt
这不是可观测性平台、错误数据库、运行时间监控器或大模型调试器。系统的基本单位是:
service + operation + version + schema_hash + failure fingerprint
+ observed recovery outcomes
术语
| 术语 | 含义 |
|---|---|
| FailEcho Network | 整个系统 |
| Failure Echo | 按指纹共享的规范化已观察故障 |
| Recovery Echo | 恢复操作奏效的证据 |
| Incident | 故障突然异常增加 |
| Reporter | 发送遥测数据的 Agent 或运行时 |
| Fingerprint | 规范化错误的规范身份标识 |
品牌术语面向人类。线格式有意不使用品牌名称:端点路径、MCP 工具名称和字段名称(fingerprint、recommendation、recovery_actions)都保持原样,因为机器清晰度比命名纯粹性更重要。
在本地体验网络效应
打开两个终端,大约一分钟。
# 1. the network
uv run uvicorn app.main:app --reload
# or: .venv/bin/python -m uvicorn app.main:app --reload
# 2. six independent agents hitting the same broken tool
uv run python examples/live_agent/run_demo.py
# or: .venv/bin/python examples/live_agent/run_demo.py
演示会启动一个小型本地工具服务器,然后让六个逻辑上相互独立的 Agent 对其进行调用。所有网络调用都通过 MCP,从外部进程发起,并使用官方 MCP SDK。
Agent A calls a tool. It fails: the provider renamed a field.
|
v
Agent A reports the failure -> the network records it
Agent A has no evidence to go on, so it retries (fails),
refreshes the tool schema (works), and reports both outcomes
|
v
Agents C, D, E, F hit the same failure with different repository ids
-> normalization collapses all of them onto ONE fingerprint
-> the network accumulates evidence from 5 independent reporters
|
v
Agent B hits the same failure with yet another id, and asks first
-> the network recognises the fingerprint
-> "refresh_schema: 5/5 successes, 5 reporters, confidence 0.57"
-> "retry: 0/5. Do not bother."
|
v
Agent B skips the retry the others wasted a call on, refreshes, succeeds,
and reports its outcome -- which makes the next agent's answer better.
Agent B 从未遇见过 Agent A。它只与网络交互。这就是整个产品。
第六个 Agent 提问时的真实输出;此前它没有提交过任何信息:
Calling tool...
x tool failed
422 validation_error
Repository 987654 rejected field body: field "body" is no longer accepted, use "content"
Checking shared failure intelligence...
Fingerprint: 6ed9ef705ff4037af2c977306b8b9f92
Known failure: YES
Observed failures: 11
Independent reporters: 6
Service status: MAJOR
Recovery actions others reported:
refresh_schema 5/5 (100.0%) confidence 0.57 reporters 5
retry 0/5 (0.0%) confidence 0.00 reporters 5
Best observed recovery:
refresh_schema
Skipping retry: other agents already proved it does not work here.
Applying recovery: refresh_schema
Refreshed tool schema -> v3.0.0, field 'content'
Retrying tool call...
+ tool call succeeded
Reporting recovery outcome...
+ accepted (refresh_schema -> success)
演示运行时,可以看到内容显示在 http://localhost:8000 首页上。演示 Agent 会使用 X-Reporter-Kind: demo 标记自身,因此其流量是真实证据,但绝不会计入采用情况——参见演示数据。
详情(包括如何单独运行工具服务器)请参见
examples/live_agent。
连接 Agent
有两种接入方式,二者的区别很重要。
MCP 允许 Agent 显式提问和报告——由模型决定何时调用 check_tool_failure,因此你能在 Agent 推理故障时,恰到好处地获得相关信息,除此之外不会发生其他操作。
SDK 插桩会为每次工具调用自动报告成功和故障遥测数据,不由模型决定是否报告。这会产生分母;没有分母,网络中的每个故障率都毫无意义。
大多数部署需要同时使用两者。
1. MCP
claude mcp add --transport http failecho https://failecho.com/mcp
{
"mcpServers": {
"failecho": {
"type": "http",
"url": "https://failecho.com/mcp"
}
}
}
| 工具 | Agent 调用时机 |
|---|---|
check_tool_failure | 工具调用失败时——重试之前 |
report_tool_failure | 上报失败 |
report_tool_success | 上报成功(作为分母) |
report_recovery_outcome | 说明修复是否奏效 |
2. Python
将 client/ 复制到你的项目中(尚未发布到 PyPI),然后:
from failecho import FailEcho
echo = FailEcho(
endpoint="https://failecho.com",
reporter_id="my-agent-1", # optional, hashed server-side
)
outcome = await echo.observe_tool_call(
service="github-mcp",
operation="create_issue",
version="2.8.1",
schema_hash="a817ce",
call=lambda: github.create_issue(**args),
)
if outcome.failed and outcome.decision.actionable:
# YOUR code decides. FailEcho never acts on your behalf.
if outcome.decision.confidence > 0.8:
refresh_schema()
await echo.report_recovery(
fingerprint=outcome.decision.fingerprint,
action="refresh_schema",
successful=True,
)
observe_tool_call 会上报成功或失败;如果调用失败,则查询 FailEcho,并将 FailureDecision 交给你。它绝不会重试、刷新或回退——执行恢复操作可能导致重复发布或重复扣费,因此由你决定如何处理。
它不会破坏你的 Agent。 每次调用都采用故障软处理:超时或无法连接主机时,会忽略该问题并照常返回工具结果。设置 FAILECHO_DISABLED=1 即可让整个客户端变为空操作。
3. 框架埋点
参考集成:Pydantic AI:
from failecho import FailEcho
from failecho.integrations.pydantic_ai import instrument_toolset
echo = FailEcho("https://failecho.com", reporter_id="my-agent-1")
agent = Agent("openai:gpt-4o", toolsets=[instrument_toolset(my_toolset, echo)])
现在,每次工具调用都会上报结果。这个包装器在行为上不可见:结果、异常和控制流均保持不变。它绝不会读取或发送工具参数。
其他框架(LangChain、LlamaIndex、CrewAI、OpenAI Agents SDK、Claude Code hooks)的集成尚未开发。它们应实现 failecho.adapters.ToolTelemetrySink——仅包含四个事件,且数据只向一个方向传递——而不是修改 FailEcho 的核心。详见 client/failecho/adapters.py。
4. REST
curl -X POST https://failecho.com/v1/query \
-H "Content-Type: application/json" \
-H "X-Reporter-ID: my-agent-1" \
-d '{
"service": "github-mcp",
"operation": "create_issue",
"error_type": "validation_error",
"error_code": "422",
"error_message": "Repository 555812 was not found"
}'
5. Claude Code 插件(自动)
连接 MCP 服务后,就只能由模型在工具失败时调用 FailEcho,而模型总会忘记。这个插件免去了这项决策:
/plugin marketplace add FailEcho/failecho
/plugin install failecho@failecho
这会同时安装 MCP 服务和一个 hook,Claude Code 会在每次 MCP 工具调用后运行它,因此每次失败都会被上报,成功调用会为失败率提供分母,而第二次尝试则会被记录为恢复操作(使用相同参数的 retry,或使用新参数的 adjust_arguments)。当网络已经知道某种失败情况时,hook 会在 Claude 重试前向它提供简短提示——其他人遇到这种情况的频率,以及哪种恢复方式奏效。
不安装插件也可以使用 hook:它是单个文件,除 Python 3 外无其他依赖:
mkdir -p ~/.claude/hooks
curl -fsSL https://raw.githubusercontent.com/FailEcho/failecho/main/plugin/hooks/failecho_hook.py \
-o ~/.claude/hooks/failecho_hook.py
然后将以下内容添加到 ~/.claude/settings.json:
{
"hooks": {
"PostToolUseFailure": [{"matcher": "mcp__.*", "hooks": [
{"type": "command", "command": "python3 ~/.claude/hooks/failecho_hook.py", "timeout": 10}]}],
"PostToolUse": [{"matcher": "mcp__.*", "hooks": [
{"type": "command", "command": "python3 ~/.claude/hooks/failecho_hook.py", "timeout": 10}]}]
}
}
离开你设备的数据:服务的公开名称、工具名称、粗略的错误类别和代码(rate_limit / 429),以及调用延迟。绝不发送工具参数、工具结果、提示词、文件路径或会话 ID;只有在设置 FAILECHO_HOOK_SEND_ERRORS=1 时,才会发送错误文本。服务名称取自其公开包(npx @scope/server、uvx server)或公开主机;本地脚本和私有主机则会被完全跳过。你可以使用 FAILECHO_HOOK_SERVICE_NAMES='{"alias": "public-name"}' 手动指定名称。如果无法连接 FailEcho,hook 会在一次短暂超时后放弃,Claude 会继续运行。
| 变量 | 默认值 | 用途 |
|---|---|---|
FAILECHO_DISABLED | 未设置 | 设为 1 可关闭 hook |
FAILECHO_HOOK_SEND_ERRORS | 未设置 | 设为 1 时也会发送错误文本,并在服务端进行规范化处理 |
FAILECHO_HOOK_REPORT_SUCCESS | 1 | 设为 0 可停止上报成功情况 |
FAILECHO_HOOK_SERVICE_NAMES | 未设置 | 将服务别名映射到公开名称的 JSON 映射 |
FAILECHO_ENDPOINT | https://failecho.com | 自行托管时使用的服务器 |
关于上报者 ID
此项可选,并非必需。稳定 ID 在收到后会加盐并哈希处理——原始值绝不会被存储——它能改进三方面:独立上报者计数、抗投毒能力,以及 FailEcho 告知你某项建议来自其他人的能力。系统始终完全支持匿名上报。
自有 Agent(第一方)
在网络启动期间,运营方自己的 Agent 也会报告真实故障。这些数据是真实的现场证据,但并非独立证据,也不代表采用情况,因此无论出现在哪里,都会带有单独的标签:
| 来源 | 来自谁 | 是否计为采用 | 向 Agent 显示为 |
|---|---|---|---|
agent | 任意真实 Agent | 是 | agent |
first_party | FailEcho 自有 Agent | 否 | first_party |
demo_agent | 发送 X-Reporter-Kind: demo 的 Agent | 否 | 演示数据 |
synthetic | scripts/seed_demo.py | 否 | 演示数据 |
first_party 表示报告者的身份,因此必须经过验证:发送
X-FailEcho-Operator: <FIN_FIRST_PARTY_TOKEN>。令牌错误或缺失时,数据会被存为演示数据,因此不会计入采用情况,也绝不会作为运营方证据展示给任何人。每个查询答复都会列出 evidence_sources,因此 Agent 可以分辨某个答复是仅由 first_party 支持,还是也有独立 Agent 的支持。
在服务器上生成一次令牌:
echo "FIN_FIRST_PARTY_TOKEN=$(openssl rand -hex 32)" >> /etc/failecho.env
然后将它提供给你自己的 Agent,不要给其他人:
# Claude Code
claude mcp add --transport http failecho https://failecho.com/mcp \
--header "X-FailEcho-Operator: <token>"
# stdio relay
FAILECHO_OPERATOR_TOKEN=<token> failecho-mcp
Python 客户端接受 operator_token="<token>",也可以读取
FAILECHO_OPERATOR_TOKEN。
为故障命名
名称是指纹的一部分,因此只有当 Agent 用相同方式为同一对象命名时,证据才会共享。将 MCP 服务自己的名称(其
serverInfo.name)或 HTTP API 的主机名用作 service,并将服务器定义的工具名称原样用作 operation:create_issue,而不是
mcp__github__create_issue。
概念
Agent A fails
|
v
reports anonymously ---------> network learns
|
Agent B hits the same problem |
| |
v v
queries the network <--------- what happened to others
|
v
skips the useless retry, uses the recovery that works
本地运行
Python 3.11+。
# with uv
uv venv
uv pip install -r requirements.txt
uv run uvicorn app.main:app --reload
# or plain venv + pip
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python -m uvicorn app.main:app --reload
填充合成演示数据,让首页有内容可显示:
.venv/bin/python scripts/seed_demo.py # add demo data
.venv/bin/python scripts/seed_demo.py --reset # replace existing demo data
.venv/bin/python scripts/seed_demo.py --purge # remove demo data
然后:
- 首页 — http://localhost:8000
- MCP 端点 — http://localhost:8000/mcp(Streamable HTTP)
- Agent 可读取的概览 — http://localhost:8000/llms.txt
- API 文档 — http://localhost:8000/docs
- 机器可读的架构 — http://localhost:8000/openapi.json
- 健康检查 — http://localhost:8000/health
运行测试:
.venv/bin/python -m pytest
将过期的原始观测数据归并为小时聚合数据(可随时安全运行):
.venv/bin/python scripts/prune.py --dry-run
.venv/bin/python scripts/prune.py
端到端示例(服务器必须正在运行):
.venv/bin/python client/example_agent.py # REST, single agent
.venv/bin/python examples/live_agent/run_demo.py # MCP, six agents, network effect
演示会在后台线程中运行其工具服务器。若要单独运行它(使用两个终端):
.venv/bin/python examples/live_agent/tool_server.py
.venv/bin/python examples/live_agent/run_demo.py --no-tool-server
MCP
MCP 服务在同一个 FastAPI 进程内运行——无需部署或管理第二个服务——并通过 /mcp 提供 Streamable HTTP。它是无状态的,使用 JSON 响应:没有会话级内存,也没有长连接流,因此可以在小型 VPS 上运行。
连接
Claude Code:
claude mcp add --transport http failecho https://failecho.com/mcp
# local:
claude mcp add --transport http failecho http://localhost:8000/mcp
通用 MCP 客户端配置(mcpServers 格式):
{
"mcpServers": {
"failecho": {
"type": "http",
"url": "https://failecho.com/mcp"
}
}
}
如果想查看运行效果,可以使用原始 JSON-RPC:
curl -s localhost:8000/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
本地 stdio 服务
有些宿主只能启动本地进程,并通过 stdin/stdout 与其通信。
failecho-mcp 就是为它们准备的。它是一个中继,而不是第二个 FailEcho:它没有
数据库,也不会存储任何内容。每次 tools/list 和 tools/call 都会转发到
共享网络,因此它提供的四种工具与上方 URL 中的工具相同,描述和证据也相同。
uvx failecho-mcp
{
"mcpServers": {
"failecho": {
"command": "uvx",
"args": ["failecho-mcp"]
}
}
}
failecho-mcp 与此仓库分开发布,且仅依赖
mcp —— 共 29 个包,约 48 MB,冷缓存时大约需要两秒。
服务端包(failecho-server,即此仓库)依赖 FastAPI、
SQLAlchemy 和 uvicorn,因为它就是服务端;中继不会导入其中任何依赖。
Node 也有同样的中继,位于 npm-relay/:
{
"mcpServers": {
"failecho": {
"command": "npx",
"args": ["-y", "failecho-mcp"]
}
}
}
零依赖,6 KB,冷 npx 缓存时大约需要一秒。提供相同的四种工具和相同的证据,不存储任何内容。使用你已有的运行时即可。
在检出代码后,可通过以下命令运行中继并进行开发:
uv run failecho-mcp
| 变量 | 默认值 | 用途 |
|---|---|---|
FAILECHO_URL | https://failecho.com/mcp | 要转发到的网络。如果你自托管,可将其指向自己的服务。 |
FAILECHO_REPORTER_KIND | 未设置 | 对演示 Agent 设置为 demo,这样它们的报告就不会计入采用率数据。 |
如果无法连接网络,工具调用会返回一条说明情况的错误结果,不会记录任何内容;Agent 会改为采用自身的重试策略,而不是一直挂起。
如果客户端支持 URL,优先使用 URL:少一次跳转,也无需安装任何内容。
工具
| 工具 | 用途 |
|---|---|
check_tool_failure | 重试前调用。 此故障目前是什么情况?哪种恢复方式确实奏效? |
report_tool_failure | 提交故障观察结果。返回其指纹。 |
report_tool_success | 提交成功结果,为故障率提供分母。 |
report_recovery_outcome | 报告恢复操作是否奏效。 |
这四种工具调用的函数与 REST 端点相同(app/core/service.py),因此 MCP 客户端和 curl 用户对故障含义的判断永远不会相互矛盾——只有一个规范化器、一个指纹函数和一个智能层。
check_tool_failure 结果示例:
{
"known": true,
"fingerprint": "01ae47053fbb3eabf8f3e480cba45ba8",
"status": "MAJOR",
"observations": { "total": 418, "last_5m": 81, "last_1h": 201, "unique_reporters": 47 },
"failure_rate": { "last_5m": 0.73, "last_1h": 0.31 },
"recovery_actions": [
{ "action": "refresh_schema", "attempts": 124, "successes": 117,
"success_rate": 0.9435, "effective_attempts": 124, "unique_reporters": 45,
"confidence": 0.8881 }
],
"recommendation": { "action": "refresh_schema", "confidence": 0.8881 },
"demo_data_included": false
}
demo_data_included 会告知 Agent 数字中是否包含合成演示数据行。设置 FIN_MCP_ENABLED=0 可完全禁用 MCP。
REST API
三个调用。无需账户、API 密钥或付费。
| 端点 | 调用时机 |
|---|---|
POST /v1/observe | 每次工具调用后——成功和失败都要调用 |
POST /v1/query | 调用失败时,在重试之前调用 |
POST /v1/outcome | 尝试恢复操作后调用 |
报告故障
curl -s localhost:8000/v1/observe \
-H 'content-type: application/json' \
-H 'X-Reporter-ID: my-agent-1' \
-d '{
"service": "github-mcp",
"operation": "create_issue",
"version": "2.8.1",
"schema_hash": "a817ce",
"outcome": "failure",
"error_type": "validation_error",
"error_code": "422",
"error_message": "Repository 918272 was not found",
"latency_ms": 421
}'
{
"accepted": true,
"fingerprint": "01ae47053fbb3eabf8f3e480cba45ba8",
"known": true,
"observations": 143,
"normalized_error": "Repository <N> was not found"
}
在存储任何内容之前,消息会先经过规范化:
Repository 918272 was not found → Repository <N> was not found。指纹为 sha256(service | operation | version | schema_hash | error_type | error_code | normalized_error),并截断为 32 个十六进制字符。
报告成功
故障率需要分母,因此也要提交成功结果:
curl -s localhost:8000/v1/observe \
-H 'content-type: application/json' \
-d '{
"service": "github-mcp", "operation": "create_issue",
"version": "2.8.1", "schema_hash": "a817ce",
"outcome": "success", "latency_ms": 318
}'
查询网络
curl -s localhost:8000/v1/query \
-H 'content-type: application/json' \
-d '{
"service": "github-mcp",
"operation": "create_issue",
"version": "2.8.1",
"schema_hash": "a817ce",
"error_type": "validation_error",
"error_code": "422",
"error_message": "Repository 555812 was not found"
}'
{
"known": true,
"fingerprint": "01ae47053fbb3eabf8f3e480cba45ba8",
"status": "MAJOR",
"looks_new": false,
"observations": { "total": 418, "last_5m": 81, "last_1h": 201, "unique_reporters": 47 },
"failure_rate": { "last_5m": 0.73, "last_1h": 0.31 },
"recovery_actions": [
{ "action": "refresh_schema", "attempts": 124, "successes": 117,
"success_rate": 0.9435, "confidence": 0.8881 },
{ "action": "retry", "attempts": 91, "successes": 17,
"success_rate": 0.1868, "confidence": 0.12 }
],
"recommendation": {
"action": "refresh_schema", "confidence": 0.8881,
"based_on_attempts": 124, "based_on_successes": 117
}
}
当网络上没有有用信息时:
{ "known": false, "status": "INSUFFICIENT_DATA", "recommendation": null }
/v1/query 为只读操作,不会存储任何内容。
报告恢复结果
curl -s localhost:8000/v1/outcome \
-H 'content-type: application/json' \
-d '{
"fingerprint": "01ae47053fbb3eabf8f3e480cba45ba8",
"action": "refresh_schema",
"successful": true
}'
{ "accepted": true }
V1 中的操作是自由格式字符串。常见操作包括:retry、wait、
refresh_schema、remove_optional_field、reconnect、use_fallback、
reauthenticate、abort。
状态
curl -s localhost:8000/v1/services # per service/operation health, worst first
curl -s localhost:8000/v1/stats # counters; real and synthetic kept separate
curl -s localhost:8000/v1/recovery-intelligence # best evidenced recovery actions
curl -s localhost:8000/health # {"status":"ok"}
curl -s localhost:8000/llms.txt # agent-readable description of the service
Python 客户端
零依赖——仅使用标准库。将 client/failure_network.py
和 client/failecho.py 复制到你的 Agent 中(该包尚未发布)。
failecho 是首选导入名称,只是重新导出
failure_network,后者仍可照常使用——此次重命名是附加的,不会导致
现有代码失效。
错误文本默认不发送。包装器的默认分类器只报告异常类和状态码,不包含消息;设置
FAILECHO_SEND_ERRORS=1 可一并发送文本。显式传入的 error_message(如下例所示)
始终会发送——是否这样做由你决定,并非默认行为。
from failecho import Client # or: from failure_network import Client
client = Client("http://localhost:8000", reporter_id="my-agent-1")
client.observe_failure(
service="github-mcp",
operation="create_issue",
version="2.8.1",
schema_hash="abc",
error_type="validation_error",
error_code="422",
error_message="Repository 91827 not found",
)
intel = client.query(
service="github-mcp",
operation="create_issue",
version="2.8.1",
schema_hash="abc",
error_type="validation_error",
error_code="422",
error_message="Repository 12345 not found",
)
if intel["recommendation"]:
action = intel["recommendation"]["action"] # e.g. "refresh_schema"
client.report_recovery(
fingerprint=intel["fingerprint"], action=action, successful=True
)
client.observe_success(service="github-mcp", operation="create_issue", latency_ms=318)
每次调用都是故障软化的:超时或无法访问服务时会返回 None
(或由 query 返回一个中性的 INSUFFICIENT_DATA 字典),而不是抛出异常。
遥测绝不能影响它所观察的 Agent。
连接需要你做什么
**什么都不需要。**托管的 MCP 端点(https://failecho.com/mcp)、REST API、
插件、代理和 failecho-autoreport 均无需密钥、令牌或账户,也不会读取任何凭据。
所有可选设置都列在配置中;其中唯一需要的秘密信息是你自己的
团队令牌(如果你选择使用私有模式)。
此仓库还包含 FailEcho 自有实验室的工具——计分板背后的测试 Agent 集群
(failecho_fleet、failecho_agent、failecho_sandbox、deploy/)。这些工具会从
我们服务器的环境中读取模型提供商密钥
(GROQ_API_KEY、GEMINI_API_KEY,等等)和 FailEcho 的运维令牌。你不需要这些信息,也没有你安装的任何内容会读取它们。公开这些内容是为了让人们核查实验室的数据,而不是让你运行它。
app/web/static/vendor/ 是 Swagger UI 未修改的上游构建产物,校验和见
其 README;如果它曾被编辑,测试就会失败。
隐私
隐私是产品特性,而非设置项。
收集的内容——仅结构化故障元数据:
| 字段 | 说明 |
|---|---|
service、operation、version、schema_hash | 调用了什么 |
outcome | success 或 failure |
error_type、error_code | 简短分类标识 |
normalized_error | 已替换标识符并删除秘密信息 |
latency_ms | |
fingerprint | SHA-256 摘要 |
reporter_hash | 可选请求头的加盐哈希,或 NULL |
created_at、source |
我们不需要,也绝不存储:
- 提示词
- 模型消息
- 工具参数
- 工具结果
- 请求正文和响应正文
- HTTP 请求头和 Cookie
- API 密钥、令牌和秘密信息
- 客户名称、电子邮件地址及任何用户内容
- 信用卡数据
仅限元数据。如果某个字段不在上表中,这个网络就不需要它——而且架构中也没有存储它的位置。
具体实施方式:
- 请求架构中没有这些字段。处理器运行前,Pydantic 会丢弃未知的 JSON 键,因此 Agent 即使意外发送了
{"prompt": ...},此处也无法将其持久化。 - 原始
error_message会在入口处规范化,随后丢弃原始字符串——绝不写入任何列,也绝不记录到日志中。只有normalized_error会保留。 - 规范化首先执行脱敏处理:符合凭据特征的子字符串(Bearer 令牌、API 密钥、JWT、类似银行卡号的数字组)会变为
<REDACTED>,而不是被分类后保留。 X-Reporter-ID是可选项,到达时会使用FIN_REPORTER_SALT加盐并进行哈希处理。原始值绝不存储。轮换盐值后,现有哈希将无法再关联。- 这里没有身份验证,因此根本不存在可能泄露的账户、电子邮件或账单身份信息。
规范化示例:
Repository 918272 was not found -> Repository <N> was not found
User [email protected] at 10.0.12.7 failed -> User <EMAIL> at <IP> failed
GET https://api.example.com/v1/x?y=2 failed -> GET <URL> failed
token=sk_live_9aBc12345678xyz rejected -> <REDACTED> rejected
HTTP 422 unprocessable -> HTTP 422 unprocessable (unchanged)
小数字会按原样保留,这是有意为之:422 和 500 表示语义,而非标识符。请参阅 app/core/normalize.py 和 app/core/privacy.py。
数字的计算方式
所有计算都基于观测次数,采用确定性算术。没有模型、没有学习到的参数,也没有任何你无法自行重新计算的内容。
事件状态(MVP 启发式逻辑,常量位于 app/core/config.py):
< 10 observations in the last hour -> INSUFFICIENT_DATA
failure rate < 5% -> HEALTHY
failure rate >= 5% and < 30% -> DEGRADED
failure rate >= 30% -> MAJOR
当 5 分钟窗口中的观测次数至少达到 5 次时,它便会取代 1 小时窗口,避免新发生的事件被过去一小时的正常历史数据稀释。这是对比率设置的阈值,不是变点检测,也不考虑季节性,且未经统计校准。它被刻意标记为 MVP 逻辑。
恢复置信度是该操作成功率的 95% 威尔逊分数区间下界。它将样本量纳入数值,因此 5/5 次成功的排名低于 117/124 次成功。只有至少有 5 次尝试且成功率达到 60%,才会推荐某项操作;置信度上限低于 1.0。证据不足时,返回 "recommendation": null。网络不会凭空捏造置信度。
独立报告者数统计不同的非空报告者哈希值,因此,一个 Agent 发送 1000 个事件不会被视为 1000 个独立报告者。匿名观测不计入此数,因此该数值是下界。
防滥用底线(V1)
没有账户,因此防御措施以结构性手段为基础,而非基于身份。两层彼此独立,且都透明:
每位报告者的证据上限。 对于置信度和推荐,每位报告者在每个 fingerprint + action + hour 组合下贡献的尝试次数最多为 FIN_MAX_REPORTER_WEIGHT_PER_HOUR(默认值为 5)。原始计数仍会如实报告——API 会同时返回 attempts 和 effective_attempts,因此你可以看到报告的数量以及实际计入的数量。如果某个桶触及上限,成功次数也会按比例缩减,因此削减数量绝不会凭空提高成功率。同一桶中的所有匿名报告都视为同一位报告者:无法归属身份的证据不能证明其彼此独立。
报告者多样性。 推荐需要 5 次有效尝试和 60% 的成功率。由少于 FIN_MIN_UNIQUE_REPORTERS(默认值为 3)位不同报告者提供支持的证据不会被屏蔽——匿名报告是一种受支持的模式——但其置信度会乘以 FIN_LOW_DIVERSITY_CONFIDENCE_FACTOR(默认值为 0.7)。
写入速率限制。 POST /v1/observe、POST /v1/outcome 和 MCP 报告工具共用一份预算:每个客户端 IP 每分钟 FIN_RATE_LIMIT_WRITES_PER_MINUTE 次(默认值为 120)。切换传输方式不会获得第二份预算。读取操作永不受速率限制;查询就是产品本身。限流器使用进程内字典:它不是分布式的,因此第二个工作进程会有自己的预算,而且它无法阻止分布式流量洪泛。证据上限才是能抵御更换 IP 的攻击者的防御措施,因为它限制的是影响力,而非请求数。
如果服务器部署在 Cloudflare 或 nginx 后方,请设置 FIN_TRUST_PROXY=1,让限流器读取 CF-Connecting-IP / X-Forwarded-For,而不是代理自身的地址。如果服务器直接暴露在外,则应保持此设置关闭:信任这些标头会让任何客户端都能伪造自己的速率限制身份。
报告者身份仍为可选项,且在存储前仍会加盐哈希。原始标识符绝不会写入任何位置。
保留与清理
原始观测是热路径(5 分钟和 1 小时窗口会直接读取它们),也是会无限增长的数据。因此:
raw observations kept FIN_RETENTION_HOURS (default 48h)
then folded into hourly aggregates and deleted
hourly aggregates kept indefinitely
两张聚合表:hourly_stats(按小时 × 服务 × 操作 × 版本 × 架构 × 来源统计成功数、失败数、唯一报告者数、延迟总和/计数)
和 hourly_recovery_stats(按小时 × 指纹 × 操作统计尝试次数、成功次数和封顶后的有效计数)。
**不变量:**原始行会在同一事务中完成聚合并删除,因此聚合数据只描述已不存在的行。“原始数据 + 聚合数据”是总数,绝不会重复计数;重新运行清理器不会产生任何变化,因为已折叠的数据已经不存在。较短的窗口(5 分钟、1 小时)始终只读取原始行,因此清理绝不会改变实时状态。恢复上限按小时分桶应用,这与聚合数据使用的粒度完全一致,因此清理也不会改变建议。
python scripts/prune.py # use FIN_RETENTION_HOURS
python scripts/prune.py --hours 24 # override the window
python scripts/prune.py --dry-run # report only, change nothing
python scripts/prune.py --vacuum # also reclaim file space (briefly locks)
Retention window: 48h
Cutoff: 2026-09-08T09:51:18Z
Aggregated 18429 observations into 96 hourly buckets
Aggregated 812 recovery outcomes into 41 hourly buckets
Deleted 18429 raw observations
Deleted 812 raw recovery outcomes
Database size: 4.21 MB
推荐的 cron(每小时在 :15 运行)——本地开发不需要:
15 * * * * /srv/failure-network/.venv/bin/python /srv/failure-network/scripts/prune.py >> /var/log/failure-network-prune.log 2>&1
或者使用捆绑的 systemd 计时器:deploy/failure-network-prune.timer。
项目结构
app/
main.py FastAPI app, CORS, static homepage, /health, /llms.txt
mcp_server.py MCP tools + Streamable HTTP endpoint (same process)
api/ observe.py query.py outcome.py services.py deps.py
core/ normalize.py fingerprint.py intelligence.py
service.py retention.py ratelimit.py
privacy.py config.py clock.py
db/ database.py (async engine) models.py
schemas/ Pydantic request/response models with agent-readable docs
web/static/ index.html style.css app.js (no framework, no build)
logo.svg favicon.svg og-image.svg
client/
failecho/ the public client package
__init__.py FailEcho: observe_tool_call, report_*, query
adapters.py ToolTelemetrySink -- the framework seam
integrations/
pydantic_ai.py reference integration (optional dependency)
failure_network.py zero-dependency REST client (still supported)
auto_recovery.py the passive wrapper FailEcho is built on
auto_recovery.py failure-aware tool wrapper (reports + asks, never acts)
example_agent.py end-to-end REST usage example
examples/live_agent/
tool_server.py local tool that just shipped a breaking change
tool_client.py agent-side tool client with a stale cached schema
network.py MCP client (official SDK) for the four network tools
agents.py the autonomous loop: fail -> report -> ask -> recover
run_demo.py one command, six independent agents
scripts/
seed_demo.py synthetic demo telemetry (source='synthetic')
prune.py aggregate + delete expired raw rows
deploy/
failure-network.service systemd unit
failure-network-prune.timer hourly retention timer
Caddyfile.failecho-dev optional origin-level .dev redirect
LICENSE SECURITY.md CONTRIBUTING.md .env.example
tests/ the suite
app/core/service.py 是确保传输层行为一致的接缝:REST 处理器和 MCP 工具都会调用 record_observation、query_intelligence 和 record_recovery_outcome。app/core/ 中的任何内容都不依赖 HTTP,因此下一个传输层(OTel 接收器、工作进程、CLI)也能以相同方式接入。
演示数据
scripts/seed_demo.py 会写入约 2000 条观测和约 300 条恢复结果,涵盖四个服务;每行都带有 source='synthetic' 标签:
| 服务 | 操作 | 场景 |
|---|---|---|
github-mcp | create_issue | MAJOR — 架构漂移;refresh_schema 可以修复,retry 不行 |
search-api | search | DEGRADED — 上游超时;use_fallback 有效 |
stripe-mcp | create_refund | HEALTHY — 偶尔触发速率限制 |
example-agent-tool | run | HEALTHY — 极少发生崩溃,只有 3 次恢复尝试,因此不会给出建议 |
非真实遥测分为两种,都会通过行级的 source 列标记:
source | 来源 | 是否计入采用情况 |
|---|---|---|
agent | 真实的自主系统 | 是 |
demo_agent | 发送了 X-Reporter-Kind: demo 的调用方(演示 Agent) | 否 |
synthetic | scripts/seed_demo.py | 否 |
demo_agent 行是来自真实工具调用的真实观测——演示确实会导致工具故障,也确实会恢复——但它们属于演示,因此不会计入采用指标。自行标记只能降低报告的可信度:调用方发送的任何内容都无法将一行数据提升为真实遥测,因此信任此标头是安全的。
FIN_DEMO_MODE=1 会将部署标记为演示实例:/v1/stats 会返回 demo_mode: true,首页会显示 DEMO MODE 徽章。它绝不会生成流量,只会标记已存储的数据。本项目不会在启动时伪造遥测数据。
这两种数据在所有出现的地方都会分别跟踪:
/v1/stats会报告不含所有演示行的real_observations_total、real_observations_24h、real_reporters_24h和real_failure_fingerprints,并单独报告synthetic_observations和demo_agent_observations。它们绝不会合并为一个采用情况数字。- 首页会在标题区块中呈现真实遥测数据,并在单独且明确标注的区块中呈现合成数据计数;
/v1/recovery-intelligence会为每条记录标记demo_data: true|false(?include_demo=false可隐藏演示数据);POST /v1/query和 MCPcheck_tool_failure工具会返回demo_data_included,让自主调用方知道其判断是否依据了演示数据。
使用 python scripts/seed_demo.py --purge 可将其全部删除。
配置
每项设置都是一个环境变量;默认值位于
app/core/config.py。
| 变量 | 默认值 | 含义 |
|---|---|---|
FIN_DATABASE_URL | sqlite+aiosqlite:///./data/failure_network.db | 之后可替换为 postgresql+asyncpg://... |
FIN_REPORTER_SALT | dev-salt-change-me | 在生产环境中更改;轮换后旧哈希将解除关联 |
FIN_WINDOW_SHORT_SECONDS | 300 | 短时间窗口 |
FIN_WINDOW_LONG_SECONDS | 3600 | 长时间窗口 |
FIN_MIN_OBSERVATIONS_FOR_STATUS | 10 | 低于此值时:INSUFFICIENT_DATA |
FIN_HEALTHY_MAX_FAILURE_RATE | 0.05 | |
FIN_DEGRADED_MAX_FAILURE_RATE | 0.30 | |
FIN_MIN_RECOVERY_ATTEMPTS | 5 | 给出建议所需的最低证据量 |
FIN_MIN_RECOVERY_SUCCESS_RATE | 0.60 | |
FIN_MAX_CONFIDENCE | 0.99 | 绝不宣称确定 |
FIN_MAX_REPORTER_WEIGHT_PER_HOUR | 5 | 单个报告者每小时针对每个指纹 + 操作最多贡献的尝试次数 |
FIN_MIN_UNIQUE_REPORTERS | 3 | 低于此值时会降低置信度(但不会阻止) |
FIN_LOW_DIVERSITY_CONFIDENCE_FACTOR | 0.7 | 降低系数 |
FIN_RATE_LIMIT_ENABLED | 1 | 开启/关闭写入速率限制 |
FIN_RATE_LIMIT_WRITES_PER_MINUTE | 120 | 按客户端 IP 计算,REST + MCP 合并计数 |
FIN_TRUST_PROXY | 0 | 读取 CF-Connecting-IP / X-Forwarded-For;仅在真实代理后方使用 |
FIN_RETENTION_HOURS | 48 | 超过此时限的原始观测数据将被汇总并删除 |
FIN_MCP_ENABLED | 1 | 挂载 MCP 端点 |
FIN_MCP_PATH | /mcp | 挂载路径 |
FIN_MCP_ALLOWED_HOSTS | (空) | 逗号分隔列表;设置后启用 DNS 重绑定防护 |
FIN_MCP_ALLOWED_ORIGINS | (空) | 逗号分隔列表;作用相同 |
FIN_ALLOWED_ORIGINS | * | 浏览器的 CORS 来源(逗号分隔) |
FIN_PUBLIC_URL | http://localhost:8000 | 规范公共来源;用于生成规范标签、OG 标签、/llms.txt 和页面上的所有示例 |
FIN_GITHUB_URL | (空) | 仓库链接(生产环境中为 https://github.com/FailEcho/failecho);为空时,任何位置都不会显示 GitHub 链接 |
FIN_DEMO_MODE | 0 | 将此部署标记为演示实例(不会生成任何内容) |
在小型 VPS 上部署
品牌素材
app/web/static/logo.svg the mark, inherits surrounding text colour
app/web/static/favicon.svg the mark with fixed neutrals, for tab bars
app/web/static/og-image.svg 1200x630 social card
此标志代表一次故障事件及其回响:一道高耸的信号红色笔画向外重复并逐渐消退。它不包含预置的字标——“FailEcho”始终作为 HTML 文本显示在旁边,因此标志在 16px 尺寸和用作头像时依然清晰可用。
og-image.svg 会原样提供。大多数社交平台无法渲染 SVG 预览;需要 PNG 时,可用任意工具导出一次,并将其放在 SVG 旁边,而不是给服务添加渲染依赖。
域名
failecho.com 是规范的公共来源。Agent 或人类所需的一切都在此域名上:
https://failecho.com/ homepage
https://failecho.com/mcp MCP endpoint (Streamable HTTP)
https://failecho.com/docs API reference
https://failecho.com/openapi.json machine-readable schema
https://failecho.com/llms.txt plain-text summary for agents
failecho.dev 是次要域名,会永久重定向到
failecho.com,并保留路径:
https://failecho.dev/* -> 301 -> https://failecho.com/*
https://failecho.dev/docs -> 301 -> https://failecho.com/docs
https://failecho.dev/mcp -> 301 -> https://failecho.com/mcp
请在边缘端执行此操作,而不是在应用中处理。应用并不知道第二个域名的存在,也不应增加相关逻辑。
www.failecho.com → failecho.com 由源站上的 Caddy 处理
(redir https://failecho.com{uri} permanent),因此无需 Cloudflare 规则 —
只需为 www 添加一条已代理的 DNS 记录。
.dev 域名优先使用 Cloudflare。 将 failecho.dev 添加到同一账户,然后选择
Rules → Redirect Rules → Create rule:
| 字段 | 值 |
|---|---|
| 匹配传入请求的条件 | Hostname contains failecho.dev |
| 然后 | 动态重定向 |
| 表达式 | concat("https://failecho.com", http.request.uri.path) |
| 状态码 | 301 |
| 保留查询字符串 | 开启 |
一条规则即可覆盖 failecho.dev 和 www.failecho.dev — Hostname contains 匹配会捕获这两个域名 — 免费套餐也无需付费。切勿从 .dev 提供网站副本:两个来源提供相同内容,是导致 Google 选错规范来源的经典原因。两个主机名仍都需要已代理的 DNS 记录(指向源站的 A 记录,或者如果你希望源站完全看不到请求,则指向 100:: 的 AAAA 记录)。
Caddy 备用方案,如果你之后改为从源站提供 .dev — 配置文件位于
deploy/Caddyfile.failecho-dev:
failecho.dev, www.failecho.dev {
redir https://failecho.com{uri} permanent
}
本 MVP 刻意不使用 api.failecho.com:第二个来源意味着第二张证书、第二个 CORS 范围,以及又一件需要解释的事情,而 API 和网站运行在同一进程中,没有任何好处。
只需在一个地方设置一次源站:
FIN_PUBLIC_URL=https://failecho.com
它会决定规范链接标签、Open Graph URL、/llms.txt、首页显示的 MCP 端点,以及每个可复制示例的内容。代码库中没有任何文件硬编码域名。若不设置,所有内容都会回退到请求自身的来源,因此本地开发和通过 IP 地址访问都能正常运行。
Cloudflare 检查清单
DNS
| 名称 | 类型 | 值 | 代理 |
|---|---|---|---|
failecho.com | A | 源站 IP | 已代理 |
www.failecho.com | A | 源站 IP | 已代理 |
failecho.dev | A | 源站 IP | 已代理 |
www.failecho.dev | A | 源站 IP | 已代理 |
www.failecho.com → failecho.com 由 Caddy 处理(redir ... permanent)。
.dev 主机名由上述重定向规则处理。
首次设置时,操作顺序很重要: 在 Caddy 获取 Let's Encrypt 证书之前,先将记录设为未代理(灰色云朵),然后再切换为已代理,并设置 SSL/TLS → Overview → Full (strict)。先开启代理,或将模式保留为“Flexible”,通常都会导致问题。
缓存。 切勿缓存实时接口。Caddy 已为 /v1/*、/health 和 /mcp 发送
Cache-Control: no-store,并为 /static/* 设置 max-age=3600;请让 Cloudflare 使用“Respect origin headers”,而不要添加一条通用缓存规则。缓存 /mcp 会破坏 MCP 会话,缓存 /v1/stats 则会让实时网络看起来像是停滞了。
速率限制。 Cloudflare 速率限制是补充措施,而非替代方案: 即使关闭代理,FailEcho 自身按 IP 限制写入频率和按报告者限制证据数量的机制也必须继续工作,因为它们是阻止投毒的关键,而投毒并不在乎你是否使用 CDN。这里的任何操作都不需要付费的 Cloudflare 套餐。
部署拓扑
预期拓扑。 应用仅绑定到环回地址;TLS 和公网地址由 Cloudflare 和本地反向代理负责:
internet
|
v
Cloudflare (TLS, DNS, DDoS)
|
v
nginx / caddy on the VPS (:443 -> :8000)
|
v
uvicorn 127.0.0.1:8000 FastAPI + SQLite (WAL)
在此拓扑中,不要将 uvicorn 绑定到 0.0.0.0。公开绑定会绕过代理,直接暴露源站,并使 FIN_TRUST_PROXY=1 变得不安全(任何客户端都可以伪造 X-Forwarded-For 并绕过速率限制)。Docker 是可选的,并非必需。
步骤 1 — 生成一次报告者盐值并妥善保存。
sudo install -d -o failurenet -g failurenet /srv/failure-network/data
printf 'FIN_REPORTER_SALT=%s\n' "$(openssl rand -hex 16)" \
| sudo tee /etc/failure-network.env > /dev/null
sudo chmod 600 /etc/failure-network.env
在命令行中内联生成会在每次重启时生成新的盐值,从而悄然重置所有报告者哈希和唯一报告者计数。只生成一次,只存储一次。
步骤 2 — 生产环境命令(systemd 单元运行的命令):
set -a; . /etc/failure-network.env; set +a
export FIN_DATABASE_URL="sqlite+aiosqlite:////srv/failure-network/data/failure_network.db"
export FIN_PUBLIC_URL="https://failecho.com"
export FIN_TRUST_PROXY=1
export FIN_ALLOWED_ORIGINS='*'
export FIN_RETENTION_HOURS=48
/srv/failure-network/.venv/bin/python -m uvicorn app.main:app \
--host 127.0.0.1 --port 8000 --workers 1 \
--proxy-headers --forwarded-allow-ips '127.0.0.1' --no-server-header
请注意 SQLite URL 中的四个斜杠:sqlite+aiosqlite:/// 加上绝对路径 /srv/...。三个斜杠会使路径相对于工作目录。
步骤 3 — 反向代理。 Caddy:
failures.example.com {
reverse_proxy 127.0.0.1:8000
}
nginx:
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off; # keeps /mcp responsive
}
然后运行 sudo cp deploy/failure-network.service /etc/systemd/system/ 和
sudo systemctl enable --now failure-network。
环境变量检查清单
| 变量 | 生产环境值 | 原因 |
|---|---|---|
FIN_REPORTER_SALT | 来自 /etc/failure-network.env 的 32 位十六进制字符 | 设置一次;轮换盐值会导致现有报告者哈希失去关联 |
FIN_DATABASE_URL | sqlite+aiosqlite:////srv/failure-network/data/failure_network.db | 绝对路径,四个斜杠 |
FIN_TRUST_PROXY | 仅在使用上述代理时设为 1 | 否则客户端可以伪造自己的速率限制身份 |
FIN_ALLOWED_ORIGINS | *,或 https://yourdomain | 以逗号分隔;* 可让浏览器调用公共 API |
FIN_RETENTION_HOURS | 48 | 超过此时限的原始行会转为每小时聚合数据 |
FIN_DEMO_MODE | 生产环境中设为 0 | 仅演示实例设为 1 |
FIN_PUBLIC_URL | https://failecho.com | 用作链接、标签和示例的规范源站 |
FIN_GITHUB_URL | 仓库 URL,或不设置 | 未设置时不会显示链接 |
其他说明
- 单个工作进程。 SQLite 本身会串行处理写入,而且速率限制器和 MCP 会话管理器都是进程级的——两个工作进程意味着两套独立的速率限制配额。只有迁移到 PostgreSQL 后才扩展实例。
- MCP 由同一进程在
/mcp提供服务;它返回纯 JSON,因此除禁用缓冲外,无需针对 SSE 进行代理调优。 - 数据保留: 使用
deploy/failure-network-prune.timer,或上文的 cron 行。 - 备份: 复制
data/(包括-wal/-shm),或运行sqlite3 data/failure_network.db ".backup backup.db"。无需停机。
挂载 MCP 服务后,常驻内存远低于 150 MB;SQLite 以 WAL 模式运行,设置为 synchronous=NORMAL,繁忙超时为 5 秒,因此读取操作不会被写入操作阻塞。
之后迁移到 PostgreSQL
所有列类型都可移植,时间戳均为无时区 UTC,没有 SQLite 专用类型,也没有表达式索引。迁移只需设置 FIN_DATABASE_URL=postgresql+asyncpg://...、运行 pip install asyncpg,并执行一次 Alembic 基线迁移。
它在运行吗?
FailEcho 会在 /v1/stats 上公布决定这个想法是否成立的数据。这些数据有意呈现得不那么好看。
| 指标 | 它回答的问题 |
|---|---|
real_observations_24h | 是否有真实数据传入? |
real_successes_24h | 我们有分母,还是只有投诉? |
real_reporters_24h | 有多少个独立系统? |
known_hit_rate_24h | Agent 发起查询时,FailEcho 能提供信息吗? |
recovery_outcome_ratio_24h | Agent 会反馈修复是否奏效吗? |
cross_agent_help_24h | Agent 是否使用了并非由自己生成的证据? |
cross_agent_help_24h 是最重要的指标。只有在调用方表明了身份、系统返回了建议,而且该建议背后至少有一名报告者是其他人时,才会计入一次查询。匿名调用方和只有一名报告者提供的证据都不计入——低估效果是诚实的,高估则不是。
recovery_outcome_ratio_24h 是最难衡量的指标。报告故障是自动的;要报告修复是否奏效,则需要 Agent 之后再次回来。如果没有这些报告,FailEcho 就只是一个错误计数器。
发布里程碑
内部实验标记,不是营销宣传:
1 one real reporter
2 ten independent real reporters
3 100+ real observations per day
4 the first repeated real fingerprint
5 the first real cross-agent recovery benefit
里程碑 5 是我们要验证的假设:Agent 遇到故障,查询 FailEcho,收到由无关 Agent 生成的证据,改变行为并恢复。此前的一切都只是基础设施。
MVP 的局限
坦诚说明这些局限,因为假装没有只会降低网络的实用性:
- 没有身份验证。 任何人都可以报告任何内容。每位报告者的证据上限和速率限制器提高了污染统计数据的成本,但无法完全阻止这种行为;来自许多 IP 的分布式洪泛仍然可以通过。
- 没有信誉评分。 报告者只计数,不排名。正确报告过一千次的报告者,和新报告者的权重相同。
- 速率限制器在进程内运行,并非分布式。 一个 uvicorn 工作进程对应一个限额,重启后会重置。
- 没有复杂的异常检测。 状态是根据两个固定时间窗口内的故障率,按固定阈值判定的。
- 聚合数据中的独立报告者数量是下限。 修剪后不会保留报告者身份,因此合并后的桶会取各桶报告者数量的最大值,而不是真正的去重计数。
- 尚不支持 OpenTelemetry 数据接入、尚无 TypeScript SDK、不支持付费(无论是
x402还是其他方式)。目前一切免费。 - SQLite 是原型阶段的选择。数据保留机制会控制文件大小,但网络繁忙后最终会需要 PostgreSQL(替换 URL 并添加
asyncpg即可)。 - 恢复操作使用自由格式字符串,因此如果 Agent 的拼写不一致,
refresh_schema和refreshSchema会被分别计数(输入会转换为小写并规范化空格,可处理常见情况)。
证据
docs/claims.md— FailEcho 提出的每项主张、背后的确切证据,以及不得提出的主张- lab.failecho.com/fleet — 实时排行榜,包括表现落后的群组
联系方式
- 一般咨询:[email protected]
- 集成帮助:[email protected]
- 安全问题报告:[email protected] — 请参阅 SECURITY.md;发现漏洞时请勿公开提交 issue
许可证
MIT。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。