ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ProxySQL RAG 索引嵌入与向量检索设计:Chunk 级 Embedding 的生产级蓝图

ProxySQL RAG 索引嵌入与向量检索设计:Chunk 级 Embedding 的生产级蓝图 后端数据库负载均衡【免费下载链接】proxysqlHigh-performance proxy for MySQL and PostgreSQL项目地址https://gitcode.com/gh_mirrors/pr/proxysql点击查看免费下载本篇指南围绕 ProxySQL 仓库中doc/RAG/embeddings-design.md的 v0→v1 实现蓝图展开系统讲解 RAG 索引中嵌入什么文本、如何用embedding_json定义、向量存到哪里、何时重算、如何查询的完整设计链路。读完本文你将掌握从rag_sources.embedding_json配置、rag_vec_chunks(sqlite3-vec) 存储、内容哈希增量更新到 MCP 层向量检索与混合检索RRF 融合 / FTS 候选重排的落地方法并能直接对照仓库中的 schema.sql 与 rag_ingest.cpp 源码验证每个设计决策。该设计以三个既有能力为前提chunk 化已由rag_chunks承载ProxySQL 已集成 sqlite3-vec 并提供vec0(...)虚拟表rag_vec_chunks检索入口主要通过 MCP 工具暴露详见 mcp-tools.md。1. 设计目标为什么嵌入要按 Chunk 粒度单独设计embeddings-design.md开篇就明确了六个核心目标它们决定了后面所有 schema 与流水线的形态Chunk 级嵌入每个 chunk 拥有自己的 embedding保证检索精度而非按整篇文档粗粒度嵌入。确定性嵌入输入被嵌入的文本由配置显式定义而不是由实现推断保证可复现、可观测。模型敏捷性系统可以在不破坏已存数据与对外 API 的前提下更换嵌入模型/维度。高效更新只有当 chunk 的嵌入输入真正变化时才重算 embedding避免无谓成本。成本与延迟有界嵌入生成本身昂贵必须限定资源开销。异步可扩展为后续引入异步嵌入任务预留空间。从源码看rag_ingest.cpp的 v0 实现已经兑现了其中大部分目标parse_embedding_json()rag_ingest.cpp#L611-L651按配置解析模型、维度、provider、批大小与超时ingest_source()rag_ingest.cpp#L1570-L1832在 chunk 创建后同步生成并存储向量。而目标 4内容哈希增量更新与 6异步 worker则作为 v1 推荐演进本文第 6、11 节会专门展开。2. 嵌入什么、不嵌入什么输入文本的语义边界2.1 推荐嵌入的文本提升语义召回对知识库类内容StackOverflow 帖子、技术文档、工单、runbook每个 chunk 的推荐嵌入输入是文档标题若存在标签以纯文本形式Chunk 正文推荐模板如下{Title} Tags: {Tags} {ChunkBody}这一模板在仓库样例中得到了完全一致的落地RAG_POC/sample_sqlite.sql第 37 行的embedding_json配置正是{enabled:true,dim:1536,model:text-embedding-3-large,input:{concat:[{col:Title},{lit:\nTags: },{col:Tags},{lit:\n\n},{chunk_body:true}]}}而 rag_ingest.cpp#L1466-L1477 的build_embedding_input()会读取input.concat规范并通过eval_concat()rag_ingest.cpp#L694-L716逐段拼接col从源行取值、lit输出固定字面量、chunk_body注入当前 chunk 正文——这正是确定性嵌入输入原则的代码级体现。2.2 默认不嵌入数值型元数据Score、ViewCount、OwnerUserId、时间戳等字段不应进入嵌入文本。它们应当保持结构化用于过滤filtering提升权重boosting打破平局tie-breaking结果整形result shaping把数值元数据混入嵌入文本通常只会引入噪声、降低语义质量。这一点与 mcp-tools.md 中的共享过滤模型一致source_ids、doc_ids、min_score、tags_any/tags_all、created_after/created_before等结构化过滤全部走元数据通道而不是靠向量相似度。2.3 代码与 HTML 的处理策略若 chunk 正文包含 HTML 或代码v0直接嵌入原始文本可用但可能含噪声。v1做归一化以提升质量剥离 HTML 标签保留文本内容代码块以纯文本保留但考虑剔除过多标记对代码密集的源可选择性创建专门的code-only chunk。归一化策略应在embedding_json.normalize中按源可配置见下一节例如{strip_html: true, collapse_whitespace: true}。3. 嵌入输入规则定义在哪里rag_sources.embedding_json嵌入输入规则必须显式声明并按源存储。rag_sources表在 schema.sql#L14-L46 中预留了embedding_json TEXT列L42注释明确指出v0 可留空后续定义而无需改表结构。3.1 推荐的 schema{ enabled: true, model: text-embedding-3-large, dim: 1536, input: { concat: [ {col:Title}, {lit:\nTags: }, {col:Tags}, {lit:\n\n}, {chunk_body: true} ] }, normalize: { strip_html: true, collapse_whitespace: true } }3.2 各字段语义字段语义enabled是否为此源计算/存储 embeddingmodel逻辑模型名用于可观测性与兼容性检查dim向量维度必须与rag_vec_chunks的 vec0 声明维度一致input.concat如何拼接嵌入输入文本col / lit / chunk_bodynormalize可选的归一化步骤3.3 源码中的实际解析与校验parse_embedding_json()rag_ingest.cpp#L611-L651读取enabled、dim、model、input并额外支持 v0 落地需要的运行时字段provider、api_base、api_key、batch_size、timeout_ms随后做防御性校验dim 0→ 回退默认 1536batch_size 0→ 回退默认 16timeout_ms 0→ 回退默认 20000ms。注意 v0 的EmbeddingConfig尚未解析normalizestrip_html 等属 v1 建议因此normalize 按源可配置目前是蓝图层面的设计落地时需在parse_embedding_json中扩展。4. 存储 schema 与模型/版本演进4.1 v0 现状单向量表rag_vec_chunks存储embedding 向量chunk_iddoc_id/source_id便捷列updated_atschema.sql#L134-L141 给出了准确定义CREATE VIRTUAL TABLE IF NOT EXISTS rag_vec_chunks USING vec0( embedding float[1536], -- change if you use another dimension chunk_id TEXT, -- join key back to rag_chunks doc_id TEXT, -- optional convenience source_id INTEGER, -- optional convenience updated_at INTEGER -- optional convenience );这在假设单一嵌入模型/单一维度的 v0 阶段完全够用。rag_ingest.cpp的init_schema()rag_ingest.cpp#L1880-L2033会在建表时按--vec-dim参数默认 1536动态生成float[dim]若 sqlite-vec 扩展未加载建表失败时仅告警并禁用向量功能不会阻塞其余索引。4.2 v1 演进支持多模型产品化场景常需要多个嵌入模型如通用模型 vs 代码专用模型两种支持方式方案 A在rag_vec_chunks中增加模型身份列新增model TEXT、dim INTEGER若按模型固定维度则可选允许每个chunk_id存在多行唯一键变为(chunk_id, model)需要 schema 变更并对 vec0 的元数据列与唯一性约束谨慎设计。方案 B每模型一张 vec 表若 vec0 约束受限推荐分别建rag_vec_chunks_1536_v1、rag_vec_chunks_1024_code_v1等MCP 工具按请求的模型或默认配置选择对应表。建议仅当你的 sqlite3-vec 构建能轻松按 model 过滤时才选方案 A否则方案 B 在运维上更干净维度天然隔离、重建单个模型不影响其他模型。5. 嵌入生成流水线何时创建、何时更新5.1 创建时机chunk 之后、入库之时v0 是同步流水线ingest row → create chunks → compute embedding → store vectoringest_source()中的真实顺序rag_ingest.cpp#L1736-L1757对每个 chunk 依次执行insert_chunk写入rag_chunks→insert_fts写入 FTS5→ 若ecfg.enabled则build_embedding_input收集到pending_embeddings批中当积压达到batch_size时立即flush_embedding_batch()。全部行处理完后若还有残余 pending 批会再 flush 一次rag_ingest.cpp#L1773-L1777。5.2 更新时机以嵌入输入的变化为准只要以下任一变化就必须重算 embedding标题变化标签变化chunk 正文变化归一化规则变化如 strip_html嵌入模型变化因此更新逻辑应基于嵌入输入的内容哈希content hash判定而不是盲目全量重算。6. 内容哈希高效增量更新的基石v1 推荐6.1 为什么需要哈希没有哈希每次同步都可能对未变化的 chunk 重复调用昂贵的嵌入服务耗时、费钱、且让增量同步失去意义。6.2 推荐做法每个 chunk × 每个模型存一份embedding_input_hash方案 A存入rag_chunks.metadata_json{ chunk_index: 0, embedding_hash: sha256:..., embedding_model: text-embedding-3-large }优点无需 schema 变更缺点JSON 解析开销。方案 B专用侧表推荐CREATE TABLE rag_chunk_embedding_state ( chunk_id TEXT NOT NULL, model TEXT NOT NULL, dim INTEGER NOT NULL, input_hash TEXT NOT NULL, updated_at INTEGER NOT NULL DEFAULT (unixepoch()), PRIMARY KEY(chunk_id, model) );优点查找快避免 JSON 解析缺点多一张表。v1 建议采用方案 B。6.3 仓库中已有的哈希雏形虽然rag_chunk_embedding_state尚属 v1 蓝图但 v0 的rag_ingest.cpp已经为文档级增量更新实现了同一思路compute_content_hash()rag_ingest.cpp#L481-L492对title|body|metadata_json拼接串做 SHA-256输出 64 位十六进制rag_documents表在运行时通过ALTER TABLE ... ADD COLUMN content_hash VARCHAR(64)增加该列rag_ingest.cpp#L1939同步时对比新旧哈希哈希相同则跳过该文档skipped_docs不同则软删除旧文档并重建其 chunks / FTS / vec 行rag_ingest.cpp#L1711-L1730。v1 只需把这一已验证的机制下移到 chunk 级并纳入embedding_json的输入串标题标签正文归一化规则模型标识即可实现仅重算输入真正变化的 chunk。7. 嵌入模型集成选项外部服务 vs 进程内运行时7.1 外部嵌入服务初期推荐ProxySQL 调用嵌入服务可选OpenAI 兼容端点本地服务如 llama.cpp server厂商专用嵌入 API。优点模型选型迭代容易ML 运行时与 ProxySQL 进程隔离。缺点存在网络延迟需要缓存与超时控制。仓库 v0 落地rag_ingest.cpp通过EmbeddingProvider抽象基类rag_ingest.cpp#L1136-L1149定义embed(inputs, dim)批接口build_embedding_provider()rag_ingest.cpp#L1319-L1329根据provider字段分派openai→OpenAIEmbeddingProviderrag_ingest.cpp#L1207-L1317libcurl POST${api_base}/embeddingsBearer 认证请求体含model、input批量数组、dimensions并校验响应维度与输入数量其他含默认→StubEmbeddingProviderrag_ingest.cpp#L1163-L1170对输入文本做确定性哈希生成归一化伪向量用于无网络、无成本的开发与测试。7.2 进程内嵌入运行时ProxySQL 直接链接嵌入运行时如 llama.cpp。优点无网络依赖调优后延迟可预期。缺点增大内存占用需要精细的资源控制。建议先从外部嵌入提供商起步同时保持模块化接口仓库中的EmbeddingProvider抽象正是为此设计后续可无痛切换。8. 查询嵌入生成MCP 层的标准流程向量检索需要查询嵌入应在 MCP 层完成取query_text应用查询归一化可选但推荐使用与 chunk 相同的模型计算查询嵌入以绑定向量执行向量检索 SQL。明确禁止不加校验就接受不可信调用方传入的任意嵌入向量允许无界的查询长度。仓库 v0 对照rag_ingest的query子命令实现了这条链路rag_ingest.cpp#L2328-L2484加载启用源 → 解析embedding_json→ 用同一 provider 对--text生成查询嵌入 → 转成 SQLiteX...十六进制 BLOB 字面量float_to_hex_blobrag_ingest.cpp#L250-L263→ 执行 vec0 KNN 查询SELECT c.chunk_id, c.source_id, SUBSTR(c.body, 1, 200) as content, v.distance, d.title FROM rag_vec_chunks v JOIN rag_chunks c ON c.chunk_id v.chunk_id JOIN rag_documents d ON d.doc_id c.doc_id WHERE v.embedding MATCH ( SELECT Xquery_hex AS embedding ) AND k limit ORDER BY v.distancerag_ingest.cpp#L2428-L2438。vec0 的 KNN 采用子查询提供查询向量 k n的写法并可用AND c.source_id ?叠加源过滤——这正是 MCP 层rag.search_vector工具见 mcp-tools.md 第 4 节内部 SQL 的原型。9. 向量检索语义距离、相似度与统一打分9.1 距离 vs 相似度根据嵌入模型与检索原语向量检索可能返回余弦距离越小越好余弦相似度越大越好L2 距离越小越好建议在 MCP 响应中统一为越大越好的分数若原始值是距离score_vec 1 / (1 distance)或其他单调变换。原始距离可保留在 debug 字段中。这与 mcp-tools.md 的约定一致score_vec归一化、distance_raw可选返回混合检索的统一score也是 higher-is-better。注意rag_ingest.cpp的 v0 直接输出v.distance并按ORDER BY v.distance升序——MCP 封装层需要完成上述变换。9.2 过滤过滤能力包括source_id限定可选元数据过滤文档级或 chunk 级。v0 中最容易的是按source_id过滤因为rag_vec_chunks已将source_id存为元数据列schema.sql 中的便捷列设计可直接参与 WHERE/JOIN。10. 混合检索集成嵌入作为检索的一条腿嵌入是混合检索hybrid retrieval的组成部分。mcp-tools.md 定义了两种推荐模式Fuse融合FTS 与向量各取 top-N按chunk_id合并用 RRF 融合打分。FTS then vector先 FTS 后向量FTS 产宽候选集再在候选内做向量重排。两种模式下嵌入的职责不同Fuse 模式需要全局向量检索 top-N候选模式需要把向量检索限制在候选 chunk_id 集合内chunk_id IN (...), 通常更便宜、更精确尤其当查询含强精确词元时。RRF 融合公式来自 architecture-runtime-retrieval.mdscore w_fts/(k0 rank_fts) w_vec/(k0 rank_vec)典型参数k060、w_fts1.0、w_vec1.0。RRF 的优势在于无需分数校准即可稳健融合 bm25 与余弦距离这类异构分数域。11. 运维控制资源上限、批处理与背压11.1 资源限制嵌入生成必须被以下项约束可嵌入的 chunk 最大尺寸每个文档最多嵌入的 chunk 数每个源嵌入速率限制调用嵌入 provider 的超时。v0 已落实超时与批量约束timeout_ms默认 20000通过CURLOPT_TIMEOUT_MS生效batch_size默认 16控制单次 API 请求的输入数。MCP 层的硬上限建议来自 mcp-tools.mdk_max50、candidates_max500、query_max_bytes8192、response_max_bytes5_000_000、timeout_ms按工具类型 250–2000ms。11.2 批量嵌入为提升吞吐批量嵌入收集 N 个 chunk → 一次请求嵌入 N 个输入 → 存储结果。flush_embedding_batch()rag_ingest.cpp#L1535-L1564正是这一实现其注释给出量化收益100 个 chunk、batch_size16 时仅需 7 次 API 调用16×64而非 100 次。11.3 背压与异步嵌入v1考虑将嵌入生成与摄入解耦摄入只存 chunk嵌入 worker 处理pendingchunk 并回填向量。收益摄入保持快速嵌入可独立扩缩嵌入失败可重试。该设计中需为每个 chunk 存储状态记录pending / ok / error、最后错误消息、重试计数。这一状态表与第 6 节的rag_chunk_embedding_state可增加status、last_error、retry_count列天然合流。12. 推荐实现步骤coding agent checklistv0同步嵌入在 ingester 中实现embedding_json解析为每个 chunk 构建嵌入输入字符串调用嵌入 provider开发期可用 stub向rag_vec_chunks插入向量行用查询嵌入 向量 SQL实现rag.search_vectorMCP 工具。仓库中的 sample_mysql.sql10 行 posts 样例数据含长正文、空值、高分/低分过滤用例与 sample_sqlite.sql含完整embedding_json的源配置可直接用于验证 v0 全链路。v1高效增量嵌入新增rag_chunk_embedding_state表按 chunk × model 存input_hash仅当哈希变化时重嵌入增加可选异步嵌入 worker为嵌入吞吐与失败增加指标。13. 总结按 chunk 计算嵌入而非按整篇文档在rag_sources.embedding_json中显式定义嵌入输入向量存入rag_vec_chunksvec0生产环境加入基于哈希的更新检测与可选异步嵌入 worker在 MCP 响应中归一化向量分数higher-is-better并保留原始距离用于调试。整套设计在仓库中的证据链清晰可循schema 见 schema.sql 与 rag_ingest.cpp 的init_schema()嵌入配置样例见 sample_sqlite.sqlprovider 抽象、批量嵌入与查询向量 SQL 见 rag_ingest.cppbuild_embedding_provider、flush_embedding_batch、query 子命令检索侧接口契约见 mcp-tools.md 与 architecture-runtime-retrieval.md。赞分享后端数据库负载均衡【免费下载链接】proxysqlHigh-performance proxy for MySQL and PostgreSQL项目地址https://gitcode.com/gh_mirrors/pr/proxysql点击查看免费下载相关推荐ProxySQL RAG 索引 SQL 实战FTS5、向量检索与混合检索查询指南ProxySQL RAG 索引 SQL 实战FTS5、向量检索与混合检索查询指南 本篇指南聚焦 ProxySQL 内嵌的 RAGRetrieval Augm后端数据库负载均衡ProxySQL RAG 索引数据模型与摄取架构SQLite 文档层、FTS5 与向量检索的落地设计ProxySQL RAG 索引数据模型与摄取架构SQLite 文档层、FTS5 与向量检索的落地设计 ProxySQL 在 MySQL/PostgreSQL后端数据库负载均衡KOReader 扫描 PDF 重排调参实操指南6 个 K2pdfopt 参数把墨水屏文字调到能看KOReader 扫描 PDF 重排调参实操指南6 个 K2pdfopt 参数把墨水屏文字调到能看 在 6 寸墨水屏上打开扫描版论文字小、版式还固定KOR后端数据库负载均衡上一篇OpenClaw Mission Control生产部署终极指南Docker Compose、systemd与反向代理TLS完整清单下一篇用StatsPAI旗舰Skill复现Card(1995)AERS为何自动发现IV估计竟然超过OLS创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表