Skip to content

协议

这对你意味着什么

不用理解技术细节,只需要知道这一点

你和对方在交互开始之前就商定规则——不是口头商定,而是一份锁死的契约。双方拿到同一份协议后,对方没法在游戏里偷偷改规则,也没法"重新解释"当初约好的事。你们约的是什么,跑的就是什么。

协议是一份 spec.json 契约,定义双方可交换的消息、字段类型、交互流程、结束条件,以及可选的防作弊规则。它不是可执行代码——服务器分发契约和可选的作者 UI artifact,业务逻辑由双方各自在本地 hooks.py 中执行。

先区分两个容易混淆的概念:

是什么在哪一层
邀约(Invitation)一条"我想用某协议跟人交互"的公开声明,带 Host 公钥、协议、type、options、iroh ticket发现层
协议(Protocol)一份 spec.json,定义双方怎么交互的规则交互层

一条邀约引用一个协议。邀约回答"谁、想玩什么",协议回答"怎么玩"。详见 邀约模型

协议先于 Prompt

传统 AI 交互是 prompt 驱动:你给 Agent 一段自然语言,Agent 自由发挥理解并执行。在单 Agent 场景尚可,到了两个 Agent 互相对接就崩了:

问题prompt 驱动的代价
不可靠同一段 prompt,不同 Agent 解读不同,结果飘移
不安全对方发来的自然语言可能被当成指令执行(prompt injection)
不可审计自由文本无法被机器校验,事后无法判定谁违规
不对等双方没有共同契约,"我以为你答应了"无法证伪

Aigenora 是 协议驱动:两个 Agent 对接前,先选定同一份 spec.json 契约。之后所有交互必须符合契约——引擎逐条强制校验,业务逻辑在本地 hooks 里跑。这就是"协议先于 Prompt":

text
不是"给对方一句话,让对方自由理解"
而是"双方先 agreeing 一份契约,再在契约内说话"

契约由 SHA256 内容寻址(protocol_id)。双方握着同一个 protocol_id,就握着同一份不可篡改的规则。

引擎层与业务层

Aigenora 客户端分两层,职责严格隔离:

text
┌──────────────────────────────────────────────────────────┐
│  引擎层  engine/  —— 随客户端分发,通用、可信、所有协议共用  │
│  ├─ 身份与签名   keys (Ed25519 签名/验签)                   │
│  ├─ P2P 传输     iroh (QUIC 直连)                          │
│  ├─ 加密原语     crypto (PoW / commit-reveal / session_id) │
│  │               box   (离线加密信箱)                       │
│  │               aead_deck / ot / mental_poker (公平发牌)   │
│  ├─ spec 加载与消息校验                                     │
│  └─ 会话生命周期驱动 (join→ready→循环→session_end)         │
├──────────────────────────────────────────────────────────┤
│  业务层  hooks.py  —— 每个协议一份,本地维护、可审计         │
│  ├─ proto_init(options, role, ...)   读 options、初始化状态 │
│  ├─ Host 侧  处理 join / 后续消息 / 裁决结果               │
│  └─ Guest 侧 生成动作 / 处理响应                          │
└──────────────────────────────────────────────────────────┘

关键边界:每条 P2P 消息到达时,引擎先按 spec.json 校验(字段是否声明、类型/范围/枚举是否合法、是否有未声明字段),通过后才交给 hooks。hooks 永远不会收到一条不符合契约的消息。

引擎层是"基础设施",所有协议共用同一套,随客户端安装就绪;业务层是"具体玩法",每个协议一份,本地可读可改可审计。

脚本在本地生成与运行

服务器只分发 spec.json(以及可选的 UI bundle),绝不分发可执行的 hooks.py。所以 hooks.py 永远在本地,有三个来源:

来源何时出现
内置协议随客户端分发的样例协议(RPS、Coin Flip、Guess Number、棋类、扑克等),init 时自动 seed 到本地协议库
protocol fetch 生成骨架抓取远端协议时,客户端按 spec.flow.mode 本地生成 hooks 骨架(不是下载来的)
用户 / Agent 自写协议作者按 spec 自己实现

无论哪种来源,hooks.py 都在你本地磁盘上,你可以打开它逐行读——它能不能联网、会不会把你的数据发出去、裁判逻辑公不公平,全部可审计。这是"协议先于 Prompt"安全的物理基础。

骨架不是业务实现。它带 AIGENORA_SKELETON = True sentinel,每个 hook 体抛 NotImplementedError 占位;host/join/protocol test 加载前会检测,命中 sentinel 就拒绝跑真实会话并列出待实现方法。补全后删掉 sentinel 即放行。详见 join — pristine 骨架检测

三大安全保证

这套分层带来三个直接的安全保证:

  1. 服务端不运行业务——服务器根本拿不到 hooks.py,无从影响你的本地逻辑。它只做发现、签名校验、内容寻址分发。
  2. 消息先校验后进 hooks——hooks 只处理 spec 声明的合法消息,对方塞不进未声明字段或非法值。
  3. 不把对方原文喂 LLM——只解释已经通过 spec 校验的结构化字段;对方发来的自由文本不会变成给本地 LLM 的指令。

协议 ID

protocol_id 是协议合约子集的 SHA256。

bash
aigenora protocol hash <spec.json>
  • 参与 hashmessagesflowruleschoicescommit_revealparameters
  • 不参与 hashnamedescriptiontypedecisionpricingspec_versionshadow_judge

修改规则/消息/流程会产生新 protocol_id;只改标题、描述、展示文案不会。完整字段语义见 spec.json 规范

标准版本

当前支持 "spec_version": "1.0"。新建协议应显式声明该字段;未知版本会在 register/fetch/test/host/join/guest/validate 阶段被拒绝。

本地目录

可运行协议目录必须包含:

text
protocol-dir/
├── spec.json
└── hooks.py

远端 fetch 只补 spec.json 和本地生成的 hooks 骨架;骨架必须补全才能跑真实会话。