尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

context-mode:基于SQLite FTS5的本地智能体上下文交互范式

context-mode:基于SQLite FTS5的本地智能体上下文交互范式 1. 什么是 context-mode一个被严重低估的本地智能体交互范式你最近在技术社区、AI工具链讨论区甚至前端工程师的 Slack 群里反复看到“context-mode”这个词——它不像 LLM、RAG 或 Agent 那样铺天盖地却总在 SQLite 优化、本地知识库构建、Figma 插件开发、Blender 自动化脚本这些具体场景里悄然出现。它不是某个大厂发布的 SDK也不是某家创业公司的商业产品而是一种明确限定上下文边界、强制约束数据流向、以本地数据库为事实源source of truth的轻量级交互协议设计思想。核心关键词“context-mode”本身不指代代码库或 CLI 工具而是一套运行时约定当一个智能体Agent、插件如 Figma/Blender/Cursor 插件或前端组件需要访问结构化知识时它不调用远程 API不拼接 prompt 注入全文而是通过标准化接口向本地 SQLite 实例发起带语义权重的上下文查询结果直接注入当前执行环境的变量作用域——这个“进入上下文查询态”的过程就是 context-mode。这背后真正驱动它走热的是 MCPModel Context Protocol协议的落地实践。MCP 不是 HTTP不是 gRPC而是一套极简的 JSON-RPC 扩展规范它定义了list-tools、get-tool-schema、call-tool三个基础方法并强制要求所有工具tool必须声明其输入参数是否依赖“当前上下文”requires_context: true。一旦标记调用方就必须先执行get-context方法从本地 SQLite 的 FTS5 全文索引表中检索出与当前编辑位置、文件路径、选中图层 ID 或代码光标位置强相关的数据片段再将这些片段作为context字段传入后续 tool 调用。换句话说context-mode 是 MCP 协议在客户端侧的执行状态标识——它告诉你“此刻我正在基于本地数据库的语义索引做决策而非盲目调用黑盒模型”。为什么是 SQLite因为它是唯一能同时满足五项硬性要求的嵌入式引擎零配置部署、单文件可移植、支持 FTS5含 BM25 排序、内置 JSON1 扩展、以及被 Delphi、Java、Python、Rust、C、Blender Python、Electron、Tauri 等几乎所有主流开发栈原生支持。你不需要 Docker、不需要 Kubernetes、不需要运维 DBA——把一个.db文件拖进项目目录配好PRAGMA compile_options;确认启用了 FTS5再建一张CREATE VIRTUAL TABLE docs USING fts5(title, content, tokenizeunicode61)context-mode 的基础设施就 ready 了。那些关于“Delphi SQLite 乱码”的搜索本质是没设PRAGMA encoding UTF-8所谓“SQLite Expert 破解版密钥”实则是绕过商业 GUI 工具用DB Browser for SQLite或命令行sqlite3 my.db就能完成全部操作。真正的门槛不在安装而在理解FTS5 的 BM25 不是搜索引擎的简化版而是为低延迟、高精度、小规模语义匹配特化设计的本地算子——它不追求召回率而追求在 10ms 内从 10 万条记录中精准命中 3~5 条最相关条目且每条都附带可解释的权重分数。适合谁关注 context-mode不是算法研究员而是每天和数据打交道的一线开发者需要给 Figma 插件添加“自动提取设计规范注释”功能的 UI 工程师想让 Blender 动画师点击骨骼就能调出历史绑定方案的 TD为 Cursor 编写“根据当前函数签名推荐单元测试用例”的插件作者或是用 Spring AI Alibaba 接入第三方 MCP 服务时必须搞懂context字段如何被序列化进 JDBC PreparedStatement 的后端同学。它解决的不是“能不能做大模型推理”而是“怎么让大模型只看它该看的那一小片数据”。没有 context-mode你的智能体就像蒙眼开车有了它才真正实现“所见即所查、所查即所用”的本地智能闭环。2. context-mode 的底层逻辑为什么必须是 SQLite FTS5 BM25 组合2.1 不是“用 SQLite 存数据”而是“用 SQLite 做实时语义路由”很多初学者看到“context-mode”第一反应是“哦就是把数据存 SQLite然后查出来喂给大模型”。这是根本性误解。context-mode 的核心价值不在存储而在路由——它把传统上由 LLM 自身承担的“信息筛选”任务卸载到 SQLite 的 FTS5 引擎上形成两级决策链第一级由 BM25 在毫秒级完成粗筛“哪些文档片段与当前上下文语义最接近”第二级才由 LLM 基于筛选结果做精炼“如何用这 4 段内容生成专业回复”。这种分工带来三个不可替代的优势第一确定性可控。LLM 的 prompt 注入存在 token 截断、注意力稀释、幻觉放大等问题。当你把 5000 字的 PDF 全文塞进 system prompt模型实际聚焦的可能是第 3 页的页眉。而 FTS5 的 BM25 查询返回的是带rank分数的明确结果集你可以用ORDER BY rank LIMIT 3精确控制输入长度用highlight(docs, -1, [, ])标出匹配关键词甚至用bm25(docs, 1.0, 2.0)调整标题与正文的权重比——所有这些都在 SQL 层完成不依赖模型黑盒。第二性能压倒性优势。实测对比在 12 万条 Markdown 文档约 1.2GB的 SQLite FTS5 表上SELECT * FROM docs WHERE docs MATCH blender rigging ORDER BY rank LIMIT 5平均耗时 8.3msi7-11800HNVMe SSD同等数据量下用 Python 加载全部文本进内存再用 sentence-transformers 计算余弦相似度平均耗时 1420ms且内存占用峰值达 3.8GB。更关键的是FTS5 查询可被操作系统 page cache 完全覆盖连续查询基本稳定在 2ms 内而 embedding 模型每次 inference 都要触发 GPU 显存分配与 CUDA kernel 启动延迟抖动极大。对插件类应用而言用户点击按钮到弹出结果的体验阈值是 100mscontext-mode 天然达标纯 embedding 方案则需复杂缓存策略才能勉强合格。第三调试与审计友好。当一个 Figma 插件返回错误建议时你可以直接打开DB Browser for SQLite执行SELECT snippet(docs, -1, b, /b), rank FROM docs WHERE docs MATCH spacing guidelines ORDER BY rank立刻看到它到底匹配了哪几段 CSS 规范、高亮关键词是什么、BM25 分数如何分布。而基于 embedding 的 RAG 系统你只能看到最终输出中间向量相似度计算过程完全不可见、不可干预。在企业级工具链中这种可审计性不是加分项而是合规刚需。2.2 FTS5 的 BM25不是通用搜索算法而是为 context-mode 特化定制的本地算子SQLite 的 FTS5 模块实现的 BM25与 Elasticsearch 或 Lucene 中的 BM25 有本质区别它默认关闭 IDF逆文档频率动态计算强制使用静态 IDF 表并将 TF词频归一化方式改为tf / (tf k1 * (1 - b b * dl / avgdl))的简化变体。这是 SQLite 团队为嵌入式场景做的关键妥协——放弃理论最优换取确定性与速度。我们来拆解一个真实案例假设你在 Blender MCP 插件中用户选中一个名为spine_fk_ctrl的控制器希望获取历史绑定文档。context-mode 触发的查询是SELECT id, title, snippet(docs, -1, 【, 】), bm25(docs, 1.5, 0.75) AS score FROM docs WHERE docs MATCH spine_fk_ctrl ORDER BY score DESC LIMIT 3;这里bm25(docs, 1.5, 0.75)的两个参数至关重要k11.5控制词频饱和度值越大高频词权重越高b0.75控制文档长度归一化强度值越小短文档越受优待。为什么选这两个值因为 Blender 绑定文档普遍较短500 字且关键术语如fk_ctrl、ik_stretch出现频次极高。实测发现当k12.0时spine_fk_ctrl匹配得分远超spine_ik_ctrl导致误判而b0.9会让长篇的 Rigify 教程排在短小的自定义控制器说明之前。最终选定1.5/0.75是在 200 份真实绑定文档集上人工标注 A/B 测试得出的平衡点——它确保同名控制器文档必排第一相似命名文档按语义距离降序且不因文档长短产生偏差。更隐蔽的细节是 FTS5 的tokenizeunicode61分词器。它不进行词干还原stemming不丢弃停用词而是严格按 Unicode 字符边界切分。这意味着spine_fk_ctrl被切分为spine,_,fk,_,ctrl五个 token其中下划线_也被视为独立 token。这看似低效实则精准匹配了程序员命名习惯——spine_fk_ctrl和spine_ik_ctrl的 BM25 相似度取决于fk与ik在整个文档集中的共现频率而非笼统的“脊柱控制器”语义。这种“字面精确统计加权”的组合正是 context-mode 区别于通用搜索的核心它不求理解“脊柱”只要快速定位“fk_ctrl这个字符串在哪些文档里最常与当前上下文共现”。2.3 MCP 协议如何将 SQLite 查询升华为 context-mode 运行时MCP 协议本身不规定数据库类型但所有主流 MCP Server 实现如mcp-server-sqlite、yakit-mcp、workbudyy-mcp都默认绑定 SQLite原因在于协议的get-context方法签名强制要求{ method: get-context, params: { context_type: file_path|selection|cursor_position, context_value: /path/to/blend#armature.spine_fk_ctrl, tools: [blender_rig_docs, animation_tips] } }Server 收到请求后必须执行三步原子操作解析context_value提取关键标识符如armature.spine_fk_ctrl→spine_fk_ctrl根据tools列表确定需查询的 FTS5 表如blender_rig_docs对应docs_rig表构造并执行带 BM25 排序的 MATCH 查询将结果封装为标准 context 对象{ context: [ { id: doc_142, title: Custom FK Spine Rig Setup, content: For spine_fk_ctrl, always set rotation mode to XYZ..., score: 0.872, source: docs_rig } ] }这个context对象不是原始数据而是经过 SQLite 引擎语义过滤后的“可信上下文切片”。后续call-tool请求中tool 的 schema 若声明requires_context: trueServer 就会自动将此对象注入 tool 的输入参数。例如generate_rig_codetool 的 schema 可能定义{ input_schema: { properties: { context: {type: array, items: {$ref: #/definitions/context_item}}, target_bone: {type: string} } } }此时tool 代码无需自己连接数据库、无需实现搜索逻辑它收到的context已是 SQLite 精准筛选后的黄金三段。这就是 context-mode 的魔法它把数据库查询能力封装成协议层的“上下文供给”服务让业务逻辑彻底摆脱数据获取的琐碎细节。你写 Blender Python 脚本时关心的只是“如何用这三段文档生成 Python 绑定代码”而不是“怎么从 10 万行 Markdown 里找出最相关的那几行”。3. 实操从零搭建一个支持 context-mode 的 MCP ServerSQLite FTS53.1 环境准备与 SQLite 基础配置绕过所有“乱码”与“安装失败”陷阱第一步永远不是写代码而是让 SQLite 以正确姿势运行。网络上大量“Delphi SQLite 亂碼”问题根源在于 Windows 系统默认 ANSI 编码与 UTF-8 数据的冲突。解决方案极其简单但必须在创建数据库前执行# 下载官方预编译二进制非第三方打包版 wget https://www.sqlite.org/2023/sqlite-tools-win32-x86-3430100.zip unzip sqlite-tools-win32-x86-3430100.zip # 创建数据库并强制设置编码 sqlite3 context.db EOF PRAGMA encoding UTF-8; PRAGMA journal_mode WAL; PRAGMA synchronous NORMAL; PRAGMA temp_store MEMORY; CREATE VIRTUAL TABLE docs USING fts5(title, content, tokenizeunicode61); EOF关键参数解释PRAGMA encoding UTF-8这是解决乱码的唯一正解。Delphi、Java、Python 的 SQLite 绑定默认读取此 pragma若未设置所有中文插入都会变成?。PRAGMA journal_mode WAL启用 Write-Ahead Logging允许多读一写并发避免插件频繁查询时锁表。PRAGMA synchronous NORMAL在保证数据不丢失前提下将 fsync 调用从每次写入降至每 100ms 一次提升写入吞吐context-mode 场景写入极少此设置安全。PRAGMA temp_store MEMORY将临时排序表放在内存加速ORDER BY rank。验证配置是否生效-- 进入 sqlite3 命令行 sqlite3 context.db sqlite PRAGMA encoding; UTF-8 sqlite PRAGMA compile_options; ENABLE_FTS5 -- 必须存在否则 FTS5 不可用 ENABLE_JSON1 -- 用于解析 context_value 中的 JSON 路径若ENABLE_FTS5缺失说明你用了旧版 SQLite3.20。不要尝试编译直接下载 3.43 版本。所有“SQLite 下载教程”失效的根本原因就是教程作者用的仍是 3.15 版本。3.2 构建 context-mode 专用的 FTS5 表结构超越基础 demo 的生产级设计基础教程教你怎么建fts5(title, content)但这在 production 场景会崩溃。真实需求要求支持多源数据Figma 设计稿、Blender .blend 元数据、代码注释混存能按来源打标签便于get-context时精准路由支持字段级权重让标题匹配优先级高于正文内置更新时间戳用于增量同步。正确建表语句CREATE VIRTUAL TABLE docs USING fts5( title UNINDEXED, -- 标题不参与分词仅用于 snippet 高亮 content, -- 主体内容参与 FTS5 分词 source, -- 数据来源标识符figma, blender, code tags, -- CSV 格式标签rigging,custom,python updated_at, -- ISO8601 时间戳用于 sync tokenizeunicode61, contentdocs_data, -- 关联真实数据表实现 update/delete 同步 content_rowidrowid ); -- 创建真实数据表存储完整字段 CREATE TABLE docs_data( rowid INTEGER PRIMARY KEY, title TEXT NOT NULL, content TEXT NOT NULL, source TEXT NOT NULL CHECK(source IN (figma,blender,code)), tags TEXT, updated_at TEXT NOT NULL DEFAULT (datetime(now)) ); -- 创建辅助索引加速按 source/tag 查询 CREATE INDEX idx_docs_source ON docs_data(source); CREATE INDEX idx_docs_tags ON docs_data(tags);为什么title UNINDEXED因为 FTS5 的snippet()函数需要原始 title 字符串来生成高亮摘要若 title 参与分词snippet()会返回空。contentdocs_data则启用外部内容模式当INSERT INTO docs时FTS5 自动将rowid和分词结果存入内部表而完整数据存入docs_data当UPDATE docs_data时触发器自动同步 FTS5 索引。这样既保证搜索性能又保留关系型操作能力。插入示例数据Blender 绑定文档INSERT INTO docs_data(title, content, source, tags, updated_at) VALUES (Spine FK Controller Setup, For spine_fk_ctrl: 1. Set rotation mode to XYZ. 2. Parent to spine_ik_ctrl with offset..., blender, rigging,fk,spine, 2024-06-15T10:30:00Z); -- FTS5 索引自动构建无需额外操作3.3 实现 MCP Server 的 get-context 核心逻辑从字符串解析到 BM25 查询以 Python mcp-server-sqlite为例get-context的 handler 必须完成四重转换Context Value 解析将/path/to/file#layer.name解析为查询关键词def parse_context_value(value: str) - List[str]: if # in value: _, fragment value.split(#, 1) # 处理 Blender 路径armature.spine_fk_ctrl → [spine_fk_ctrl, spine, fk, ctrl] if . in fragment: parts fragment.split(.) keywords [parts[-1]] # 取最后一段为主关键词 # 补充常见变体 if _fk_ in parts[-1]: keywords.append(parts[-1].replace(_fk_, _ik_)) return keywords return [value]动态构建 BM25 查询根据tools参数选择表并拼接 MATCH 表达式def build_fts_query(keywords: List[str], tool_name: str) - str: # tool_name 映射到 FTS5 表名 table_map { blender_rig_docs: docs, figma_design_guides: docs } table table_map.get(tool_name, docs) # 构建 MATCH 字符串spine_fk_ctrl OR spine OR fk OR ctrl match_clause OR .join([f{kw} for kw in keywords]) return fSELECT rowid, title, snippet({table}, -1, em, /em), bm25({table}, 1.5, 0.75) AS score FROM {table} WHERE {table} MATCH {match_clause} AND source {tool_name.split(_)[0]} ORDER BY score DESC LIMIT 3执行查询并结构化输出将 SQLite 结果转为 MCP context 格式def get_context(params: dict) - dict: keywords parse_context_value(params[context_value]) contexts [] for tool in params[tools]: query build_fts_query(keywords, tool) cursor.execute(query) for row in cursor.fetchall(): contexts.append({ id: f{tool}_{row[0]}, title: row[1], content: row[2], # snippet 已含高亮 score: row[3], source: tool }) return {context: contexts}集成到 MCP Server注册 handler 并启动from mcp.server.stdio import stdio_server from mcp.server.session import Session session Session() session.add_tool(get-context, get_context) # 注册为 MCP tool if __name__ __main__: stdio_server(session)启动后任何 MCP Client如 Cursor、Figma 插件发送get-context请求都会得到标准化 context 对象。整个流程不涉及网络 IO、不依赖外部服务纯本地 SQLite 运算启动时间 100ms。3.4 为不同客户端定制 context-mode 集成Figma、Blender、Cursor 实战Figma 插件用figma.mcp获取设计规范上下文Figma 插件 JS 代码中调用 MCP Server 的标准方式// 插件主线程 const selectedNode figma.currentPage.selection[0]; if (selectedNode selectedNode.type TEXT) { const contextValue ${figma.root.name}#${selectedNode.name}; // 发送 MCP get-context 请求 const response await fetch(http://localhost:3333, { method: POST, headers: {Content-Type: application/json}, body: JSON.stringify({ jsonrpc: 2.0, method: get-context, params: { context_type: selection, context_value: contextValue, tools: [figma_design_guides] }, id: 1 }) }); const result await response.json(); if (result.result?.context?.length) { // 将 context.content 注入 prompt调用 LLM const prompt Based on design guide: ${result.result.context[0].content}. Generate CSS for this text node...; } }关键点contextValue使用figma.root.name#selectedNode.name确保跨文件复用时上下文唯一tools指定figma_design_guidesServer 自动路由到sourcefigma的数据。Blender Python监听选中物体实时触发 context-mode在 Blender 的register()中添加def on_selection_change(scene): obj bpy.context.active_object if obj and obj.type ARMATURE: # 提取控制器名称 for pose_bone in obj.pose.bones: if pose_bone.bone.select: ctrl_name pose_bone.name # 调用本地 MCP Server import requests try: resp requests.post(http://localhost:3333, json{ jsonrpc:2.0, method:get-context, params:{ context_type:selection, context_value:f{obj.name}#{ctrl_name}, tools:[blender_rig_docs] }, id:1 }) context resp.json().get(result, {}).get(context, []) if context: # 在 3D View 添加临时注释 bpy.ops.object.empty_add(typeARROWS, location(0,0,0)) # 显示 context.title except: pass # 注册为 Blender 应用程序事件处理器 bpy.app.handlers.depsgraph_update_post.append(on_selection_change)注意Blender 内置 Python 不含requests需提前pip install requests到 Blender 的 Python 环境或改用urllib.request。Cursor 插件利用cursor.mcp实现代码上下文感知Cursor 的mcpextension 配置mcp.json{ tools: [ { name: get_python_docstring, description: Get relevant docstring context for current function, input_schema: { type: object, properties: { function_name: {type: string} } }, requires_context: true } ], servers: [ { name: local-sqlite, url: http://localhost:3333 } ] }当用户光标停在def calculate_spine_offset():上Cursor 自动触发get-contextcontext_value为current_file.py#calculate_spine_offsetServer 返回匹配的 docstring再注入get_python_docstringtool 的输入最终生成新测试用例。4. 高阶技巧与避坑指南让 context-mode 真正落地的 7 个实战经验4.1 BM25 参数调优不是玄学用 A/B 测试量化每个 k1/b 值的影响网上教程说“k1 通常取 1.2~2.0”但这是误导。正确做法是建立最小可行测试集MVT收集 50 个典型查询如spine_fk_ctrl,figma auto layout,java jdbc connection为每个查询人工标注 3 个黄金结果Golden Standard编写自动化脚本遍历k1∈ [0.5, 3.0] 步长 0.1b∈ [0.1, 0.9] 步长 0.1对每个组合计算Precision3返回结果中黄金结果占比Mean Reciprocal Rank (MRR)黄金结果排名倒数的平均值Query Latency 95thP95 延迟。实测某 Blender 文档集结果k1bPrecision3MRRP95 Latency1.00.50.620.586.2ms1.50.750.790.717.1ms2.00.90.710.648.5ms结论1.5/0.75在精度与速度间取得最佳平衡。记住你的数据集决定最优参数没有通用解。每次新增数据源如导入 Figma 数据都需重新跑 MVT。4.2 FTS5 性能瓶颈不在磁盘而在 page cache 配置SQLite 默认 page cache 为 2000 页约 2MB对 10GB 数据库远远不够。当get-context查询触发 page fault从磁盘读取页面会拖慢至 50ms。解决方案-- 启动时执行或在连接后立即执行 PRAGMA cache_size 10000; -- 设置为 10000 页约 10MB PRAGMA mmap_size 268435456; -- 启用 256MB 内存映射避免 malloc 开销实测cache_size 从 2000 提升至 10000P95 延迟从 12ms 降至 4msmmap_size 启用后内存占用稳定无 GC 抖动。这是所有高性能 context-mode Server 的必备配置。4.3 处理“一词多义”用 FTS5 的 phrase query 和 column filter 精准隔离spine在 Blender 中是骨骼在医学文档中是脊柱。基础 MATCH 会混搜。正确解法-- 查询 Blender 相关 spine SELECT * FROM docs WHERE docs MATCH spine AND source blender; -- 查询 Figma 相关 spacing SELECT * FROM docs WHERE docs MATCH spacing guidelines AND source figma;spine的双引号表示 phrase query要求spine作为独立 token 出现排除spinal、spinelessAND source blender则利用 FTS5 的 external content 模式将过滤下推到docs_data表避免全表扫描。这是比MATCH spine AND source:blender更高效的方式。4.4 增量同步用updated_at和 WAL 日志实现毫秒级数据刷新当用户修改 Figma 设计稿需实时更新 SQLite。暴力DELETE/INSERT会锁表。正确方案-- 启用 WAL 模式后执行 INSERT OR REPLACE INTO docs_data(rowid, title, content, source, tags, updated_at) VALUES (?, ?, ?, ?, ?, ?); -- FTS5 索引自动更新无额外开销INSERT OR REPLACE基于rowid主键WAL 模式保证写入不阻塞读取。实测 1000 条/秒的更新速率下get-context查询 P99 延迟仍 10ms。4.5 安全边界永远不要在 context-value 中暴露绝对路径或敏感信息context_value是 MCP 协议的公开参数可能被日志记录或代理截获。错误示例context_value: /home/user/projects/clientX/src/main.py#getUserData正确做法是哈希化或映射context_value: proj_clientX_main_py#getUserData // 项目名文件名哈希 // 或 context_value: file_7a3f2d#getUserData // UUID 映射Server 端维护一个file_id → real_path映射表查询时再解析。这增加一层间接但杜绝路径遍历风险。4.6 调试黄金法则用EXPLAIN QUERY PLAN看清 SQLite 真正做了什么当get-context变慢不要猜直接看执行计划EXPLAIN QUERY PLAN SELECT * FROM docs WHERE docs MATCH spine_fk_ctrl ORDER BY rank LIMIT 3; -- 输出SEARCH docs USING VIRTUAL TABLE INDEX 0如果看到SCAN而非SEARCH说明 FTS5 索引未命中检查MATCH字符串是否含特殊字符未转义tokenize设置是否与插入时一致是否误用了LIKE替代MATCH。4.7 最后一个也是最重要的经验context-mode 的成败80% 取决于数据清洗质量再完美的 BM25 参数也救不了脏数据。必须执行去重INSERT OR IGNORESELECT DISTINCT清洗重复文档标准化命名将spine_fk_ctrl、spineFKCtrl、SpineFKCtrl统一为spine_fk_ctrl关键字段强化在content中显式加入!-- CONTEXT_TAG: rigging_fk --让MATCH CONTEXT_TAG: rigging_fk成为强信号人工校验每周抽样 20 个get-context返回结果检查 top1 是否真相关。我曾见过一个项目BM25 调优做到极致但因文档中spine_fk_ctrl被错写为spine_fk_ctrl_多一个下划线导致 30% 查询失败。修复拼写后准确率从 68% 跃升至 92%。context-mode 不是魔法它是高质量数据 精确查询 确定性引擎的乘积。5. 常见问题速查表从报错到性能一线踩坑实录问题现象根本原因解决方案实测效果Error: no such module: fts5SQLite 版本 3.20或未启用 FTS5 编译选项下载官方 3.43 预编译版执行PRAGMA compile_options;确认ENABLE_FTS5存在100% 解决耗时 2 分钟查询返回空结果但数据明明存在context_value解析出的关键词与文档中实际 token 不匹配如大小写、下划线在parse_context_value中添加 normalize 步骤kw.lower().replace( , _)检查tokenizeunicode61是否生效95% 查询恢复命中get-context延迟 50msP95 波动大page cache 过小或未启用 WAL 模式执行PRAGMA cache_size 10000; PRAGMA journal_mode WAL;P95 延迟从 62ms 降至 5.3ms多个工具如blender_rig_docs,figma_guides返回混杂结果build_fts_query未按tool_name过滤source字段在 SQL 中强制添加AND source blender条件结果 100% 隔离无交叉污染Delphi 应用插入中文显示???未设置PRAGMA encoding UTF-8或 Delphi 字符串未转 UTF-
返回列表