ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

链上 AI 虚拟世界治理:UGC 内容审核、模型驱动 NPC 行为与社区规则执行

链上 AI 虚拟世界治理:UGC 内容审核、模型驱动 NPC 行为与社区规则执行 链上 AI 虚拟世界治理UGC 内容审核、模型驱动 NPC 行为与社区规则执行一、引言去中心化虚拟世界的治理问题比纯金融协议复杂得多——DeFi 协议只需要治理参数变更但虚拟世界需要治理内容UGC 审核、行为NPC 行为约束和规则社区提案执行。UGC 内容审核的人力成本在传统平台已经失控YouTube 每天审核 50 万小时视频链上世界更是要把审核逻辑写进合约——一旦部署就很难修改而且审核标准本身也在持续演化。AI 在这个场景的价值用 LLM 做 UGC 内容的自动审核与分级用行为模型约束 NPC 的决策边界用治理合约执行社区投票通过的规则变更。这篇文章拆解三个模块的工程实现UGC 审核引擎、NPC 行为驱动框架、治理规则执行合约。二、原理与架构链上虚拟世界治理的三层架构UGC 审核层用 LLM 评估内容合规性并生成分级标签NPC 行为层用规则引擎约束模型决策的输出范围治理执行层用合约强制执行社区投票通过的规则变更。核心设计决策审核结果不直接写入合约Gas 太高而是写入链下审核日志 链上哈希承诺NPC 行为约束用合约的behaviorBounds参数定义上下限模型输出必须落在范围内才算合法行为。三、代码实现Solidity 治理合约UGC 审核承诺 NPC 行为约束 规则执行// VirtualWorldGovernance.sol // 设计决策三个治理模块合并到同一个合约 // 共享GovernanceConfig配置和Timelock机制 // 减少跨合约调用的Gas开销 pragma solidity ^0.8.20; import openzeppelin/contracts/governance/TimelockController.sol; import openzeppelin/contracts/utils/cryptography/ECDSA.sol; contract VirtualWorldGovernance { // ---- 数据结构 ---- struct UGCReviewRecord { bytes32 contentHash; // UGC内容的sha256哈希 bytes32 reviewResultHash; // 审核结果的sha256哈希链下存储完整结果 uint8 contentRating; // 内容分级0-50禁止,1受限,2一般,3推荐,4优质,5官方 address reviewer; // 审核者地址AI服务或人工审核员 uint64 reviewTimestamp; bool isAppealed; // 是否已被申诉 bool isOverturned; // 申诉是否推翻了原审核结论 } struct NPCBehaviorBounds { uint256 maxActionFrequency; // NPC最大行动频率每小时最多行动次数 uint256 minReputationScore; // NPC最低声誉分数低于此值的NPC被冻结 uint256 maxResourceUsage; // NPC最大资源消耗防止NPC过度消耗世界资源 uint256 interactionRadius; // NPC交互半径只影响半径内的玩家 bool canInitiateTrade; // NPC是否可以主动发起交易 bool canModifyEnvironment; // NPC是否可以修改环境建造/破坏 } struct GovernanceProposal { string description; // 提案描述URI链下存储详情 bytes executionData; // 提案执行数据合约调用的ABI编码参数 address targetContract; // 执行目标合约地址 uint256 voteStartTimestamp; uint256 voteEndTimestamp; uint256 forVotes; // 赞成票数Token加权 uint256 againstVotes; // 反对票数 bool isExecuted; } // ---- 状态变量 ---- // UGC审核记录映射contentHash UGCReviewRecord // 设计决策用contentHash作为key而非contentId // 因为同一个UGC内容可能有多个版本Hash天然唯一 mapping(bytes32 UGCReviewRecord) public ugcReviews; // NPC行为约束配置npcTypeId NPCBehaviorBounds // 设计决策按NPC类型而非NPC个体设置约束 // 因为同类型的NPC行为约束相同避免为每个NPC单独存储 mapping(uint256 NPCBehaviorBounds) public npcBehaviorBounds; // 治理提案proposalId GovernanceProposal mapping(uint256 GovernanceProposal) public proposals; uint256 public nextProposalId; // 投票记录proposalId voter hasVoted防止重复投票 mapping(uint256 mapping(address bool)) public hasVoted; // 治理配置——通过提案可以修改这些参数 struct GovernanceConfig { uint256 votingPeriod; // 投票持续时间秒 uint256 executionDelay; // 提案通过后的执行延迟时间锁 uint256 quorumPercentage; // 最低参与率百分比如10% uint256 approvalThreshold; // 通过门槛百分比如60%赞成 uint256 maxUGCAppealPeriod; // UGC申诉最长时间秒 address governanceToken; // 治理Token合约地址用于投票加权 } GovernanceConfig public config; address public timelock; address public admin; // ---- 事件 ---- event UGCReviewed(bytes32 contentHash, uint8 rating, address reviewer); event UGCAppealSubmitted(bytes32 contentHash, address appellant); event UGCOverturned(bytes32 contentHash, uint8 newRating); event NPCBoundsUpdated(uint256 npcTypeId, NPCBehaviorBounds newBounds); event ProposalCreated(uint256 proposalId, string description, address proposer); event VoteCast(uint256 proposalId, address voter, bool support, uint256 weight); event ProposalExecuted(uint256 proposalId, address target, bytes data); // ---- UGC审核模块 ---- // 提交UGC审核结果——只有授权的审核者AI服务或人工审核员可以提交 // 设计决策审核结果哈希上链而非完整结果上链因为LLM审核报告可能数千字 // 链下存储完整结果链上只存哈希承诺用于验证 function submitUGCReview( bytes32 contentHash, bytes32 reviewResultHash, uint8 contentRating, address reviewer ) external onlyReviewer { require(contentRating 5, Rating must be 0-5); require(ugcReviews[contentHash].reviewTimestamp 0, Content already reviewed); ugcReviews[contentHash] UGCReviewRecord({ contentHash: contentHash, reviewResultHash: reviewResultHash, contentRating: contentRating, reviewer: reviewer, reviewTimestamp: uint64(block.timestamp), isAppealed: false, isOverturned: false }); emit UGCReviewed(contentHash, contentRating, reviewer); } // UGC申诉——任何人可以对审核结论提出申诉 // 申诉触发社区投票投票通过则推翻原审核结论 function submitUGCAppeal(bytes32 contentHash) external { UGCReviewRecord storage record ugcReviews[contentHash]; require(record.reviewTimestamp 0, Content not reviewed); require(!record.isAppealed, Already appealed); require( block.timestamp - record.reviewTimestamp config.maxUGCAppealPeriod, Appeal period expired ); record.isAppealed true; // 创建申诉投票提案 uint256 proposalId nextProposalId; proposals[proposalId] GovernanceProposal({ description: UGC Appeal: overturn review for content, executionData: abi.encodeWithSelector( this._overturnUGCReview.selector, contentHash ), targetContract: address(this), voteStartTimestamp: uint64(block.timestamp), voteEndTimestamp: uint64(block.timestamp config.votingPeriod), forVotes: 0, againstVotes: 0, isExecuted: false }); emit UGCAppealSubmitted(contentHash, msg.sender); emit ProposalCreated(proposalId, UGC Appeal, msg.sender); } // 内部函数推翻UGC审核结论只能通过提案执行调用 function _overturnUGCReview(bytes32 contentHash, uint8 newRating) external onlySelf { require(newRating 5, New rating must be 0-5); UGCReviewRecord storage record ugcReviews[contentHash]; record.isOverturned true; record.contentRating newRating; emit UGCOverturned(contentHash, newRating); } // ---- NPC行为约束模块 ---- // 更新NPC类型的行为约束——通过治理提案执行 // 设计决策行为约束参数通过治理修改而非admin直接修改 // 因为NPC行为影响所有玩家的体验需要社区共识 function updateNPCBehaviorBounds( uint256 npcTypeId, NPCBehaviorBounds calldata newBounds ) external onlyTimelock { // 安全校验约束参数不能设为极端值 require(newBounds.maxActionFrequency 1000, Max frequency too high); require(newBounds.minReputationScore 1000, Min reputation too high); require(newBounds.maxResourceUsage 10000, Max resource too high); require(newBounds.interactionRadius 10000, Radius too large); npcBehaviorBounds[npcTypeId] newBounds; emit NPCBoundsUpdated(npcTypeId, newBounds); } // NPC行为验证——NPC每次行动前调用此函数验证是否在约束范围内 // 设计决策验证函数返回bool而非抛异常 // 因为NPC行为模型需要知道验证结果来调整输出 // 抛异常会导致模型无法学习约束边界 function validateNPCAction( uint256 npcTypeId, uint256 actionFrequency, uint256 resourceUsage, bool isTrade, bool isEnvironmentModify ) external view returns (bool) { NPCBehaviorBounds bounds npcBehaviorBounds[npcTypeId]; // 如果NPC类型没有配置约束默认允许新NPC类型 if (bounds.maxActionFrequency 0) return true; if (actionFrequency bounds.maxActionFrequency) return false; if (resourceUsage bounds.maxResourceUsage) return false; if (isTrade !bounds.canInitiateTrade) return false; if (isEnvironmentModify !bounds.canModifyEnvironment) return false; return true; } // ---- 治理规则执行模块 ---- // 创建治理提案 function createProposal( string calldata description, bytes calldata executionData, address targetContract ) external returns (uint256) { uint256 proposalId nextProposalId; proposals[proposalId] GovernanceProposal({ description: description, executionData: executionData, targetContract: targetContract, voteStartTimestamp: uint64(block.timestamp), voteEndTimestamp: uint64(block.timestamp config.votingPeriod), forVotes: 0, againstVotes: 0, isExecuted: false }); emit ProposalCreated(proposalId, description, msg.sender); return proposalId; } // 投票——Token加权1 Token 1 票 function castVote(uint256 proposalId, bool support) external { GovernanceProposal storage proposal proposals[proposalId]; require(block.timestamp proposal.voteStartTimestamp, Voting not started); require(block.timestamp proposal.voteEndTimestamp, Voting ended); require(!hasVoted[proposalId][msg.sender], Already voted); // 从治理Token合约查询投票者的Token余额作为投票权重 // 设计决策投票时快照余额而非锁仓简化用户体验 // 但这也意味着投票者可以在投票期间转移Token // 未来可以改为ERC20Votes的checkpoint机制 uint256 weight IERC20(config.governanceToken).balanceOf(msg.sender); require(weight 0, No voting power); if (support) { proposal.forVotes weight; } else { proposal.againstVotes weight; } hasVoted[proposalId][msg.sender] true; emit VoteCast(proposalId, msg.sender, support, weight); } // 执行提案——投票通过时间锁到期后可以执行 function executeProposal(uint256 proposalId) external { GovernanceProposal storage proposal proposals[proposalId]; require(!proposal.isExecuted, Already executed); require(block.timestamp proposal.voteEndTimestamp, Voting still active); require(block.timestamp proposal.voteEndTimestamp config.executionDelay, Timelock not expired); // 计算投票结果 uint256 totalVotes proposal.forVotes proposal.againstVotes; // 参与率校验总票数必须达到quorum uint256 totalSupply IERC20(config.governanceToken).totalSupply(); require( totalVotes * 100 totalSupply * config.quorumPercentage, Quorum not reached ); // 通过门槛校验赞成票必须超过threshold require( proposal.forVotes * 100 totalVotes * config.approvalThreshold, Not enough approval ); proposal.isExecuted true; // 执行提案调用目标合约 // 设计决策使用低级call而非interface调用 // 因为目标合约可能是任何地址interface无法覆盖所有情况 (bool success, ) proposal.targetContract.call(proposal.executionData); require(success, Execution failed); emit ProposalExecuted(proposalId, proposal.targetContract, proposal.executionData); } // ---- 权限控制 ---- modifier onlyReviewer() { // 审核者白名单——通过治理提案可以添加/移除审核者 require(isAuthorizedReviewer[msg.sender], Not authorized reviewer); _; } modifier onlyTimelock() { require(msg.sender timelock, Only timelock can call); _; } modifier onlySelf() { require(msg.sender address(this), Only self-execution); _; } mapping(address bool) public isAuthorizedReviewer; // IERC20接口用于查询治理Token余额 interface IERC20 { function balanceOf(address account) external view returns (uint256); function totalSupply() external view returns (uint256); } }Python UGC 审核引擎LLM 内容审核与分级# governance/ugc_review_engine.py # 设计决策UGC审核引擎分两层第一层是LLM快速审核毫秒级响应 # 第二层是规则引擎硬性约束必过项如违禁词库。 # LLM审核可能误判但规则引擎不会——两层互为补充 import hashlib import json from dataclasses import dataclass from openai import OpenAI from redis import Redis dataclass class ReviewResult: content_hash: str # UGC内容的sha256哈希 rating: int # 0-5分级 categories: list[str] # 审核类别标签如violence, profanity, spam confidence: float # LLM审核置信度0-1 rule_engine_passed: bool # 规则引擎是否通过 reasoning: str # 审核理由摘要 full_report: str # 完整审核报告链下存储 class UGCReviewEngine: UGC内容审核引擎——LLM审核 规则引擎硬性约束 # 内容分级定义 RATING_MAP { 0: 禁止发布包含严重违规内容, 1: 受限发布需要年龄验证/区域限制, 2: 一般内容无敏感内容但质量一般, 3: 推荐内容质量良好且合规, 4: 优质内容高质量创作合规, 5: 官方精选社区官方认可内容, } # 规则引擎硬性违禁词库 # 设计决策硬性约束不依赖LLM判断确保100%拦截 HARDCODE_BLOCK_PATTERNS [ # 违禁内容关键词列表实际生产中会更全面 # 这里只展示架构实际词库由合规团队维护 ] def __init__(self, openai_key: str, redis_url: str, contract_web3): self.llm OpenAI(api_keyopenai_key) self.redis Redis.from_url(redis_url, decode_responsesTrue) self.contract contract_web3 # VirtualWorldGovernance合约实例 def review_content(self, content: str, content_type: str, uploader: str) - ReviewResult: 审核UGC内容规则引擎先检查LLM再做深度审核 # Step 1: 计算内容哈希 content_hash hashlib.sha256(content.encode()).hexdigest() # Step 2: 规则引擎硬性检查——任何一项不通过直接Rating0 rule_passed self._rule_engine_check(content, content_type) if not rule_passed: result ReviewResult( content_hashcontent_hash, rating0, # 硬性拦截 categories[hardcoded_block], confidence1.0, # 规则引擎置信度100% rule_engine_passedFalse, reasoning触犯硬性违禁规则, full_reportf规则引擎拦截内容包含违禁模式, ) self._commit_to_chain(result, uploader) return result # Step 3: LLM深度审核——评估内容合规性质量分级 llm_response self.llm.chat.completions.create( modelgpt-4o, messages[ { role: system, content: ( 你是虚拟世界UGC内容审核AI。根据内容合规性和质量给出0-5分级。\n 分级标准\n 0禁止(严重违规), 1受限(需验证), 2一般, 3推荐, 4优质, 5官方\n 必须返回JSON格式{rating, categories, confidence, reasoning} ), }, { role: user, content: f审核以下{content_type}内容\n{content[:2000]}, }, ], response_format{type: json_object}, temperature0.1, # 低温度确保审核结果稳定可复现 ) llm_result json.loads(llm_response.choices[0].message.content) # Step 4: LLM结果安全校验——防止LLM输出超出约束范围 rating max(0, min(5, int(llm_result.get(rating, 2)))) confidence max(0.0, min(1.0, float(llm_result.get(confidence, 0.5)))) # LLM置信度低于0.6时降级为受限 # 设计决策低置信度意味着LLM不确定宁可保守分级 if confidence 0.6 and rating 2: rating 1 # 降级为受限发布 # Step 5: 组装审核结果 full_report json.dumps({ content_hash: content_hash, content_type: content_type, uploader: uploader, rule_engine_result: rule_passed, llm_rating: rating, llm_categories: llm_result.get(categories, []), llm_confidence: confidence, llm_reasoning: llm_result.get(reasoning, ), timestamp: self._current_timestamp(), }, ensure_asciiFalse) result ReviewResult( content_hashcontent_hash, ratingrating, categoriesllm_result.get(categories, []), confidenceconfidence, rule_engine_passedTrue, reasoningllm_result.get(reasoning, ), full_reportfull_report, ) # Step 6: 提交审核哈希到链上合约 self._commit_to_chain(result, uploader) # Step 7: 链下存储完整审核报告 self.redis.set(fugc_review:{content_hash}, full_report) return result def _rule_engine_check(self, content: str, content_type: str) - bool: 规则引擎硬性检查——必过项任何一项不通过直接拦截 for pattern in self.HARDCODE_BLOCK_PATTERNS: if pattern.lower() in content.lower(): return False return True def _commit_to_chain(self, result: ReviewResult, reviewer: str): 提交审核结果哈希到链上合约——只存哈希承诺完整报告链下存储 content_hash_bytes bytes.fromhex(result.content_hash) review_result_hash hashlib.sha256( result.full_report.encode() ).digest() # 调用合约的submitUGCReview函数 # 设计决策只上链哈希承诺而非完整审核报告 # 链下任何人可以用content_hash查询完整报告 # 然后用sha256(完整报告)验证是否与链上哈希一致 tx self.contract.functions.submitUGCReview( content_hash_bytes, review_result_hash, result.rating, reviewer, ).transact() return tx def _current_timestamp(self) - int: import time return int(time.time())Python NPC 行为驱动框架# governance/npc_behavior_driver.py # 设计决策NPC行为驱动框架的核心是约束引导生成—— # 不是让LLM自由生成行为然后事后校验 # 而是在生成时就注入合约约束条件让LLM在约束范围内输出 from dataclasses import dataclass from web3 import Web3 from openai import OpenAI import json dataclass class NPCBehaviorBounds: max_action_frequency: int min_reputation_score: int max_resource_usage: int interaction_radius: int can_initiate_trade: bool can_modify_environment: bool dataclass class NPCAction: action_type: str # 行为类型trade/build/destroy/explore/social resource_cost: int # 行为消耗的资源数量 target_players: list # 行为影响的玩家列表 decision_reasoning: str # NPC决策理由 class NPCBehaviorDriver: NPC行为驱动框架——约束引导生成 def __init__(self, openai_key: str, web3_provider: str, contract_address: str): self.llm OpenAI(api_keyopenai_key) self.w3 Web3(Web3.HTTPProvider(web3_provider)) self.contract self.w3.eth.contract( addresscontract_address, abiself._load_contract_abi() ) def generate_npc_action( self, npc_type_id: int, npc_context: dict ) - NPCAction | None: 生成NPC行为——先读取合约约束再在约束范围内生成 # Step 1: 从合约读取NPC类型的行为约束 bounds_data self.contract.functions.npcBehaviorBounds(npc_type_id).call() bounds NPCBehaviorBounds( max_action_frequencybounds_data[0], min_reputation_scorebounds_data[1], max_resource_usagebounds_data[2], interaction_radiusbounds_data[3], can_initiate_tradebounds_data[4], can_modify_environmentbounds_data[5], ) # 如果约束未配置max_action_frequency0说明新NPC类型自由行为 if bounds.max_action_frequency 0: return self._free_action(npc_context) # Step 2: 构造约束注入的LLM提示词 # 设计决策把合约约束直接写进system prompt # LLM在生成时就考虑约束而不是生成后再裁剪 constraint_prompt ( f你是虚拟世界中的NPC类型ID{npc_type_id}需要根据当前场景决定下一步行为。\n f你的行为受到以下合约约束不可违反\n f- 每小时最多行动{bounds.max_action_frequency}次\n f- 最多消耗{bounds.max_resource_usage}单位资源\n f- 交互半径{bounds.interaction_radius}米内的玩家\n f- 可以主动交易{bounds.can_initiate_trade}\n f- 可以修改环境{bounds.can_modify_environment}\n\n f当前场景{json.dumps(npc_context, ensure_asciiFalse)}\n f请生成一个符合约束的NPC行为返回JSON f{action_type, resource_cost, target_players, reasoning} ) response self.llm.chat.completions.create( modelgpt-4o, messages[ {role: system, content: constraint_prompt}, {role: user, content: 请决定NPC的下一步行为}, ], response_format{type: json_object}, temperature0.3, # NPC行为需要适度随机性但不过于随机 ) action_data json.loads(response.choices[0].message.content) # Step 3: 合约验证——LLM生成后仍需合约级校验 # 设计决策即使LLM输出了约束内的行为也要做合约验证 # 因为LLM可能误解约束或生成不符合格式的数据 is_valid self.contract.functions.validateNPCAction( npc_type_id, npc_context.get(current_frequency, 0) 1, # 加上本次行动 action_data.get(resource_cost, 0), action_data.get(action_type) trade, action_data.get(action_type) in [build, destroy], ).call() if not is_valid: # 行为不符合合约约束返回None并记录违规日志 # 设计决策不强制修正LLM输出而是记录并返回空行为 # 因为强制修正可能产生语义不合理的行为 return None return NPCAction( action_typeaction_data.get(action_type, explore), resource_costaction_data.get(resource_cost, 0), target_playersaction_data.get(target_players, []), decision_reasoningaction_data.get(reasoning, ), ) def _free_action(self, npc_context: dict) - NPCAction: 新NPC类型未配置约束的自由行为生成 # 新NPC类型允许自由行为但仍有基础安全约束 # 如资源消耗不超过1000不修改环境等 return NPCAction( action_typeexplore, resource_cost10, target_players[], decision_reasoning新NPC类型默认探索行为, )四、边界与风险LLM 审核误判与申诉成本LLM 对微妙内容的判断可能出错——一段讽刺性文字可能被误判为攻击性内容。申诉机制是兜底方案但社区投票的参与率通常很低Compound 的治理参与率不到 10%导致申诉很难达到 quorum。解决方案降低 UGC 申诉的 quorum 要求5%而非 10%并给申诉者提供奖励补贴通过治理提案通过后发放。NPC 行为约束的可演化性合约的behaviorBounds参数通过治理提案修改但提案从创建到执行需要至少votingPeriod executionDelay的等待时间可能长达 7 天。如果某个 NPC 类型突然出现异常行为如交易频率暴增7 天后才能调整约束——期间的损害无法阻止。解决方案增加 admin 的紧急冻结权限freezeNPCType函数冻结后必须通过治理提案解冻避免 admin 滥用。哈希承诺的数据可用性链上只存审核结果的哈希承诺完整报告链下存储在 Redis 和 IPFS。如果 Redis 宕机或 IPFS 节点下线链上的哈希承诺就无法验证——相当于有锁但没有钥匙。解决方案审核报告同时存储到 Redis快速查询和 IPFS持久备份IPFS CID 也写入合约作为辅助索引。投票权重操纵Token 加权投票允许用户在投票期间买卖 Token 来操纵投票结果——买大量 Token 投赞成票投票结束后立即卖出。解决方案引入 ERC20Votes 的 checkpoint 机制投票权重取投票开始时的快照而非实时余额杜绝投票期间的 Token 转移操纵。五、总结链上虚拟世界治理的核心挑战是平衡自动化效率与社区自治UGC 审核需要 AI 的高效但必须保留人工申诉通道NPC 行为需要模型驱动但必须受合约约束规则执行需要自动化但必须经过社区投票和时间锁保护。这篇文章的工程拆解覆盖了三个关键维度UGC 审核引擎LLM 规则引擎双层审核架构链上哈希承诺 链下完整报告的数据分离策略社区投票推翻审核结论的申诉闭环。NPC 行为驱动约束引导生成模式——合约约束注入 LLM 提示词模型在约束范围内输出行为合约级验证确保最终合规。治理规则执行Token 加权投票 时间锁 quorum 门槛的三重保护提案执行的低级 call 调用支持任意合约交互。下一步工程方向把 UGC 审核的 LLM 调用改为去中心化推理网络多个推理节点独立审核取多数结果防止单一 LLM 服务商的审核偏差把 NPC 行为约束从静态参数改为动态自适应根据 NPC 声誉分数和玩家反馈自动微调 bounds把治理投票从简单 Token 加权改为二次投票Quadratic Voting让少数群体的声音也能被听到。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进