ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s

This commit is contained in:
2026-08-20 13:12:50 +00:00
commit b119135836
10275 changed files with 3284984 additions and 0 deletions
+347
View File
@@ -0,0 +1,347 @@
# Sparse Vector Search Engine (BM25) / 稀疏向量搜索引擎(BM25)
> Companion material for *AI Agents in Depth*, Chapter 3 — **Experiment 3-5**: educational BM25 / inverted-index sparse search with offline CLI evaluation.
> 配套《深入理解 AI Agent》第 3 章 **实验 3-5**:从零理解 BM25 与倒排索引,含可离线评测的 CLI。
← [Chapter 3 index / 返回第 3 章目录](../README.md)
---
## English
### Overview
An educational sparse vector search engine using an inverted index and BM25. It demonstrates core IR concepts with extensive logging and visualization.
### Features
- **Full BM25 implementation**
- **Advanced tokenization**: numbers, codes, technical terms, mixed case
- **Inverted index** for term lookup
- **HTTP API** (FastAPI)
- **Interactive Web UI** for index/search
- **Educational logging** through index and search
- **Index visualization** APIs
- **In-memory storage** (educational simplicity)
#### Tokenization capabilities
- **Numbers**: `404`, `3.14`, `2.0.1`
- **Codes**: `XK9-2B4-7Q1`, `API_KEY_123`
- **Technical terms**: `C++`, `.NET`, `Node.js`
- **Mixed case**: `JavaScript`, `PyTorch`, `iPhone`
- **Email**: `user@example.com`
- **Hex**: `#FF5733`, `0x1234`
- **Acronyms**: `API`, `HTTP`, `NASA`
- **Alphanumeric**: `Python3`, `ES6`, `HTML5`
### Architecture
1. **TextProcessor**: tokenizer for words, numbers, codes, technical terms, mixed case
2. **InvertedIndex**: term/document frequencies
3. **BM25**: ranking
4. **SparseSearchEngine**: orchestration
5. **HTTP Server**: FastAPI surface
BM25 uses TF, IDF, and document-length normalization. Key params: `k1` (default 1.5), `b` (default 0.75).
### Installation
```bash
# From the repository root: use the shared Chapter 3 environment
uv sync --locked --python 3.12 --extra ch3
# Activate it before changing directories:
# macOS/Linux:
source .venv/bin/activate
# Windows PowerShell: .venv\Scripts\Activate.ps1
# Windows cmd: .venv\Scripts\activate.bat
# pip fallback when uv is not installed:
# python -m pip install -e ".[ch3]"
cd chapter3/sparse-embedding
# Single-project compatibility path, still supported during migration:
# python -m pip install -r requirements.txt
```
`cli.py` (below) uses only the Python standard library and runs offline with no third-party packages; `server.py` / `demo.py` need the shared `ch3` environment or the compatibility `requirements.txt` path.
### CLI tool `cli.py` (Experiment 3-5, recommended entry)
Fully offline CLI: BM25 on a built-in 10-doc corpus, per-term TF/IDF/BM25 contribution logs (as in the book), and labelled recall/precision/MRR. All flags have Chinese `--help`.
```bash
python cli.py --help # all flags (Chinese)
python cli.py # default demo query "model distillation"
python cli.py -q "model distillation" --explain # per-term TF/IDF/BM25
python cli.py --eval # recall@k / precision@k / MRR
python cli.py -q "cat" # synonym failure (kitten/feline miss)
python cli.py --corpus my.json -q "查询" -o out.json
python cli.py --k1 2.0 -b 0.5 -q "..."
python cli.py --method splade -q "..." # SPLADE (needs downloaded model)
```
| Flag | Description |
| --- | --- |
| `-q, --query` | Query string (default `model distillation`) |
| `-c, --corpus` | Corpus (`.json` array or `.jsonl`); default built-in sample |
| `-m, --method` | `bm25` (default, offline) or `splade` (learned sparse; needs model) |
| `-k, --top-k` | Top-k (default 5) |
| `-o, --output` | Write results/metrics JSON |
| `--eval` | Evaluate recall@k / precision@k / MRR on labels |
| `--labels` | Custom labels `{query: [doc_id,...]}` |
| `--explain` | Per-term TF / IDF / BM25 on hits |
| `--k1` / `-b` | BM25 k1 and b |
| `-v, --verbose` | Engine DEBUG logs |
#### Retrieval quality (`--eval`)
Built-in labels cover exact keywords, error codes, proper names, and synonym-only queries. Real `python cli.py --eval` output (k=5):
```
查询 'model distillation' recall@5=1.00 precision@5=1.00 RR=1.00
查询 'HTTP 404 error' recall@5=1.00 precision@5=0.50 RR=1.00
查询 'XK9-2B4-7Q1' recall@5=1.00 precision@5=1.00 RR=1.00
查询 'BM25 ranking function' recall@5=1.00 precision@5=1.00 RR=1.00
查询 'cat' recall@5=0.00 precision@5=0.00 RR=0.00 <- 漏召回(同义词短板)
宏平均 recall@5=0.800 precision@5=0.700 MRR=0.800 漏召回率(1-recall@5)=0.200
```
BM25 excels on exact keywords, codes, and names (recall=1.0) but misses synonyms—query `cat` does not hit docs that only say `kitten` / `feline`. That gap motivates hybrid search (Experiment 3-6 `retrieval-pipeline`).
#### Learned sparse (`--method splade`)
SPLADE weights terms with a masked LM and can expand semantically related terms. Needs pretrained `naver/splade-cocondenser-ensembledistil` (`torch`, `transformers`). Offline without weights, the command fails fast with a clear message (BM25 path needs no model). Online: `huggingface-cli download naver/splade-cocondenser-ensembledistil` then run.
### Server usage
```bash
python server.py
```
Server: `http://localhost:4241`. Web UI: open that URL. API docs: `http://localhost:4241/docs`.
#### API endpoints
```bash
POST /index
{
"text": "Your document text here",
"metadata": {"title": "Document Title", "category": "Category"}
}
POST /search
{
"query": "your search query",
"top_k": 10
}
GET /stats
GET /index/structure
GET /document/{doc_id}
DELETE /index
```
#### Demo
```bash
python demo.py
```
Demo: clear index → sample CS docs → stats → index structure → sample queries → document get.
### Educational features
Logging covers tokenization, TF, IDF, per-term BM25, query processing, candidates. `/index/structure` returns inverted map, doc stats, BM25 params, global TF distribution. Search results include matched terms, doc length, TFs, per-term score contributions.
### Project structure
```
sparse-embedding/
├── bm25_engine.py # Core engine
├── cli.py # Offline CLI: BM25/SPLADE + metrics
├── server.py # FastAPI server
├── demo.py # Demo script
├── requirements.txt
└── README.md
```
### Limitations
In-memory only; basic tokenization (no lemmatization); English stopwords; no phrase queries / synonyms / multi-thread.
---
## 中文
### 概述
基于倒排索引与 BM25 的教学型稀疏向量搜索引擎,用详细日志与可视化帮助理解信息检索基本概念。
### 功能特性
- **完整 BM25 实现**
- **高级分词**:数字、编码、技术术语、大小写混合
- **倒排索引**
- **HTTP API**FastAPI
- **交互式 Web UI**
- **教学日志**
- **索引结构可视化 API**
- **内存存储**(教学简化)
#### 分词能力
- **数字**`404``3.14``2.0.1`
- **编码**`XK9-2B4-7Q1``API_KEY_123`
- **技术术语**`C++``.NET``Node.js`
- **大小写混合**`JavaScript``PyTorch``iPhone`
- **邮箱**`user@example.com`
- **十六进制**`#FF5733``0x1234`
- **缩写**`API``HTTP``NASA`
- **字母数字**`Python3``ES6``HTML5`
### 架构
1. **TextProcessor**:分词
2. **InvertedIndex**:词频 / 文档频率
3. **BM25**:相关性打分
4. **SparseSearchEngine**:总控
5. **HTTP Server**FastAPI
BM25 使用 TF、IDF 与文档长度归一化。关键参数:`k1`(默认 1.5)、`b`(默认 0.75)。
### 安装
```bash
# 在仓库根目录使用统一的第 3 章环境
uv sync --locked --python 3.12 --extra ch3
# 切换目录前先激活环境:
# macOS/Linux
source .venv/bin/activate
# Windows PowerShell.venv\Scripts\Activate.ps1
# Windows cmd.venv\Scripts\activate.bat
# 未安装 uv 时可用 pip 兜底:
# python -m pip install -e ".[ch3]"
cd chapter3/sparse-embedding
# 迁移期间仍支持单项目兼容路径:
# python -m pip install -r requirements.txt
```
`cli.py` 只依赖 Python 标准库,无需第三方包即可离线运行;`server.py` / `demo.py` 需要统一 `ch3` 环境或兼容 `requirements.txt` 路径提供的 FastAPI 等依赖。
### 命令行工具 cli.py(实验 3-5,推荐入口)
完全离线:在内置 10 篇小语料上跑 BM25、复现书中「逐词 IDF/TF/BM25 贡献」日志,并在标注集上算 recall/precision/MRR。参数均有中文 `--help`
```bash
python cli.py --help # 查看全部参数(中文)
python cli.py # 默认演示:查询 "model distillation"
python cli.py -q "model distillation" --explain # 逐词展示 TF/IDF/BM25 贡献
python cli.py --eval # recall@k / precision@k / MRR
python cli.py -q "cat" # 观察同义词短板(kitten/feline 漏召回)
python cli.py --corpus my.json -q "查询" -o out.json
python cli.py --k1 2.0 -b 0.5 -q "..."
python cli.py --method splade -q "..." # SPLADE(需预先下载模型)
```
| 参数 | 说明 |
| --- | --- |
| `-q, --query` | 查询字符串(默认 `model distillation` |
| `-c, --corpus` | 语料(`.json` 数组或 `.jsonl`);缺省用内置示例 |
| `-m, --method` | `bm25`(默认,离线)或 `splade`(学习型稀疏,需模型) |
| `-k, --top-k` | 返回前 k 条(默认 5 |
| `-o, --output` | 结果 / 指标写入 JSON |
| `--eval` | 在标注集上评测 |
| `--labels` | 自定义标注 `{query: [doc_id,...]}` |
| `--explain` | 逐词 TF / IDF / BM25 |
| `--k1` / `-b` | BM25 参数 |
| `-v, --verbose` | DEBUG 日志 |
#### 检索质量评测(`--eval`
内置标注覆盖精确关键词、错误码、专有名称与「只有同义表达」的查询。真实输出(k=5):
```
查询 'model distillation' recall@5=1.00 precision@5=1.00 RR=1.00
查询 'HTTP 404 error' recall@5=1.00 precision@5=0.50 RR=1.00
查询 'XK9-2B4-7Q1' recall@5=1.00 precision@5=1.00 RR=1.00
查询 'BM25 ranking function' recall@5=1.00 precision@5=1.00 RR=1.00
查询 'cat' recall@5=0.00 precision@5=0.00 RR=0.00 <- 漏召回(同义词短板)
宏平均 recall@5=0.800 precision@5=0.700 MRR=0.800 漏召回率(1-recall@5)=0.200
```
BM25 在精确关键词、错误码、专有名称上极佳,但读不懂同义词——查询 `cat` 无法命中只写 `kitten` / `feline` 的文档。这正是引入混合检索(实验 3-6 `retrieval-pipeline`)的动机。
#### 学习型稀疏检索(`--method splade`
用掩码语言模型为词项打权,并可为语义相关词项补权。需下载 `naver/splade-cocondenser-ensembledistil`(依赖 `torch``transformers`)。离线无权重时会快速给出清晰提示。联网可先 `huggingface-cli download naver/splade-cocondenser-ensembledistil`
### 服务端用法
```bash
python server.py
```
服务地址:`http://localhost:4241`。Web UI 打开该地址。API 文档:`http://localhost:4241/docs`
#### API 端点
```bash
POST /index
{
"text": "Your document text here",
"metadata": {"title": "Document Title", "category": "Category"}
}
POST /search
{
"query": "your search query",
"top_k": 10
}
GET /stats
GET /index/structure
GET /document/{doc_id}
DELETE /index
```
#### 运行演示
```bash
python demo.py
```
演示:清空索引 → 示例文档 → 统计 → 索引结构 → 查询 → 按 ID 取文档。
### 教学特性
日志覆盖分词、TF、IDF、逐词 BM25、查询处理、候选文档。`/index/structure` 返回倒排映射、文档统计、BM25 参数、全局词频分布。检索结果含匹配词、文档长度、词频与分项得分。
### 项目结构
```
sparse-embedding/
├── bm25_engine.py # 核心检索引擎
├── cli.py # 离线 CLIBM25/SPLADE + 指标
├── server.py # FastAPI 服务
├── demo.py # 演示脚本
├── requirements.txt
└── README.md
```
### 局限
仅内存存储;分词较基础(无词形还原);英文停用词;不支持短语查询 / 同义扩展 / 多线程。
---
## Notes / 说明
- Related next step / 相关后续:[`../retrieval-pipeline/`](../retrieval-pipeline/) hybrid dense+sparse pipeline (Exp. 3-6).
- 相关后续:[`../retrieval-pipeline/`](../retrieval-pipeline/) 混合稠密+稀疏流水线(实验 3-6)。