LLM 嵌入向量 Python API 完全指南从模型加载到语义相似度检索【免费下载链接】llmAccess large language models from the command-line项目地址: https://gitcode.com/gh_mirrors/llm/llm导读本文以 LLM 项目的llm.Collection与EmbeddingModel两大核心类为主线系统讲解如何通过 Python API 加载嵌入模型、批量生成 embedding 向量、在 SQLite 中构建集合collection并执行基于余弦相似度的语义检索。读完本文你将掌握从llm.get_embedding_model()到collection.similar()的完整调用链并理解底层 SQL 表结构与向量二进制编码格式可直接用于构建语义搜索、相关文章推荐等应用。本文所有代码示例均可直接运行关键结论附有仓库源码与测试佐证。一、加载嵌入模型llm.get_embedding_model()LLM 通过插件机制注册多个嵌入模型。安装插件后即可使用模型 ID 或别名加载模型实例import llm embedding_model llm.get_embedding_model(3-small)这里的3-small是 OpenAI 文本嵌入模型text-embedding-3-small的别名。从源码看get_embedding_model()的实现位于 llm/init.pydef get_embedding_model(name): aliases get_embedding_model_aliases() try: return aliases[name] except KeyError: raise UnknownModelError(Unknown model: str(name))它首先通过get_embedding_models_with_aliases()llm/init.py收集所有插件通过register_embedding_modelshook 注册的模型再合并aliases.json中用户自定义的别名最终构建别名 → 模型实例映射。这意味着你可以用模型 ID如text-embedding-3-small加载也可以用插件声明的别名如3-small加载还可以用llm aliases命令为任意模型配置自定义别名后加载。若传入的名字无法解析会抛出UnknownModelError。测试 tests/test_embed.py 验证了通过测试插件embed-demo加载并调用embed()的完整流程。二、嵌入单个字符串.embed()对文本字符串做嵌入返回一个 Pythonlist[float]vector embedding_model.embed(my happy hound)EmbeddingModel.embed()定义在 llm/models.py内部先调用_check()校验输入类型与模型能力再委托给_embed_batch()生成器取首个向量。嵌入模型的抽象基类EmbeddingModelllm/models.py声明了四个核心类属性属性类型默认值含义model_idstr必填模型的唯一标识supports_textboolTrue是否支持文本输入supports_binaryboolFalse是否支持二进制如图片输入batch_sizeint \| NoneNone模型自身偏好的批量大小None表示不限传入 API Key默认情况下模型会从llm keys set存储的密钥或key_env_var指定的环境变量中读取 API key。你也可以在调用时用key直接传入vector embedding_model.embed(my happy hound, keysk-...)key既可以接收密钥本身也可以接收llm keys set存储的密钥别名。从EmbeddingModel._embed_batch()llm/models.py的实现可以看到key会被解析为实际密钥后传递给插件的embed_batch(items, key...)对于尚未支持key参数的旧版插件则会回退到兼容路径临时把密钥写入self.key再调用。测试 tests/test_embed.py 确认传入keysekrit后模型实例收到该值。三、文本与二进制supports_text与supports_binary部分嵌入模型如 CLIP 类模型可以处理二进制输入例如直接对图片文件做嵌入。是否支持可以通过两个只读属性判断from pathlib import Path if embedding_model.supports_binary: vector embedding_model.embed(Path(my-image.jpg).read_bytes())supports_binary为True时.embed()可接受bytessupports_text为True时.embed()可接受str。_check()校验逻辑llm/models.py会在类型不匹配时抛出ValueError。测试 tests/test_embed.py 用embed-binary-only仅二进制与embed-text-only仅文本两个测试模型验证了错误类型输入会触发异常、正确类型输入正常工作的行为binary_only.embed(hello world) # raises ValueError binary_only.embed(bhello world) # OK text_only.embed(bhello world) # raises ValueError四、批量嵌入.embed_multi()与batch_size对大量文本逐条调用embed()会产生多次网络往返。多数嵌入模型支持批量请求效率更高。使用.embed_multi()一次嵌入多个字符串vectors list(embedding_model.embed_multi([my happy hound, my dissatisfied cat]))该方法返回一个生成器generator按序产出每个输入对应的向量list[float]。embed_multi()与embed()一样接受key参数。分批处理嵌入按批次计算。默认情况下所有条目在一个批次中处理完除非底层模型在类属性batch_size上定义了自身偏好的批次大小。你也可以用batch_sizeN显式覆盖vectors list(embedding_model.embed_multi(lines_from_file, batch_size20))从 llm/models.py 的实现看embed_multi()的批处理逻辑是effective_batch_size self.batch_size if batch_size is None else batch_size即显式传入的batch_size优先于模型自身配置随后用islice按批次切片逐批调用_embed_batch()并yield from合并结果。若effective_batch_size为None则一次性处理全部输入。测试 tests/test_embed.py 验证了该语义对 1000 条文本不传batch_size模型默认batch_size100时产生 100 个批次传batch_size10时同样按模型默认的 100 处理而模型未定义批次大小时显式batch_size才会生效。五、集合Collections把向量存进 SQLite单个向量用完即弃的场景有限。更常见的需求是把一批内容嵌入后持久化存储再反复做相似度检索。llm.Collection类正是为此设计一个集合collection是命名的一组嵌入向量每个向量连同其 ID 存储在 SQLite 数据库表中。构造 Collection使用集合需要先有一个 sqlite-utils 的Database对象再把它与集合名、嵌入模型 ID 一起传给llm.Collectionimport sqlite_utils import llm # 不传 db 时使用内存数据库Python 进程退出后数据即被丢弃 collection llm.Collection(entries, model_id3-small) # 持久化到磁盘上的 SQLite 文件 db sqlite_utils.Database(my-embeddings.db) collection llm.Collection(entries, db, model_id3-small) # 也可以直接传模型实例而非模型 ID embedding_model llm.get_embedding_model(3-small) collection llm.Collection(entries, db, modelembedding_model)构造细节llm/embeddings.pydb 可选默认使用Database(memoryTrue)内存库新建集合时model与model_id必须二选一否则抛出ValueError传入model_id时会先经get_embedding_model()解析别名同样可用集合创建后模型 ID 会写入collections表的model列因此如果集合已存在于数据库中再次构造时可以省略model/model_id模型 ID 会自动从collections表读取构造函数会在首次调用时自动对数据库执行embeddings_migrations迁移llm/embeddings_migrations.py确保collections与embeddings表结构正确。存储单个条目collection.embed()collection.embed(hound, my happy hound)这会把字符串my happy hound的嵌入向量存入entries集合条目 ID 为hound。可用的参数key...传入 API key 或密钥别名embed_multi、embed_multi_with_metadata同样支持storeTrue把文本内容本身也存进数据库表的content列二进制内容则存入content_blob列metadata{...}附加 JSON 兼容的元数据字典序列化为 JSON 存入metadata列。collection.embed( hound, my happy hound, metadata{name: Hound}, storeTrue, )从 llm/embeddings.py 的实现看embed()还做了一件重要的事基于内容哈希去重。它对输入值计算 MD5content_hash见 llm/embeddings.py若该哈希在集合中已存在则直接返回、不再重复调用模型否则才嵌入并插入replaceTrue覆盖同 ID 旧行。updated列记录 Unix 时间戳。批量存储embed_multi()与embed_multi_with_metadata()collection.embed_multi( [ (hound, my happy hound), (cat, my dissatisfied cat), ], # 加上这一行可以把字符串存进 content 列 storeTrue, )需要为每个条目附带元数据时使用embed_multi_with_metadata()元数据以第三个元素传入三元组collection.embed_multi_with_metadata( [ (hound, my happy hound, {name: Hound}), (cat, my dissatisfied cat, {name: Cat}), ], # 同样支持 storeTrue 参数 storeTrue, )batch_size参数默认值为100且只有在嵌入模型自身没有定义更小的批次大小时才使用该默认值实现见 llm/embeddings.pybatch_size min(batch_size, self.model().batch_size or batch_size)。如果嵌入大集合时内存吃紧可以调小collection.embed_multi( ( (i, line) for i, line in enumerate(lines_in_file) ), batch_size10 )注意这里传入的是生成器表达式而不是列表——embed_multi接受任意可迭代对象配合生成器可以做到流式分批处理避免一次性载入全部内容。底层实现llm/embeddings.py会先对每批条目计算哈希、跳过已存在的 ID再用db.atomic()事务批量insert_all写入兼顾去重、性能与一致性。测试 tests/test_embed.py 对 1000 条数据验证了默认与自定义batch_size的批次数量、storeTrue写入content列、元数据写入metadata列等行为。六、Collection 类参考Collection实例定义于 llm/embeddings.py提供以下属性与方法成员签名 / 类型说明idint集合在数据库中的整数主键namestr集合名称数据库内唯一model_idstr该集合使用的嵌入模型 IDmodel()- EmbeddingModel根据model_id解析并返回模型实例惰性加载并缓存count()- int集合中的条目数量embed()embed(id: str, value: str \| bytes, metadata: dict \| None None, store: bool False, *, key: str \| None None)嵌入给定值并以指定 ID 存入集合可选元数据存为 JSON、存储原文/原二进制内容、传入 API key 或密钥别名embed_multi()embed_multi(entries: Iterable[tuple[str, str \| bytes]], store: bool False, batch_size: int 100, *, key: str \| None None)批量嵌入并存储embed_multi_with_metadata()embed_multi_with_metadata(entries: Iterable[tuple[str, str \| bytes, dict \| None]], store: bool False, batch_size: int 100, *, key: str \| None None)批量嵌入并存储附带元数据similar()similar(value: str \| bytes, number: int 10, prefix: str \| None None)返回与给定值嵌入向量最相似的条目列表similar_by_id()similar_by_id(id: str, number: int 10, prefix: str \| None None)返回与集合中某 ID 条目最相似的条目列表similar_by_vector()similar_by_vector(vector: list[float], number: int 10, skip_id: str \| None None, prefix: str \| None None)返回与给定嵌入向量最相似的条目列表可跳过指定 IDdelete()delete()从数据库中删除该集合及其全部嵌入此外还有类方法Collection.exists(db, name) - bool用于判断数据库中是否已存在同名集合if Collection.exists(db, entries): print(The entries collection exists)Collection.DoesNotExist异常会在查找不存在的条目如similar_by_id传入未知 ID时抛出构造函数若传createFalse且集合不存在也会抛出该异常。七、检索相似条目similar()与similar_by_id()集合填充完毕后即可做语义检索。similar()接收一个字符串或二进制值先用集合对应的模型对其嵌入再与集合中所有向量逐一计算相似度for entry in collection.similar(hound): print(entry.id, entry.score)返回的entry对象是llm.embeddings.Entryllm/embeddings.py具有以下属性id条目的字符串 IDscore条目与查询之间的浮点相似度得分余弦相似度1.0为完全一致见 llm/init.py 的cosine_similarity实现content若存储时用了storeTrue则为文本内容否则为Nonemetadata若存储时附了元数据则为解析后的字典否则为None。默认返回最相似的 10 个条目可用number调整for entry in collection.similar(hound, number5): print(entry.id, entry.score)prefix参数可按 ID 前缀过滤结果测试 tests/test_embed.py 演示了prefix2只返回 ID 以2开头的条目。similar_by_id()则基于已存储的向量检索无需重新嵌入查询内容——它取出指定 ID 的条目向量再与其他条目比较并自动排除自身for entry in collection.similar_by_id(cat): print(entry.id, entry.score)底层原理暴力检索与向量解码从 llm/embeddings.py 可以看到similar_by_vector()采用暴力检索brute force它把llm.cosine_similarity注册为 SQLite 自定义函数通过 SQLselect id, content, metadata, distance_score(embedding) as score from embeddings ... order by score desc limit N对集合内每个条目计算余弦相似度并按得分降序返回。每次查询需要解码库中所有已存向量llm.decode因此对小型集合非常合适但无法扩展到超大集合——项目计划未来通过插件提供的向量索引解决规模化问题。测试 tests/test_embed.py 给出了可量化的验证对hello world查询最相似的条目得分约0.9999999999999999即自身次相似的goodbye world得分约0.986。八、底层存储SQL 表结构与向量编码SQL 模式集合数据库由llm.embeddings_migrations迁移创建llm/embeddings_migrations.py最终表结构如下CREATE TABLE collections ( id INTEGER PRIMARY KEY, name TEXT, model TEXT ) CREATE TABLE embeddings ( collection_id INTEGER REFERENCES collections(id), id TEXT, embedding BLOB, content TEXT, content_blob BLOB, content_hash BLOB, metadata TEXT, updated INTEGER, PRIMARY KEY (collection_id, id) )要点collections.name建有唯一索引保证集合名唯一model列记录该集合使用的嵌入模型 ID这也是已存在集合可省略model/model_id的原因embeddings以(collection_id, id)为联合主键同一集合内条目 ID 唯一不同集合可有相同 IDembedding是二进制 BLOBcontent/content_blob分别保存文本与二进制原文storeTrue时content_hash用于去重并建有索引metadata为 JSON 文本updated为 Unix 时间戳。向量的二进制编码embeddingBLOB 列存储的是小端序little-endian32 位浮点数序列每个浮点数占 4 字节比 JSON 数组紧凑得多存储格式详见 docs/embeddings/storage.md。转换函数以llm.encode()/llm.decode()形式公开llm/init.pydef encode(values): return struct.pack( f * len(values), *values) def decode(binary): return struct.unpack( f * (len(binary) // 4), binary)若使用 NumPy可用如下方式解码import numpy as np numpy_array np.frombuffer(value, f4)其中f4表示按小端序解析 32 位浮点。理解这一格式对直接操作数据库如用外部工具做向量分析很有帮助。九、与命令行、存储文档的关系本文的 Python API 与 docs/embeddings/cli.md 介绍的llm embed、llm embed-multi等命令行工具共用同一套Collection实现——CLI 只是 Python API 的命令行封装两者写入的数据库格式完全一致可以混用。嵌入模型本身通过插件注册参见 docs/embeddings/writing-plugins.md密钥管理与别名配置参见 docs/aliases.md。十、一个完整的端到端示例把以上内容串起来一个完整的构建语义搜索流程如下import sqlite_utils import llm # 1. 准备数据库与集合 db sqlite_utils.Database(my-embeddings.db) collection llm.Collection(entries, db, model_id3-small) # 2. 批量嵌入文档含元数据与原文存储 docs [ (dog, A happy hound that loves chasing balls, {category: pet}), (cat, A dissatisfied cat that naps all day, {category: pet}), (car, An electric vehicle with long range, {category: vehicle}), ] collection.embed_multi_with_metadata(docs, storeTrue) # 3. 语义检索不包含任何关键词也能命中 for entry in collection.similar(a furry four-legged friend): print(entry.id, entry.score, entry.content, entry.metadata)整个流程构造集合自动建表迁移→ 批量嵌入自动按批次、去重、存原文与元数据→ 暴力余弦相似度检索。从 docs/embeddings/index.md 可知这类能力可用于相关文章推荐、语义搜索查询与结果无需共享任何关键词等场景支持二进制的模型如 CLIP 类插件还可以扩展为以图搜图或以文搜图。【免费下载链接】llmAccess large language models from the command-line项目地址: https://gitcode.com/gh_mirrors/llm/llm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
电动车大灯耐用性技术分析:散热、防水与 DC 功率匹配 跑外卖属于电动车大灯的极限工况:单日点灯时长可达数小时,远近光频繁切换,叠加雨雾、粉尘和持续震动。本文从 LED 结温、散热结构、密封防水、DC 功率链路四个技术维度,解释大灯"耐不耐用"由什么决定,并给出… · 2026/9/23 13:21:37
安防系统集成项目经理证有必要报班吗?从报名学习到考试拿证,报考全攻略 安防系统集成项目经理是安防工程领域的”管理技术”复合岗位。想考证进阶,报不报班?本文围绕安防系统集成项目经理证,把自学与报班的差距、费用、选班要点和报考流程讲透。
先说结论:项目经理岗位重管理与经验,报班的价… · 2026/9/23 13:21:37
机械工程师证有必要报班吗?从报名学习到考试拿证,报考全攻略 机械工程师是制造业的基础技术岗,机械工程师证是工科领域的老牌证书。想考这个证,报不报班?本文围绕机械工程师证,把自学与报班的差距、费用、选班要点和报考流程讲透。
先说结论:机械是”理论制图实践”的方向&#x… · 2026/9/23 13:21:37
智能停车场管理系统开发实战:SpringBoot+微信小程序 1. 项目概述这个智能停车场管理系统是我去年带队开发的一个实际项目,已经在三个商业停车场落地运行。传统停车场最大的痛点就是信息不透明——你永远不知道里面还有没有车位,经常要兜好几圈才能找到位置。我们通过微信小程序SpringBoot的技术方案&#x… · 2026/9/23 14:52:17
3大主流企业考核制度深度对比,新手避坑指南 3大主流企业考核制度深度对比,新手避坑指南 复制来的考核代码跑不通,报错信息满屏飞,改了一个变量又炸了另一个?别慌,这不仅是代码逻辑的问题,更是底层选型没选对。很多新手在落地 企业考核制度… · 2026/9/23 14:52:11
3个坑搞定中国专利检索网爬虫新手避坑指南 3个坑搞定中国专利检索网爬虫新手避坑指南 刚学完 Python 语法,是不是觉得代码写得飞起,但一到实际项目就懵圈?看着满屏的 import 和 def… · 2026/9/23 14:51:57
Java解析CDR文件:LibreOffice转SVG与矢量面积计算实战 接手过一个挺有代表性的需求:用户在设计平台上传 CorelDRAW 生成的 CDR 文件,后端要读取文件里所有矢量图形的面积,用来做报价和物料估算。文件来源也分两种——网页端直接上传的 MultipartFile,以及运营后台填写的网络文件 URL。… · 2026/9/23 14:51:57
3招搞定手机怎么下载微信面试难题实战项目解析 3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29