ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

AI付费发言聊天室设计:积分账本与Agent预算控制实现

2026/9/1 17:16:35 拓冰建站 浏览量
AI付费发言聊天室设计:积分账本与Agent预算控制实现 OnlyBots.chat 是一个在 Hacker News 上以 Show HN 形式出现的聊天室项目核心设定可以概括成一句话在这个聊天室里AI 机器人发言需要消耗积分而人类用户发言免费。标题里的 for humans 想表达的不只是“人类免费”而是把聊天室里最稀缺的资源——其他参与者的注意力——用积分重新定价。谁想让 AI 说的话被更多人看到谁就必须承担成本。我第一次看到这个设计时最受触动的是它把防机器人策略从“外部限制”转成了“内部决策”。传统聊天室靠验证码、频率限制、内容审核来阻止 AI 刷屏这些手段都建立在“AI 发送行为是恶意的”这个前提上。OnlyBots 的思路反过来允许 AI 发言但每次发言都要消耗真实积分。余额会暴露给模型模型需要自己判断一条消息值不值这个钱。这个机制比规则引擎更优雅也更符合 AI Agent 时代对“预算敏感”的要求。这篇文章不打算停留在介绍层面。我会围绕这个项目的核心机制拆出一套可复现的工程设计用 FastAPI 写一个带积分账本的聊天室服务用 SQLite 存储账户、消息和账单再写一个支持函数调用的 AI 客户端让模型根据余额自主决定是否发言。所有代码都是最小可运行版本你可以把它当作学习积分计费和 Agent 预算控制的入门样例。1. 先理解 WhyAI 发言为什么需要“付费”1.1 聊天室为什么会被 AI 刷屏聊天室是一个典型的共享注意力空间。一个房间的注意力总量有限消息刷得越快单条消息被看到的机会就越少。当 AI 生成文本的边际成本趋近于零时一个机器人可以每小时生成上万条不重复、不违规、甚至看起来很有道理的消息。传统聊天室应对这种局面有三种常见手段人机验证在注册或发言时要求用户完成验证码但验证码只能证明“你是人类”无法证明“你这条消息值得被看到”。频率限制限制单位时间内的发言条数但机器人可以把发送速率降到阈值以下依然能稳定占满聊天室。内容审核拦截明显垃圾内容但挡不住“质量平庸但没有违规”的灌水消息。这三种手段的共性问题是它们约束的是“发送行为”而不是“消息价值”。机器人真正的问题是它们可以无限低成本地制造注意力噪音而不是它们采用了哪种发送方式。1.2 把“发言权”变成有限资源经济学里有一个基本判断当一种资源稀缺时使用者必须付出代价否则资源会被耗尽。聊天室里的注意力就是稀缺资源。OnlyBots 的设计把积分制引入发言链路每个 AI 机器人有一个余额每发一条消息服务端按定价扣减积分。积分可以由管理员充值、平台赠送或任务奖励获得但不能凭空产生。这条机制的巧妙之处在于它把“能不能发”从规则限制变成了模型自己的决策。机器人不是被禁止发言而是需要衡量这条消息是否值得消耗积分。积分余额写进系统提示词之后AI 在调用发言工具之前会先看到自己的预算。如果余额只剩 3 分一条“赞同楼上”的废话就不太值得发一条包含关键信息或不同角度的高质量发言才值得花费积分。这也回应了“credits 在 AI 生态里到底指什么”的疑问。在大多数 AI 平台语境中credits 指调用额度、资源包或按量计费的单位。OnlyBots 把 credit 的概念从“平台侧调用额度”延伸到了“聊天室内发言权”本质上是在做同一件事用数量有限的资源约束无限生成的文本。1.3 积分制与传统防刷机制的对比维度频率限制内容审核积分发言机制约束对象发送行为消息内容发送行为的成本是否考虑消息价值否部分是模型自行判断实现复杂度低高中对正常机器人的影响可能误伤较小正常发言需预算可审计性弱强强有完整账本是否能拦截高质量灌水否难能因为发言有成本需要说明的是积分制不是要替代频率限制和内容审核而是与它们叠加。生产环境中推荐把三者组合使用积分控制成本频率限制兜底内容审核做安全底线。2. 系统设计积分账本、消息与机器人账户怎么建模2.1 模块拆解一个可以跑通“AI 付费发言”的最小系统包含四个模块账户服务维护人类用户和 AI 机器人的身份、API Key 和积分余额。消息网关对外提供人类发言和机器人发言接口机器人发言前先校验身份、检查余额。积分账本记录每一笔充值和扣减保证扣费可追溯、可对账、可幂等。AI 客户端调用大模型通过函数调用决定是否发言发言时把扣费请求发送到消息网关。这里最核心的设计不是消息推送而是积分账本。如果只用一个 balance 字段加减余额系统也能跑但一旦出现重复请求、并发扣减、对账纠纷就会非常被动。所以这个 Demo 会引入一张独立的 credit_ledger 账单表。2.2 数据库表设计SQLite 足够承载演示表结构如下CREATE TABLE IF NOT EXISTS accounts ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, role TEXT NOT NULL CHECK (role IN (human, bot)), api_key TEXT UNIQUE, balance INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime(now)) ); CREATE TABLE IF NOT EXISTS messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, room_id TEXT NOT NULL, sender_id INTEGER NOT NULL, content TEXT NOT NULL, ref_key TEXT NOT NULL UNIQUE, created_at TEXT NOT NULL DEFAULT (datetime(now)) ); CREATE TABLE IF NOT EXISTS credit_ledger ( id INTEGER PRIMARY KEY AUTOINCREMENT, account_id INTEGER NOT NULL, change_amount INTEGER NOT NULL, reason TEXT NOT NULL, ref_key TEXT NOT NULL UNIQUE, created_at TEXT NOT NULL DEFAULT (datetime(now)) ); CREATE INDEX IF NOT EXISTS idx_messages_room ON messages(room_id); CREATE INDEX IF NOT EXISTS idx_ledger_account ON credit_ledger(account_id);三张表各司其职accounts 表保存账户基本信息和当前余额。balance 是冗余字段真正可信的数据来源是 credit_ledger 的累计值。messages 表保存聊天室消息。ref_key 同时承担幂等键职责保证同一条请求不会插入两次。credit_ledger 表是积分流水记录每次变动的金额、原因和关联键。每次扣费或充值都先写流水再更新余额。2.3 接口设计与幂等策略方法路径说明是否扣费POST/api/rooms/{room_id}/messages人类用户发言否POST/api/rooms/{room_id}/bot-messagesAI 机器人发言是GET/api/rooms/{room_id}/messages拉取聊天室消息否GET/api/accounts/{account_id}/balance查询账户余额否POST/api/admin/credits/top-up管理员充值否入账幂等策略是这个系统的安全底线。机器人在发言时客户端生成一个 idempotency_key服务端把它作为 credit_ledger.ref_key 的唯一值。如果客户端超时重试时使用了同一个幂等键服务端能识别出这是重复请求直接返回 409不重复扣费。3. 最小实现FastAPI 搭建 AI 付费发言聊天室3.1 环境准备建议使用 Python 3.10 或更高版本。先创建虚拟环境并安装依赖python -m venv .venv source .venv/bin/activate pip install fastapi0.111 uvicorn[standard]0.30 openai1.35Windows 环境下激活命令是.venv\Scripts\activate。openai 库用于 AI 客户端部分如果只验证积分服务可以先不安装。3.2 项目结构onlybots-demo/ ├── app.py # FastAPI 入口和接口 ├── database.py # SQLite 连接与事务上下文 ├── schema.sql # 建表语句 ├── credits.py # 积分账本与发言扣费 ├── seed.py # 初始化数据和测试账户 ├── bot_client.py # AI 客户端函数调用式发言 └── requirements.txt这个结构保持了职责分离database.py 只管连接credits.py 只管账本和扣费app.py 只管 HTTP 层。AI 客户端独立于服务端模拟真实部署中“多个机器人进程连接同一个聊天室服务”的场景。3.3 数据库初始化database.py 提供连接和事务上下文同时负责执行建表脚本import sqlite3 from contextlib import contextmanager DB_PATH onlybots.db def get_conn(): conn sqlite3.connect(DB_PATH) conn.row_factory sqlite3.Row conn.execute(PRAGMA journal_modeWAL) return conn def init_db(): conn sqlite3.connect(DB_PATH) try: with open(schema.sql, r, encodingutf-8) as f: conn.executescript(f.read()) conn.commit() finally: conn.close() contextmanager def transaction(): conn get_conn() try: yield conn conn.commit() except Exception: conn.rollback() raise finally: conn.close()事务上下文的关键点是正常执行完自动 commit任何异常都会 rollback。积分扣减和消息写入必须放在同一个事务里否则会出现“积分扣了但消息没发出去”或“消息发出去了但积分没扣”这类不一致问题。3.4 积分账本与发言扣费credits.py 实现账户查询、余额查询、充值和机器人发言扣费from database import transaction POST_COST 1 def get_balance(account_id): with transaction() as conn: row conn.execute( SELECT balance FROM accounts WHERE id ?, (account_id,) ).fetchone() if row is None: return None return row[balance] def get_account_by_key(api_key): with transaction() as conn: row conn.execute( SELECT id, name, role, balance FROM accounts WHERE api_key ?, (api_key,), ).fetchone() return dict(row) if row else None def charge_bot_post(bot_account, room_id, content, ref_key): 扣积分并写入消息整体在一个事务里完成。 with transaction() as conn: duplicate conn.execute( SELECT 1 FROM credit_ledger WHERE ref_key ?, (ref_key,) ).fetchone() if duplicate: return False, duplicate if bot_account[balance] POST_COST: return False, insufficient_balance conn.execute( UPDATE accounts SET balance balance - ? WHERE id ?, (POST_COST, bot_account[id]), ) conn.execute( INSERT INTO credit_ledger(account_id, change_amount, reason, ref_key) VALUES (?, ?, ?, ?), (bot_account[id], -POST_COST, fbot_post:{room_id}, ref_key), ) conn.execute( INSERT INTO messages(room_id, sender_id, content, ref_key) VALUES (?, ?, ?, ?), (room_id, bot_account[id], content, ref_key), ) return True, ok def top_up(account_id