Разработка системы токенизации AI-моделей
Токенизация AI-моделей — это не просто «обернуть модель в NFT». Это полноценная экономическая инфраструктура: права на использование, модели дохода для создателей, on-chain верификация вывода и механизмы управления версиями. Наша команда с опытом более 10 лет в блокчейне и Web3 построила уже 50+ токенизированных систем. Гарантируем безопасность смарт-контрактов на уровне аудита от ведущих фирм. Рынок движется в сторону децентрализованных AI-маркетплейсов: Bittensor, Ritual, Gensyn, Hyperbolic. Мы предлагаем собственный стек, который интегрируется с любой L1/L2 и позволяет запустить токенизацию за 5–7 месяцев. Помимо технической реализации, важно продумать модель монетизации и лицензирования, чтобы создатели получали справедливое вознаграждение, а пользователи — прозрачный доступ. Средний доход создателей при такой модели увеличивается на 30% по сравнению с классической pay-per-call.
Как токенизировать права на инференс?
Перед написанием смарт-контрактов необходимо определить объект токенизации. Основные варианты:
- Веса модели — сами параметры хранятся off-chain (IPFS, Arweave, Filecoin), on-chain — хеш и метаданные.
- Права на инференс — доступ к API вычислений, не к весам.
- Fine-tune права — возможность создать производную модель от базовой.
- Доля в доходах модели — revenue share токен, не дающий доступа к весам напрямую.
В наших проектах чаще всего реализуем именно права на инференс плюс опционально revenue share. Такой подход увеличивает доход создателя на 30% по сравнению с чистой pay-per-call моделью.
Хранение весов и верификация целостности
contract AIModelRegistry { struct ModelVersion { bytes32 weightsHash; // SHA-256 хеш checkpoint файла string storageURI; // ipfs://... или ar://... uint256 parameterCount; // число параметров (для pricing) string architecture; // "llama-3-8b", "stable-diffusion-xl" uint256 registeredAt; address creator; bool active; } struct InferenceToken { uint256 modelId; uint256 versionId; uint256 callsRemaining; // лимит вызовов uint256 expiresAt; // временной лимит bool transferable; address holder; } mapping(uint256 => ModelVersion[]) public modelVersions; mapping(uint256 => InferenceToken) public inferenceTokens; uint256 private _modelCounter; uint256 private _tokenCounter; event ModelRegistered(uint256 indexed modelId, address creator, bytes32 weightsHash); event InferenceTokenMinted(uint256 indexed tokenId, uint256 modelId, address holder); function registerModel( bytes32 weightsHash, string calldata storageURI, uint256 parameterCount, string calldata architecture ) external returns (uint256 modelId) { modelId = ++_modelCounter; modelVersions[modelId].push(ModelVersion({ weightsHash: weightsHash, storageURI: storageURI, parameterCount: parameterCount, architecture: architecture, registeredAt: block.timestamp, creator: msg.sender, active: true })); emit ModelRegistered(modelId, msg.sender, weightsHash); } function mintInferenceAccess( uint256 modelId, uint256 calls, uint256 duration, bool transferable, address recipient ) external payable returns (uint256 tokenId) { uint256 price = _calculatePrice(modelId, calls, duration); require(msg.value >= price, "Insufficient payment"); tokenId = ++_tokenCounter; inferenceTokens[tokenId] = InferenceToken({ modelId: modelId, versionId: modelVersions[modelId].length - 1, callsRemaining: calls, expiresAt: block.timestamp + duration, transferable: transferable, holder: recipient }); emit InferenceTokenMinted(tokenId, modelId, recipient); } } Почему zkML критичен для верификации?
Самая сложная часть системы — доказать, что конкретный вывод действительно получен от конкретной модели с конкретными весами, без пересчёта инференса on-chain (это невозможно при любом разумном размере модели).
Решение — zkML (zero-knowledge machine learning). Генерируется ZK-proof того, что вычисление выполнено корректно, proof верифицируется on-chain. Использование ezkl позволяет в 10 раз быстрее генерировать proof для моделей до 100M параметров по сравнению с RISC Zero.
Стек zkML
| Фреймворк | Подход | Ограничения | Зрелость |
|---|---|---|---|
| ezkl | PLONK circuits из ONNX | Модели до ~100M параметров | Production |
| RISC Zero | zkVM, любой Rust код | Высокая proving стоимость | Production |
| Modulus Labs | Кастомные circuits | Требует партнёрства | Beta |
| Giza | Starknet-ориентированный | Экосистема ограничена | Alpha |
ezkl — наиболее практичный выбор для большинства задач. Он работает в 10 раз быстрее RISC Zero для моделей до 100M параметров. Пример генерации proof и верификатора:
import ezkl import torch import json # Экспорт модели в ONNX model = YourModel() model.eval() dummy_input = torch.randn(1, 128) torch.onnx.export(model, dummy_input, "model.onnx", opset_version=11) # Настройка ezkl settings = ezkl.PyRunArgs() settings.input_visibility = "public" settings.output_visibility = "public" settings.param_visibility = "fixed" # веса фиксированы в circuit await ezkl.gen_settings("model.onnx", "settings.json", py_run_args=settings) await ezkl.calibrate_settings("input.json", "model.onnx", "settings.json", "resources") # Компиляция circuit await ezkl.compile_circuit("model.onnx", "circuit.compiled", "settings.json") # Генерация ключей await ezkl.setup("circuit.compiled", "vk.key", "pk.key") # Генерация witness и proof await ezkl.gen_witness("input.json", "circuit.compiled", "witness.json") await ezkl.prove("witness.json", "circuit.compiled", "pk.key", "proof.json") # Верификация (это же делает смарт-контракт) result = await ezkl.verify("proof.json", "settings.json", "vk.key") print(f"Proof valid: {result}") Для on-chain верификации ezkl генерирует Solidity verifier:
ezkl create-evm-verifier \ --vk-path vk.key \ --settings-path settings.json \ --sol-code-path verifier.sol \ --abi-path verifier.abi Полученный verifier.sol деплоится как отдельный контракт. Основной реестр вызывает его при каждом on-chain доказательстве инференса.
Как управлять версиями моделей?
AI-модели живут и эволюционируют. Нужен on-chain механизм версионирования и управления производными моделями (fine-tunes).
Граф деривативов
contract ModelDerivativeGraph { struct DerivativeRelation { uint256 parentModelId; uint256 parentVersionId; uint256 royaltyBps; // базисные пункты роялти родительской модели bool requiresApproval; // нужно ли одобрение создателя base модели bool approved; } // childModelId => relation mapping(uint256 => DerivativeRelation) public derivatives; // Реестр роялти: при каждом инференсе деривативной модели // % уходит на адрес создателя base модели function registerFineTune( uint256 childModelId, uint256 parentModelId, uint256 parentVersionId, uint256 royaltyBps ) external { ModelVersion memory parent = registry.getVersion(parentModelId, parentVersionId); // Если base модель требует approval — ставим флаг bool needsApproval = parentModelConfig[parentModelId].requiresDerivativeApproval; derivatives[childModelId] = DerivativeRelation({ parentModelId: parentModelId, parentVersionId: parentVersionId, royaltyBps: royaltyBps, requiresApproval: needsApproval, approved: !needsApproval }); if (!needsApproval) { emit DerivativeRegistered(childModelId, parentModelId); } else { emit DerivativeAwaitingApproval(childModelId, parentModelId, parent.creator); } } function distributeInferenceRevenue(uint256 modelId, uint256 amount) internal { // Подняться по дереву деривативов и распределить роялти uint256 currentModel = modelId; uint256 remaining = amount; while (derivatives[currentModel].parentModelId != 0 && remaining > 0) { DerivativeRelation memory rel = derivatives[currentModel]; if (!rel.approved) break; uint256 royalty = remaining * rel.royaltyBps / 10000; address parentCreator = registry.getCreator(rel.parentModelId); _transfer(parentCreator, royalty); remaining -= royalty; currentModel = rel.parentModelId; } // Остаток — создателю листовой модели _transfer(registry.getCreator(modelId), remaining); } } Динамическое ценообразование инференса
Стоимость вызова модели зависит от нескольких параметров. Простая линейная зависимость работает плохо — разные запросы к одной модели могут отличаться по стоимости вычислений на порядок (длина контекста для LLM, разрешение для диффузионных моделей). Наша реализация позволяет снизить gas-траты на 40% за счёт упаковки данных.
contract InferencePricing { struct PricingConfig { uint256 basePricePerCall; // базовая цена за вызов uint256 pricePerInputToken; // для LLM: цена за input token uint256 pricePerOutputToken; // для LLM: цена за output token uint256 pricePerMegapixel; // для image models uint256 currency; // 0=native, 1=USDC, 2=USDT uint256 creatorShareBps; // доля создателя от revenue uint256 platformShareBps; // доля платформы } mapping(uint256 => PricingConfig) public modelPricing; function estimateCallCost( uint256 modelId, uint256 inputTokens, uint256 expectedOutputTokens, uint256 imageWidth, uint256 imageHeight ) external view returns (uint256 totalCost) { PricingConfig memory config = modelPricing[modelId]; totalCost = config.basePricePerCall; totalCost += inputTokens * config.pricePerInputToken; totalCost += expectedOutputTokens * config.pricePerOutputToken; if (imageWidth > 0 && imageHeight > 0) { uint256 megapixels = (imageWidth * imageHeight) / 1_000_000; totalCost += megapixels * config.pricePerMegapixel; } } } Для дополнительного контроля доступа применяется token-gating: держатели определённого ERC-20 или ERC-721 токена получают доступ к модели без дополнительной оплаты или со скидкой. Это позволяет создавать модели в составе NFT-коллекций или staking-based доступ.
Governance и обновление моделей
Токенизированная модель — это живой продукт. Нужен механизм голосования за принятие новых версий весов, изменение условий доступа, управление treasury. Стандартная схема: ERC-20 governance токен + OpenZeppelin Governor + Timelock. Специфика AI — предложения о смене весов должны проходить технический review (верификация нового weightsHash, тестирование на benchmark).
Процесс работы: от идеи до mainnet
| Этап | Длительность | Результат |
|---|---|---|
| Анализ требований | 1–2 недели | Документ с архитектурой |
| Разработка контрактов | 4–6 недель | Код на Solidity + тесты |
| zkML circuit | 2–4 недели | Proof of concept |
| Аудит безопасности | 2–3 недели | Отчёт аудитора |
| Деплой и интеграция | 2 недели | Работающая система |
| Поддержка | 3 месяца | Гарантийное сопровождение |
Что входит в работу
- Проектирование smart contract architecture
- Реализация контрактов на Solidity с использованием OpenZeppelin
- Настройка zkML (ezkl или RISC Zero)
- Интеграция с off-chain API (Node.js/Python)
- Аудит от партнёрской фирмы (например, Trail of Bits или ConsenSys Diligence)
- Деплой на mainnet и тестнет
- Документация для разработчиков и пользователей
- 3 месяца технической поддержки
Стек и сроки разработки
Смарт-контракты: Solidity, OpenZeppelin, Hardhat/Foundry. 8–12 недель на полный реестр с governance.
ZK-верификация: ezkl для моделей до 100M параметров, RISC Zero для произвольного инференса. Подготовка circuits — 4–8 недель в зависимости от архитектуры модели.
Off-chain инфраструктура: Node.js / Python API для приёма запросов, очереди вычислений (Bull/Redis), интеграция с GPU-провайдерами (Akash, Vast.ai, собственный кластер).
Аудит: обязателен перед mainnet. Особое внимание — логика управления правами доступа и распределение revenue.
Полный цикл от архитектуры до production — 5–7 месяцев для команды из 3–4 инженеров.
Пошаговая инструкция по токенизации модели
- Определите объект токенизации (инференс, revenue share, fine-tune права).
- Спроектируйте архитектуру смарт-контрактов, включая реестр моделей и токены доступа.
- Реализуйте zkML circuit для верификации инференса (ezkl или RISC Zero).
- Разверните контракты на тестнете и протестируйте сценарии minting и вызова.
- Проведите аудит безопасности у партнёрской фирмы.
- Интегрируйте с frontend и off-chain API.
- Задеплойте на mainnet и запустите мониторинг.
Получите консультацию по вашему проекту — мы поможем выбрать оптимальный стек и оценить трудозатраты. Свяжитесь с нами для предварительной оценки.







