1. 项目概述Context-Mode 不是玄学而是可落地的上下文感知架构范式“Context-mode”这个词最近在开发者社区里频繁冒头尤其和 MCP、SQLite、FTS5、BM25 这些词绑在一起出现——它既不是某个新发布的开源库名也不是某家大厂刚注册的商标而是一种正在被一线工程团队反复验证、逐步沉淀下来的上下文驱动型系统设计思路。我过去三年带过六个跨端智能体项目从 Figma 插件到工业 SCADA 数据桥接凡是最终跑得稳、迭代快、调试不抓狂的底层都悄悄用了 context-mode 的核心逻辑。它解决的不是“能不能查到数据”这种基础问题而是“在当前用户操作路径、当前界面焦点、当前设备能力、当前网络状态这四重约束下该优先加载哪条数据、该触发哪个技能、该用哪种检索策略、该返回多深的上下文片段”这类动态决策问题。关键词里的MCPModel-Controller-Protocol是它的骨架SQLite FTS5是它的本地神经突触BM25是它判断信息相关性的直觉三者合起来才构成一个真正能“懂你此刻在想什么”的轻量级智能体底座。它特别适合那些不想堆大模型、但又厌倦了写一堆 if-else 判断当前页面状态的中后台工具开发者也适合硬件资源受限但需要快速响应的边缘设备场景比如 Kingscada 连接 SQLite 做本地缓存时加一层 context-mode 就能让历史报警查询从“等三秒”变成“点完就出”。这不是给简历镀金的概念包装而是我在蓝湖 MCP 插件里实测把 Figma 画布缩放图层选中时间轴位置这三项状态编码进 context key 后技能调用准确率从 68% 提升到 92% 的真实经验。2. 核心设计逻辑为什么必须放弃“全局状态”转向“上下文切片”2.1 传统 MCP 架构的隐性瓶颈控制器成了状态黑洞先说清楚我们到底在优化什么。标准的 MCP 模式里“Model”管数据“Controller”管逻辑“Protocol”管通信——听起来很美。但实际一上手就会发现Controller 很快变成一个塞满各种if (currentView canvas)、if (isMobile hasNetwork)的巨型 switch 语句。我去年帮一家做 MasterGo 插件的团队重构时他们 Controller 文件已经膨胀到 2300 行光是判断“用户此刻是否在编辑文本图层且光标在第 3 行”这个条件就嵌套了四层 if。问题根源在于传统 MCP 把“上下文”当成需要被 Controller 主动读取的被动变量而不是驱动整个流程的主动信号源。结果就是 Controller 越写越胖每次新增一个功能都要去翻旧逻辑生怕改崩了某个隐藏分支。更麻烦的是这种设计让“状态同步”变成噩梦——Figma 插件里画布缩放比例变了Controller 要通知 Model 更新缩略图缓存再通知 Protocol 重发尺寸参数中间任何一环掉链子UI 就卡在旧状态。context-mode 的破局点就是把“当前上下文”从被读取的对象变成唯一可信的单一事实源Single Source of Truth所有模块只认 context key不认全局变量。2.2 Context-Mode 的三层切片机制Key → Scope → Payload真正的 context-mode 实现核心是建立一套可穷举、可组合、可版本化的上下文切片体系。它不是简单地把当前 URL 或窗口标题当 context而是分三层结构化表达Key 层标识层由固定前缀 动态维度拼成例如mcp:figma:canvas:zoom1.5layerselectedcursorline3。这里的关键是“固定前缀”——mcp:figma:表明这是 Figma 场景下的 MCP 协议上下文canvas:表明作用域是画布而非图层面板。前缀决定了后续解析器和处理器的路由规则避免不同插件的 context key 冲突。Scope 层作用域层定义该 context 影响的边界。比如scopelocal表示只影响当前插件实例scopeworkspace表示影响整个 Figma 工作区scopeteam表示跨团队同步。我们在 Cursor 开发推荐 Skill 时就用scopeworkspace让 AI 推荐的代码片段自动适配当前工作区已安装的 LSP 插件列表而不是硬编码一堆 if 判断。Payload 层载荷层这才是真正携带业务语义的部分。它必须是结构化 JSON且字段名遵循统一规范。比如{zoom:1.5,layer_id:layer_abc,cursor:{line:3,column:12}}。重点来了Payload 字段必须全部可索引、可模糊匹配、可范围查询——这正是后面 SQLite FTS5 和 BM25 发挥作用的地方。我们不用{state:zoomed_in}这种字符串枚举因为没法做数值比较也不用{props:{...}}这种 JSON 字符串因为没法直接 SQL 查询。Payload 就是干净的键值对为后续检索留足空间。提示Key 层必须保证 URL 安全只含字母、数字、下划线、连字符避免?/等符号引发解析歧义。我们内部约定用替代:做键值分隔用替代,做字段分隔这样可以直接塞进 HTTP Header 的X-Context-Key字段里不用额外 Base64 编码。2.3 为什么 SQLite FTS5 是 context-mode 的黄金搭档很多人看到 context-mode 就想到 Redis 或内存 Map但实际项目里SQLite 才是更优解。原因很实在第一Figma/MasterGo/Cursor 这些桌面应用的插件运行环境根本没权限开 TCP 端口连外部 Redis但 SQLite 的.db文件就躺在插件沙盒目录里零配置第二context key 的生命周期天然适合本地持久化——用户关闭 Figma下次打开时我们希望自动恢复到上次的画布缩放和图层选中状态而不是重置为默认值。这时候 SQLite 的 ACID 事务就比内存 Map 可靠得多。但普通 SQLite 的LIKE %xxx%模糊查询太慢根本扛不住高频 context 匹配。FTS5 就是为此而生的。它本质是 SQLite 内置的全文搜索引擎支持倒排索引、词干提取、短语匹配。我们把 context key 的 Key 层和 Payload 层内容分别存进两个 FTS5 虚拟表-- 存储 context key 字符串本身用于精确匹配和前缀搜索 CREATE VIRTUAL TABLE context_keys USING fts5(key TEXT, scope TEXT); -- 存储 payload 的扁平化字段用于 BM25 相关性排序 CREATE VIRTUAL TABLE context_payloads USING fts5( zoom REAL, layer_id TEXT, cursor_line INTEGER, cursor_column INTEGER, contentcontext_data, content_rowidid );关键技巧在于payload 表不存原始 JSON而是把每个字段单独建列并标注数据类型。这样 FTS5 才能对zoom做数值范围查询zoom 1.2 AND zoom 2.0对cursor_line做整数比较cursor_line 3同时保留全文检索能力layer_id MATCH text*。我们测试过在 50 万条 context 记录下SELECT * FROM context_payloads WHERE zoom 1.5 AND layer_id MATCH title ORDER BY rank的平均响应时间是 17ms完全满足插件实时交互需求。2.4 BM25 如何让 context 匹配从“能用”升级到“懂你”FTS5 提供了基础检索能力但 context-mode 的灵魂在于“相关性”。比如用户在 Figma 里缩放画布到 1.8 倍同时选中了一个名为 “Header_Title” 的图层此时系统要匹配最合适的 Skill——是调用“文字样式批量修改”还是“图层导出为 SVG”还是“生成设计说明文案”如果只用zoom1.8 AND layer_idHeader_Title这种精确匹配那只能返回预设的几条规则毫无泛化能力。BM25 就是解决这个问题的它根据词频TF、逆文档频率IDF、字段长度归一化三个因子动态计算每条 context 记录与当前 query 的相关度得分。具体到我们的实现query 就是当前 context key 的 Key 层字符串如mcp:figma:canvas:zoom1.8layerHeader_Title而 FTS5 的rank列默认就是 BM25 算法计算出的相关度分数。但直接用默认 rank 会有偏差——zoom1.8这种数值型字段在 BM25 里和layerHeader_Title这种字符串型字段权重一样显然不合理。我们的解决方案是在插入 context 记录时对不同字段赋予不同 boost 权重-- 插入时对 layer_id 字段加权 3 倍zoom 字段加权 1.5 倍 INSERT INTO context_payloads(rowid, zoom, layer_id, cursor_line) VALUES (1, 1.8, Header_Title, 3); -- 然后在查询时用 FTS5 的 bm25 函数显式指定权重 SELECT id, bm25(context_payloads, 1.5, 3.0, 1.0) AS score FROM context_payloads WHERE zoom 1.5 AND layer_id MATCH Header* ORDER BY score DESC LIMIT 5;这个bm25(..., 1.5, 3.0, 1.0)里的三个数字分别对应zoom、layer_id、cursor_line字段的权重系数。实测下来把layer_id权重设为 3.0 后当用户选中 “User_Profile” 图层时“生成用户画像描述文案” 这个 Skill 的匹配得分会显著高于“调整图层透明度”因为前者在训练数据里layer_id字段与文案类 Skill 的关联强度更高。这就是 BM25 带来的“语义理解”感——它不依赖大模型只靠本地数据分布和字段权重就能让系统表现出“懂你意图”的效果。3. 实操落地从零搭建 context-mode 核心模块3.1 环境准备与 SQLite 配置绕过 Windows 下的乱码雷区很多开发者卡在第一步Windows 下 SQLite 中文乱码。这不是 SQLite 的锅而是 Windows 控制台默认编码GBK和 SQLite 内部 UTF-8 的冲突。Delphi SQLite 乱码、Java 连接 SQLite 乱码根子都在这儿。解决方案必须一步到位下载官方预编译二进制别用包管理器装的 SQLite。去 sqlite.org/download.html 下载sqlite-tools-win32-x86-*.zip解压后得到sqlite3.exe。这个官方版本强制使用 UTF-8不会受系统区域设置影响。创建数据库时指定编码用命令行执行sqlite3.exe context.db PRAGMA encoding UTF-8;注意PRAGMA encoding必须在建表前执行且只对新数据库生效。已有数据库需导出为 SQL 文本再用sqlite3 context_new.db dump.sql重建。FTS5 表的特殊处理FTS5 虚拟表不继承主数据库的 encoding 设置必须在建表时显式声明CREATE VIRTUAL TABLE context_keys USING fts5( key TEXT, scope TEXT, tokenizeunicode61 remove_diacritics 1 );关键是tokenizeunicode61 remove_diacritics 1—— 这启用了 Unicode 分词器并移除变音符号比如把café当作cafe索引确保中文、英文、带符号的拉丁文都能正确分词。我们测试过没有这行layer_id里存用户头像用MATCH 用户*就查不到。注意DB Browser for SQLite 这类图形工具在 Windows 下默认用系统编码读取文件打开 UTF-8 数据库时会显示乱码。解决方案是在 DB Browser 的File → Open Database对话框里勾选Open with encoding并选择UTF-8。或者更干脆全程用sqlite3.exe命令行操作避免 GUI 工具的编码陷阱。3.2 Context Key 生成器用正则和模板引擎控制爆炸式增长context key 看似简单但一旦项目变大手动拼接mcp:figma:canvas:zoom1.5layerselected这种字符串很快就会失控。我们的方案是用 JSON Schema 定义 context 结构用 Mustache 模板生成 key。首先定义一个context_schema.json{ type: object, properties: { platform: {enum: [figma, mastergo, cursor]}, domain: {enum: [canvas, layers, assets]}, state: { type: object, properties: { zoom: {type: number}, layer_id: {type: string}, cursor_line: {type: integer} } } } }然后用一个轻量级模板key_template.txtmcp:{{platform}}:{{domain}}:{{#state}}zoom{{zoom}}layer{{layer_id}}cursorline{{cursor_line}}{{/state}}最后用 JavaScript或 Python写一个生成器function generateContextKey(schema, state) { // 1. 校验 state 是否符合 schema用 ajv 库 const valid validator.validate(schema, state); if (!valid) throw new Error(Invalid context state: ${validator.errorsText()}); // 2. 渲染模板用 mustache.js const template fs.readFileSync(key_template.txt, utf8); const key Mustache.render(template, { ...state, platform: figma, domain: canvas }); // 3. URL 安全化替换空格、斜杠等 return key.replace(/[^a-zA-Z0-9_\-]/g, _); } // 调用generateContextKey(schema, {zoom: 1.5, layer_id: Header_Title, cursor_line: 3}) // 输出mcp:figma:canvas:zoom1.5layerHeader_Titlecursorline3这个方案的好处是Schema 是唯一真相源。前端改了 UI 状态字段只要更新 schema所有生成器、校验器、数据库迁移脚本都自动同步。我们曾用这套机制在三天内把蓝湖 MCP 插件的 context key 从 12 种扩展到 47 种零线上事故。3.3 FTS5 索引优化让百万级 context 查询保持毫秒级FTS5 默认配置在大数据量下会变慢。我们在 Kingscada 连接 SQLite 做本地报警日志 context 管理时遇到过 200 万条记录下查询延迟飙升到 800ms 的问题。通过以下四步优化压到了 23ms启用自动合并AutomergeFTS5 的 segment 机制会把写入分成小块定期合并。默认合并阈值太低导致查询要扫太多 segment。执行INSERT INTO context_payloads(context_payloads) VALUES(automerge16); -- 16 表示当有 16 个 segment 时触发合并比默认的 4 更激进禁用不必要的分词器如果 payload 字段全是数值如zoom,cursor_line它们不需要分词只需精确匹配。在建表时对这些字段用unindexedCREATE VIRTUAL TABLE context_payloads USING fts5( zoom REAL UNINDEXED, -- 不建倒排索引只存原始值 layer_id TEXT, -- 需要全文检索 cursor_line INTEGER UNINDEXED, contentcontext_data, content_rowidid );为高频查询字段建普通 B-tree 索引FTS5 擅长全文但不擅长范围查询。对zoom这种常用来BETWEEN的字段额外建索引CREATE INDEX idx_zoom ON context_data(zoom); -- 注意context_data 是真实的主表context_payloads 是它的 FTS5 虚拟表查询时用ORDER BY rank强制走 BM25 排序不要用ORDER BY id或ORDER BY zoom那会让 SQLite 放弃 FTS5 的优化路径。必须显式写ORDER BY rank才能触发 BM25 相关性计算。我们把这四步写成一个optimize_fts5.sql脚本每次数据库初始化时自动执行。实测在 150 万条 context 记录下SELECT * FROM context_payloads WHERE layer_id MATCH header* AND zoom 1.2 ORDER BY rank LIMIT 10的 P95 延迟稳定在 18~25ms。3.4 BM25 权重调优用 A/B 测试找到业务最优解BM25 的字段权重不是拍脑袋定的。我们在 Figma 插件里做了为期两周的 A/B 测试对照组用默认权重全 1.0实验组按业务逻辑设权重layer_id:3.0,zoom:1.5,cursor_line:1.0统计用户点击 Skill 的准确率。测试方法很土但有效在插件里埋点记录每次 context 匹配后用户实际点击了返回列表中的第几个 Skill。如果点击的是第一个算“精准匹配”点击第二或第三个算“次优匹配”点击第四及以后算“匹配失败”。结果如下权重配置精准匹配率次优匹配率匹配失败率平均点击位置全 1.0默认41%33%26%2.8layer_id:3.0, zoom:1.572%21%7%1.3数据说明layer_id字段对 Skill 选择的决定性远超其他字段。进一步分析发现当layer_id包含text、title、label这类关键词时“生成文案”类 Skill 的点击率高达 89%而当layer_id是icon、avatar时“图标导出”类 Skill 点击率是 82%。于是我们把权重策略升级为动态权重在生成 context key 时根据layer_id的内容自动计算 boost 值def calculate_layer_boost(layer_id): text_keywords [text, title, label, heading] icon_keywords [icon, avatar, logo, profile] if any(kw in layer_id.lower() for kw in text_keywords): return 4.0 elif any(kw in layer_id.lower() for kw in icon_keywords): return 3.5 else: return 2.0 # 插入时动态传入 boost calculate_layer_boost(User_Title_Header) cursor.execute( INSERT INTO context_payloads(rowid, zoom, layer_id, cursor_line) VALUES (?, ?, ?, ?), (rowid, 1.8, User_Title_Header, 3) ) # 查询时用这个 boost score_sql fSELECT id, bm25(context_payloads, 1.5, {boost}, 1.0) AS score ...这个动态权重上线后精准匹配率又提升了 9 个百分点达到 81%。这证明 context-mode 的威力不在于技术多炫而在于把业务知识编码进权重规则里。4. 典型场景实战从 Figma 插件到工业 SCADA 的 context-mode 落地4.1 Figma 插件用 context-mode 实现“所见即所得”的 Skill 推荐Figma 插件开发最头疼的是用户操作太自由——可能在画布上拖拽可能在图层面板里右键可能在属性面板调字体大小。传统做法是监听几十个事件再写一堆 if 判断当前焦点在哪。context-mode 的解法是把每一次用户操作都翻译成 context key 的变更。具体步骤监听核心事件流用 Figma API 监听onSelectionChange选中变化、onViewportChange视口缩放、onNodeChange节点属性变更。聚合状态生成 context key不是每个事件都立刻生成新 key而是用防抖debounce聚合 300ms 内的所有变更生成一个综合 key。例如用户快速缩放选中图层修改字体最终只生成一个 keymcp:figma:canvas:zoom1.8layerUser_Titlefont_size16。查询并渲染 Skill 列表用这个 key 查询 FTS5 表按 BM25 得分排序取前 5 条渲染成侧边栏按钮。每个 Skill 的payload里存着action_type如export、generate_text和params如{format: svg, scale: 2}。Skill 执行时回传 context当用户点击“导出为 SVG”Skill 执行后主动调用setContext({action: export_success, format: svg})这个新 context 会被存入数据库成为下一次匹配的训练数据。我们上线这个方案后用户从打开插件到完成导出的平均操作步数从 7 步降到 3 步。最关键的是插件不再需要预判所有可能的用户路径——只要 context key 覆盖了足够多的状态组合Skill 就能自动涌现。比如新增一个“一键适配暗色模式”的 Skill只需在数据库里插入一条layer_id MATCH header AND zoom 1.0的 context 记录无需改一行插件代码。4.2 工业 SCADAKingscada 连接 SQLite 做本地 context 缓存Kingscada 是国内主流的工业监控软件但它连接远程数据库如 SQL Server时网络抖动会导致画面刷新卡顿。客户要求“报警弹窗必须在 200ms 内显示不管网络好不好”。context-mode 的解法是把报警规则、设备状态、用户权限全部编码成 context存在本地 SQLite 里用 FTS5 实时匹配。实施细节Context 结构设计kingscada:alarm:devicePLC_A1levelcriticaluser_roleadmin数据同步机制Kingscada 的 OPC UA 服务端每 5 秒把当前所有报警状态推送到一个本地 HTTP 接口接口收到后解析 JSON生成 context key并插入 SQLite。FTS5 表优化device字段用UNINDEXED因为总是精确匹配level字段用TEXT并建 FTS5 索引支持critical*模糊匹配user_role字段用TEXT并加权 2.0管理员能看到更多报警。查询逻辑当操作员点击“查看当前报警”前端不查远程库而是执行SELECT * FROM alarm_contexts WHERE device MATCH PLC_A1 AND level MATCH critical ORDER BY bm25(alarm_contexts, 1.0, 2.0, 2.0) DESC LIMIT 10;因为所有数据都在本地P99 延迟稳定在 12ms。这个方案上线后客户反馈“以前网络不好时报警弹窗要等 3~5 秒现在点了就出来跟本地程序一样快。” 更重要的是context-mode 让权限控制变得极其灵活——以前要改 Kingscada 的 C 权限模块现在只需在 SQLite 里增删几条user_roleoperator的 context 记录重启服务即可生效。4.3 Cursor / VS Code 插件用 context-mode 做 AI 编程助手的“上下文感知”Cursor 和 VS Code 的 AI 编程助手如 Claude Code最大的痛点是“不知道你此刻在写什么”。它看到的是一整段代码但用户真正关心的可能是当前光标所在的函数、当前文件的框架类型、当前 Git 分支的特性名。context-mode 的解法是把 IDE 的编辑状态实时编码成 context key喂给 AI Skill。我们为 Cursor 开发的 MCP 服务context key 长这样mcp:cursor:editor:filesrc/api/user.tslangtypescriptcursor_funcgetUserProfilegit_branchfeat/auth关键实现文件语言识别用vscode.languages.getLanguages()获取当前文件后缀映射到lang字段。函数名提取用 Tree-sitter 解析 TypeScript AST定位光标所在节点向上遍历直到找到FunctionDeclaration取其name.text。Git 分支获取调用git rev-parse --abbrev-ref HEAD命令结果存入git_branch。AI Skill 调用当用户按快捷键触发 AI 时不传整段文件而是传这个 context key。后端 MCP Server 根据 key 查询 FTS5匹配到langtypescript且cursor_func包含get的 Skill如“生成 TypeScript 接口定义”再把file对应的代码片段作为 prompt 的 context 部分发送给大模型。效果非常直观以前用户要手动选中getUserProfile函数再右键选“生成接口”现在光标停在函数名上按CtrlShiftIAI 就直接输出interface UserProfile {...}。因为 context key 已经告诉系统“用户此刻在 TypeScript 文件里光标在 get 开头的函数上”AI Skill 就能精准触发而不是泛泛地“分析代码”。5. 常见问题与避坑指南那些只有踩过才知道的细节5.1 问题速查表高频报错与根因定位现象可能原因排查命令解决方案Error: no such module: fts5SQLite 版本太低 3.22或未启用 FTS5sqlite3 --versionsqlite3 context.db PRAGMA compile_options;下载最新版 SQLite或编译时加-DSQLITE_ENABLE_FTS5FTS5 查询返回空但数据明明存在MATCH查询的字段未建索引或用了UNINDEXEDPRAGMA table_info(context_payloads);查看字段属性确保被MATCH的字段是TEXT类型且未标记UNINDEXEDBM25rank得分全为 0查询条件过于宽泛或字段值为空SELECT * FROM context_payloads WHERE layer_id IS NOT NULL LIMIT 5;检查插入数据时layer_id等关键字段是否为NULL或空字符串Windows 下插入中文后查询不到数据库编码非 UTF-8或客户端连接时未指定编码sqlite3 context.db PRAGMA encoding;重建数据库执行PRAGMA encoding UTF-8插入前用sqlite3.context_db .encoding UTF-8context key 变更太频繁SQLite 写入压力大防抖时间太短或监听了过多细粒度事件在事件监听器里加console.time(context_update)将防抖时间从 100ms 提高到 300ms合并onSelectionChange和onViewportChange5.2 实操心得来自产线的 5 条血泪经验永远不要在 context key 里存敏感信息曾经有团队把用户邮箱、API Key 编进mcp:cursor:editor:user_emailjohnxxx.com结果日志上报时泄露了。正确做法是key 里只存脱敏 ID如user_idusr_abc123详细信息查数据库关联表。FTS5 的content表必须是真实存在的普通表很多人以为contentcontext_data是虚拟表名其实context_data必须是提前建好的普通表且结构要和 FTS5 表字段一一对应。否则插入数据时会静默失败。BM25 权重不是越高越好我们试过把layer_id权重设到 10.0结果发现匹配结果过于集中丢失了“缩放级别”带来的差异化。最终定稿是layer_id:3.0、zoom:1.5、cursor_line:1.0这个比例在 12 个不同项目里都表现稳健。SQLite 的 WAL 模式必须开启context-mode 的写入是高频的每秒可能几次默认的 DELETE 模式会导致写锁阻塞读。执行PRAGMA journal_mode WAL;后读写可以并发性能提升 3 倍。context key 的版本管理比代码还重要我们用 Git 管理context_schema.json每次新增字段都打 tag如context-v2.1并在数据库里加schema_version字段。这样老版本插件读新数据库时能优雅降级而不是直接崩溃。5.3 性能压测实录100 万 context 记录下的真实表现我们用真实业务数据做了压测模拟 Figma 插件 3 个月产生的 context 记录共 98.7 万条在一台 2018 款 MacBook Pro16GB RAMSSD上测试写入性能单线程连续插入平均 1200 条/秒。开启 WAL 模式后提升到 2100 条/秒。查询性能P95 延迟精确匹配key xxx0.8msFTS5 全文匹配layer_id MATCH user*14ms复合查询layer_id MATCH user* AND zoom 1.2 ORDER BY rank22ms磁盘占用98.7 万条记录数据库文件大小 142MB。其中 FTS5 索引占 89MB主表数据占 53MB。结论很明确SQLite FTS5 完全能胜任百万级 context 的实时匹配瓶颈不在数据库而在你的 context key 设计是否合理。如果 key 里塞了 50 个字段每个字段都建 FTS5 索引那性能肯定崩。我们的经验是核心匹配字段控制在 5 个以内其余字段用UNINDEXED或存进普通表关联查询。6. 进阶思考context-mode 如何与大模型协同而非替代6.1 明确分工context-mode 做“决策”大模型做“生成”很多人误以为 context-mode 是要取代大模型。恰恰相反它是大模型的“最佳拍档”。我的理解是context-mode 解决“该做什么”大模型解决“怎么做”。比如在 Figma 插件里用户选中一个图层context-mode 根据layer_id和zoom匹配出 Skill“生成设计说明文案”决策这个 Skill 的执行逻辑是调用大模型 API把图层截图、图层名称、当前画布缩放比例作为 prompt 的 context 部分让大模型生成文案生成。如果没有 context-mode大模型就得自己从海量图层中判断“用户此刻最可能想生成文案”准确率很低有了 context-mode大模型只需要专注把“文案”这件事做好效率和质量都大幅提升。6.2 用 context 数据反哺大模型微调context-mode 产生的海量匹配日志是极佳的微调数据源。我们收集了 6 个月的 Figma 插件日志context_key用户最终点击的 Skill ID点击耗时。清洗后得到 23 万条高质量样本格式如下{ input: mcp:figma:canvas:zoom1.5layerHeader_Titlecursorline3, output: generate_design_doc, reward: 0.9
