Feast 向量数据库(Alpha):从 Embedding 存储到 OpenAI 兼容检索的完整实践

Feast 向量数据库(Alpha):从 Embedding 存储到 OpenAI 兼容检索的完整实践 Feast 向量数据库Alpha从 Embedding 存储到 OpenAI 兼容检索的完整实践【免费下载链接】feastThe Open Source Feature Store for AI/ML项目地址: https://gitcode.com/GitHub_Trending/fe/feast功能状态说明向量数据库是 Feast 的一项实验性Alpha功能。官方文档声明该功能目前总体稳定但在使用体验上仍存在一些粗糙之处欢迎社区贡献改进。本文基于当前仓库的 alpha-vector-database.md 文档及 sdk/python/feast 源码编写帮助读者掌握如何用 Feast 存储与检索 Embedding并接入 RAG 与 LLM 应用。1. 概览Feast 如何抽象向量检索向量数据库允许用户存储并检索 Embedding 向量。Feast 提供了通用 API来完成 Embedding 的写入与相似度检索其核心思路是把带向量的 Feature View物化到支持向量检索的在线存储中再通过统一的 SDK / HTTP 接口完成 top-k 相似度搜索。从源码结构看这一能力由 feature_store.py 中的retrieve_online_documents/retrieve_online_documents_v2两个方法以及 vector_store.py 中的FeastVectorStore封装类共同承担。其中FeastVectorStore是一个便捷门面同时支持文本、图像与多模态检索它会在初始化时自动扫描 Feature View 中带vector_index的字段并读取其vector_search_metric作为默认距离度量参见 vector_store.py。2. 支持的向量数据库与集成矩阵官方文档给出了当前仓库中已集成的向量数据库及其能力矩阵向量数据库检索 (Retrieval)索引 (Indexing)V2 支持*在线读取 (Online Read)Pgvector✔️———Elasticsearch✔️✔️——Milvus✔️✔️✔️✔️Faiss————SQLite✔️—✔️✔️Qdrant✔️✔️——ScyllaDB✔️✔️✔️✔️*V2 支持指 SDK 支持在向量相似度检索的同时一并取回标准特征Feature与向量 Embedding。两点补充说明SQLite 处于受限访问状态目前仅在 Python 3.10 上可用其能力会随 sqlite-vec 项目进展而更新从仓库测试与示例看Milvus、SQLite、ScyllaDB已在 SDK 层实现了 v2 方法retrieve_online_documents_v2相关实现在 milvus.py、sqlite.py、scylladb.py 中。3. API 演进retrieve_online_documents与retrieve_online_documents_v2官方文档对两代检索方法给出了明确的演进说明摘自文档中的 danger 提示未来 SDK 将弃用retrieve_online_documents官方推荐改用retrieve_online_documents_v2。v2 的优势在于可以直接在 Feature View 上配置向量索引并且能够在返回向量 Embedding 的同时取回标准特征便于做更丰富的上下文注入。长远来看两个方法最终会合并为一个届时retrieve_online_documents与retrieve_online_documents_v2都会指向get_online_features以兼容业界标准命名约定。两代方法在源码中的差异也印证了这一演进方向retrieve_online_documentsfeature_store.py只接受Embedding 向量作为查询query: Union[str, List[float]]若直接传字符串会抛出ValueError提示需先完成文本 Embedding且一次只支持单个 Feature Viewfeature_view_set长度大于 1 即报错。retrieve_online_documents_v2feature_store.py支持query文本 Embedding、query_string混合检索文本、query_image_bytes图像相似度检索三种查询形态并支持combine_with_text多模态融合text_weight image_weight必须等于 1.0否则报错、filters元数据过滤以及可选的include_feature_view_version_metadata版本元数据。此外v2 还内置了对 On-Demand Feature View 的支持会从available_odfv_views中解析使检索链路可以衔接在线变换。4. Feature Server 检索端点总览官方文档给出了 Feature Server 对外暴露的检索端点速查表端点适用场景POST /search你已持有 Embedding 向量或使用api_version: 2传query_string希望获得 Feast 原生的在线特征响应格式GET /v1/vector_stores发现可用的向量存储及其vs_{hash}IDOpenAI 兼容GET /v1/vector_stores/{id}获取某个具体向量存储的元数据OpenAI 兼容POST /v1/vector_stores/{id}/search使用纯文本查询 服务端 Embedding返回 OpenAI 兼容响应POST /retrieve-online-documents已弃用请改用POST /search。这一点在 feature_server.py 中也有体现/retrieve-online-documents路由会先返回弃用提示再转发到与/search相同的处理逻辑。5. [Alpha] OpenAI 兼容向量存储 APIAlpha 特性警告该 API 面已可运行且经过测试但可能在后续版本中调整欢迎反馈与贡献。Feast 暴露了一组OpenAI 兼容的向量存储端点让客户端可以用纯文本查询 服务端 Embedding来发现、查看与检索向量存储。这意味着AI Agent、LLM 工具调用框架以及任何 OpenAI 兼容客户端都可以直接对接调用方无需自行产出原始 Embedding 向量。5.1 向量存储 ID 的生成规则每个包含至少一个vector_indexTrue字段的 Feature View都会被自动分配一个确定性标识符形如vs_{hash}其中{hash}是SHA-256(project : feature_view_name)的前 24 个字符。该 ID 在服务重启与 Registry 刷新后保持稳定。例如项目my_project下的 Feature Viewproduct_catalog总是映射到同一个vs_...标识。列出端点会返回这些 ID客户端可以在运行时发现存储。这一规则在 vector_store_utils.py 中有精确实现def feature_view_to_vs_id(project: str, feature_view_name: str) - str: digest hashlib.sha256(f{project}:{feature_view_name}.encode()).hexdigest()[:24] return fvs_{digest}5.2 端点与权限方法路径所需权限说明GET/v1/vector_storesDESCRIBE列出调用方有权限访问的全部向量存储GET/v1/vector_stores/{vector_store_id}DESCRIBE获取单个向量存储的元数据POST/v1/vector_stores/{vector_store_id}/searchREAD_ONLINE用纯文本查询检索向量存储配置了认证后以上所有端点都会强制RBAC校验列出端点会自动过滤掉调用方无权DESCRIBE的存储。这些路由定义于 feature_server.py服务端通过store.openai_search(...)处理POST .../search请求。5.3 启用前置条件要使用该 API需要满足以下三点① 配置 Embedding 模型—— 在feature_store.yaml中增加embedding_model段。默认使用Sentence Transformers做本地 Embedding无需外部 API Key安装pip install sentence-transformers即可embedding_model: provider: sentence_transformers # 默认值可省略 model: all-MiniLM-L6-v2② 定义带向量索引的 Feature View—— 至少有一个 Feature View 在向量字段上设置了vector_indexTrue并且物化到支持向量检索的在线存储中。③ 可选数值过滤支持—— 若元数据过滤涉及数值或布尔比较需要在在线存储配置中开启enable_openai_compatible_store: true然后执行feast apply以在数据库中新增value_num列。5.4 自定义 Embedding Provider内置的 Sentence Transformers Provider 适用于大多数场景。若想接入其他 Embedding 后端OpenAI、Cohere 或自研模型可以实现EmbeddingProvider协议并将实例传给FeatureStorefrom feast.embedder import EmbeddingProvider class MyEmbeddingProvider: def embed(self, texts: list[str]) - list[list[float]]: # 在此调用你的 Embedding API return my_model.encode(texts) async def aembed(self, texts: list[str]) - list[list[float]]: return await my_model.aencode(texts) store FeatureStore( repo_path., embedding_providerMyEmbeddingProvider(), )从源码看该协议定义于 embedder.py内置的SentenceTransformersEmbeddingProviderembedder.py通过from_config工厂构造模型加载采用惰性初始化——只有真正调用embed/aembed时才导入 sentence-transformers避免启动开销。get_embedding_provider工厂会按config.provider分发默认sentence_transformers未知 Provider 名称会抛出ValueError。5.5 数值存储enable_openai_compatible_store默认情况下特征值在在线存储中以文本形式保存因此字符串排序规则生效例如9 100为true。当在线存储配置中开启enable_openai_compatible_store: true后Feast 会新增一个value_num列用原生类型存储int、float、double和bool值从而保证数值过滤结果正确online_store: type: postgres # 或 sqlite # ... 连接配置 ... enable_openai_compatible_store: true修改该配置后需运行feast apply更新数据库表结构。5.6 端点使用示例以下请求默认 Feature Server 运行在localhost:6566feast serve启动。列出向量存储curl http://localhost:6566/v1/vector_stores{ object: list, data: [ { id: vs_a1b2c3d4e5f6a1b2c3d4e5f6, object: vector_store, name: product_catalog, status: completed, created_at: 1717200000 } ] }获取单个向量存储curl http://localhost:6566/v1/vector_stores/vs_a1b2c3d4e5f6a1b2c3d4e5f6返回对象形状与列表响应中的单个条目一致若 ID 不匹配任何带向量索引的 Feature View返回404。执行检索curl -X POST http://localhost:6566/v1/vector_stores/vs_a1b2c3d4e5f6a1b2c3d4e5f6/search \ -H Content-Type: application/json \ -d { query: wireless noise-cancelling headphones, max_num_results: 5 }5.7 请求字段说明字段类型默认值说明querystring或list[string]必填纯文本检索查询。列表会在 Embedding 前用空格拼接max_num_resultsint10返回结果的最大条数filtersobjectnullOpenAI 风格过滤器见下文ranking_optionsobjectnull为向前兼容而接受但当前被忽略在其中设置score_threshold或ranker将返回 422 错误rewrite_queryboolnull接受false默认/无操作true尚未支持将返回 422 错误metadataobjectnull可选metadata.features_to_retrieve用于挑选特定特征5.8 元数据过滤器OpenAI 风格端点支持在向量相似度之外用 OpenAI 风格过滤器进一步收窄结果。比较运算符eq、ne、gt、gte、lt、lte、in、nin{type: eq, key: category, value: Electronics}复合运算符and、or可任意深度嵌套{ type: and, filters: [ {type: eq, key: category, value: Electronics}, {type: gte, key: rating, value: 4.5} ] }使用限制对于Postgres 与 SQLite后端所有过滤包括字符串相等比较都要求在线存储开启enable_openai_compatible_store: true开启后执行feast apply更新表结构ScyllaDB支持通过retrieve_online_documents_v2进行向量检索但OpenAI 风格元数据过滤尚未实现——传入filters会抛出NotImplementedError。5.9 响应格式与分数转换响应遵循 OpenAIvector_store.search_results.page模式{ object: vector_store.search_results.page, search_query: [wireless noise-cancelling headphones], data: [ { file_id: vs_a1b2c3d4e5f6a1b2c3d4e5f6_42, filename: vs_a1b2c3d4e5f6a1b2c3d4e5f6, score: 0.92, attributes: {name: ..., category: ...}, content: [ {type: text, text: ...} ] } ], has_more: false, next_page: null }要点解读file_id与filename字段使用vs_{hash}标识符而非原始 Feature View 名称score是越高越好的相关性分数由原始向量距离按度量类型换算而来距离度量换算公式取值范围L2默认1 / (1 distance)(0, 1]Cosine1 - distance[0, 1]内积 / 点积-distance不定度量由 Feature View 向量字段上的vector_search_metric决定不由 API 参数指定。该换算逻辑在 utils.py 的_distance_to_score中实现省略features_to_retrieve时默认返回全部非向量特征向量 Embedding 列会被排除分页尚未实现has_more恒为false。从 feature_store.py 的openai_search实现可以看到完整的响应组装链路先经embedding_provider.aembed对查询文本做 Embedding再调用retrieve_online_documents_v2获取结果最后逐行将distance换算为score、把字符串特征组装进content、并用排序后的实体键拼接file_id无实体时回退为下标。5.10 通过 Python SDK 直接调用OpenAI 兼容检索也可直接通过 Python SDK 使用注意openai_search是异步方法import asyncio from feast import FeatureStore store FeatureStore(repo_path.) result asyncio.run(store.openai_search( vector_store_idproduct_catalog, querywireless noise-cancelling headphones, max_num_results5, filters{type: eq, key: category, value: Electronics}, )) for item in result[data]: print(f{item[score]:.3f} {item[attributes]})SDK 参数与 HTTP 端点一一对应vector_store_id对应 Feature View 名称内部映射为vs_{hash}filters既支持字典也支持ComparisonFilter/CompoundFilter类型对象。5.11 各在线存储的 OpenAI 兼容支持情况官方文档确认已为下列在线存储实现了 OpenAI 兼容过滤在线存储向量检索元数据过滤备注Milvus✔️✔️布尔表达式Elasticsearch✔️✔️Query DSL 子句Postgrespgvector✔️✔️需enable_openai_compatible_store: trueSQLitesqlite-vec✔️✔️需enable_openai_compatible_store: trueMongoDB✔️✔️聚合管道ScyllaDB✔️❌仅向量检索元数据过滤暂未支持6. 端到端示例Milvus 上的 RAG 检索官方文档给出了一条完整的 RAG 链路v1 路线基于retrieve_online_documents_v2完整可运行示例见仓库中的 examples/rag/milvus-quickstart.ipynb配套的 Feature Repo 位于 examples/rag/feature_repo。v0 路线的retrieve_online_documents用法见 Rag Demo 的 module_4_rag官方已计划迁移与弃用。6.1 准备离线 Embedding 数据集运行以下命令生成 Embedding 数据集python pull_states.py python batch_score_documents.py输出将存储在data/city_wikipedia_summaries.csv中。6.2 初始化 Feature Store 并物化到在线存储使用下面的feature_store.yaml初始化特征仓库数据源使用本地文件作为离线存储Milvus 作为在线存储project: local_rag provider: local registry: data/registry.db online_store: type: milvus path: data/online_store.db vector_enabled: true embedding_dim: 384 index_type: IVF_FLAT offline_store: type: file entity_key_serialization_version: 3 # 默认 no_auth其他可选值kubernetes、oidc详见相关文档 auth: type: no_auth然后在终端执行feast apply执行feast apply时会注册下面这个后续用于检索的 Feature Viewdocument_embeddings FeatureView( nameembedded_documents, entities[item, author], schema[ Field( namevector, dtypeArray(Float32), # 看开启 RAG 就是这么简单 vector_indexTrue, vector_search_metricCOSINE, ), Field(nameitem_id, dtypeInt64), Field(nameauthor_id, dtypeString), Field(namecreated_timestamp, dtypeUnixTimestamp), Field(namesentence_chunks, dtypeString), Field(nameevent_timestamp, dtypeUnixTimestamp), ], sourcerag_documents_source, ttltimedelta(hours24), )随后用 SDK 把包含 Embedding 的 DataFrame 写入在线存储store.write_to_online_store(feature_view_namecity_embeddings, dfdf)6.3 生成查询 Embedding推理阶段例如用户提交聊天消息时需要对输入文本做 Embedding。这可以看作对输入数据的一次特征变换。示例中使用 Hugging Face 的小型 Sentence Transformer 完成import torch import torch.nn.functional as F from feast import FeatureStore from pymilvus import MilvusClient, DataType, FieldSchema from transformers import AutoTokenizer, AutoModel from example_repo import city_embeddings_feature_view, item TOKENIZER sentence-transformers/all-MiniLM-L6-v2 MODEL sentence-transformers/all-MiniLM-L6-v2 def mean_pooling(model_output, attention_mask): token_embeddings model_output[ 0 ] # model_output 的第一个元素包含所有 token 的 Embedding input_mask_expanded ( attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float() ) return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp( input_mask_expanded.sum(1), min1e-9 ) def run_model(sentences, tokenizer, model): encoded_input tokenizer( sentences, paddingTrue, truncationTrue, return_tensorspt ) # 计算 token Embedding with torch.no_grad(): model_output model(**encoded_input) sentence_embeddings mean_pooling(model_output, encoded_input[attention_mask]) sentence_embeddings F.normalize(sentence_embeddings, p2, dim1) return sentence_embeddings question Which city has the largest population in New York? tokenizer AutoTokenizer.from_pretrained(TOKENIZER) model AutoModel.from_pretrained(MODEL) query_embedding run_model(question, tokenizer, model).detach().cpu().numpy().tolist()[0]6.4 检索 top-K 相似文档创建 Feature Store 实例调用retrieve_online_documents_v2检索与查询最相似的 3 条文档context_data store.retrieve_online_documents_v2( features[ city_embeddings:vector, city_embeddings:item_id, city_embeddings:state, city_embeddings:sentence_chunks, city_embeddings:wiki_summary, ], queryquery_embedding, top_k3, distance_metricCOSINE, ).to_df()注意这里features以feature_view:feature形式引用多个特征一次调用即可同时取回向量相似度结果与文档相关的标准特征这正是 v2 方法的核心价值。6.5 用 LLM 生成最终回答假设已有基础提示词BASE_PROMPT和格式化检索结果的函数format_documents可以将检索到的上下文拼入提示词后调用 OpenAI 的 Chat Completion APIFULL_PROMPT format_documents(rag_context_data, BASE_PROMPT) from openai import OpenAI client OpenAI( api_keyos.environ.get(OPENAI_API_KEY), ) response client.chat.completions.create( modelgpt-4o-mini, messages[ {role: system, content: FULL_PROMPT}, {role: user, content: question} ], ) # 输出回答内容。端到端示例见 examples/rag/milvus-quickstart.ipynb print(\n.join([c.message.content for c in response.choices]))至此文档入库 → 向量检索 → 上下文注入 → LLM 生成的完整 RAG 闭环就打通了。7. 配置与安装Feast 为向量数据库场景提供以下在线存储选项Milvus、PGVector、SQLitesqlite-vec、Elasticsearch、Qdrant。其中 Milvus 提供了便捷的本地实现用于向量相似度检索。按需选择对应的安装方式# Milvus pip install feast[milvus] # Elasticsearch pip install feast[elasticsearch] # Qdrant pip install feast[qdrant]SQLite 特殊说明若使用pyenv管理 Python 版本需要先安装带可加载扩展支持的 Python 3.10PYTHON_CONFIGURE_OPTS--enable-loadable-sqlite-extensions \ LDFLAGS-L/opt/homebrew/opt/sqlite/lib \ CPPFLAGS-I/opt/homebrew/opt/sqlite/include \ pyenv install 3.10.14然后安装 Feast 的 SQLite 向量扩展包pip install feast[sqlite_vec]8. 小结与建议新项目直接使用 v2 路线retrieve_online_documents_v2支持在 Feature View 上直接声明向量索引vector_indexTruevector_search_metric并能在检索向量的同时取回标准特征是官方推荐的长期方案AI Agent 集成首选 OpenAI 兼容 API/v1/vector_stores/*系列端点支持纯文本查询与服务端 Embedding配合 embedder.py 的EmbeddingProvider协议可以无缝替换任意 Embedding 后端无需调用方关心向量细节数值过滤需显式开启Postgres / SQLite 上若元数据过滤涉及数值或布尔比较务必开启enable_openai_compatible_store: true并重新执行feast apply关注功能演进该 API 处于 Alpha 阶段retrieve_online_documents已进入弃用计划ranking_options、rewrite_query等参数尚未实现使用时建议以当前仓库文档与源码为准。【免费下载链接】feastThe Open Source Feature Store for AI/ML项目地址: https://gitcode.com/GitHub_Trending/fe/feast创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考