# emb-cli
**Repository Path**: cc123hh/emb-cli
## Basic Information
- **Project Name**: emb-cli
- **Description**: 命令行文本向量化与语义搜索:零依赖 Python 脚本,macOS/Linux/Windows 通用,支持任意 OpenAI 兼容的 /embeddings 接口
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-10-30
- **Last Updated**: 2026-11-01
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
emb
把文字变成向量,再按「意思」把东西找回来。
零依赖 · 跨平台 · 单文件索引 · 支持任何 OpenAI 兼容的 /embeddings 接口
---
## 📑 目录
- [它解决什么问题](#-它解决什么问题)
- [快速开始](#-快速开始)
- [安装](#-安装)
- [配置](#-配置)
- [用法](#-用法)
- [维护索引](#-维护索引)
- [参数速查](#-参数速查)
- [索引格式](#-索引格式)
- [常见问题](#-常见问题)
- [License](#license)
## 🎯 它解决什么问题
普通搜索是**按字匹配**:
```
搜「电脑连不上网」 → 笔记里写的是「Clash 代理端口 7890」 → ❌ 一个字都对不上,搜不到
```
`emb` 是**按意思匹配**:
```
搜「电脑连不上网」 → 命中「先检查 Clash 是否开着」 → ✅
搜「晚饭吃什么」 → 命中「隔夜饭适合做炒饭」 → ✅
```
原理:把每段文字交给 embedding 接口,转成一串数字(向量)。**意思相近的文字,数字也相近**。
于是「找相似的」就变成了「算距离」,正好是机器的强项。
## 🚀 快速开始
```console
$ emb add ./notes -i notes.embindex
正在向量化 1-6 / 6 …
完成:新增 6 条,跳过 0 条,索引共 6 条(1024 维,模型 BAAI/bge-m3)
$ emb search "电脑连不上网怎么办" -i notes.embindex -k 3
1. 0.7388 [notes/网络.md:1] 公司电脑连不上外网时,先检查 Clash 是否开着…
2. 0.5341 [notes/网络.md:2] 代理只对命令行生效的情况下,记得给 curl 加 -x 参数…
3. 0.4630 [notes/编程.md:2] 提交代码前先跑一遍测试…
$ emb add ./notes -i notes.embindex # 再跑一次:只算新增
全部已存在:跳过 6 条,无需调用接口
```
## ✨ 特性
| | |
|---|---|
| 🪶 **零依赖** | 只用 Python 标准库;装了 numpy 会自动走矩阵加速,没装照样跑 |
| 🖥️ **跨平台** | macOS / Linux / Windows,安装脚本与文档全覆盖 |
| 📦 **单文件索引** | 一个 `.embindex` 装下向量 + 原文 + 来源,拷贝备份都方便 |
| 🔁 **增量更新** | 重复执行 `add` 只计算新内容,按内容哈希去重 |
| 🔍 **语义搜索** | 按意思找,不靠关键词 |
| 🧰 **可维护** | 导出 / 删除 / 合并 / 清理 / 体检,一整套命令 |
| 🌐 **接口通用** | 任何兼容 OpenAI `/embeddings` 的服务都能接 |
| 🔒 **秘钥不落库** | 全部走环境变量,代码里搜不到 key |
## 📥 安装
> 前提:Python 3.8+(`python3 --version`;Windows 上 `python --version`)
### macOS / Linux
```bash
git clone https://gitee.com/cc123hh/emb-cli.git
cd emb-cli
./install.sh
```
### Windows
```powershell
git clone https://gitee.com/cc123hh/emb-cli.git
cd emb-cli
powershell -ExecutionPolicy Bypass -File .\install.ps1
```
免安装直接用:`emb.cmd similar "甲" "乙"`
### 所有平台(pipx)
```bash
pipx install git+https://gitee.com/cc123hh/emb-cli.git
```
## ⚙️ 配置
```bash
# 必需
export EMB_API_KEY="你的key"
# 可选:接口地址(默认 OpenAI 官方)
export EMB_BASE="https://api.openai.com/v1"
# 可选:模型名(默认 text-embedding-3-small)
export EMB_MODEL="BAAI/bge-m3"
# 可选:代理
export EMB_PROXY="http://127.0.0.1:7890"
```
Windows:
```powershell
setx EMB_API_KEY "你的key"
setx EMB_BASE "https://api.openai.com/v1"
setx EMB_MODEL "BAAI/bge-m3"
```
> ⚠️ **换模型必须重建索引**:不同模型维度不同(1024 / 1536 / 3072),不能混在一个文件里。
## 📖 用法
### 1. 临时向量化(不落盘)
```bash
emb embed "今天天气不错" # 输出一行 JSON
emb embed notes.txt -o notes.jsonl # 文件按行切
cat a.md | emb embed - # 从管道读
emb embed ./docs/ -o docs.jsonl # 目录批量(递归 .md/.txt/.markdown)
```
### 2. 建索引 / 增量更新
```bash
emb add ./notes/ -i notes.embindex # 首次建库
emb add ./notes/ -i notes.embindex # 再跑:只算新增
emb add "临时补一条" -i notes.embindex --text
```
### 3. 语义搜索
```bash
emb search "怎么配置代理" -i notes.embindex -k 5
emb search "怎么配置代理" -i notes.embindex --json # 管道友好
```
### 4. 比较两句话
```bash
$ emb similar "我喜欢吃白米饭" "我爱吃米饭"
0.9026 高度相似
$ emb similar "我喜欢吃白米饭" "Python 虚拟环境"
0.3643 基本无关
```
### 5. 查看索引
```bash
emb info -i notes.embindex
```
## 🧰 维护索引
```bash
emb doctor -i notes.embindex # 体检:重复、空文本、失效来源
emb export -i notes.embindex -o notes.jsonl # 导出可读文件(备份 / 进 Git)
emb export -i notes.embindex -o notes.csv --format csv
emb remove -i notes.embindex --id a1b2c3d4e5f6 # 删一条
emb remove -i notes.embindex --source notes/旧.md # 删某来源(前缀匹配)
emb remove -i notes.embindex --all # 清空
emb merge a.embindex b.embindex -o all.embindex # 合并(同模型同维度,内容去重)
emb prune -i notes.embindex # 清理源文件已删除的条目
emb prune -i notes.embindex --dry-run # 先看看会删什么
```
## 📋 参数速查
| 参数 | 适用命令 | 说明 |
|---|---|---|
| `--text` | embed / add | 强制把参数当文本(即使像路径) |
| `--paragraph` | embed / add | 按空行分段,而不是按行 |
| `--max-chars` | embed / add | 单段最大字符数,默认 6000 |
| `--batch-size` | embed / add | 每批请求条数,默认 32 |
| `-k, --top-k` | search | 返回条数,默认 5 |
| `--json` | search | 输出 JSON |
| `--format` | export | `jsonl`(默认)或 `csv` |
| `--id` / `--source` / `--all` | remove | 删除条件,至少一个 |
| `--dry-run` | prune | 只显示,不改动 |
| `--base/--model/--proxy/--timeout` | 全部 | 覆盖环境变量 |
## 💾 索引格式
单文件二进制:`魔数(8B) + 版本(2B) + meta长度(4B) + meta(JSON) + float32 向量区`。
写入采用临时文件 + 原子替换——中途失败不会毁掉旧索引。
| 条数 | 向量部分(1024 维) | 含原文约 |
|---|---|---|
| 1,000 | 4 MB | ≈ 4.3 MB |
| 3,000 | 12 MB | ≈ 13 MB |
| 10,000 | 40 MB | ≈ 43 MB |
## ❓ 常见问题
能不能不建索引直接搜?
搜索依赖持久化索引。临时比较两句话用 `emb similar`,不落盘。
换模型后提示维度不一致?
不同模型维度不同。删掉旧索引重新 `emb add`,或用 `emb export` 备份原文后再重建。
接口报 429 / 503 / 504?
工具会自动退避重试(1/2/4/8 秒,最多 4 次)。持续失败请调小 `--batch-size` 或稍后再试。
中文分句效果不好?
默认按行切。笔记建议一行一个知识点;长文可用 `--paragraph` 按空行分段。
支持图片向量吗?
暂不支持,当前只处理文本。
索引能不能进 Git?
二进制文件不适合 diff。建议把 `emb export` 出来的 jsonl 进 Git,索引本身丢进 `.gitignore`。
## 🤝 贡献
欢迎 Issue / PR。报告兼容性问题请附:操作系统、`python --version`、完整报错。
## License
[MIT](LICENSE)