txtai Embeddings 方法全解析:从索引构建到语义搜索的完整 API 指南
【免费下载链接】txtai💡 All-in-one AI framework for semantic search, LLM orchestration and language model workflows项目地址: https://gitcode.com/GitHub_Trending/tx/txtai
txtai 的 Embeddings 是驱动语义搜索的核心引擎:数据被转换为 embeddings 向量,含义相近的概念会得到相近的向量,从而让检索结果“语义相关”而非仅仅“关键词相同”。本文以官方文档 docs/embeddings/methods.md 为主体,结合 Embeddings 源码 与 indexing.md、query.md 等配套指南,系统讲解Embeddings类的构造、索引、搜索、更新删除、持久化与资源管理等全部核心方法,读完即可在自己的项目中构建、保存并检索一个可用的语义搜索引擎。
快速上手:构建并搜索一个 Embeddings 索引
先看一个最小可运行示例,它完整演示了“创建实例 → 索引数据 → 语义搜索”三步流程,也是理解后续所有方法的起点。
from txtai import Embeddings # 创建 embeddings 模型,底层由 sentence-transformers & transformers 驱动 embeddings = Embeddings(path="sentence-transformers/nli-mpnet-base-v2") data = [ "US tops 5 million confirmed virus cases", "Canada's last fully intact ice shelf has suddenly collapsed, " + "forming a Manhattan-sized iceberg", "Beijing mobilises invasion craft along coast as Taiwan tensions escalate", "The National Park Service warns against sacrificing slower friends " + "in a bear attack", "Maine man wins $1M from $25 lottery ticket", "Make huge profits without work, earn up to $100,000 a day" ] # 索引文本列表 embeddings.index(data) print(f"{'Query':20} Best Match") print("-" * 50) # 对每个查询执行语义搜索 for query in ("feel good story", "climate change", "public health story", "war", "wildlife", "asia", "lucky", "dishonest junk"): # 取第一条结果的 uid # search 结果格式: (uid, score) uid = embeddings.search(query, 1)[0][0] # 打印命中的原文 print(f"{query:20} {data[uid]}")这段代码演示了 txtai 语义搜索的核心价值:"feel good story"会命中彩票中奖的新闻,"climate change"会命中冰架坍塌的报道,"dishonest junk"会命中诈骗广告——检索依据是语义而非字面关键词。
Build:配置驱动的 Embeddings 实例构造
Embeddings实例是配置驱动的,构造函数接受一个配置字典(也可全部以关键字参数传入)。从源码看,构造函数会合并config与kwargs为单一字典,再调用configure()加载各类模型组件:
def __init__(self, config=None, models=None, **kwargs): # 合并配置 config = {**config, **kwargs} if config and kwargs else kwargs if kwargs else config # 设置初始配置并加载配置驱动的模型 self.configure(config)上面示例通过 path 参数指定了具体的向量模型。也可以创建一个不带任何配置的实例:
embeddings = Embeddings()此时,当加载和检索数据时,会使用默认的 transformers 向量模型sentence-transformers/all-MiniLM-L6-v2对数据做向量化。这一点在源码 base.py 的 defaults 方法中有明确体现:当没有显式模型且允许默认值时,会写入self.config["path"] = "sentence-transformers/all-MiniLM-L6-v2"。向量模型的选型建议可参考模型指南。
从源码结构看,一个Embeddings实例会按需挂载以下组件(对应 base.py 的初始化清单):
| 属性 | 作用 |
|---|---|
model | 稠密向量模型,将数据转换为相似度向量 |
ann | 近似最近邻(ANN)索引,存储稠密向量 |
database | 文档数据库,存储文档原文内容 |
scoring | 稀疏向量/关键词索引(BM25、TF-IDF、SPLADE 等) |
graph | 语义图网络 |
indexes | 子索引(subindexes),也是 embeddings 数据库 |
ids | 关闭内容存储时的 indexid→id 映射 |
query | 查询翻译模型,把自然语言查询转成 SQL |
Index:向索引添加数据
创建实例后,下一步就是写入数据:
embeddings.index(rows)index方法接受一个可迭代对象,其中每个元素支持三种格式:
(id, data, tags)—— 默认处理格式元素 说明 id 唯一记录 id data 待索引的输入数据,可以是文本、字典或对象 tags 可选的标签字符串,用于在索引时标记/标注数据 (id, data)—— 同上,但没有 tags。data—— 单一元素。此时会自动生成唯一 id。注意:对于自动生成的 id,后续的 upsert 和 delete 调用需要先执行一次搜索来拿到目标 id。
当data是字典时,文本通过text键传入,二进制对象通过object键传入。需要特别注意的是:必须开启 content 才能存储元数据,开启 objects 才能存储二进制对象;如果提供了id和tags键,也会被自动提取。
输入可迭代对象可以是列表或生成器(generator)。对于非常大的数据集,生成器能显著降低内存占用,因为任意时刻只有一部分数据驻留内存。索引的更多细节(向量化、后端设置、稀疏向量、子索引等)参见索引指南。
从源码看,index内部流程(base.py#L103-L153)大致为:初始化索引 → 用Stream流式读取文档 → 用Transform将文档写入数据库并转为向量(结果暂存到临时.npy文件)→ 可选执行 PCA 降维 → 创建 ANN 并把向量灌入 → 再依次索引稀疏评分、子索引与图网络。因此一次index调用是“全量重建”语义:它会覆盖已有索引。
Search:执行语义查询
数据索引完成后即可检索:
embeddings.search(query, limit)search方法接收两个参数:查询语句与结果条数限制。返回结果的格式取决于是否开启 content 存储:
- 未存储内容时:返回
(id, score)元组列表 - 存储内容时:返回
{**query columns}字典列表(包含查询中涉及的全部列)
自然语言查询与 SQL 查询都被支持。简单自然语言查询示例:
embeddings.search("feel good story") embeddings.search("wildlife")开启内容存储后,还能使用带过滤条件的 SQL:
SELECT text, flag, actiondate FROM txtai WHERE similar('query') AND flag = 1 AND actiondate >= '2022-01-01'关于similar()子句、绑定参数、聚合查询、自定义 SQL 函数、混合检索权重、图检索与子索引查询的完整说明,见查询指南。
从搜索执行源码(search/base.py)可以看清查询分派逻辑:当存在图网络且查询是图语句时走图搜索;否则若未强制索引搜索且有数据库,则走“索引 + 数据库”联合搜索(先做相似度检索拿到候选 id,再注入数据库查询完成过滤);其余情况走纯向量索引搜索(稀疏、稠密或两者加权融合的 hybrid 搜索)。limit默认值为 3,hybrid 权重默认值为 0.5。
批量查询
与index对应,search也提供了批量版本batchsearch(queries, limit, weights, index, parameters, graph),一次调用可处理多条查询,返回按查询分组的嵌套列表。源码中search就是batchsearch对单条查询的封装(base.py#L356-L376)。
增删改:upsert、delete 与 reindex
Upsert:插入或更新记录
embeddings.upsert(documents)upsert在索引已存在时,把新数据追加进索引、已存在的数据更新;若索引尚不存在或为空,则退化为标准index操作(源码见 base.py#L166-L169)。与index的全量重建不同,upsert不需要重建整个索引。
Delete:删除记录
embeddings.delete(ids)delete接收 id 列表并返回实际删除的 id 列表(base.py#L203-L258)。从源码看:有数据库时,先从数据库查询 indexid→id 映射,再删除数据库记录;没有数据库时,则在ids映射中按 id 反查内部索引位置;随后依次对 ANN、稀疏评分、子索引和图网络执行删除。
Reindex:换模型/换后端重索引
开启内容存储后,可以调用reindex用新配置重建索引——例如把后端从 faiss 切换为 hnsw,或更换向量模型,而无需回到原始数据:
embeddings.reindex(path="sentence-transformers/all-MiniLM-L6-v2", backend="hnsw")源码(base.py#L260-L290)会保留原有的content与objects配置以确保数据库得以复用,从已存文档重新向量化并建索引。
其他常用方法
除上述主流程外,Embeddings还提供以下实用方法(均可从 base.py 中查看实现):
transform(document, category, index)/batchtransform(documents, ...):把单个/多个文档转换为 embeddings 向量,支持指令式嵌入的category参数与子索引的index参数。similarity(query, data)/batchsimilarity(queries, data):计算查询与一组数据的相似度,返回按得分降序的(id, score)列表(id 即数据在列表中的下标)。实现上利用归一化向量的点积等价于余弦相似度(base.py#L441-L445)。explain(query, texts, limit):解释查询中每个输入 token 的重要程度(分数越高越相关),需要开启内容存储或显式传入texts。terms(query)/batchterms(queries):把查询缩减为关键词项,常用于稀疏检索场景。count():返回索引中的元素总数(按 ANN、scoring、database、ids 的顺序择一计算)。info():以 JSON 打印当前索引的完整配置,便于调试。
资源管理:上下文管理器与 close
Embeddings数据库实现了上下文管理器协议(__enter__/__exit__,见 base.py#L85-L89),以下代码块结束后会自动调用 close 释放资源:
# 创建新的 Embeddings 数据库,索引数据并保存 with Embeddings() as embeddings: embeddings.index(rows) embeddings.save(path) # 加载已保存的 Embeddings 数据库并搜索 with Embeddings().load(path) as embeddings: embeddings.search(query)虽然不显式调用close也通常没问题(资源会被垃圾回收),但最佳实践是:一旦不再需要,就尽早释放数据库连接等共享资源。从源码看,close会依次关闭 ANN、数据库、scoring、图网络、子索引与向量模型,并把所有引用置空。
持久化:save、load 与 exists
索引可以保存到目录或压缩文件中:
# 保存到目录 embeddings.save("/path/to/save") # 保存为压缩包 embeddings.save("/path/to/save/index.tar.gz") # 加载 embeddings.load("/path/to/load")从 save 实现可以看到,保存会按组件分文件落盘:config(配置)、embeddings(ANN 向量)、lsa(PCA 降维模型)、ids、documents(数据库)、scoring、indexes、graph,路径以.tar.gz、.tar.bz2、.tar.xz或.zip结尾时自动打包为压缩文件。load则按同名规则逐一恢复(base.py#L533-L604),并支持传入config覆盖已有配置。
此外,索引还可以持久化到云存储(仅支持压缩包形式,适合 serverless 或临时计算环境),以及通过exists(path)检查某路径下是否已存在有效索引。更多索引读写场景见索引指南的 Save 章节。
方法背后的架构:多组件协同
Embeddings之所以能同时支持语义搜索、关键词搜索与结构化过滤,是因为它把多种存储与索引组件组合在了一起:内容存储在底层关系数据库中,同时维护 ANN 索引、关键词索引(scoring)与可选的图网络。
以一次带数据库的查询为例,检索链路是:自然语言查询 → 向量化 → ANN 相似度检索得到候选 id → 将这些 id 注入底层 SQL 查询 → 结合动态列过滤返回结构化结果。动态列在 SQLite 中会转换为json_extract子句,客户端-服务器数据库则通过 SQLAlchemy 方言支持(前提是底层引擎具备 JSON 类型支持)。这一“相似度检索 + 结构化过滤”的组合架构,正是 txtai 查询层的核心设计。
延伸阅读
- Embeddings 总览:语义搜索引擎的定位与入门示例
- 索引指南:向量化、后端设置、稀疏向量、图与子索引的深入讲解
- 查询指南:SQL、similar 子句、绑定参数、混合检索、图检索
- 配置参考:
path、content、objects、scoring、indexes等全部配置项 - 示例集合:语义搜索相关的完整 notebook 示例列表
【免费下载链接】txtai💡 All-in-one AI framework for semantic search, LLM orchestration and language model workflows项目地址: https://gitcode.com/GitHub_Trending/tx/txtai
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考