让浏览器智能体可靠编辑乐谱的接口设计
ScoreTail 通过 WebMCP 向浏览器智能体开放读取与编辑乐谱的工具,复用页面内的文档、选区和现有编辑操作。实践重点是定义结构化表示、校验修改,并让智能体操作进入与人工编辑相同的文档和撤销历史。
AI 深度解读
让浏览器里的 AI「改写这两小节,再播放给我听」,难点不只是识谱。音符是 SVG 图形,同一拍可能叠着多个声部,改错一个时值就可能破坏整小节。碰上多人协作,还得处理同步和撤销。
ScoreTail 作者的做法,是通过 WebMCP 把编辑器已有的读谱、改谱和播放操作交给 agent。它最值得借鉴的地方,是如何让 AI 的修改遵守文档规则,并进入人类用户正在使用的同一套编辑流程。
给 agent 的应该是操作接口,而不只是页面
ScoreTail 是支持实时协作的浏览器乐谱编辑器。WebMCP 是一项提议中的浏览器 API,页面可以通过它注册工具,提供工具描述和输入 schema。
在这个实现里,工具处理函数不额外调用模型。用户的 agent 负责理解请求和推理,ScoreTail 提供乐谱表示、校验、编辑与播放能力。当前打开的文档和选区都在标签页里,工具可以直接利用这些上下文。

工具还会随页面权限变化。公共查看器允许未登录用户读谱和播放;修改记谱的工具,只在编辑器具有编辑权限时注册。只读操作带有 readOnlyHint,但它只是行为提示,权限仍由应用自身控制。
这一点对前端应用很实用:agent 可调用的操作,也应当与当前页面能完成的事情一致。公共查看器既然不能改谱,就没必要向 agent 展示改写工具。
当前接入范围也有边界:完整编辑器和公共乐谱查看器支持 WebMCP,访客快速编辑工作区还没有接入。
改写前,先定义清楚「替换哪一块」
ScoreTail 使用 MusicXML 交换乐谱。它表达能力强,但也包含小范围改写不需要的细节,例如为了表示同时发声的多个声部,需要编码顺序游标的移动。
作者复用了内置 AI 编辑功能的紧凑文本格式,称为 lanes-seq。每行指定乐器分部、谱表、声部和小节,再列出音高与时值。
下面两行解决的是「让 agent 能直接读懂音符所在位置」:
P1 s1 v1 m2: D5=1/4 E5=1/4 F5=1/2
P2 s1 v1 m2: G2=1
要看清第一行的 P1 s1 v1 m2:它定位到第一分部、第一谱表、第一声部的第二小节。时值按全音符的分数表示,1/4 是四分音符;音高使用绝对音高,C4 表示中央 C。和弦用括号包住音高,休止符用 r,例如原文中的 (C5 E5 G5)=1/2 r=1/2。
read_measures 会返回这种记谱文本,并附上分部信息和音乐上下文。agent 读完以后,可以用相同格式调用 rewrite_measures:
{
"start_measure": 2,
"parts": [1],
"lanes_seq": "P1 s1 v1 m2: D5=1/4 E5=1/4 F5=1/2"
}
这里要关注 parts 和 lanes_seq 的范围是否一致。这个例子还假设目标是完整的 4/4 小节,并且对应的分部、谱表和声部已经存在,所以合理流程是先读,再改。
更容易踩坑的是替换粒度:改写单位是「某一小节中的某一谱表」,提交该单位的内容会替换其中全部声部。
因此,遗漏一个谱表表示保留它;但已经提交某个谱表,却漏掉其中一个声部,不能理解成那个声部会自动保留。想改旋律、保留另一谱表上的伴奏,必须先弄清这个边界。
读取一次最多接受 64 小节,改写一次最多接受 32 小节;插入或删除小节还需要显式传入 allow_measure_count_change。工具描述中的格式指南与内置 AI 功能由同一个函数生成,减少两套说明各自演变造成的不一致。
真正需要补齐的是校验、撤销和协作路径
JSON schema 能确认 lanes_seq 是字符串,却不能证明它是一段完整乐谱。例如完整的 4/4 小节只提交 D5=1/4,JSON 合法,时值却没填满。
作者把处理过程分成:解析 lanes-seq,构建并校验改写计划,开启撤销手势,通过已有乐谱操作应用修改,最后选中变化范围。
计划阶段会检查音符是否超出指定小节或分部、时值是否正确填满小节,也会处理延音线和连音线修复。解析或规划失败时,工具返回以 Nothing was changed 开头的错误,再列出校验问题,agent 可以修正输入后重试。
这里的关键是先把改写计划校验完整,再动文档。
撤销也需要单独处理。ScoreTail 原本通过 pointerdown、keydown 等输入事件划分撤销手势,工具调用却不会触发这些事件。写入工具因此显式调用 beginUndoGesture(),让一次成功改写可以一步撤销。
作者专门测试了连续调用:先改写第二小节并保存快照,再移调第三小节,撤销一次后,文档应当回到保存的快照。另一个测试确认,一次有效改写后撤销,会恢复原谱。这比只检查「调用成功」更能发现工具接入的问题。
协作方面,人类 UI 和 WebMCP 都经过已有的乐谱操作层,写入同一份 Yjs 文档,再走原有渲染与同步路径。没有额外维护一份 AI 乐谱等待合并。不过,文档收敛只能解决共享状态的一致性,不能保证改编好听,也不能代表其他协作者同意这次修改。
生命周期和播放同样有工程细节。桥接层检测 document.modelContext,等乐谱数据就绪后动态加载工具;通过 AbortSignal 在清理或权限依赖变化时撤销注册。播放回调用 ref 获取最新函数,避免每次渲染都重新注册工具。
页面从未获得用户激活时,播放工具会返回错误,请用户先点击。否则 AudioContext.resume() 可能一直等待,让 agent 迟迟收不到结果。
我的判断
这套实现最有价值的地方,是把模型输出放进了应用已有的约束里:先限定范围,再校验结构,最后通过同一操作层修改文档。与让 agent 直接操作 SVG 音符相比,这条路径给出了更明确的编辑语义;但原文没有提供两者的成功率或耗时对照,不能据此断言效率提升了多少。
lanes-seq 也有适用前提。它服务于乐谱的局部读写,并复用了已有 AI 功能,不代表所有创作软件都需要再设计一种文本语言。应用若已有适合局部修改的结构化格式,可以先评估复用成本。
作者报告当前工具套件有 15 项通过的测试,覆盖权限工具集、范围读取、改写成功与拒绝、小节数量变化、撤销分组、移调、选区和播放状态。测试使用真实的内存乐谱模型,播放则是 mock。它们证明了应用处理逻辑,尚不能证明每种浏览器 agent 都能发现并正确调用工具。
还有一个明确取舍:当前改写立即生效,WebMCP 处理函数没有独立的预览确认阶段。可见选区和可靠撤销很有帮助,但对于多人共同编辑的作品,是否需要预览、如何表达协作者意愿,原文还没有给出完整方案。
WebMCP 仍处于实验阶段。原文提到 Chrome 的 origin trial 和本地测试 flag,但未给出具体版本号或 flag 名称。浏览器支持,也不等于某个 assistant 一定能调用工具,演示前仍要验证具体组合。
能拿来做什么
- 给已有 Web 编辑器接入 agent 时,优先封装现成的文档操作,并明确每次替换的最小单位、遗漏内容的含义和修改范围。
- 将输入 schema 校验与业务校验分开。结构化参数合法之后,还要在写入前检查文档约束,让失败结果足够具体,方便 agent 修正。
- 为连续工具调用补充撤销测试,尤其检查「调用两次,撤销一次」能否准确回到中间状态,同时确认修改沿用已有协作同步路径。
- 试用 ScoreTail 时,可先在公共查看器请求读取前八小节、解释和弦进行并播放;需要编辑时,复制到有编辑权限的完整编辑器,从小范围改写开始,随后试听并验证撤销。