恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Refly 向量检索服务深度解析:基于 Qdrant 与 LanceDB 的可插拔 Vector Search 架构

  • 首页
  • 资讯中心
  • /
  • Refly 向量检索服务深度解析:基于 Qdrant 与 LanceDB 的可插拔 Vector Search 架构

相关资讯

C51与L298直流电机PWM调速详解:定时器中断与Proteus仿真 2026/9/16 15:07:58
EIP-8304 解读:基于系统合约的免信任日志与交易索引(Index Tables) 2026/9/16 15:02:57
无细胞蛋白表达系统:48小时快速获取高纯度靶标蛋白 2026/9/16 15:02:57

最新资讯

AI如何解决毕业论文写作痛点:书匠策AI深度测评
5分钟部署免费AI简历编辑器:Magic Resume完整上手实录
claude-code-action 能力边界指南:Claude 在 GitHub 自动化中能做什么、不能做什么
Spring Boot库存管理系统实战:数据模型、事务与乐观锁并发控制
MSW接口Mock实战:规则改写与断点拦截提升前后端联调效率
数据可视化核心要素与实战技巧解析

今日推荐

IoT-For-Beginners 智能语音计时器:Wio Terminal 基于 DMAC 与 Flash 的音频采集实战
基于MATLAB的CRI显色指数计算:从SPD光谱到Ra的完整流程
JSP+Servlet+MySQL博客系统源码部署与优化全攻略

本周热门

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化
Flutter应用改名全指南:从Android到iOS的配置与工具实践

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

Refly 向量检索服务深度解析:基于 Qdrant 与 LanceDB 的可插拔 Vector Search 架构

发布时间:2026/9/16 15:07:58
Refly 向量检索服务深度解析:基于 Qdrant 与 LanceDB 的可插拔 Vector Search 架构 Refly 向量检索服务深度解析基于 Qdrant 与 LanceDB 的可插拔 Vector Search 架构【免费下载链接】reflyThe first open-source agent skills builder. Define skills by vibe workflow, run on Claude Code, Cursor, Codex more. Build Clawdbot · APIs for Lovable · Bots for Slack Lark/Feishu · Skills are infrastructure, not prompts.项目地址: https://gitcode.com/GitHub_Trending/re/refly导读Refly 作为一个开源 Agent Skills Builder 平台其知识检索RAG、语义搜索等能力背后依赖一套统一的向量检索基础设施。本文将以 apps/api/src/modules/common/vector-search/README.md 为核心骨架结合 vector-search 模块源码深入解析这套后端无关backend-agnostic的向量检索服务如何通过工厂模式在 Qdrant 与 LanceDB 之间无缝切换、如何编写统一过滤器、如何完成批量写入与相似度检索以及如何在业务服务如 rag.service.ts中实际注入使用。读完本文你将掌握在 Refly 中配置、调用并扩展向量检索能力的完整实战方案。一、服务定位与总体架构Refly 的向量检索能力被抽象为一个独立的 Common 模块子服务其设计目标是让业务代码与底层向量数据库解耦无论底层是 Client-Server 架构的 Qdrant还是嵌入式 LanceDB业务侧都通过同一套VectorSearchService接口完成操作。从 index.ts 可以看出模块通过工厂函数 NestJS 依赖注入组装后端export const createVectorSearchFactory () { return (configService: ConfigService) { const backendType configService.get(vectorStore.backend, qdrant); let backend: VectorSearchBackend; if (backendType qdrant) { backend new QdrantVectorSearchBackend(configService); } else if (backendType lancedb) { backend new LanceDBVectorSearchBackend(configService); } else { throw new Error( Unknown vector search backend type: ${backendType}. Supported backends: qdrant, lancedb, ); } return new VectorSearchService(backend); }; };架构上对应文档中的结构图VectorSearchService ├── VectorSearchBackend (interface) ├── QdrantVectorSearchBackend ├── LanceDBVectorSearchBackend └── [Future backends...]其中VectorSearchService是一个薄门面Facade所有方法均委托给注入的VectorSearchBackend实现见 index.ts真正执行向量操作的是具体后端类。这意味着新增数据库时业务代码零改动。二、支持的后端对比Qdrant 与 LanceDB文档明确列出两个受支持后端结合源码实现二者定位差异非常清晰维度QdrantLanceDB类型Client-Server 向量数据库嵌入式Embedded向量数据库适用场景生产部署、大规模应用开发环境、小型部署、本地应用部署要求需要独立 Qdrant 服务器无需额外服务直接连接本地目录或云存储通信方式REST/gRPC 客户端qdrant/js-client-rest进程内读写lancedb/lancedb数据存储服务端管理本地目录 / S3 / GCS支持多模态与云存储特性高级过滤、水平扩展、REST/gRPC API自动索引、无需网络开销、高效存储格式源码印证了两者的连接差异Qdrant 后端在构造函数中通过ConfigService.getOrThrow(vectorStore.qdrant.host)与getOrThrow(vectorStore.qdrant.port)强制要求连接地址见 backend/qdrant.ts并在初始化时以 10 秒超时校验集合是否存在LanceDB 后端通过vectorStore.lancedb.uri默认./lancedb连接本地目录表不存在时会在首次写入时自动创建见 backend/lancedb.ts。从性能特征看Qdrant 适合大规模部署、支持水平扩展但存在网络延迟LanceDB 针对读密集负载优化、本地部署无网络开销、自动建索引。三、安装与依赖注入该服务随 Common 模块自动可用无需单独安装。CommonModule是一个全局模块Global()在 common.module.ts 中通过工厂注册VECTOR_SEARCHtoken 并导出因此任何业务模块都能直接注入。引入 tokenimport { VECTOR_SEARCH } from ../common/vector-search/tokens;tokens.ts中定义的是 Symbol 类型的 DI token// Token for the vector search service export const VECTOR_SEARCH Symbol(VECTOR_SEARCH);在业务 Service 中注入文档示例import { Injectable, Inject } from nestjs/common; import { VectorSearchService } from ../common/vector-search; import { VECTOR_SEARCH } from ../common/vector-search/tokens; Injectable() export class MyService { constructor( Inject(VECTOR_SEARCH) private readonly vectorSearchService: VectorSearchService, ) {} }注文档示例中的导入路径../common/vector-search与../common/vector-search/tokens是模块内部相对写法在 Refly 仓库中的实际文件位于 apps/api/src/modules/common/vector-search/业务代码中请按实际目录层级调整导入路径。index.ts同时导出了VectorSearchService、token 与全部类型见 index.ts。四、配置详解4.1 Qdrant 后端文档给出的配置骨架vectorStore: backend: qdrant url: http://localhost:6333 collectionName: refly_vectors对照 backend/qdrant.ts 的源码实现实际生效的配置键为嵌套结构且host与port为必填getOrThrow缺失会直接抛错vectorStore: backend: qdrant # 后端选择默认 qdrant qdrant: host: localhost # 必填Qdrant 服务地址 port: 6333 # 必填Qdrant 服务端口 apiKey: # 可选云服务或开启鉴权时使用 collectionName: refly_vectors # 可选集合名默认 refly_vectors其他关键实现细节客户端以checkCompatibility: false创建QdrantClientqdrant.ts首次写入数据时若集合不存在会自动以Cosine 距离、磁盘存储on_disk创建集合并为tenantId字段创建keyword类型 payload 索引qdrant.ts初始化带 10 秒超时保护INIT_TIMEOUT超时会抛出Qdrant initialization timed out after 10000msqdrant.ts。4.2 LanceDB 后端文档给出的配置骨架vectorStore: backend: lancedb uri: ./data/lancedb # 本地目录 # OR uri: s3://my-bucket/lancedb # S3 存储 # OR uri: gs://my-bucket/lancedb # Google Cloud Storage对照 backend/lancedb.ts源码中还有tableName配置项vectorStore: backend: lancedb lancedb: uri: ./lancedb # 连接 URI默认 ./lancedb支持本地目录、S3、GCS tableName: vectors # 可选表名默认 vectorsLanceDB 后端同样有 10 秒初始化超时保护lancedb.ts且连接后若表不存在不会报错而是等待首次batchSaveData时自动建表db.createTable。五、核心用法从写入到检索的完整流程5.1 保存向量点Batch Save文档示例const points [ { id: doc1, vector: [0.1, 0.2, 0.3, 0.4], payload: { title: Document Title, content: Document content..., type: document, userId: user123, }, }, ]; await this.vectorSearchService.batchSaveData(points);源码级补充Qdrant 后端在保存前会自动推导向量维度取首个点的向量长度维度非法非数组或长度 ≤ 0时抛出明确错误随后将VectorPoint[]转换为 QdrantPointStruct[]并以wait: true的 upsert 方式写入qdrant.ts。LanceDB 后端则将id、vector与 payload 展开合并为扁平记录后写入首次写入自动建表返回{ success: true, count }lancedb.ts。5.2 相似向量检索Search文档示例const results await this.vectorSearchService.search( { vector: [0.1, 0.2, 0.3, 0.4], limit: 10, }, { must: [ { key: type, match: { value: document } }, { key: userId, match: { value: user123 } }, ], } );源码级补充Qdrant 端将过滤器转换为 Qdrant 格式后调用client.searchlimit缺省为 10结果统一映射为{ id, score, payload }qdrant.tsLanceDB 端必须提供向量缺失直接抛Vector is required for LanceDB search通过table.search(vector).where(...).limit(...)链式查询并将_distance转换为相似度分数score 1 - _distancelancedb.ts。这是两个后端在“分数语义”上的关键差异Qdrant 返回 Cosine 相似度LanceDB 返回的是转换后的相似度。5.3 滚动遍历Scroll文档示例const points await this.vectorSearchService.scroll({ filter: { must: [{ key: type, match: { value: document } }], }, limit: 100, });源码级补充Qdrant 后端会自动遍历全部页只要next_page_offset存在就继续翻页直到取完并兼容多向量multi-vector情况下取第一维向量的场景qdrant.tsLanceDB 后端使用table.query().where(...).limit(...)但不支持 offset 分页传入 offset 时仅记录 warninglancedb.ts。若需分页需自行实现游标逻辑。5.4 更新元数据Update Payload文档示例await this.vectorSearchService.updatePayload( { must: [{ key: id, match: { value: doc1 } }] }, { updated: true, lastModified: new Date().toISOString() } );源码级补充Qdrant 通过client.setPayload实现原地更新LanceDB 没有直接更新方法采用读-改-写策略先查询匹配记录 → 合并 payload → 删除旧记录 → 追加新记录lancedb.ts。5.5 批量删除Batch Delete文档示例await this.vectorSearchService.batchDelete({ must: [{ key: id, match: { value: doc1 } }], });源码级补充Qdrant 通过client.delete(collection, { wait: true, filter })删除LanceDB 将过滤器转为 SQL WHERE 子句后调用table.delete(whereClause)无合法过滤器时会给出警告并跳过lancedb.ts。六、统一过滤器系统一个 Filter双端通用这是该模块最核心的抽象。文档与 backend/README.md 共同描述了增强版VectorFilter系统其联合类型定义在 backend/interface.tsexport type VectorFilter | QdrantFilter // Qdrant 风格结构化过滤器 | LanceDBFilter // LanceDB SQL 字符串过滤器 | SimpleFilter // 简单键值过滤器 | string | Recordstring, any;6.1 三种过滤器形态① 简单过滤器Simple Filter——最常见的键值匹配const simpleFilter: VectorFilter { tenantId: tenant-123, category: document, status: active, };② Qdrant 结构化过滤器——支持mustAND、shouldOR、must_notNOT逻辑组合const qdrantFilter: VectorFilter { must: [ { key: tenantId, match: { value: tenant-123 } }, { key: score, range: { gte: 0.5, lte: 1.0 } }, ], should: [ { key: category, match: { value: document } }, { key: category, match: { value: image } }, ], must_not: [{ key: status, match: { value: deleted } }], };③ LanceDB SQL 字符串过滤器const lancedbFilter: VectorFilter tenantId tenant-123 AND score 0.5 AND category IN (document, image);6.2 条件类型一览interface.ts 定义了完整的FilterCondition类型体系条件说明示例match.value精确匹配{ key: category, match: { value: document } }match.any匹配多个值之一IN{ key: tags, match: { any: [important, urgent] } }match.except排除多个值NOT IN{ key: status, match: { except: [deleted, archived] } }match.text文本包含匹配{ key: title, match: { text: refly } }range数值/时间戳范围{ key: score, range: { gte: 0.5, lte: 1.0 } }geo_bounding_box地理包围盒{ top_left: {lat,lon}, bottom_right: {lat,lon} }geo_radius地理半径检索{ center: {lat,lon}, radius: 1000 }is_empty/is_null空值/空字符串判断{ key: note, is_empty: {} }has_idID 集合匹配{ key: id, has_id: { has_id: [a,b] } }6.3 双端自动转换FilterUtils过滤器之所以能做到“一套代码双端通用”关键在于 backend/filter-utils.ts 提供的双向转换toQdrantFilter(filter)将任意形态的过滤器转成 Qdrant 结构化过滤器SQL 字符串会被解析为{ must: [...] }支持、IN、、、、等常见表达式toLanceDBFilter(filter)将任意形态的过滤器转成 LanceDB SQL WHERE 子句Qdrant 结构被编译为(cond1 AND cond2) AND (c1 OR c2) AND NOT (...)形式的 SQL。类型检测逻辑为字符串 → LanceDB 过滤器含must/should/must_not数组 → Qdrant 过滤器其余键值全为原始类型string/number/boolean/null→ 简单过滤器filter-utils.ts。注意backend/README.md中提到的validateFilter导出在当前 filter-utils.ts 源码中未找到对应实现若依赖该校验能力请以实际代码为准或自行实现。七、API 参考方法与类型7.1 VectorSearchService 方法index.ts方法签名说明isCollectionEmpty(): Promiseboolean集合不存在或为空时返回truebatchSaveData(points: VectorPoint[]): Promiseany批量保存向量点batchDelete(filter: VectorFilter): Promiseany按过滤器批量删除search(request, filter): PromiseVectorSearchResult[]相似向量检索scroll(request: VectorScrollRequest): PromiseVectorPoint[]滚动遍历点集updatePayload(filter, payload): Promiseany按过滤器更新元数据estimatePointsSize(points: VectorPoint[]): number估算点集占用字节数其中estimatePointsSize的估算公式qdrant.ts向量 4 字节/float32 × 维度 payload 的 UTF-8 字节数 id 的 UTF-8 字节数。该能力被 RAG 服务用于统计写入体量。7.2 核心类型backend/interface.ts// 向量点 interface VectorPoint { id: string; vector: number[]; payload: Recordstring, any; } // 检索请求query 为可选vector 必填于 LanceDB interface VectorSearchRequest { query?: string; vector?: number[]; limit?: number; } // 检索结果 interface VectorSearchResult { id: string; score: number; payload: Recordstring, any; } // 滚动请求 interface VectorScrollRequest { filter?: VectorFilter; limit?: number; offset?: string | null; with_payload?: boolean; with_vector?: boolean; }后端抽象接口VectorSearchBackend定义了与VectorSearchService一致的七个方法外加initialize()是新增后端的契约interface.ts。八、测试与 Mock由于服务通过 token 注入单元测试中可以轻松替换为 Mock 实现文档示例const mockVectorSearchService { isCollectionEmpty: jest.fn(), batchSaveData: jest.fn(), search: jest.fn(), scroll: jest.fn(), batchDelete: jest.fn(), updatePayload: jest.fn(), estimatePointsSize: jest.fn(), }; beforeEach(async () { const module: TestingModule await Test.createTestingModule({ providers: [ YourService, { provide: VECTOR_SEARCH, useValue: mockVectorSearchService }, ], }).compile(); });Refly 仓库中已有真实范例rag.service.spec.ts 即采用同样的 token 覆盖方式测试依赖向量检索的 RAG 服务可作为编写测试时的参照。九、在 Refly 中的真实应用RAG 知识检索向量检索服务并非孤立存在apps/api/src/modules/rag/rag.service.ts 是其典型业务消费者通过Inject(VECTOR_SEARCH) private vectorSearch: VectorSearchService注入rag.service.ts文档写入场景先用scroll查询既有向量点并计算待写入体量用batchDelete清理旧数据后再以batchSaveData批量 upsertrag.service.ts检索场景this.vectorSearch.search(param, filter)返回相似向量结果rag.service.ts元数据维护updatePayload(filter, metadata)更新文档元信息rag.service.ts全量索引与配额统计多处调用scroll配合estimatePointsSize估算存储占用。这段真实调用链完整覆盖了文档中全部核心 API是“写入 → 检索 → 更新 → 删除”生命周期的最佳参考实现。十、新增后端的扩展指南文档给出三步扩展法结合源码可进一步明确第 1 步实现VectorSearchBackend接口export class MyVectorBackend implements VectorSearchBackend { // 需实现initialize / isCollectionEmpty / batchSaveData / // batchDelete / search / scroll / updatePayload / estimatePointsSize }接口契约见 backend/interface.ts可参照 backend/qdrant.ts 与 backend/lancedb.ts 两个现成实现。第 2 步注册到工厂在 index.ts 的createVectorSearchFactory中新增分支if (backendType my-backend) { backend new MyVectorBackend(configService); }第 3 步补充配置支持vectorStore: backend: my-backend # 添加后端特有配置项由于VectorSearchService对后端完全透明扩展后业务代码无需任何改动。此外若新后端存在与 Qdrant/LanceDB 不同的过滤器语义可复用filter-utils.ts的双向转换体系确保上层 API 一致性。十一、性能与运维要点11.1 后端选型建议Qdrant适合大规模生产环境支持水平扩展与高级索引选项但需关注网络延迟首次建集自动启用磁盘索引on_disk与tenantIdpayload 索引LanceDB读密集、本地/云存储场景无网络开销、自动索引、存储格式高效但 offset 分页与原地更新能力受限。11.2 过滤器性能实践优先使用已索引字段如tenantId作为首个过滤条件简单等值匹配快于复杂范围查询范围查询尽量收窄边界避免深层嵌套字段访问如metadata.nested.deeply.field会显著拖慢过滤性能。11.3 常见故障排查问题排查方向后端未找到检查vectorStore.backend配置值是否为qdrant/lancedb连接超时Qdrant 检查网络连通性与端口LanceDB 检查目录/存储的读写权限类型错误确认使用VectorPoint、VectorFilter等正确接口类型集合不存在即查询两个后端在集合未创建/表不存在时均返回空数组或true属预期行为服务会在初始化与出错时自动输出日志关键词如Vector search service initialized、Failed to initialize Qdrant collection排查时关注应用日志中的 vector search 相关记录即可。十二、小结Refly 的 Vector Search Service 以“接口抽象 工厂装配 过滤器双端转换”三层设计实现了对 Qdrant 与 LanceDB 的统一访问上层业务只需关心VectorSearchService的七个方法底层数据库可随部署环境自由切换。从 README.md 到 index.ts、backend/qdrant.ts、backend/lancedb.ts、backend/filter-utils.ts再到真实消费者 rag.service.ts这条完整的调用链展示了向量检索能力从基础设施到业务落地的全过程也为后续接入更多向量数据库预留了清晰的扩展路径。【免费下载链接】reflyThe first open-source agent skills builder. Define skills by vibe workflow, run on Claude Code, Cursor, Codex more. Build Clawdbot · APIs for Lovable · Bots for Slack Lark/Feishu · Skills are infrastructure, not prompts.项目地址: https://gitcode.com/GitHub_Trending/re/refly创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号