
最近我重新整理“未来之窗”项目组代码库时发现第60期这个“昭和仙君(六十)多模态虚拟键盘—东方仙盟筑基期”确实值得单独拿出来聊聊。这个名字初看像是网文更新公告实际上是一个完整的人机交互实验项目把传统的屏幕键盘升级成融合语音、手势、眼动与触控的多模态输入系统并且用修仙叙事来给整个开发过程分层。“筑基期”对应的是项目的地基建设阶段——先把输入感知、事件分发、模态仲裁这些底层能力立起来后面才有资格谈金丹期、元婴期的智能补全和自主执行。这个系列是东方仙盟一个我参与的开源软硬件互助社群的长期接力项目我负责第60期的“筑基”部分。刷了几天热搜满屏都是多模态大模型、AI Agent、多模态融合算法这些词。说实话大众对“多模态”的注意力几乎被ChatGPT和文生图拿去了很少有人关注到离用户最近的一个多模态场景——键盘输入。但恰恰是这个不起眼的场景是能最直接体验到多模态价值的地方。我们每天在电脑、平板上敲字一旦把键盘从“物理按键”换成“多模态虚拟键盘”语义输入的方式会被彻底重写说话能打字眼神能定位手指悬空能翻页AI还能在你开口之前补全你想说的半句话。这套东西单看哪个模态都不稀奇把多个模态拧成一股绳、让它们不打架才是真正的“筑基”难题。这篇我尽量用大白话把我做这套系统的思路、踩过的坑、以及可以复现的步骤写清楚。想做智能输入法、虚拟键盘、AR交互或者单纯对多模态融合感兴趣的朋友应该都能从里面抄到点东西。1. 内容整体设计与思路拆解1.1 这个“赛博修仙”标题到底在说什么很多第一次看到“昭和仙君(六十)多模态虚拟键盘—东方仙盟筑基期”的朋友第一反应是“标题党”。真不是这套命名体系是东方仙盟内部的版本管理约定每个项目不仅有版本号还有境界位阶用境界位阶标示当前系统的成熟度。项目主品牌叫“未来之窗”定位是面向下一代交互方式的桌面与移动输入方案。“昭和仙君”是本项目的虚拟形象IP一个把昭和复古机械美学和仙侠角色设定揉在一起的赛博符号没有现实指代纯粹是审美趣味。“东方仙盟”是社群的统称我作为该系列第60期的维护者负责把“多模态虚拟键盘”从脑子里搬到可运行的原型。“筑基期”不是形容词而是技术含义系统的感知层和仲裁层刚刚成型各模块之间能通信但还没到稳定运行、智能调度的高级阶段。在修仙设定里筑基是修行者超凡入圣的起点决定了一个人这辈子能修的功法上限。把这套隐喻搬到软件工程上非常贴切虚拟键盘如果只是把物理键盘映射成屏幕上的点按区域那它的上限就是一块“玻璃板”。而筑基期要做的是给这块玻璃板装上“感知系统”——让它能听、能看、能感应手部动作并且能在这些纷杂的信息里找到用户真正的输入意图。这个地基打得牢不牢直接决定后面能不能接大模型、能不能做AI Agent自主操作、能不能在AR眼镜里只用眼睛和手指就能完成一场演示汇报。所以这一期我作为“筑基期”的负责人实际干的事是先梳理清楚虚拟键盘需要哪些输入模态、每个模态要解决什么问题、模态之间的冲突如何仲裁然后把它们落到一个能跑的框架里。听起来不复杂但工程量确实不小。1.2 为什么物理键盘修成了仙还要搞虚拟键盘有人会问物理键盘打得那么爽为什么非要折腾虚拟键盘我用几个真实场景回答第一物理键盘需要实体空间和特定姿势平板和折叠屏没有物理键盘随便找个咖啡馆的沙发瘫着就不可能把手架在实体键盘上第二物理键盘只能接收手指这一个模态虚拟键盘可以听、可以看、可以感知触碰输入通道从一根手指变成整套身体行为第三物理键盘的布局是上个世纪为打字机设计的信息密度很低虚拟键盘可以把候选词、语义联想、AI补全直接嵌到输入流程里。数据也能说明问题。有统计说手机触摸屏上的虚拟键盘输入速度只有实体键盘的70%左右误触率却高出不少。问题不在于“虚拟”二字而在于绝大多数虚拟键盘只是把实体键盘“画”在屏幕上换汤不换药。真正的多模态虚拟键盘应该解决的是用户想说“帮我查一下附近能撸猫的咖啡店”不用一个字一个字戳屏幕而是说出这句话系统语音识别后自动补全或者在安静场合不方便说话就用手势在空中划出候选甚至在看屏幕时眼神多停留半秒系统就明白你要选的是哪块候选区。这就引出了整个项目的灵魂——键盘不再是字符输入工具而是意图理解入口。用行话讲它是AI Agent与用户之间的神经接口。这个思路才是“多模态虚拟键盘”真正区别于普通屏幕键盘的地方。1.3 筑基期最难的不是技术是想清楚谁听谁的我在做这个项目时最深的体会是多模态系统技术上各有各的成熟方案难的是怎么让它们协作时不打架。体感是人其实是天然的“多模态动物”——我们和人聊天时一边听声音一边看表情一边注意手势所有信息在大脑里瞬间融合毫无迟滞。但计算机不一样语音识别输出一段文本视觉模块输出一个坐标点触控模块输出键盘码三个模块来自不同算法、不同延迟、不同置信度放到一个系统里冲突是必然的。举个最直接的例子我对着屏幕说“你好”语音识别已经输出“你好”两个字并准备提交到输入框但我手又也按到了“n”“i”两个键这时候输入框如果同时接收语音结果和键盘结果就会变成“你好ni”。这种重复注入问题在做原型的第一周就出现了比我想象的频繁得多。所以筑基期的核心任务可以概括为三件事统一事件格式、设计仲裁策略、建立状态机。只有把这三件事做好后面接入更多模态肌电手环、脑机接口、AR空间定位时才能像插件一样即插即用。这也是修仙叙事里的“道基”底层逻辑通顺上层法术才能顺畅施展。2. 核心细节解析与实操要点2.1 虚拟键盘基础技术栈选型做项目第一步是选型。虚拟键盘可选的技术路线很多我梳理了一下主流的就四条方案技术特点适合场景上手难度我的评价Qt Virtual KeyboardC/QML写的开源虚拟键盘框架支持插件扩展桌面Linux/Windows嵌入式设备中生态成熟适合做系统级输入法Electron 前端实现JS/HTML渲染键盘界面跨平台桌面应用低好写好改但内存占用偏高Web/Web HID浏览器直接调虚拟键盘网页/云桌面低适合远程演示但受限多自绘渲染 IME接入底层自绘键盘对接系统输入法接口移动OS深度定制高自由度最大工程量也最大考虑到项目主线是验证多模态交互逻辑而不是重新发明一遍底层渲染我最后选了Qt Virtual Keyboard作为基础框架。原因有三第一它本身是在QML里声明式描述键盘布局改布局很快实测改一套键位布局不超过一小时第二它支持插件机制可以注入自定义的输入法后端正好用来对接语音和视觉模块的输出第三Qt的基础事件循环天然适合处理触摸事件、按键事件和多模态事件总线能无缝衔接。如果读者只是在Windows或macOS上做原型验证Electron路线会更快我初期也试过半天就能把一套虚拟键盘界面跑起来。但后续接MediaPipe视觉管线时进程间通信的复杂度会急剧上升所以我最终还是移到了Qt这条路上。提示项目初期不要把精力浪费在键盘皮肤和动画上。一套朴素但能跑通全链路的键盘价值远超一套漂亮但只支持触摸的“壳”。2.2 多模态感知模块的实现原理解读多模态虚拟键盘的感知模块我的划分方式是按人的生理通道来划分——触觉通道负责指尖听觉通道负责声音视觉通道负责眼睛和手部动作。每个通道对应一个独立的感知算法最后统一汇聚到仲裁层。触觉通道是最简单的Qt虚拟键盘原生处理触摸/鼠标点击输出标准按键事件。真正难的是视觉和听觉。听觉通道目前主流选择是Whisper、Vosk、以及各家云API。我在本地和云端都实验过OpenAI Whisper识别质量高中英文混说表现好但本地CPU推理延迟高。tiny模型大约能到500ms-1s延迟base模型要1-2s对交互来说偏慢。GPU环境下可以用base或small延迟能压到200-500ms。Vosk专门为流式识别设计模型小CPU上延迟可以做到300ms左右平均每100-200ms输出一次中间结果。早期版本中文识别不如Whisper但胜在延迟低。云API国内外的云语音API质量高、延迟可控但隐私和费用是个问题。做原型可以做个人主力工具要考虑成本。视觉通道我用的是MediaPipe。这套谷歌开源的方案可以直接在CPU上跑实时视觉模型不需要GPU。FaceMesh可以检测468个面部关键点我利用这些点估算视线方向Hands可以检测21个手部关键点判断手指捏合、展开、水平移动等动作。视线估算的具体原理不复杂用FaceMesh定位左右眼的眼角与瞳孔中心结合头部姿态角度算出注视点在屏幕上的投影坐标。MediaPipe没有直接给出“眼睛在看哪”所以需要自己做透视变换校准。手势识别相对成熟直接输出手指关键点的坐标后设定阈值判断“食指前伸指针”、“食指与拇指捏合选中”即可。还有一类模态——脑机和肌电网上讨论度很高尤其是“多模态记忆包括4D吗”这种神问题都冒出来了。但我必须泼点冷水消费级脑机接口目前分辨率还不足以精确控制键盘输入肌电手环倒是有一些商业产品但SDK封闭、价格贵不适合个人项目做实验。我的处理方式是在设计事件总线和仲裁层时预留通用接口脑机/肌电只要把输出转成标准输入事件就能无缝接入不影响现有架构。这才是筑基期应该有的前瞻性。2.3 融合仲裁与冲突消解策略详解多模态系统的核心机制就是仲裁层。我把它设计成一个基于状态机的事件分发器整个系统有四种工作状态空闲、聆听、凝视、手势。空闲不处理任何特殊输入键盘表现为普通虚拟键盘。聆听用户按住语音键或说出唤醒词系统进入语音输入模式麦克风数据流入ASR识别文本直接进候选框。凝视系统检测到用户眼睛盯住候选区超过设定的驻留阈值我默认设450ms自动触发选中逻辑。手势空中手势接管指针食指指向位置映射为光标位置拇指食指捏合映射为点击。仲裁策略的关键是“谁先声明谁优先”。我采用带优先级的置信度加权机制每个模态在输出事件时附带一个置信度分数score0到1之间和一个来源标识。仲裁层对候选事件做综合评估P_final max(score_touch × w_touch, score_speech × w_speech, score_gaze × w_gaze, score_gesture × w_gesture)其中权重是我根据场景预设的。意图比较明确的模态权重大比如触摸点击是最高优先级1.0因为物理触碰的意图最明确语音其次0.9凝视因为存在Midas Touch问题——眼睛看东西和想点东西是完全两回事权重设为0.6手势因为容易抖动权重设为0.7。光和优先级还不够。比如上边那个“说你好又按ni”的例子语音结果已经进入候选文本此时手指又按了键系统如果不加约束就会重复。我的解决办法是引入“模态独占窗口”语音识别的最终确认结果一旦进入候选框就生成一个200ms的锁定期锁定期内其他模态的字符输入请求直接丢弃只允许撤销命令通过。这个细节解决了我99%的重复输入问题。另一个容易踩坑的地方是误唤醒。语音唤醒词识别极容易把“好了”“call”之类的话误判成唤醒导致莫名其妙进入聆听状态。我的方案是双阶段确认唤醒词命中后要求用户在500ms内再按下物理空格键确认否则退出聆听状态。虽然多了一步操作但误触率大幅下降整体体验反而更好。3. 实操过程与核心环节实现3.1 搭建最小可用的“筑基框架”整个项目的源码结构我尽量保持简洁方便新人理解。一个最小可复现的项目大概长这样future-window-keyboard/ ├── main.py # 入口初始化Qt应用 ├── keyboard_ui.py # 虚拟键盘界面基于Qt Virtual Keyboard二次封装 ├── event_bus.py # 多模态事件总线发布订阅模式 ├── arbiter.py # 模态仲裁器状态机置信度决策 ├── asr_engine.py # 语音识别模块Whisper/Vosk封装 ├── vision_engine.py # 视觉模块MediaPipe手势眼动 └── config.yaml # 参数配置阈值、权重、端口依赖安装没什么玄学三条命令搞定。Linux下Qt要用到xcb插件Windows下需要装对应的VC运行时macOS则要注意在系统设置里给终端开“辅助功能”权限不然模拟按键事件会被系统拦截。我主要跑在Ubuntu 22.04上以这个环境为准。pip install openai-whisper vosk mediapipe pyyaml sudo apt install qtbase5-dev qtdeclarative5-dev qml-module-qtquick-virtualkeyboard建项目千万不要一步到位我吃过亏。我第一版是想把所有模态都接好再跑测试结果语音、视觉、键盘三个环境各自出问题排查了整整一周都没跑通全链路。后来改成“先跑通键盘再挂语音再挂视觉最后仲裁”每一步增量验证反而三天就走通了全流程。筑基期不要贪。3.2 从触控到语音接入第一个多模态输入通道触控通道是键盘自带能力不用写逻辑所以第一个要接的多模态通道就是语音。我核心写的event_bus.py长这样功能是让各模块之间解耦通信# event_bus.py import queue import threading class EventBus: def __init__(self): self.subscribers {} self.queue queue.Queue() self._running False def publish(self, event_type: str, payload: dict, confidence: float 1.0, source: str unknown): 统一事件入口所有模态都走这个方法上报事件 self.queue.put({ type: event_type, payload: payload, confidence: confidence, source: source, timestamp: time.time() }) def subscribe(self, event_type: str, callback): 订阅指定类型事件仲裁器和UI都通过订阅接收事件 if event_type not in self.subscribers: self.subscribers[event_type] [] self.subscribers[event_type].append(callback) def start(self): self._running True threading.Thread(targetself._dispatch_loop, daemonTrue).start()语音模块的接入思路是设置一个全局热键比如Altspace作为“即按即说”的语音键。按住说话松开确认识别结果走EventBus发出去。这里的关键参数是静音检测阈值和尾音切断时间我根据环境噪音调了几次# asr_engine.py import whisper import sounddevice as sd import numpy as np class WhisperASR: def __init__(self, model_namebase, sample_rate16000): self.model whisper.load_model(model_name) self.sample_rate sample_rate self.silence_threshold 0.02 # 低于该振幅视为静音 self.tail_ms 600 # 尾音静音时间超过则自动停止录音 def transcribe(self, audio_np): result self.model.transcribe(audio_np, languagezh, fp16False) return result[text]Whisper识别结果的置信度可以通过logprob字段间接获取但我实测一个更简单的方法是看文本的熵——如果识别出的文字全是高频词且长度适中置信度通常不低。仲裁层接到的语音事件大致是event_bus.publish(text_insert, {text: 你好}, confidence0.91, sourcespeech)事件总线的好处是UI层不用去关心这条文本到底来自语音还是键盘只需要在“text_insert”订阅里把文本渲染到输入框。从后面的架构角度看任何模态只要能输出合规的“text_insert”事件就能接入这个键盘系统。这也让我后面接视觉模块省了很多事。3.3 眼动与手势接入的“真实施工记录”视觉模块我选择了MediaPipe理由之前说过CPU可跑、开源、跨平台。眼动部分的核心代码思路如下# vision_engine.py import cv2 import mediapipe as mp import numpy as np mp_face_mesh mp.solutions.face_mesh class GazeTracker: def __init__(self): self.face_mesh mp_face_mesh.FaceMesh( static_image_modeFalse, max_num_faces1, refine_landmarksTrue, # 开启瞳孔关键点只有这个版本能拿到精确瞳孔位置 min_detection_confidence0.5 ) # 校准参数用3x3矩阵把视线向量映射到屏幕坐标 self.calib_matrix np.eye(3) def estimate_gaze_point(self, image, screen_w, screen_h): rgb cv2.cvtColor(image, cv2.COLOR_BGR2RGB) results self.face_mesh.process(rgb) if not results.multi_face_landmarks: return None landmarks results.multi_face_landmarks[0].landmark # 左眼瞳孔 468, 右眼瞳孔 473, 鼻尖 1兼容不同版本模型 left_pupil np.array([landmarks[468].x, landmarks[468].y]) right_pupil np.array([landmarks[473].x, landmarks[473].y]) nose_tip np.array([landmarks[1].x, landmarks[1].y]) # 简单的视线向量瞳孔中心与鼻尖的差向量乘上校准矩阵 gaze_vec np.array([(left_pupil[0] right_pupil[0]) / 2 - nose_tip[0], (left_pupil[1] right_pupil[1]) / 2 - nose_tip[1], 1.0]) screen_point self.calib_matrix gaze_vec return int(screen_point[0] * screen_w), int(screen_point[1] * screen_h)说实话这个眼神跟踪的原始结果非常抖直接映射到屏幕会像喝醉了一样乱飘。我试过很多平滑算法最终效果最好的是“指数移动平均滞回阈值”# 在GazeTracker里维护平滑状态 self.smooth_x, self.smooth_y 0.5, 0.5 alpha 0.35 # 平滑系数越大越灵敏越抖越小越稳越慢 self.smooth_x alpha * raw_x (1 - alpha) * self.smooth_x self.smooth_y alpha * raw_y (1 - alpha) * self.smooth_y但光平滑还不够。Midas Touch问题是眼动交互的“阿喀琉斯之踵”——人眼天然会扫描屏幕如果看一眼就触发点击系统会疯掉。所以我在“凝视”状态下设置了另一种触发机制眼睛停留在目标区域超过450ms后目标区域会持续高亮再停留150ms才真正触发点击。这个过程让用户能感知系统“正在看你想要的位置”也给了用户自然的反悔时间。实测下来450ms150ms的阈值误触率比单纯看哪点哪低了大约七成。手势部分相对简单主要判断食指关键点的坐标与捏合动作然后把它们映射成鼠标事件。这里有一个非常实用的参数捏合阈值设置为“食指指尖与拇指指尖欧氏距离/中指指尖到手腕距离”的比值好处是不同手型、不同拍摄距离下效果都稳定。比值小于0.3判定为捏合。3.4 与AI Agent联调让键盘听懂“半句话”筑基期的最后一个环节是把大模型能力接进输入链路。现在的智能输入法都有AI补全但我做的不是简单的下一个词预测而是让虚拟键盘变成一个能理解上下文的输入智能体。具体来说键盘不再等用户打完整句话而是实时把当前输入框里的文本片段发送给一个本地跑的Qwen2.5-1.5B模型让模型生成5个“候选后续”直接显示在候选栏里。这里遇到一个很现实的取舍本地推理还是走API本地推理隐私好、响应可控但小模型生成质量有限API质量高但每一项输入都发到云端隐私没法保证而且网络波动会造成输入卡顿。我的做法是“分层处理”短短语义补全用本地小模型需要整段生成、重写、翻译之类的复杂操作由用户手动触发“AI助手”按钮再走API。这个折中方案兼顾了响应速度和复杂性。代码层面其实不复杂# ai_agent.py from transformers import AutoModelForCausalLM, AutoTokenizer class InputAgent: def __init__(self, model_nameQwen/Qwen2.5-1.5B-Instruct): self.tokenizer AutoTokenizer.from_pretrained(model_name) self.model AutoModelForCausalLM.from_pretrained(model_name, device_mapauto) def predict_next(self, current_text, top_k5): messages [{role: system, content: 你是一个输入法助手用简洁自然的中文续写用户输入一次只给一个短句。}, {role: user, content: current_text}] text self.tokenizer.apply_chat_template(messages, tokenizeFalse) inputs self.tokenizer(text, return_tensorspt).to(self.model.device) outputs self.model.generate(**inputs, max_new_tokens20, num_return_sequencestop_k, do_sampleTrue, temperature0.8) results [] for out in outputs: decoded self.tokenizer.decode(out[len(inputs[input_ids][0]):], skip_special_tokensTrue) results.append(decoded.strip()) return results实际体验下来用户打完“帮我写一封”之后键盘候选栏直接弹出“邮件给客户”“辞职信”“生日祝福”三个候选配合语音或眼动选中输入效率提升非常明显。有一说一模型推理在CPU上要1到2秒所以在用户停止输入600ms后才触发预测避免每个按键都造成卡顿。另外我还做了防抖如果用户正在用键盘快速连续输入就不触发预测只有停顿超过阈值才激活AI补全。这个逻辑需要在仲裁层判断“用户当前处于输入间歇期”。4. 常见问题与排查技巧实录4.1 高频问题速查表我把自己在实际跑这套系统时踩到的典型问题整理成了表格按出现频率和危害程度排序问题现象可能原因解决思路耗时语音识别结果和键盘输入重复模态独占窗口未生效给语音文本插入事件加200ms锁定期半小时眼动光标乱飘校准矩阵不准或平滑系数过小重新执行三点校准alpha调到0.35-0.45十几分钟手势识别在弱光下失灵MediaPipe对手部轮廓敏感增加补光开启MediaPipe的model_complexity1半小时语音尾音捕捉不到老吃最后一个字尾音切断时间太短tail_ms从600ms调到800ms静音阈值降到0.015几分钟Qt虚拟键盘在输入框获得焦点时自动弹出系统输入法上下文被触发禁用Qt的inputMethod改用自定义事件注入两小时AI补全内容和上下文完全无关本地小模型能力不足换更大的量化模型或接入远程API视情况多模态同时触发导致输入顺序错乱仲裁层未做时间戳排序给每个事件加时间戳仲裁前先按时间排序一小时4.2 实战中的独家调试技巧做多模态系统最头疼的是问题复现。因为涉及摄像头、麦克风、键盘同时工作有时候一个bug在100次里只出现几次靠人的感觉根本抓不到。我后来总结出一套“录制回放”打法所有模态的原始事件都带时间戳、来源、置信度写入本地日志文件。日志格式用JSON Lines每行一个事件。发现输入异常时把日志文件留档写一个replay脚本逐条重放事件到仲裁器模拟完整的多模态输入流程。重放时对了说明问题出在感知模块重放时还是错说明仲裁逻辑有bug。一次就能定位80%的疑难杂症。这套方法帮我解决过一个特别隐蔽的时序问题语音结果比手势事件的延迟高了120ms导致仲裁层先处理了手势点击然后才插入语音文本结果候选词被点击事件覆盖。如果没有录制回放这个问题会反复出现且很难复现。另外强烈建议把置信度分数可视化。我写了一个简单的调试面板用三个颜色条实时显示当前语音、眼神、手势的置信度和触发状态。这样一眼就能看出是哪个模态在误报调试效率提升巨大。跑演示的时候这个调试面板还能当“上帝视角”给观众看。提示不要迷信高置信度。有时候用户明明按下按键但因为手一抖触摸的置信度低于某个阈值被仲裁层丢弃反而体验很差。我的经验是触摸通道的置信度只做信息展示不做是否使用的依据——只要物理上点了就一定要执行。宁可多误触几次也不能让用户觉得“我明明按了却不响应”。4.3 如何控制误触率与安全兜底多模态输入的误触问题是决定项目成败的大山。人机交互有个“肥手指”问题在触摸屏上很难精确命中目标键到了眼动和语音场景误触更是家常便饭。我用的组合拳是第一双阶段确认。任何非触摸模态要执行“提交文本”“点击按钮”这类破坏性操作时都要经过候选高亮→确认触发两个阶段中间隔一个可配置的时间窗口。我默认设350ms用户在350ms内如果按了取消键就撤销这次触发。第二永远保留“撤销通道”。多模态再怎么智能都一定会有识别错误。我在系统里加了一个全局手势快速顺时针画圈是“撤销上一条输入”。这个手势独立于其他模态不参与仲裁只要识别到就立刻执行undo。实测这是用户用得最多的手势之一——“唉我说错了撤销一下”。第三物理急停键。键盘上的ESC永远响应并且优先级最高任何模态都不能屏蔽它。紧急状态下按ESC会清空当前多模态锁定期、关闭语音和视觉识别、恢复到纯触摸键盘模式。这个设计看起来朴实无华但关键时刻能救命尤其是当着领导演示的时候。5. 写在“筑基完成”之后的几句大实话这套多模态虚拟键盘的筑基期我断断续续做了大概两个月中间推翻重写了两版。最开始的版本把所有逻辑全塞进UI层写到最后自己都看不懂哪个事件从哪来、要往哪去后来痛下决心重构出event_bus和arbiter两层才感觉整个系统真正“稳住了”。做这类多模态项目最大的教训就是感知模块可以糙但架构不能烂。感知模块糙后面还能慢慢调参优化架构烂了每加一个模态都是重构一场直接劝退。按东方仙盟的版本规划筑基期验收之后下一期是“开光期”会围绕AI Agent做更多自动化让键盘不只是补全文字还能根据聊天记录直接生成完整邮件并预览润色再往后还有“融合期”大概会尝试把空间定位和可穿戴设备拉进来。这个项目目前在我看来最有趣的不是键盘本身而是它其实是一个通往“意图接口”的小小起点——当人们发现“说话、看、指”都能输入的时候传统的图形界面就已经开始松动了。如果你也想动手试试我建议就从最简单的两个模态开始触摸加语音。把这两条链路调通再去碰视觉别一上来就搞四模态全家桶。做多模态不丢人丢人的是拼命做多模态却连最核心的触摸输入都做得不顺手——那不叫多模态那叫给键盘加了几个花哨的开关。先筑基再修仙顺序错了可就没法返工了。