
“Between Tokens” 这类交互作品的核心设定很直接把玩家放进语言模型的位置上让玩家亲身体验“预测下一个 Token”这件事。它不是一个让你围观模型输出的演示页而是一个让玩家变成模型本人的角色扮演式教学工具。对于刚接触大语言模型的开发者、产品经理、学生以及想设计 AI 科普作品的技术作者来说理解这类作品的设计逻辑比直接跑一个 Chatbot 更能触及语言模型的工作本质。这篇文章不讨论某个具体网站的源码而是把“你即模型”这种交互形式拆开来看它要教什么、底层涉及哪些语言模型机制、如何用前端代码搭一个最小可玩原型、参数怎么调、玩家体验怎么验证、常见问题怎么排查。最终你会得到一份可以自己复刻并扩展的交互作品设计框架。1. 先理解 Between Tokens 的设计意图为什么让玩家扮演模型1.1 这类交互作品想解决什么问题绝大多数 AI 科普都在回答“模型能做什么”比如生成文章、写代码、回答问题。但很少回答“模型思考时到底发生了什么”。语言模型的推理过程对外部观察者来说几乎是不可见的输入一段文本输出一串文本中间是海量矩阵运算。用户看到的是结果不是过程。Between Tokens 这类交互作品选择换一个视角。它让玩家亲自坐在模型的位置上看着一段只有前半句的文本努力猜测下一个词是什么。玩家会很快发现自己不是在“创造”而是在“做选择”。每个位置都有很多可能性有些可能性更容易出现有些则很离谱自己的猜测既受前文影响也受日常语言习惯影响。这种第一人称体验比任何讲解都更直接地传达了“语言模型是概率系统”这一事实。换句话说这类作品解决的是科普中最难的部分让用户从“知道概念”变成“体会概念”。知道“模型预测下一个 Token”是一回事真正对着一个残缺句子感觉“这里最可能接‘了’吧”是另一回事。1.2 玩家扮演模型时会经历哪几个关键环节把一个完整的交互流程拆开玩家通常要经历五个环节读取上下文看到一段已经被截断的文本例如“今天天气很”。形成候选在自己大脑中快速枚举可能的后续词例如“好”“热”“冷”“棒”。猜测输出从候选里挑选一个自己认为最可能的词提交。看到真实概率系统揭晓模型对该位置各个候选词的预测概率。获得反馈根据猜测结果给出得分、难度变化或解释文字。这五个环节对应着语言模型推理过程中的几个关键概念上下文窗口、词表、概率分布、采样策略、损失或困惑度。玩家每完成一轮就相当于手动执行了一次前向推理的一部分。1.3 为什么比自己读科普文章更有效阅读文章时读者处于被动接收状态很容易把“模型预测下一个词”理解成“模型像人一样知道该说什么”。而交互作品强迫玩家主动输出一个预测逼着玩家把隐性知识调动出来。玩家会意识到自己给出的预测也不是唯一答案而是多个答案按可能性排序的结果。这种“把自己当模型”的换位体验能有效拆掉“模型有意识、模型真懂”这层误解。从工程角度看设计这样一个交互作品本身就是一次很好的教学工程练习。你需要处理分词、概率分布、界面状态管理、反馈逻辑还要考虑难度曲线和用户体验。下面就从语言模型的基础机制说起。2. 要设计“你即模型”先拆解语言模型的三个底层机制2.1 Token模型看到的不是字符串而是编号序列大语言模型的输入输出单位不是“字”也不是“词”而是 Token。Token 是模型词表中的一个编号可以对应半个词、一个词、一个汉字或一个标点。模型把输入文本切分成 Token 序列再映射成编号向量参与计算。设计交互作品时Token 概念必须被可视化地呈现出来。不能在界面上只展示完整句子还要让玩家看到句子被切分成了哪些片段。例如输入文本今天天气很好 常见分词结果[今天, 天气, 很好]更接近真实模型的展示方式是用字节对编码BPE风格切分例如英文中的「tokenization」可能被切成token、ization等多个子词。但交互原型不必真的实现 BPE可以先按空格和标点切分再在说明文字里强调“真实模型使用的是子词切分”。这里要注意一个常见坑直接用单字或单词的普通分词方式会让玩家误以为模型是按“字”或“词”理解语言的。建议在界面角落显示一行小字“为了便于展示这里用简化分词真实模型使用子词 Token。”否则玩家学到的概念会有偏差。2.2 上下文窗口能看多远决定预测质量上下文窗口是模型在预测下一个 Token 时能参考的最大 Token 数量。窗口越大模型能利用的历史信息越多预测通常越准。在交互作品里上下文窗口是一个天然的游戏难度旋钮上下文只有 1 到 2 个 Token 时预测难度极高因为信息不足。上下文有 10 到 20 个 Token 时答案开始有迹可循。上下文包含明确线索例如“小明把伞放在了门口出门时他一定会带”玩家基本能猜中。设计原型时可以给每个句子标注“有效提示点”也就是那些能显著缩小下一个 Token 范围的词语。这能帮助玩家理解为什么某些位置的预测概率分布很尖锐另一些位置则很平坦。2.3 下一个 Token 的概率分布核心中的核心语言模型在每一步真正输出的是一张概率表对于词表中的每一个 Token给出一个介于 0 和 1 之间的概率所有概率之和为 1。模型不是直接输出“最正确的词”而是输出整个分布再通过采样策略选择具体 Token。交互作品最需要传达的就是这一点。玩家猜完一个词后系统应当展示类似下面的分布上下文今天天气很 候选 Token 及概率 好 0.31 热 0.18 冷 0.12 不错 0.09 糟糕 0.05 ...看到这个分布玩家才明白模型并不是“想好了说‘好’”而是“所有候选都有一定可能只是‘好’的机会更大”。这种理解是纸面讲解很难代替的。3. 用前端三件套搭建一个最小可玩原型3.1 原型需求与运行方式目标不是做完整产品而是做一个能验证“玩家即模型”体验的最小闭环。建议先做单机网页版用 HTML、CSS、JavaScript 实现双击index.html即可运行不需要后端。最小闭环包含以下能力展示一条带高亮上下文的文本。由玩家输入或选择下一个 Token。揭晓模型给出的概率分布。根据概率计算得分并给出解释。支持切换多条测试句子。3.2 HTML 页面与游戏流程先建立页面结构分为四个区域上下文展示区、输入区、结果反馈区、句子切换区。!DOCTYPE html html langzh-CN head meta charsetUTF-8 / titleBetween Tokens 最小原型/title style body { font-family: sans-serif; max-width: 720px; margin: 40px auto; line-height: 1.7; } .context { background: #f4f4f4; padding: 16px 20px; border-radius: 8px; font-size: 18px; } .token { border-bottom: 2px solid #999; padding: 2px; } .candidate { color: #b45309; font-weight: bold; } .result { margin-top: 16px; padding: 16px; border: 1px solid #ddd; border-radius: 8px; } table { border-collapse: collapse; margin-top: 8px; } td, th { border: 1px solid #ccc; padding: 6px 12px; } .score { font-size: 20px; margin-top: 8px; } /style /head body h2你正在扮演语言模型/h2 p阅读下面的上下文猜测最可能出现的下一个 Token。/p div idcontextBox classcontext/div div stylemargin-top:16px; input idguessInput placeholder输入你预测的下一个 Token / button idguessBtn提交预测/button button idnextBtn styledisplay:none;下一句/button /div div idresultBox classresult styledisplay:none;/div script srcmain.js/script /body /html这里把上下文区域单独放一个容器是为了在揭晓结果时能够高亮显示“模型真正预测的位置”。按钮的显示与隐藏由 JavaScript 控制避免玩家在结果揭晓后还能重复提交。3.3 JavaScript 核心逻辑JavaScript 里最重要的结构是“题目数据”。每条题目包含上下文、正确答案候选的概率表以及解释文字。// main.js const DATASET [ { // 注意玩家看到的上下文是截断后的文本 contextTokens: [今天, 天气, 很], candidates: { 好: 0.31, 热: 0.18, 冷: 0.12, 不错: 0.09, 糟糕: 0.05, 差: 0.04, 适合: 0.03 }, explanation: 中文日常表达中“天气很 形容词”是高频搭配其中“好”的出现概率最高但“热”“冷”也都有相当概率。 } ]; let currentIndex 0; function renderContext() { const item DATASET[currentIndex]; const box document.getElementById(contextBox); box.innerHTML item.contextTokens .map((t, i) span classtoken${t}/span) .join() span classcandidate___/span; } function submitGuess() { const item DATASET[currentIndex]; const input document.getElementById(guessInput).value.trim(); const resultBox document.getElementById(resultBox); const p item.candidates[input]; const rows Object.entries(item.candidates) .sort((a, b) b[1] - a[1]) .map(([token, prob]) { const highlight token input ? stylebackground:#fef3c7 : ; return tr${highlight}td${token}/tdtd${(prob * 100).toFixed(1)}%/td/tr; }) .join(); resultBox.style.display block; if (p undefined) { resultBox.innerHTML p“${input}”不在候选概率表中模型给它的概率接近 0。/p; } else { resultBox.innerHTML p“${input}”的概率是 ${(p * 100).toFixed(1)}%/p; } resultBox.innerHTML tabletrth候选 Token/thth概率/th/tr${rows}/table div classscore${p ? 本轮得分${Math.round(p * 100)} : 本轮得分0}/div p${item.explanation}/p ; document.getElementById(nextBtn).style.display inline-block; } function nextSentence() { currentIndex (currentIndex 1) % DATASET.length; document.getElementById(resultBox).style.display none; document.getElementById(guessInput).value ; document.getElementById(nextBtn).style.display none; renderContext(); } document.getElementById(guessBtn).addEventListener(click, submitGuess); document.getElementById(nextBtn).addEventListener(click, nextSentence); renderContext();这段代码的关键点有三个。第一玩家提交的词如果不在候选表里默认概率为 0这能模拟真实模型面对词表中低概率 Token 的表现。第二概率大于 0 但不高的候选也要展示让玩家看到“猜对但不意外”和“猜对且很意外”的区别。第三解释文字必须存在否则玩家只看到概率不知道背后的语言规律。4. 关键参数与交互细节温度、困惑度和“猜对”判定4.1 温度参数如何改变难度温度Temperature是影响采样分布的参数。温度越高分布越平滑低概率 Token 被选中的机会变大输出更随机温度越低分布越尖锐高概率 Token 更容易被选中。在交互作品里温度可以变成一个玩家可调的难度开关T 0.2分布非常集中玩家只需要猜最高概率 Token。T 1.0保持原始分布难度适中。T 2.0分布变平任何候选都可能出现玩家很难“猜中”。温度对概率的调整公式如下调整后概率 exp(logit / T) / sum(exp(logit / T))原型里不需要真的训练模型。可以直接用原始概率作为 logit 的指数形式演示温度的影响。例如原始概率为 0.31 的“好”在高温下会被压缩到与其他候选更接近的值。实现时可以用下面的思路function applyTemperature(rawProbs, temperature) { const logits Object.entries(rawProbs).map(([t, p]) { return { token: t, logit: Math.max(Math.log(p), -20) }; }); const scaled logits.map(x ({ token: x.token, value: Math.exp(x.logit / temperature) })); const sum scaled.reduce((acc, x) acc x.value, 0); const adjusted {}; scaled.forEach(x { adjusted[x.token] x.value / sum; }); return adjusted; }这里用Math.log(p)把概率转回 logit再除以温度。注意Math.log(0)会得到负无穷所以要加一个下限避免计算崩溃。生产环境里还要考虑数值稳定性先减最大值再取指数。4.2 困惑度Perplexity怎么计算困惑度是衡量模型预测质量的核心指标之一。简单理解困惑度越低说明模型对下一个 Token 的预测越有信心困惑度越高说明模型越“迷茫”。每轮交互都可以计算玩家预测的困惑度。假设玩家对一条上下文预测了最优概率真正揭晓的 Token 是w_i其概率为p(w_i)那么对应困惑度是perplexity exp(- (1 / N) * sum( ln p(w_i) ) )单轮情况下N 1公式简化为困惑度 1 / p(真实Token)例如真实 Token 概率是 0.5困惑度就是 2概率是 0.1困惑度就是 10。可以用 Python 快速计算多轮平均困惑度import math probabilities [0.5, 0.2, 0.1] perplexity math.exp(-sum(math.log(p) for p in probabilities) / len(probabilities)) print(round(perplexity, 2))在作品界面里可以把困惑度显示成“迷茫值”低于 2 表示玩家几乎确定高于 10 表示玩家基本在乱猜。这个反馈比单纯“答对/答错”更有教育意义因为它告诉玩家语言预测从来不是二值判断。4.3 判定规则不要把“猜中”当唯一成功标准设计反馈系统时要特别注意玩家输入一个概率为 0.3 的词即使不是概率最高的也算是一次合理的预测。如果只统计“是否猜中概率最高 Token”会让玩家形成错误认知以为模型每一步都有唯一正确答案。建议采用分级反馈玩家猜测概率反馈文案教育含义大于等于最高概率的一半“预测很合理”玩家理解了分布的相对关系大于 0 但低于一半“有这个可能但概率不高”玩家意识到多候选并存等于 0“这个词在当前位置几乎不会出现”玩家意识到分布的稀疏性这种分级反馈能避免玩家因为连续“猜不中”而产生挫败感也能更真实地反映语言模型的不确定性。5. 运行验证与体验检查怎样判断作品真的教懂了5.1 功能验证清单原型写完后不能只看页面能打开就收工。建议逐项验证以下功能点检查项预期结果验证方式上下文展示能看到切分后的 Token 和待填空位打开页面观察提交预测点击按钮后出现概率表格输入一个候选词并提交输入不在候选表显示“概率接近 0”且得分 0输入明显无关词例如“苹果”温度切换概率分布随温度变化添加温度滑块后观察表格变化下一句切换上下文、概率、解释全部刷新连续切换多个句子重复提交结果揭晓后不能再次提交观察按钮是否被禁用检查时要注意按钮防重复提交是新手最容易漏掉的功能。可以给提交按钮加disabled状态或者用状态变量记录当前轮次是否已经揭晓。5.2 体验设计检查清单功能正确只是第一步还要验证玩家是否真的学到了概念。可以找几个没看过提示的人试玩观察他们会不会提出以下问题“为什么有些地方好几个词都可以”“那我猜哪个都对吗”“模型是不是有时候也在瞎猜”如果试玩者能问出这类问题说明设计方向正确。如果试玩者只问“怎么才算赢”“下一关在哪”说明游戏化元素压过了教学目标需要重新平衡。完成一轮试玩后还应该确认两件事玩家是否理解了“模型输出的是概率分布”以及玩家是否理解了“预测质量取决于上下文信息量”。这两点是 Between Tokens 这类作品最核心的教学目标。6. 常见体验问题与排查路径6.1 玩家乱猜导致游戏失去意义现象是玩家不读上下文随便输入几个字就提交反馈阶段也只看分数不看概率表。常见原因有两种。一是界面没有视觉引导玩家不知道上下文里哪些词是关键线索。二是得分机制过于强调“猜中最高概率”让玩家觉得随便猜也能试错。处理方式在上下文中高亮能显著影响下一词的“提示 Token”。把反馈从“得分”改为“预测质量”例如“你的预测在所有人类玩家中排在前 20%”。增加“为什么是这个概率”的解释区域让玩家必须停留阅读才能进行下一步。6.2 难度曲线不合理现象是前几轮句子太简单玩家觉得无聊后几轮句子太长、线索太少玩家完全猜不出来。真实语言模型的难度并不平均因此交互作品要有意识地控制难度曲线。建议把题目按难度分组难度上下文特征概率分布特征示例入门高频搭配最高概率大于 0.4“今天天气很”进阶带有语义转折最高概率 0.2 到 0.4“虽然下着雨他还是”困难包含生僻表达最高概率小于 0.2专业领域句子出现难度问题时先检查题目数据是否做过排序再检查概率分布是否由真实语料统计而来而不是人工随意拍脑袋。人工写的概率很容易分布失真。6.3 上下文展示影响判断现象是玩家反馈“我看到空格就知道答案了”或者“被高亮干扰了判断”。这类问题的根源在于交互揭示时机不对。高亮提示应当在玩家提交预测后才出现而不是在上下文展示阶段就提前给出。如果提前高亮玩家就不再是“模型”而是“解谜者”。设计原则做题阶段只展示原始上下文结果阶段再展示高亮提示、概率分布和解释。这样既保留第一人称体验又不影响学习反馈。6.4 排查顺序如果交互效果始终不对按以下顺序排查先确认题目数据本身是否合理概率之和是否为 1候选是否覆盖了真实高频词。再确认状态机是否正常上下文读取、提交、揭晓、下一句四个状态是否严格互斥。接着检查计算逻辑温度转换、困惑度计算、百分比显示是否存在精度问题。最后检查教学反馈解释文案是否真的解释了概率来源而不是复读候选词。7. 最佳实践与扩展方向7.1 如何让交互更接近真实模型手写概率表适合验证原型但长期使用会有两个问题题目数量有限概率不够真实。更可靠的方案是离线统计 n-gram 概率或者调用一个开源的轻量模型生成概率分布。n-gram 方案的思路是准备一份语料统计每个 n-1 元组合后面紧跟各个 Token 的次数再归一化成条件概率。例如统计“天气很”后面出现的所有词及次数。这个方案不需要 GPU适合教学原型。# 伪代码表示统计过程实际实现可以用 Python 的 collections.Counter python build_ngram_probs.py --corpus news.txt --n 3 --output probs.json生成的概率表可以存放成 JSON 文件前端启动时加载。生产环境还要为语料缺失的 n-gram 做平滑处理否则很多上下文会得到空分布。7.2 避免把模型拟人化过度反馈文案里不要出现“模型觉得”“模型想表达”“模型意识到”这类表述。模型没有感受它的输出来自统计规律。正确写法是把“模型知道”改成“模型中该 Token 的条件概率较高”。把“模型想接‘好’”改成“在训练语料中‘天气很’后面出现‘好’的频率较高”。这一条看起来是文案细节实际上是作品最重要的教学立场。Between Tokens 这类作品的初衷就是消除对模型的拟人化误解如果反馈文案自己却使用了拟人化表述等于自相矛盾。7.3 上线前检查清单在把作品发布给更多人之前建议逐项核对所有概率表都做过归一化且覆盖了玩家可能输入的常见候选。每轮都显示完整的前五名候选而不是只显示正确答案。每轮都有解释文案说明概率分布的来源。温度功能有下限保护避免除零。移动端布局可用按钮大小适合触屏。试玩者能准确说出“模型输出的是一张概率表”这句话。没有任何反馈文案把模型描述成有意识的主体。题目数据文件独立于页面代码方便后续扩充语料。7.4 扩展方向原型跑通后可以沿着三个方向扩展。第一是机制扩展加入注意力可视化用色块展示上下文里每个 Token 对预测的影响权重第二是数据扩展接入真实语料统计让玩家自由输入任意句子实时看到下一个 Token 的概率分布第三是角色扩展让玩家同时扮演“模型”“采样器”和“评估者”三种角色分别体验概率生成、随机采样和困惑度评估这三层过程。对于想深入学习的读者建议下一步认真研究三块内容子词分词算法比如 BPE、softmax 与温度采样的数学关系、困惑度与交叉熵损失的关系。这三块知识不但能支撑你把这个交互作品做得更真实也会帮你真正读懂大语言模型的推理过程。写这类作品的底线只有一个不要把模型讲成会思考的生命体。让玩家亲手预测一次 Token看到概率表感受到“答案并不唯一”这门课就算真正上完了。