去中心化 AI 模型市场:从中心化托管到链上验证推理

cover

一、AI 模型分发的信任困境:中心化平台的黑箱推理

当前 AI 模型的分发和推理高度中心化——用户将数据发送到模型提供商的 API,无法验证推理过程是否使用了声称的模型,也无法确认输出是否被篡改。这种"黑箱推理"模式在隐私敏感场景(如医疗诊断、金融风控)中不可接受,用户不愿将敏感数据发送到不可验证的第三方。

去中心化 AI 模型市场的核心思路是:模型提供者将模型哈希注册到链上,推理节点在链下执行推理并提交结果和证明,验证者通过密码学方法验证推理的正确性。这种"链上验证 + 链下计算"的架构,在去中心化和性能之间取得了平衡。

二、去中心化模型市场的架构设计

去中心化模型市场包含三个核心角色:模型提供者(注册模型并设置定价)、推理节点(执行推理并提交证明)和验证者(验证推理结果的正确性)。链上智能合约负责模型注册、支付结算和争议仲裁,链下推理网络负责实际的模型执行。

flowchart TB
    A[模型提供者] --> B[链上模型注册]
    B --> C[模型元数据: 哈希/版本/定价]
    C --> D[推理节点发现]

    E[用户] --> F[提交推理请求]
    F --> G[链上支付锁定]
    G --> H[推理任务分发]

    H --> I[推理节点 A: 执行推理]
    H --> J[推理节点 B: 执行推理]

    I --> K[提交结果 + 证明]
    J --> K

    K --> L{验证者校验}
    L -->|通过| M[链上结算支付]
    L -->|失败| N[争议仲裁]

    M --> O[用户获取结果]
    N --> P[惩罚恶意节点]

    subgraph 链上
        B
        C
        G
        L
        M
        N
        P
    end

    subgraph 链下
        I
        J
        K
    end

上图展示了去中心化模型市场的完整交互流程。关键设计点在于"验证者校验"——验证推理结果正确性的成本必须远低于执行推理本身的成本,否则验证机制没有经济意义。

三、生产级实现:去中心化模型市场合约

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

error ModelNotFound(bytes32 modelId);
error InsufficientPayment(uint256 required, uint256 provided);
error InferenceNotVerified(bytes32 requestId);
error NodeNotRegistered(address node);

/**
 * @title DecentralizedAIModelMarket
 * @notice 去中心化 AI 模型市场:链上注册、链下推理、链上验证
 */
contract DecentralizedAIModelMarket is Ownable, ReentrancyGuard {

    // 模型注册信息
    struct Model {
        address provider;           // 模型提供者地址
        bytes32 modelHash;          // 模型文件哈希(SHA-256)
        string modelUri;            // 模型文件 URI(IPFS/Arweave)
        uint256 pricePerInference;  // 每次推理价格(wei)
        uint8 inputDim;             // 输入维度
        uint8 outputDim;            // 输出维度
        bool active;                // 是否可用
    }

    // 推理请求
    struct InferenceRequest {
        address user;               // 请求用户
        bytes32 modelId;            // 请求的模型 ID
        bytes inputHash;            // 输入数据哈希(链下存储实际数据)
        bytes output;               // 推理结果
        bytes proof;                // 推理证明
        address inferenceNode;      // 执行推理的节点
        bool verified;              // 是否已验证
        uint256 timestamp;          // 请求时间
    }

    // 推理节点注册信息
    struct InferenceNode {
        address nodeAddress;
        uint256 stake;              // 质押金额(作恶时扣除)
        uint256 successCount;       // 成功推理次数
        uint256 failCount;          // 失败推理次数
        bool active;
    }

    // 状态变量
    mapping(bytes32 => Model) public models;
    mapping(bytes32 => InferenceRequest) public requests;
    mapping(address => InferenceNode) public nodes;
    bytes32[] public modelIds;

    // 事件
    event ModelRegistered(bytes32 indexed modelId, address provider, uint256 price);
    event InferenceRequested(bytes32 indexed requestId, bytes32 indexed modelId, address user);
    event InferenceCompleted(bytes32 indexed requestId, address node, bool verified);
    event NodeRegistered(address indexed node, uint256 stake);

    // 模型注册
    // 设计意图:提供者注册模型时提交哈希,用户可验证
    // 推理节点使用的模型是否与注册的一致
    function registerModel(
        bytes32 modelHash,
        string calldata modelUri,
        uint256 pricePerInference,
        uint8 inputDim,
        uint8 outputDim
    ) external returns (bytes32) {
        bytes32 modelId = keccak256(abi.encodePacked(
            msg.sender, modelHash, block.timestamp
        ));

        models[modelId] = Model({
            provider: msg.sender,
            modelHash: modelHash,
            modelUri: modelUri,
            pricePerInference: pricePerInference,
            inputDim: inputDim,
            outputDim: outputDim,
            active: true
        });

        modelIds.push(modelId);
        emit ModelRegistered(modelId, msg.sender, pricePerInference);
        return modelId;
    }

    // 提交推理请求
    // 设计意图:用户支付费用并锁定,推理完成后自动结算
    function requestInference(
        bytes32 modelId,
        bytes calldata inputHash
    ) external payable returns (bytes32) {
        Model memory model = models[modelId];
        if (!model.active || model.provider == address(0))
            revert ModelNotFound(modelId);
        if (msg.value < model.pricePerInference)
            revert InsufficientPayment(model.pricePerInference, msg.value);

        bytes32 requestId = keccak256(abi.encodePacked(
            msg.sender, modelId, inputHash, block.timestamp
        ));

        requests[requestId] = InferenceRequest({
            user: msg.sender,
            modelId: modelId,
            inputHash: inputHash,
            output: "",
            proof: "",
            inferenceNode: address(0),
            verified: false,
            timestamp: block.timestamp
        });

        emit InferenceRequested(requestId, modelId, msg.sender);
        return requestId;
    }

    // 推理节点提交结果
    // 设计意图:推理节点提交结果和证明,
    // 验证者后续校验证明的正确性
    function submitResult(
        bytes32 requestId,
        bytes calldata output,
        bytes calldata proof
    ) external {
        InferenceNode memory node = nodes[msg.sender];
        if (!node.active) revert NodeNotRegistered(msg.sender);

        InferenceRequest storage request = requests[requestId];
        request.output = output;
        request.proof = proof;
        request.inferenceNode = msg.sender;

        // 简化验证:实际生产中应使用 zk-proof 验证
        // 此处仅做格式校验
        if (output.length > 0 && proof.length > 0) {
            request.verified = true;
            _settlePayment(requestId);
        }
    }

    // 结算支付
    function _settlePayment(bytes32 requestId) internal nonReentrant {
        InferenceRequest storage request = requests[requestId];
        Model memory model = models[request.modelId];

        // 支付给推理节点(90%)和模型提供者(10%)
        uint256 nodePayment = (model.pricePerInference * 90) / 100;
        uint256 providerPayment = model.pricePerInference - nodePayment;

        (bool nodeOk,) = request.inferenceNode.call{value: nodePayment}("");
        (bool providerOk,) = model.provider.call{value: providerPayment}("");

        require(nodeOk && providerOk, "Payment failed");

        // 退还多余支付
        if (msg.value > model.pricePerInference) {
            uint256 refund = msg.value - model.pricePerInference;
            (bool refundOk,) = request.user.call{value: refund}("");
            require(refundOk, "Refund failed");
        }

        emit InferenceCompleted(requestId, request.inferenceNode, true);
    }

    // 推理节点注册
    function registerNode() external payable {
        require(msg.value >= 1 ether, "Minimum stake: 1 ETH");

        nodes[msg.sender] = InferenceNode({
            nodeAddress: msg.sender,
            stake: msg.value,
            successCount: 0,
            failCount: 0,
            active: true
        });

        emit NodeRegistered(msg.sender, msg.value);
    }
}

四、边界分析与架构权衡

去中心化模型市场在工程落地中需要正视以下 Trade-off:

验证成本与安全性的矛盾。零知识证明(zk-proof)可以验证推理正确性,但生成证明的计算成本极高(约为推理本身的 100-1000 倍)。对于大模型推理,zk-proof 的生成时间可能长达数小时。折中方案是使用"多节点冗余推理"——多个独立节点执行同一推理,结果一致则视为正确。但这增加了推理成本。

模型隐私保护。模型提供者可能不愿公开模型权重(商业机密),但链上注册要求提交模型哈希。加密推理(如同态加密、TEE)可以在不暴露模型的情况下执行推理,但性能开销巨大。目前最实用的方案是 TEE(可信执行环境),如 Intel SGX 或 AWS Nitro Enclaves。

链上存储成本。推理结果和证明存储在链上成本极高。一个 1KB 的推理结果,存储 Gas 约为 0.02 ETH(约 40 美元)。建议仅在链上存储结果哈希,实际数据存储在 IPFS/Arweave。

适用边界:去中心化模型市场最适合对推理可验证性有强需求的场景(如医疗 AI、法律 AI、金融风控)。对于对延迟敏感的场景(如实时推荐),中心化 API 仍是更优选择。

五、总结

去中心化 AI 模型市场将 AI 推理从"黑箱 API"推进到"可验证计算"。核心架构:链上注册模型哈希和定价,链下执行推理并提交证明,链上验证和结算支付。落地建议:第一,使用多节点冗余推理替代 zk-proof 降低验证成本;第二,推理结果存 IPFS,链上仅存哈希;第三,TEE 保护模型隐私。关键原则:去中心化不是目的,可验证性才是——用户不需要"信任"推理节点,而是可以"验证"推理结果。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐