链上 AI Agent 的决策可审计架构:事件溯源与不可篡改日志设计
链上 AI Agent 的决策可审计架构:事件溯源与不可篡改日志设计
一、Agent 决策链路不可追溯就等于黑箱
AI Agent 在链上执行操作——代币转移、合约调用、治理投票——会产生真实的资产和权限影响。如果 Agent 的决策链路不可追溯,出了问题只能看到"Agent 做了某件事",但无从得知"Agent 是在什么状态下做出这个决定的"。
一次看似异常的代币兑换,可能是正常策略执行(价格触及阈值),可能是 Oracle 数据延迟导致的误判,也可能是外部攻击者通过操纵链上数据误导了 Agent。没有完整决策链路的记录,系统将无法审计、无法复盘、无法问责。
可审计架构的核心诉求不是"记录一切",而是记录到能还原决策逻辑的程度。事件溯源(Event Sourcing)提供了天然合适的架构范式:不存储当前状态,而是存储状态变化的事件序列,当前状态是事件序列的回放结果。这和区块链的"交易序列 → 世界状态"模型完全吻合。
二、架构:事件溯源 + 链上日志 + 链下索引
flowchart TD
A[Agent 决策请求] --> B[输入快照模块<br/>记录: 区块高度/价格/账户状态]
B --> C[推理模块<br/>记录: 模型 ID/输入/输出/耗时]
C --> D[决策模块<br/>记录: 决策动作/参数/置信度]
D --> E[操作执行模块<br/>记录: 交易哈希/Gas/状态]
B --> F[事件总线]
C --> F
D --> F
E --> F
F --> G[链上日志合约<br/>存储事件哈希 + 元数据]
F --> H[链下索引<br/>存储完整事件详情]
G --> I[链上可验证]
H --> J[全文检索 + 可视化]
输入快照、推理、决策、执行——每个环节都产生事件。事件分为两类:
- 链上事件:只存储哈希、时间戳、事件类型标识——数据量小,适合链上永久记录
- 链下事件:存储完整的决策上下文、LLM 输入输出、模型参数——数据量大,存在索引层供检索
链上哈希保证"这个决策过程确实在某时某刻发生过"且不可篡改,链下数据保证"这个决策过程的细节可以被完整查看和审计"。两层一起构成不可否定的审计证据链。
三、生产级实现
链上审计日志合约
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/**
* @title AgentAuditLog
* @notice AI Agent 决策过程的链上审计日志
*
* 设计决策:
* - 只存哈希不存明文:链上存储贵,决策详情在链下索引
* - 事件类型分级:INPUT_SNAPSHOT / REASONING / DECISION / EXECUTION
* - 每个事件都有自增序号——保证顺序可追溯
* - 不可删除、不可修改——写一次就是永久的审计记录
*/
contract AgentAuditLog {
/// @notice 事件类型枚举
enum EventType {
INPUT_SNAPSHOT, // 输入快照:记录了 Agent 看到的世界状态
REASONING, // 推理过程:模型信息、输出原文
DECISION, // 决策:选择了哪个动作、参数、置信度
EXECUTION, // 执行:链上交易哈希、Gas 消耗、状态变化
EXCEPTION // 异常:决策失败、执行回滚的原因
}
/// @notice 单条审计事件
struct AuditEvent {
uint256 id; // 自增事件 ID(同一 Agent 内唯一)
EventType eventType; // 事件类型
address agentAddress; // Agent 合约地址
bytes32 eventHash; // 链下事件详情哈希(用于链下数据完整性验证)
bytes32 parentHash; // 上一事件的哈希——形成事件链
uint256 blockNumber; // 此时所在的区块高度
uint256 timestamp; // 区块时间戳
bytes metadata; // 压缩元数据(模型 ID + 版本 + 决策类型)
}
/// @notice 每个 Agent 的事件计数器
mapping(address => uint256) public eventCounters;
/// @notice 事件存储:agentAddress => eventId => AuditEvent
mapping(address => mapping(uint256 => AuditEvent)) public events;
event AuditEventRecorded(
address indexed agent,
uint256 indexed eventId,
EventType eventType,
bytes32 eventHash,
bytes32 parentHash
);
/**
* @notice 写入一条审计事件——只有 Agent 合约本身可以调用
* @param eventType 事件类型
* @param eventHash 链下事件详情的 keccak256 哈希
* @param metadata 压缩元数据(编码格式由 Agent 自定义)
*
* 设计决策:
* - 限制调用者必须是 Agent 合约(通过白名单或接口检测)
* 防止外部地址写入伪造的审计日志
* - eventHash 连接链下详情:审计者可以用它验证链下数据是否被篡改
*/
function recordEvent(
EventType eventType,
bytes32 eventHash,
bytes calldata metadata
) external returns (uint256 eventId) {
// 这里简化了调用者检查——生产环境需要维护 Agent 白名单
// 或要求调用者实现 IAgent 接口
eventId = ++eventCounters[msg.sender];
bytes32 parentHash = eventId > 1
? events[msg.sender][eventId - 1].eventHash
: bytes32(0);
events[msg.sender][eventId] = AuditEvent({
id: eventId,
eventType: eventType,
agentAddress: msg.sender,
eventHash: eventHash,
parentHash: parentHash,
blockNumber: block.number,
timestamp: block.timestamp,
metadata: metadata
});
emit AuditEventRecorded(msg.sender, eventId, eventType, eventHash, parentHash);
}
/**
* @notice 获取 Agent 的审计事件历史(分页)
* @param agent Agent 地址
* @param startId 起始事件 ID
* @param count 返回数量上限(最多 100)
*
* 分页是必需的——Agent 运行数月后可能有数万条事件
*/
function getEventHistory(
address agent,
uint256 startId,
uint256 count
) external view returns (AuditEvent[] memory result) {
uint256 total = eventCounters[agent];
uint256 end = startId + count;
if (end > total + 1) end = total + 1;
if (count > 100) count = 100;
result = new AuditEvent[](end - startId);
for (uint256 i = startId; i < end; i++) {
result[i - startId] = events[agent][i];
}
}
/**
* @notice 验证链下数据完整性
* @param eventId 事件 ID
* @param offchainData 链下存储的完整事件数据
* @return 数据哈希是否匹配链上记录
*/
function verifyOffchainData(
uint256 eventId,
bytes calldata offchainData
) external view returns (bool) {
AuditEvent storage evt = events[msg.sender][eventId];
return keccak256(offchainData) == evt.eventHash;
}
}
Agent 合约集成
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "./AgentAuditLog.sol";
/**
* @notice 可审计的 AI Agent 基类
*
* 设计决策:
* - 决策和执行分离:先记录决策事件,再执行链上操作
* - 即使执行失败,决策事件也会被记录——用于事后分析"为什么这个决策导致了失败"
* - parentHash 链:每条事件引用上一条事件,形成不可篡改的事件链
* 篡改中间任意一条,后续所有 parentHash 都会断裂
*/
abstract contract AuditableAgent {
AgentAuditLog public immutable auditLog;
constructor(AgentAuditLog _auditLog) {
auditLog = _auditLog;
}
/**
* @notice 执行一个完整的决策周期
* @param snapshotHash 输入快照的哈希(链下存储完整快照)
* @param reasoningHash 推理过程的哈希
* @param decisionData 决策元数据(动作类型、参数摘要等)
*
* 流程:输入快照 → 推理 → 决策 → 执行 → 记录
* 任何步骤失败都会记录 EXCEPTION 事件
*/
function executeDecisionCycle(
bytes32 snapshotHash,
bytes32 reasoningHash,
bytes calldata decisionData
) external returns (bool) {
// 步骤 1:记录输入快照
auditLog.recordEvent(
AgentAuditLog.EventType.INPUT_SNAPSHOT,
snapshotHash,
abi.encode(block.number, block.timestamp)
);
// 步骤 2:记录推理过程
auditLog.recordEvent(
AgentAuditLog.EventType.REASONING,
reasoningHash,
decisionData[:64] // 前 32 字节 = 模型 ID + 版本
);
// 步骤 3:执行决策(由子合约实现)
try this._executeDecision(decisionData) returns (bytes32 txHash) {
// 成功:记录执行事件
auditLog.recordEvent(
AgentAuditLog.EventType.EXECUTION,
txHash,
bytes("")
);
return true;
} catch Error(string memory reason) {
// 失败:记录异常事件,包含失败原因
auditLog.recordEvent(
AgentAuditLog.EventType.EXCEPTION,
keccak256(bytes(reason)),
bytes(reason)
);
return false;
}
}
/// @notice 子合约实现具体决策逻辑
function _executeDecision(bytes calldata decisionData) external virtual returns (bytes32 txHash);
}
链下索引服务:事件数据存储与检索
// lib/audit/OffchainEventStore.ts
interface OffchainEvent {
eventId: string; // "agentAddress-eventCounter"
eventType: "input_snapshot" | "reasoning" | "decision" | "execution" | "exception";
agentAddress: string;
blockNumber: number;
timestamp: number;
// 详情(不同事件类型有不同字段)
details: {
// input_snapshot
oraclePrices?: Record<string, number>;
accountBalances?: Record<string, string>;
// reasoning
modelId?: string;
modelVersion?: string;
prompt?: string;
response?: string;
latencyMs?: number;
// decision
actionType?: string;
params?: Record<string, any>;
confidence?: number;
// execution
txHash?: string;
gasUsed?: number;
status?: string;
// exception
errorMessage?: string;
errorStack?: string;
};
}
/**
* 链下事件存储——不可篡改的追加写
*
* 设计决策:
* - 使用 S3/Cloud Storage 的版本控制 + WORM(Write Once Read Many)
* 确保存储层本身不可修改
* - 每条事件独立存储:eventId 作为 key,方便按需检索
* - 定时同步链上事件哈希:定期验证链下数据是否与链上一致
*/
class OffchainEventStore {
private storage: any; // S3 / GCS / IPFS
async saveEvent(event: OffchainEvent): Promise<string> {
// 序列化并计算哈希——这个哈希必须和链上的 eventHash 一致
const serialized = JSON.stringify(event, Object.keys(event).sort());
const eventHash = ethers.keccak256(ethers.toUtf8Bytes(serialized));
await this.storage.put(`${event.agentAddress}/${event.eventId}.json`, serialized);
return eventHash;
}
async getEventHistory(
agentAddress: string,
fromId: number,
toId: number
): Promise<OffchainEvent[]> {
const events: OffchainEvent[] = [];
for (let id = fromId; id <= toId; id++) {
try {
const raw = await this.storage.get(`${agentAddress}/${id}.json`);
events.push(JSON.parse(raw));
} catch {
// 跳过不存在的记录——可能是索引未同步
continue;
}
}
return events;
}
/**
* 完整性验证:对比链上 eventHash
*/
async verifyIntegrity(
agentAddress: string,
eventId: number,
auditLog: ethers.Contract
): Promise<boolean> {
const raw = await this.storage.get(`${agentAddress}/${eventId}.json`);
return auditLog.verifyOffchainData(eventId, ethers.toUtf8Bytes(raw));
}
}
四、边界分析:日志完整 ≠ 问责完整
审计日志能保证的东西:
- 决策过程的时序完整性:事件 A→B→C 的因果关系可追溯
- 数据不可篡改:链上哈希 + 链下 WORM 存储,事后无法修改
- 可审计性:第三方可以独立验证链上 eventHash 与链下数据的一致性
审计日志不能保证的东西:
- Agent 的推理质量:日志只记录"Agent 看到了什么、输出了什么",不判断推理是否正确
- Oracle 数据的原始可信度:如果 Oracle 提供了错误价格,日志如实记录了错误价格——这不代表 Agent 可以免责
- 多 Agent 协作的因果关系:如果 Agent A 的决策影响了 Agent B,各自的日志独立存在,跨 Agent 的因果关系需要额外分析
数据增长问题:
一个活跃的 Agent 每天可能产生 100-10000 条事件。一年下来(按 1000 条/天)就是 36.5 万条。链上只存哈希没问题(gas 可控),但链下索引需要设计分层存储策略——热数据(近 7 天)在数据库,温数据(近 30 天)在对象存储,冷数据(> 30 天)归档到 Glacier 类存储。
隐私风险:
审计日志如果包含用户的链上地址、资产余额和决策偏好,构成了一个"行为画像"。被审计方(Agent 运营方)和被审计对象(用户)之间需要明确数据权限——用户应该可以查看与自己相关的日志,但不能查看其他用户的日志。这需要在存储层做按用户隔离,不能用统一的 plain JSON 文件。
五、总结
链上 AI Agent 的可审计架构基于事件溯源:将决策过程分解为输入快照、推理、决策、执行四个阶段的事件序列,每条事件同步写入链上合约(存哈希)和链下索引(存详情)。
链上 eventHash 保证不可篡改,parentHash 链接形成不可断裂的事件链。链下存储提供全文检索和决策回放能力。第三方可通过比对链上哈希和链下数据验证审计日志的完整性。数据增长需要分层存储策略,隐私需要按用户隔离。审计日志不能替代对推理质量、Oracle 可信度和多 Agent 协作的分析。
更多推荐

所有评论(0)