实现指南:基于 SQLite FTS5 的数据库元数据与 LLM 产物检索)
后端数据库负载均衡【免费下载链接】proxysqlHigh-performance proxy for MySQL and PostgreSQL项目地址https://gitcode.com/gh_mirrors/pr/proxysql点击查看免费下载导读本文深入剖析 ProxySQL MCPModel Context Protocol插件中基于 SQLite FTS5 扩展的全文检索Full Text Search, FTS能力介绍其如何让 AI Agent 在mcp_catalog.db中发现式 SchemaDiscovery Schema内快速检索索引化的数据库元数据与 LLM 生成产物。读完本文你将掌握fts_objects与fts_llm两张 FTS5 虚拟表的建表与索引策略、catalog_search与llm.search两个 MCP 工具的调用方式与返回结构以及从静态采集到全文索引重建的完整实现链路。该功能当前状态为IMPLEMENTED已实现并通过测试。一、功能背景与设计需求ProxySQL MCP 的 Discovery 子系统负责对 MySQL / PostgreSQL 目标实例进行元数据采集Harvest并将采集结果沉淀到 SQLite 数据库mcp_catalog.db中。随着库表、列、外键、视图定义与 LLM 生成的 question template、note 等产物不断累积Agent 需要一种比精确 SQL 匹配更快、更灵活的检索手段——即全文检索。关联文档 FTS_Implementation_Plan.md 明确了该系统的五条核心需求它们直接决定了后续的架构选型索引策略支持可选的 WHERE 过滤条件不采用增量更新重索引时全量重建full rebuild on reindex检索范围由 Agent 自行决定是单表检索还是跨表检索存储所有行全部建立索引不做数量限制目录集成FTS 与 catalog 交叉引用——Agent 先用 FTS 拿到 Top N 的对象 ID再回查真实数据库获取详情使用场景FTS 只是 Agent 工具包中的一员与catalog_get_object、run_sql_readonly等工具配合使用。二、整体架构与组件分层MCP Query Endpoint ↓ Query_Tool_Handler (routes tool calls) ↓ Discovery_Schema (manages FTS database) ↓ SQLite FTS5 (mcp_catalog.db)MCP Query Endpoint接收 MCP 客户端Agent/LLM发来的工具调用请求Query_Tool_Handler统一路由层负责解析tool_name与arguments把llm.search等调用分发到对应的执行函数见 Query_Tool_Handler.cppMySQL 相关的catalog_search等工具则由 MySQL_Tool_Handler.cpp 承载Discovery_Schema发现式 Schema 管理器掌握mcp_catalog.db的读写锁、预编译语句与全部 FTS 方法见 Discovery_Schema.h 与 Discovery_Schema.cppSQLite FTS5底层的全文索引引擎存放于mcp_catalog.db数据库内。关于数据库位置mcp_catalog.db的路径被硬编码为datadir/mcp_catalog.db见 ProxySQL_MCP_Server.cpp 中std::string(GloVars.datadir) /mcp_catalog.db的初始化逻辑以保证目录数据库在多次运行间保持稳定。数据库设计集成而非独立FTS 功能并未另起一个独立数据库而是直接内建在已有的 Discovery Schemamcp_catalog.db中因此不需要单独的配置变量来开启。两张 FTS5 虚拟表分别是fts_objects对数据库对象的 FTS5 索引采用contentless模式fts_llm对 LLM 生成产物的 FTS5 索引直接内嵌内容with content。三、FTS 表结构与建表实现源码中的create_fts_tables()见 Discovery_Schema.cpp L700-L725实际执行的建表语句与规划文档略有差异仓库实际实现如下-- fts_objectscontentless 模式只存索引 token不复制原始数据 CREATE VIRTUAL TABLE IF NOT EXISTS fts_objects USING fts5( object_key, schema_name, object_name, object_type, comment, columns_blob, definition_sql, tags , content , tokenizeunicode61 remove_diacritics 2 ); -- fts_llm直接存储内容支持全文搜索 CREATE VIRTUAL TABLE IF NOT EXISTS fts_llm USING fts5( kind, key, title, body, tags , tokenizeunicode61 remove_diacritics 2 );对比规划文档 FTS_Implementation_Plan.md 中的简化版定义fts_objects(schema_name, object_name, object_type, content, content, content_rowidobject_id)可以观察到实现上的几个关键升级tokenizeunicode61 remove_diacritics 2使用 Unicode61 分词器并移除变音符号对多语言元数据包括中文注释、带重音字符的注释更友好fts_objects增加了object_key、comment、columns_blob、definition_sql、tags等字段将对象注释、列清单、建表 DDL 和快速画像标签一并纳入索引显著扩大可命中面fts_llm采用kind, key, title, body, tags五列结构kind目前包含question_template与note两种类型。若 FTS5 扩展未被启用create_fts_tables()会记录proxy_error(Failed to create fts_objects FTS5 table - FTS5 may not be enabled\n)并返回 -1。四、索引维护全量重建策略规划文档强调不做增量更新重索引时全量重建。这条策略在源码中落实为Discovery_Schema::rebuild_fts_index(int run_id)见 Discovery_Schema.cpp L1215-L1346先通过sqlite_master检查fts_objects是否存在若不存在则仅打印 warning 并返回 0非致命采集流程可以在无 FTS 的情况下继续按run_id清空该批次对应的 FTS 条目DELETE FROM fts_objects WHERE object_key IN (SELECT schema_name || . || object_name FROM objects WHERE run_id ...)从objects表取回该 run 的全部对象object_id, schema_name, object_name, object_type, object_comment, definition_sql对每个对象从columns表按ordinal_pos排序拼出列摘要格式如column_name:data_type column_comment从profiles表读取profile_kindtable_quick的profile_json提取guessed_kind作为tags组装object_key schema_name . object_name用预编译语句INSERT INTO fts_objects(...)写入索引。触发时机在采集链路中非常清晰Static_Harvester::run_full_harvest()的阶段注释明确列出9. Rebuild FTS index见 Static_Harvester.cpp L1259-L1329即元数据采集完成后、finish_run之前执行rebuild_fts_index()若重建失败则以 Failed during FTS rebuild 结束本次 run。LLM 产物的自动索引LLM 产物的索引采用写入即索引的方式在 upsert 操作内同步完成新增 question template 时llm_question_templates表插入完成后立即执行INSERT INTO fts_llm(rowid, kind, key, title, body, tags) VALUES(?1, question_template, ...)以template_id作为 rowid见 Discovery_Schema.cpp L2097新增 note 时llm_notes表插入完成后立即执行INSERT INTO fts_llm(rowid, kind, key, title, body, tags) VALUES(?1, note, ...)见 Discovery_Schema.cpp L2149。class Discovery_Schema对外暴露的 FTS 接口汇总如下见 Discovery_Schema.hclass Discovery_Schema { private: // FTS 方法 int create_fts_tables(); int rebuild_fts_index(int run_id); std::string fts_search(int run_id, const std::string query, int limit, const std::string object_type, const std::string schema_name); std::string fts_search_llm(int run_id, const std::string query, int limit, bool include_objects); int log_rag_search_fts(...); public: // FTS 在以下流程中自动维护 // - 对象插入静态采集 static harvest // - LLM 产物 upsert // - 目录重建操作 };五、搜索工具详解5.1 catalog_search跨对象 LLM 产物检索参数名称类型必填说明querystring是FTS5 搜索查询串include_objectsboolean否是否包含对象详细信息默认 falseobject_limitinteger否include_objectstrue 时最多返回的对象数默认 50返回示例{ success: true, query: customer order, results: [ { kind: table, key: sales.orders, schema_name: sales, object_name: orders, content: orders table with columns: order_id, customer_id, order_date, total_amount, rank: 0.5 } ] }开启include_objectstrue后每个结果还会附加details字段包含object_id、object_type、row_count_estimate、has_primary_key、has_foreign_keys、has_time_column以及columns数组每列含column_name、data_type、is_nullable、is_primary_key——这些信息正是从 catalog 的objects、columns、indexes、foreign_keys表中按需回查得到的。实现逻辑分别对fts_objects与fts_llm执行 FTS5 查询合并结果并按相关性排序按需获取对象详细信息跨表 join 到objects/columns/indexes/foreign_keys返回排序后的结果集。在 MySQL 侧的具体实现位于 MySQL_Tool_Handler.cpp 的catalog_search(schema, query, kind, tags, limit, offset)其内部委托给catalog-search(...)再把schema/query/results封装为 JSON 返回。注意该文件中还包含另一组面向数据表内容的 FTS 工具fts_index_table、fts_search、fts_list_indexes它们与本文所述的对象元数据 FTS 是不同层次的能力前者索引的是业务表行数据后者索引的是数据库元数据使用时注意区分。5.2 llm.searchLLM 产物检索参数名称类型必填说明querystring是FTS5 搜索查询串typestring否内容类型过滤summary、relationship、domain、metric、noteschemastring否按 schema 过滤limitinteger否最大返回条数默认 10返回示例{ success: true, query: customer segmentation, results: [ { kind: domain, key: customer_segmentation, content: Customer segmentation based on purchase behavior and demographics, rank: 0.8 } ] }实现逻辑对fts_llm执行 FTS5 查询应用类型 / schema 过滤条件返回带内容与排序分数的结果。仓库中llm.search的实际实现与规划文档略有演进。在 Query_Tool_Handler.cpp L1638-L1643 中工具注册信息如下必填参数target_id、run_id可选参数querystring、limitinteger默认 25、include_objectsboolean功能描述明确说明对 question_template 类结果会额外返回example_sql、related_objects、template_json、confidenceinclude_objectstrue且 query 非空时搜索模式会附加完整对象 schema 详情query 为空时列表模式只返回模板不附加对象以避免超大响应。路由执行在 L2609-L2637先解析target_id与run_id通过catalog-resolve_run_id()将 schema 名解析为 run_id然后记录搜索日志log_llm_search(run_id, query, limit)最终调用catalog-fts_search_llm(run_id, query, limit, include_objects)并封装为成功响应。底层fts_search_llm见 Discovery_Schema.cpp L2165 起的实现要点query 为空时进入列表模式SELECT f.kind, f.key, f.title, f.body, 0.0 AS score ... FROM fts_llm f LEFT JOIN llm_question_templates qt ON CAST(f.key AS INT) qt.template_id ORDER BY f.kind, f.title LIMIT ...query 非空时进入搜索模式同样 LEFT JOINllm_question_templates但追加WHERE f.fts_llm MATCH query ORDER BY score LIMIT ...score即bm25(fts_llm)的相关性分值当include_objectstrue且 query 非空时会先从objects表建立object_name - schema_name映射再对每条结果的related_objects逐个调用get_object(run_id, -1, schema_name, name, true, false)拉取完整对象详情拼装为objects_details数组附在结果上。5.3 fts_search对象元数据检索的底层入口Discovery_Schema::fts_search(run_id, query, limit, object_type, schema_name)见 Discovery_Schema.cpp L1348-L1394是对象检索的底层实现展示了 FTS 与过滤条件的组合方式SELECT object_key, schema_name, object_name, object_type, tags, bm25(fts_objects) AS score FROM fts_objects WHERE fts_objects MATCH query [AND object_type type] [AND schema_name schema] ORDER BY score LIMIT limit;可见可选 WHERE 过滤这一需求正是通过拼接object_type、schema_name条件实现的。六、SQLite 并发与错误处理模式FTS 检索发生在 MCP 插件多线程环境中Discovery Schema 通过读写锁保证一致性见 Discovery_Schema.cpp 中 SQLite Operations Patterndb-wrlock(); // 写操作索引写入 db-wrunlock(); db-rdlock(); // 读操作搜索 db-rdunlock(); // 预编译语句 sqlite3_stmt* stmt NULL; db-prepare_v2(sql, stmt); (*proxy_sqlite3_bind_text)(stmt, 1, value.c_str(), -1, SQLITE_TRANSIENT); SAFE_SQLITE3_STEP2(stmt); (*proxy_sqlite3_finalize)(stmt);ProxySQL 对 sqlite3 API 的函数指针封装proxy_sqlite3_*保证了在跨发行版链接场景下调用的一致性。错误处理遵循统一 JSON 约定json result; result[success] false; result[error] Descriptive error message; return result; // 日志 proxy_error(FTS error: %s\n, error_msg); proxy_info(FTS search completed: %zu results\n, result_count);在 Discovery_Schema.cpp 中FTS 相关的失败路径均有对应日志建表失败记录proxy_error搜索执行失败时proxy_error(FTS search error: %s\n, error)并返回[]空数组fts_objects表缺失时仅proxy_warning并跳过重建保证采集主流程不因索引问题中断。七、Agent 工作流示例以下是规划文档给出的典型 Agent 编排流程Python 伪代码展示 FTS 与 catalog 的交叉引用# Agent 搜索相关对象 search_results call_tool(catalog_search, { query: customer orders with high value, include_objects: True, object_limit: 20 }) # Agent 搜索 LLM 洞察 llm_results call_tool(llm.search, { query: customer segmentation, type: domain }) # Agent 用结果构建认知 for result in search_results[results]: if result[kind] table: # 获取详细表信息 table_details call_tool(catalog_get_object, { schema: result[schema_name], object: result[object_name] })实际使用时llm.search需要携带target_id与run_id或可解析的 schema 名例如llm_results call_tool(llm.search, { target_id: my_mysql_target, run_id: 3, query: customer segmentation, limit: 10, include_objects: True })对于 question_template 类命中返回中会附带example_sql可直接执行的示例 SQL与confidence模板置信度Agent 可据此直接构造查询或继续深挖关联对象。八、性能考量Contentless FTSfts_objects采用 contentless 索引content索引只保存 token 与行号映射不复制原始元数据显著降低存储开销、提升检索速度对象原始数据仍保留在objects等普通表中需要详情时按需回查自动维护采集完成自动全量重建LLM 产物写入即索引索引始终与 catalog 保持同步BM25 相关性排序排名使用 FTS5 内置的 bm25 算法fts_search与fts_search_llm均以bm25(...) AS score计算相关性并按ORDER BY score输出分页大结果集可自动分页MySQL 侧catalog_search接受limit/offset底层fts_search/fts_search_llm均有LIMIT约束非致命降级FTS 表缺失或重建失败时采集流程照常进行避免索引问题拖垮主链路。九、测试与验证状态规划文档列出的测试项全部标记为完成对象 FTS 搜索、LLM 产物 FTS 搜索、合并排名搜索、详细信息获取、按内容类型过滤、按 schema 过滤、大目录性能、错误处理。这些测试在单元测试 genai_discovery_schema_unit-t.cpp 中有直接对应test_rebuild_fts_index()L778-L796插入users、orders两张表及列后执行rebuild_fts_index(run_id)断言返回 0test_fts_search()L798-L824插入带注释的对象User accounts and authentication、Customer purchase orders、Payment transactions后重建索引分别搜索 users 与 orders断言至少返回 1 条结果验证了注释文本可被 FTS5 命中test_log_rag_search_fts()L519-L524验证 FTS 搜索日志记录函数返回 0。此外测试文件顶部注释还点出了被测能力包括rebuild_fts_index() / fts_search()与log_llm_search() / log_rag_search_fts()等可作为后续阅读与回归验证的入口。十、注意事项与总结注意事项FTS5 依赖编译进 SQLite 的 FTS5 扩展若建表失败请检查 ProxySQL 构建时 SQLite 的编译选项fts_objects采用 contentless 模式无法直接通过 FTS 表反查原始内容对象详情必须回查objects/columns等表fts_llm直接存储内容支持对title、body的全文检索key字段与llm_question_templates.template_id或llm_notes.note_id对应可用CAST(f.key AS INT)进行 join重建索引是按run_id隔离的DELETE ... WHERE object_key IN (SELECT schema_name || . || object_name FROM objects WHERE run_id ...)多批次采集之间互不污染llm.search空 query 为列表模式不带对象详情非空 query 为搜索模式可附带对象详情两者响应体积差异很大Agent 应谨慎使用include_objectstrue。总结ProxySQL MCP 的 FTS 能力以两张 FTS5 虚拟表为核心遵循全量重建 自动维护的索引策略把数据库对象元数据与 LLM 生成产物统一纳入可全文检索的范畴并通过catalog_search、llm.search两个 MCP 工具暴露给 Agent。底层实现中 contentless 索引、BM25 排序、读写锁与错误降级机制的组合使其既能支撑大规模目录检索又能与catalog_get_object、run_sql_readonly等工具协同完成先检索、再精查、后执行的完整 Agent 工作流。相关实现与测试可分别在 Discovery_Schema.cpp、Query_Tool_Handler.cpp、MySQL_Tool_Handler.cpp、Static_Harvester.cpp 与 genai_discovery_schema_unit-t.cpp 中继续深入。赞分享后端数据库负载均衡【免费下载链接】proxysqlHigh-performance proxy for MySQL and PostgreSQL项目地址https://gitcode.com/gh_mirrors/pr/proxysql点击查看免费下载相关推荐ProxySQL MCP 全文检索FTS实战指南基于 SQLite FTS5 的 MySQL 数据快速发现ProxySQL MCP 全文检索FTS实战指南基于 SQLite FTS5 的 MySQL 数据快速发现 本文围绕 ProxySQL GenAI 插件中后端数据库负载均衡ProxySQL RAG 索引数据模型与摄取架构SQLite 文档层、FTS5 与向量检索的落地设计ProxySQL RAG 索引数据模型与摄取架构SQLite 文档层、FTS5 与向量检索的落地设计 ProxySQL 在 MySQL/PostgreSQL后端数据库负载均衡Mermaid Live Editor 新手指南免费三步画好、预览、分享第一张图Mermaid Live Editor 新手指南免费三步画好、预览、分享第一张图 Mermaid Live Editor 是一款免费开源的在线图表编辑器用前端开发者工具数据可视化上一篇MCP for Unity v5 迁移指南从 UnityMcpBridge 平滑升级到全新 MCPForUnity 包结构下一篇CuratorGPT 内容策展 GPT 提示词解析联网检索、引用溯源与防幻觉设计创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考