技术

QuireKit 编辑器的 AI-Native 是如何设计的?谈谈我对真正 AI-Native 的理解

先说结论,我个人认为,AI-Native 的编辑器,不在于形式,无论是左编辑器右输入框,还是选中后弹出 AI 润色、续写框,又或是正文下方放类似对话形式的输入框,本质并没有任何不同。在 Tiptap 体系下,只要不是通过命令原生操作,我认为就全都不算 Native 。个人认为真正的 Native ,是模型能原生操作编辑器,不是先生成 markdown 再通过兼容层转为编辑器内容,也不是将 markdown 转为兼容的 HTML 再通过兼容层转为编辑器内容,并且你不需要为每个功能都为模型编写提示词,你只需要一种机制,让模型能够知道编辑器有哪些能力,并且知道这些能力的参数,调用方式就够了,至于如何调用,那就得看模型的调度能力到底几何了。
下面是 QuireKit Classic 里的一次真实运行:一句话让 AI 把第一行设为标题并居中、改写第二段、把百分比和日期加粗标红,再在文末插入表格。修改先以修订呈现,最后一次批准。演示用的模型是 DeepSeek Flash ,后面两段也一样。

具体的实现方案来自一个之前做的 CLI

前段时间想要把公司后端的所有接口包装成一套对 AI 友好的 CLI ,让 Codex 、Claude Code 、DSH 、WorkBuddy 等任何 Agent 都能自己学会使用我们的产品。接口有上百个,版本有几十条标准包、几千家定制包,给每个 Agent 写提示词显然不现实,所以我设计了一套自描述的方案,Agent 只需要会三个命令:
cli api list    --target test --json        # 这个环境能用哪些能力cli api explain <id> --target test --json   # 能力的参数 Schema 、风险、认证方式cli api call    <id> --target test --input @request.json --json有哪些接口、参数如何填写,都由 Agent 在运行时向 CLI 询问。这样一来,更换 Agent 不需要做任何修改,新增接口或升级版本之后,Agent 下一次 list 时自然就能知道。
做 QuireKit 编辑器的 AI 时,面对的其实是同一个问题,只不过对象从成百上千的后端接口换成了成百上千的编辑器命令。
第一版设计的 AI 输出正确性评测只有 48%

我最早的做法,是每个插件分别给 AI 注册单独的工具,各写各的说明和提示词。九月底用 20 个日常任务做评测,例如“标题居中”“行距 1.5 倍”“文末加个三列的表”,第一次通过率只有 48.3%。让 AI 分析失败记录后发现,问题基本不在模型:有的能力压根没开放,有的写入失败却回了成功,表格和页眉各有一套定位方式,模型来回尝试,直到轮次耗光,最终以失败结束。
后来我推翻了让插件各自给 AI 注册工具的方案。仔细想想,这不就跟之前做的 CLI 一样吗?为什么不能让编辑器自己描述自己的能力?于是改成了自描述的方案,定位方式也统一成了一种。同一个模型、同一批任务,通过率到了 98.3%,平均每个任务 1.1 次工具调用,剩下那一次失败也是因为题目本身有歧义。到这里,我感觉应该是对了。下面是重做时改的几件事:
插件命令自描述的改造

模型能看到的工具改为固定的几个:读文档、改文档、查帮助。工具叫什么、参数长什么样、出错怎么提示,都由 AI 核心统一定。插件不再专门给模型写工具和提示词来告诉它怎么用,而是只描述自己的情况:节点在视图里怎么显示,有哪些属性能改、取值范围是什么、用哪个命令改。所有开放给 AI 的命令,在定义时都会用 defineCommand 包一层描述:用途说明、参数的 JSON Schema ,以及作用在哪个位置。
开放给 AI 的命令,插件在 addCommands() 里用 defineCommand 声明。比如书签插件的“加书签”命令:
addWordBookmark: defineCommand({  // 给模型看的用途说明  description: "Adds a bookmark named `name` on `text` in the block (the whole block when `text` is left out), replacing a bookmark of that name. A link to \"#name\" jumps to it.",  // 作用位置:块里的一段文字  target: "text",  // 参数的 JSON Schema  params: { type: "object", required: ["name"], properties: { name: visibleNameSchema }, additionalProperties: false },  // 真正执行的命令,和工具栏调用的是同一个  run: createAddWordBookmarkCommand(startTypeName, endTypeName)}),defineCommand 本身只是一层带类型的包装:它接收一个描述对象,返回的仍然是一个命令函数,调用时原样转给 run;描述被冻结后挂在这个函数的隐藏属性上。Classic 用的核心包里,实现就这几行( MD Editor 用的 MSFE 也有同名的 defineCommand,区别是它直接返回 run 本身,把描述登记在一张以命令函数为键的表里):
const descriptorKey = Symbol.for("quirekit.command.descriptor");export function defineCommand(definition) {  const { run, ...descriptor } = definition;  // 返回新的函数,调用时转给 run ,对编辑器来说它就是普通命令  const command = function (...args) { return run.apply(this, args); };  // 描述挂在不可枚举的 Symbol 属性上  Object.defineProperty(command, descriptorKey, { value: Object.freeze({ ...descriptor }), enumerable: false });  return command;}包装之后,插件拿到的仍然是原来的命令函数,工具栏和快捷键照常调用;描述挂在函数的隐藏属性上,AI 核心再从所有命令里把带描述的提取出来,汇总成一张表:

除了命令,插件还用 addAiCapabilities() 声明格式属性。比如段落对齐,完整声明如下:
{  // 能力种类:格式属性  kind: "format",  // 模型在文档视图和编辑工具里看到的属性名  name: "align",  // 作用在段落上,而不是文字上  level: "paragraph",  // 给模型看的含义和取值说明  description: "Alignment: \"start\", \"center\", \"end\", \"justify\" or \"distribute\".",  // 合法取值,编辑工具按它校验参数  schema: { enum: ["start", "center", "end", "justify", "distribute"] },  // 读:从段落的 Word 属性里取当前对齐方式,没设置时返回 undefined ,表示沿用样式  read: target => target.level === "paragraph" && target.node.attrs.wordParagraph !== undefined    ? resolveWordParagraphFormatting(target.node.attrs.wordParagraph).alignment ?? undefined    : undefined,  // 写:调用段落插件自己的命令,和用户点工具栏上的“居中”是同一个命令  apply: ({ commands }, value) => commands.setWordParagraphProperties({ properties: { alignment: value } }),  // 审阅修改时给人看的名称和取值,不给模型看  present: {    label: "对齐",    value: value => ({ start: "左对齐", center: "居中", end: "右对齐", justify: "两端对齐", distribute: "分散对齐" })[value] ?? String(value)  }}加一个插件,"改文档"这个工具就多认识一种属性,即多一种操作能力,但模型所会的工具数量不变,已经学会的工具用法也不变。这就是开头说的那种机制:不为每个功能写提示词,只让模型知道有哪些能力、参数是什么、怎么调用。
比如下面这份简历排版:页边距、字号、加粗、颜色、字距、段落下边框、项目符号、行距和段前段后间距,都是各插件声明的能力。AI 先读取了内置的简历技能,再用一次编辑调用全部改好,最后一次批准。

写到这里应该能看出来,这跟前面那个 CLI 是一个路子。document_read 相当于 list ,document_help 相当于 explain ,document_edit 相当于 call 。参数写错了,报错会直接说是哪个字段。我们自己的 AI 助手和第三方自己写的 Agent 用的也是同一套工具,没有给自己留后门。

确保模型的修改和人工修改走同一套底层命令

通常情况下,大多数编辑器 AI 生成内容是生成一段 markdown 或 HTML ,再经过兼容层转成编辑器内容替换选区。而由于 markdown 和 HTML 自身的限制,在复杂文档中本就不能完美存储所有有效信息,因此转换必然丢失一部分信息。在 Prosemirror 体系下,HTML 存储 Attrs 还会依赖各种标签属性,当存在大量属性时,生成复杂文档可能还存在出错的问题。
但是在 QuireKit 里,AI 的每次写入,走的都是跟用户点击工具栏时完全相同的一套底层命令。一次调用里如果有操作不合法,只需退回那几个操作并说明原因,其余照常写入。打开“修订编辑”模式,AI 的修改会记为成修订,这些修订与 Word 修订互通,可在 Word 中逐条通过或拒绝。
处理复杂格式配置专属命令包

对于一些特殊格式,我们专门做了相关的命令包,如公文生成。因为即便 AI 可正确操作编辑器,也并不意味着它可以正确理解某个标准。我们最初的想象是美好的,我认为 AI 可正确操作编辑器后,它就拥有了解锁一切文档格式的能力,理论上确实是这样。但实测下来,没有清晰的规则,AI 生成的内容仍需人工持续校对。它可能丢失红头,也可能划线不是红色,又或是字体设置某些地方会有遗漏。
因此,针对这种随意发挥,我们为编辑器增加了专属命令包以及 skill 。典型的场景就是公文,公文本身有 GB/T 9704—2012 标准要求,因此我们可以将标准封装为不同的命令,再配合公文模板 skill ,即可又快有准地生成公文。
下面是一份只有正文的通知草稿,一句话排成正式公文:红头、发文字号、红线、标题、版记都由程序按国标生成,模型只负责从草稿里整理出机关、标题、主送、正文层次和抄送这些内容。

Agent 工具确实不能贪多

通过自描述机制改造过后,其实它撞上的正是社区 Agent 工具设计的理念,Agent 工具设计不应该盲目球多。工具越多,Agent 反而越容易 “变蠢”,一套合理的机制才是让模型发挥最大价值的保障。
初版的做法是每个插件为 AI 声明注册一个工具,结果是正确性评测只有 48%,当工具数量过多时,模型在相似名称、重叠边界或参数结构相似的工具之间容易犹豫,会导致 “选择困难与误选率上升”。替换为自描述机制后,正确率上升到了 98% 以上,且唯一错误还只是因为输入描述有问题导致。
参考与使用

如果你也在给自己的编辑器做智能助手,可以参考 Quirekit 的解决方案是否对自己的产品有用,如果直接用 QuireKit ,那这些都已经做好了:

  • 对于 classic-editor ,我们有 @quirekit/classic-ai(目前暂时为商业包,但可在官网使用,只需配置自己的模型 key 即可),它通过侧边栏助手提供使用入口,并配备模型设置和技能库。
  • 我们也通过 MIT 开源了可以直接使用的 @quirekit/ai-runtime,它是  @quirekit/classic-ai 的底层核心,classic-ai 只是在其之上做了一层包装,将其封装为了可用成品。runtime 已包含 document_read、document_help 以及 document_edit 核心工具机制,任何人均可用它封装自己的 AI 助手。
  • 对于 Markdown 编辑器的,对应的是 @quirekit/md-editor-ai。
  • 针对 QuireKit 写插件,可参考 @quirekit/ai-contract 里的类型声明格式能力,开放给 AI 的命令用 defineCommand 包一层描述,AI 就能用上,不用写提示词。
除了 Classic AI ,其他 AI 相关的包最近都改成了 MIT 开源,已经发到 npm 的 alpha 版。接入文档在 https://docs.quirekit.com 。
后续也长路漫漫

回头看,我们花在模型身上的功夫其实并不多,大部分时间在给编辑器设计合理的工具与机制:让模型通过编辑器自己的命令操作文档,用一种机制让它知道有哪些能力和参数,程序能保证的结构不交给它,然后用评测盯着。这些都做好以后,其实一个便宜的快模型也就够了,目前大多数模型处理文档的能力都非常强了,文中三段演示用的都是 DeepSeek Flash V4.1 ,换成更强的模型结果也一样。虽然已经取得了一部分进展,但其实 AI 的坑目前还有很多,很多犄角旮旯的操作仍有限制,因此长路漫漫,优化仍在进行。
<hr>最后 QuireKit 是我在做的开源文档编辑器框架,有 Word 式的分页编辑器 Classic-editor 、块编辑器 Block-editor 和 Markdown 编辑器框架 MSFE 以及成品 md-editor ,Classic 和 MD Editor 用的是同一套 AI 核心。现在还是 alpha ,block-editor 也会是 classic 同一套,目前正在迁移适配。

  • 官网: https://quirekit.com
  • GitHub: https://github.com/quirekit/quirekit
<hr>本文首发并持续更新于 yishuai.wang。


⚠️内容来自互联网,如有侵权请点击反馈!侵权投诉
本帖共 1 条回复,登录后即可查看

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

hot.热文换一批
  1. 宇宙到底是大还是小?一张纸对折103次的厚度,宇宙已装不下
  2. 别眨眼!人类首次"看见"光子!你家灯泡里全是它!
  3. 人类至今无法彻底解释的15个顶级现象,看完敬畏万物
  4. 二十出头就显成熟?揭秘上一代人的"大人模样"背后原因
  5. 明明含有氢和氧,氢可燃氧助燃,为什么水偏偏不能燃烧?
  6. 🎉庆祝应用中心上架15个插件了,抽波优惠券![开奖时间:2026-04-26 20:00]
  7. 人类已发现外星生命?科学家:就在12亿公里外,可能以甲烷为食
  8. 又一个新游戏上线了,欢迎体验!
  9. 自来水微塑料3000万/升,煮沸后降到480万,比桶装水高还是低?
  10. 女装退货率飙至80%,商家为何挂密码锁发货?
  11. 现在这金价是不是还有余地
  12. 世界上最凶猛的10种鸟,金雕到底有多厉害?猎杀野狼轻而易举?
  13. 古人为何50岁就百病缠身?揭秘1972年7月30日“马王堆女尸”出土之谜
  14. 中国真挖到“宝”了!海水里藏45亿吨铀,美国70年难题被突破
  15. 太阳和银河系之间,还有一个神秘结构?
  16. 科学家:在人类出生前,有两种神秘的力量帮助构建了人脑
  17. 下潜到1万多米的海底,人类发现了不该出现的东西?需要引起警惕
  18. 🌱牛马论坛-每日早报-2026年10月08日
  19. 终于装上了LightSNS,然后模块一通买,还是花了上千
  20. 吃一块能顶一天?军用压缩饼干为啥抗饿?
  21. 小时候父母不让玩手机的秘密,网友亲测:经历过才懂!
  22. 牛马论坛[NIUMABBS]-行为规范准则
  23. [Day 21] - 10.26 - Tibo 又要重置了
  24. 测试
牛马论坛(niumabbs.com),一个专注于分享日常新鲜事、职场工作点滴、摸鱼乐趣与各类生活感悟的交流平台。

    关注我们

  • 加入Q群
  • 微信客服
  • QQ客服
Copyright © 2026 NIUMABBS 版权所有 All Rights Reserved. |网站地图 劰载中...
关灯 在本版发帖
扫一扫添加微信客服
QQ客服返回顶部
快速回复 返回顶部 返回列表