Gemma 嵌入搜索
根据含义检索本地文件。一个嵌入空间容纳图像、音频和文本,因此一个打字查询会返回与之匹配的图片、剪辑或文档。模型通过本地服务器在用户硬件上运行;没有任何内容上传到任何地方。
scripts/embed_search.py 执行四项操作:doctor 检查服务器,init 保存连接,index 将文件嵌入到缓存中,search 根据查询对它们进行排名。
本地配置
设置保存在 config.json 中,绝不保存到此文件中:
- Linux 和 macOS:
~/.config/gemma-embed-search/config.json - Windows:
%USERPROFILE%\.config\gemma-embed-search\config.json
首先读取该文件。如果其中有 url 和 model,则后续所有命令都无需连接标志即可工作,并且可以跳过步骤 2。
如果该文件缺失或不完整,请询问用户服务器的 URL 和要索引的文件夹,运行 doctor 列出服务器实际提供的模型,然后运行 init 写入文件。init 是合并的,因此一次补充一个设置是安全的。切勿猜测模型名称。
将 config.example.json 从此文件夹复制到该路径并编辑它,与 init 的作用相同,适用于希望直接编辑文件的用户。仅当服务器需要时才在其中添加 "api_key"。
切勿将设置保存在技能文件夹本身内部。更新技能会替换其中的每个文件,并且写入那里的任何内容都会丢失。
设置清单
进度:
- 步骤 1:确认服务器并选择一个模型名称 (
doctor) - 步骤 2:保存连接 (
init) - 步骤 3:索引一个包含 20 个文件的试点项目并快速查看一个查询
- 步骤 4:索引整个文件夹
- 步骤 5:回答用户的真实查询,并使用
--html以便他们可以看到结果
如果 config.json 已经具有 url 和 model,请跳过步骤 2。
使用 uv run scripts/embed_search.py(从脚本的内联元数据安装 Pillow)或 python3 scripts/embed_search.py(如果 Pillow 已可导入)运行脚本。
步骤 1 — 查找服务器和模型名称。 切勿猜测模型名称;从服务器读取它。
uv run scripts/embed_search.py --url http://127.0.0.1:1235 doctor
doctor 打印服务器提供的模型并探测一个嵌入。如果用户尚未启动服务器,请阅读 references/setup.md 并向他们提供其模型的命令。
步骤 2 — 保存它,以便后续调用无需标志。仅当服务器需要时才传递 --api-key;它将以模式 0600 写入配置文件。在任何后续命令中传递 --root 以处理不同的文件夹,而无需更改已保存的内容。
uv run scripts/embed_search.py --url http://127.0.0.1:1235 --model <name-from-doctor> init --root <folder>
uv run scripts/embed_search.py index --limit 20
步骤 3 — 在长时间运行之前进行试点。 索引是昂贵的步骤:在桌面 GPU 上大约每张图像 0.25 秒,因此 10,000 个文件大约需要 40 分钟。索引 20 个文件,运行一个查询,并在提交到完整处理之前确认结果看起来正确。
步骤 4 — 完整索引。 重新运行 index 仅嵌入新的或更改的文件,因此中断的运行会自动恢复。
uv run scripts/embed_search.py index
步骤 5 — 搜索。
uv run scripts/embed_search.py search "海滩上的黑色拉布拉多犬" --top 20 --html hits.html
查询备忘单
| 意图 | 命令 |
|---|---|
| 纯语义搜索 | search "拥挤的夜市" |
| 两个条件都必须满足 | search "一个女人" --must "黄色" |
| 同义词,以免一种措辞占主导 | search "一个女人" --also "一个女孩" --also "女性肖像" |
| 查找包含 X 的每个图像 | search "红发角色" --top 60 --html hits.html |
| 主题加上真实颜色约束 | search "一个女人" --color yellow --min-color 0.05 |
| 主要是单色或暗色调画面 | search "任何图像" --max-color blue --modality image |
| 只有一种文件类型 | search "警笛声" --modality audio |
| 机器可读,用于进一步处理 | search "..." --json --top 50 |
| 更快,分数准确性略低 | search "..." --dims 256 |
--also 将释义向量平均为一个查询。--must 保留最弱方面的分数,这就是表达 AND 的方式。对同义词使用 --also,对独立条件使用 --must。
读取输出
纯文本输出是 score [modality] path,最好的排在第一。颜色运行会在分数后插入像素比例。--json 在标准输出上发出 {"query", "index", "total", "filtered_out", "results": [{"rank", "score", "color", "modality", "path"}]};所有进度信息都发送到标准错误,因此标准输出始终可以干净地通过管道传输到 jq。
来自此模型系列的余弦分数介于大约 0.3 到 0.8 之间。绝对数值意义不大;命中与未命中之间的差距才重要。如果列表顶部是错误的,则查询是错误的——重新措辞,而不是信任排名。切勿将一个长列表呈现为同样好:指出可靠结果在何处停止,猜测从何处开始。
短列表不是完整的答案。 每个索引文件都会获得一个分数,因此输出中的 total 会计算整个语料库,但绝不会告诉您有多少结果是合理的。相反,找到悬崖——即分数停止急剧下降的点。如果您显示的列表在该点之前结束,请说明结果已被截断,并提供更长的运行:更大的 --top 只需要多生成一个联系人页面,而不是另一个索引。尊重用户指定的数量,并且仍然陈述您应用的截止点。切勿在未使用扩展列表(至少 --top 100 或更多)并且有人实际查看过的情况下声称“没有结果”。
对于视觉审查,始终提供 --html:它会写入一个包含分数和文件名的缩略图联系人页面,用户可以在浏览器中打开。裸 --html 会在工作目录中写入 hits.html;--html FILE 设置路径。缩略图以 Base64 形式嵌入,因此该页面是自包含的,可以独立传输。该页面嵌入了匹配文件的真实缩略图,因此将其视为该库的一部分副本:将其保留在版本控制和任何您转发的内容之外。默认宽度为 512 像素;要提高 --thumb-width 以进行细节的近距离检查。
注意事项
- 查询文本中的颜色词是软提示,而不是过滤器。
"一个具有黄色主题的女人"会将穿着橙色夹克的女人排在第一位。使用--color yellow --min-color 0.05进行实际约束;它是根据像素计算的,而不是根据模型。 - 风格词也是一个软提示,而且更弱。
"一个红发的逼真女人"会将红发女人的墨水插画排在第一位,因为主题名词的权重超过了风格。将风格移入--must,以便将其作为自己的方面进行评分,并使用--color固定视觉属性。两者都不是真正的过滤器:--must取各方面的最小值,因此在一个方面用力过猛会牺牲另一个方面。 - 一个画面中的多个主题会融合成一个单一向量,因此该画面在单主题查询中的得分低于专门针对该主题的画面:一个红发女人与一个男人并排的肖像在
"红发女人"搜索中可能会排在很后面,而在"红发角色"搜索中则可能位居前列。同一个单一想法的同义词无济于事;复数或集体形式才有帮助。当问题是“查找包含 X 的所有内容”时,扩大--top的范围。 --color需要索引保存颜色统计信息,这只能由index计算。使用旧版本构建的索引会为所有内容报告 0.0:如果颜色过滤悄悄地排除了每个文件,请使用--force重新索引。- 索引和查询必须使用相同的模型。切换
--model会悄悄地混合不兼容的向量;在模型更改后使用--force重新索引,并在stats中注明模型。 - 服务器必须运行具有均值池化并加载了其视觉投影仪(
--mmproj)的嵌入模型。没有投影仪,图像请求会失败或返回一个忽略图片的向量。doctor证明文本有效;运行一个图像查询以证明视觉功能。 - 图像在发送前会以最长边 1536 重新编码为 JPEG。重新编码是必需的,而不是装饰性的:服务器通常会拒绝 WebP、16 位或标签错误的文件,而 Pillow 会读取这些文件。模型没有像素限制——服务器会将每张图像重新采样为固定的视觉令牌预算——因此
--resize是用上传大小来换取保真度,而不是正确性。测量数据以及详细信息在 references/setup.md 中。 - 除非 Pillow 是使用插件构建的,否则不会读取 HEIC 和原始相机格式。脚本会记录
skip <file>: cannot identify image file并继续;检查索引摘要中的skipped_errors,而不要假设完全覆盖。 - 在从未索引过的文件夹上运行
search会退出并显示消息,返回码为 4。在stats中的索引计数看起来正确之前,不要将空结果列表视为“无匹配”。 - 音频受服务器上下文限制:每秒 25 个令牌,每个剪辑大约 5.5 分钟。较长的文件会因请求错误而失败,而不是作为错误匹配。
- 分数不能跨语料库或跨量化进行比较。切勿承诺阈值;根据用户看到的情况调整
--min-color和--top。
脚本参考
doctor 检查服务器,列出模型,探测一个嵌入
init [--root DIR] 将 url、model、key 和默认根目录保存到配置文件中
index --root DIR 嵌入新的和更改的文件(增量式,可恢复)
[--modality auto|image|audio|text] [--include '*.png,sub/*.jpg']
[--exclude-dir node_modules,.git] [--limit N] [--batch 16] [--resize 1536]
[--force] [--compact]
search "query" 对索引文件进行排名;打印分数、模态和路径
[--also P]... [--must P]... [--color NAME --min-color F | --max-color F]
[--modality image] [--dims 512|256|128] [--top 20] [--offset 0]
[--json] [--html [FILE]] [--thumb-width 512]
stats 条目数、模态混合、模型、索引大小
退出码:0 成功,2 用法错误,3 服务器不可达或身份验证被拒绝,4 索引缺失,5 无操作,6 服务器运行中错误。运行 scripts/embed_search.py <command> --help 获取完整的标志文档。
配置解析顺序为:标志 > 环境变量(EMBED_SEARCH_URL、EMBED_SEARCH_MODEL、EMBED_SEARCH_API_KEY、EMBED_SEARCH_ROOT)> 配置文件 ~/.config/gemma-embed-search/config.json。索引默认为 ~/.cache/gemma-embed-search/<folder>-<hash>.jsonl,每个文件一个 JSON 记录,因此可以安全地为不同文件夹保留多个索引。
更多详情
- references/setup.md — 启动服务器,模型和标志要求,
doctor的含义 - references/query-guide.md — 查询构建,方面逻辑,颜色阈值,针对实际结果进行调整
- references/errors.md — 每个退出码以及每种失败模式的修复方法