- anchor.py: 锚点提取(中文 2/3-gram、英文单词、代码标识符) - block.py: 对话块数据结构 - topic_gate.py: 话题门控(overlap/new_ratio 判断切换) - sparse.py: 稀疏召回(BM25/IDF-overlap + exact match 加分) - selector.py: 最小覆盖贪心选择 - gatekeeper.py: 完整流程封装 - tests/: 单元测试 + 端到端测试(含 MiniMax API 验证) 特性: - 纯 Python,无额外模型依赖 - 支持 2 核 2G 环境 - 话题门控 + 稀疏召回 + 最小覆盖选择
102 lines
2.6 KiB
Markdown
102 lines
2.6 KiB
Markdown
# 上下文门控器 (Context Gatekeeper)
|
||
|
||
轻量级上下文选择器,在同一会话中自动从历史对话里选出最小且相关的片段,减少话题污染和控制上下文长度。
|
||
|
||
## 特性
|
||
|
||
- 🚀 **纯 Python**,无需额外模型依赖
|
||
- 💻 **轻量运行**,支持 2 核 2G 环境
|
||
- 🔍 **话题门控**,智能判断继续/切换
|
||
- 📦 **稀疏召回**,BM25/IDF-overlap 评分
|
||
- 🎯 **最小覆盖**,贪心算法选择最优子集
|
||
- ⚙️ **稳定约束区**,持久化用户偏好
|
||
|
||
## 安装
|
||
|
||
```bash
|
||
pip install -e .
|
||
```
|
||
|
||
## 快速开始
|
||
|
||
```python
|
||
from src.gatekeeper import ContextGatekeeper
|
||
|
||
# 初始化,token 预算 4000
|
||
gate = ContextGatekeeper(token_budget=4000)
|
||
|
||
# 添加对话历史
|
||
gate.add_turn("Redis 锁续租为什么会脑裂", "因为 TTL 设置不合理...")
|
||
gate.add_turn("如何避免脑裂", "可以增加时钟偏移检测...")
|
||
|
||
# 为当前查询选择上下文
|
||
selected = gate.select("锁的 TTL 怎么设置")
|
||
|
||
for item in selected:
|
||
print(f"轮次 {item['turn_id']}: {item['user']}")
|
||
print(f"助手: {item['assistant']}\n")
|
||
|
||
# 设置稳定约束
|
||
gate.set_constraint("language", "中文")
|
||
gate.set_constraint("style", "简洁")
|
||
|
||
# 构建完整 prompt
|
||
prompt = gate.build_prompt("Redis 集群如何搭建")
|
||
```
|
||
|
||
## 核心流程
|
||
|
||
```
|
||
用户输入 → 锚点提取 → 话题门控 → 稀疏召回 → 最小覆盖选择 → 组装 Prompt
|
||
```
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
context-gatekeeper/
|
||
├── src/
|
||
│ ├── __init__.py
|
||
│ ├── anchor.py # 锚点提取
|
||
│ ├── block.py # Block 数据结构
|
||
│ ├── topic_gate.py # 话题门控
|
||
│ ├── sparse.py # 稀疏召回
|
||
│ ├── selector.py # 最小覆盖选择
|
||
│ └── gatekeeper.py # 主模块
|
||
├── tests/
|
||
│ ├── test_gatekeeper.py # 单元测试
|
||
│ └── test_e2e.py # 端到端测试
|
||
├── SPEC.md # 规格文档
|
||
├── README.md
|
||
├── .env.example
|
||
└── .gitignore
|
||
```
|
||
|
||
## 运行测试
|
||
|
||
```bash
|
||
# 单元测试
|
||
pytest tests/test_gatekeeper.py -v
|
||
|
||
# 端到端测试(需要配置 .env)
|
||
cp .env.example .env
|
||
# 编辑 .env 填入你的 MiniMax API Key
|
||
pytest tests/test_e2e.py -v
|
||
```
|
||
|
||
## 算法细节
|
||
|
||
### 话题门控
|
||
|
||
- **overlap > 0.45**:继续当前话题
|
||
- **overlap < 0.20** 且 **new_ratio > 0.70**:切换新话题
|
||
- 有指代词(这个/那个/它/上面)→ 强制继续
|
||
|
||
### 稀疏召回评分
|
||
|
||
```
|
||
score = 1.5 * lex(user) + 0.7 * lex(assistant) + 1.0 * exact + 0.2 * recency
|
||
```
|
||
|
||
### 最小覆盖选择
|
||
|
||
贪心选择"单位长度收益最大"的 block,直到覆盖率达到 85% 或 token 预算耗尽。 |