yangxiaohui 1 Minggu lalu
induk
melakukan
d481d212a5

+ 237 - 0
README_text_embedding.md

@@ -0,0 +1,237 @@
+# text_embedding 使用说明
+
+## 这是什么?
+
+**精简的文本相似度计算模块**,基于 similarities 库(BERT 向量模型)。
+
+- ✅ 只有 **1 个函数**:`compare_phrases()`
+- ✅ 支持 **4 种模型**
+- ✅ 返回格式兼容 `semantic_similarity.py`
+- ✅ 零成本,本地运行
+- ✅ 总共 163 行代码
+
+---
+
+## 安装
+
+```bash
+pip install -U similarities torch
+```
+
+---
+
+## 快速开始
+
+```python
+from lib.text_embedding import compare_phrases
+
+result = compare_phrases("如何更换花呗绑定银行卡", "花呗更改绑定银行卡")
+
+print(result['相似度'])  # 0.855
+print(result['说明'])     # "基于向量模型计算的语义相似度为 高 (0.86)"
+```
+
+---
+
+## 支持的模型
+
+### 简称方式(推荐)
+
+```python
+# 1. chinese(默认)- 中文通用模型
+result = compare_phrases("文本1", "文本2")
+result = compare_phrases("文本1", "文本2", model_name="chinese")
+
+# 2. multilingual - 多语言模型(中英韩日德意等)
+result = compare_phrases("Hello", "Hi", model_name="multilingual")
+
+# 3. paraphrase - 中文长文本模型
+result = compare_phrases("长文本1...", "长文本2...", model_name="paraphrase")
+
+# 4. sentence - 中文短句子模型
+result = compare_phrases("短句1", "短句2", model_name="sentence")
+```
+
+### 完整名称方式
+
+```python
+result = compare_phrases(
+    "文本1", "文本2",
+    model_name="shibing624/text2vec-base-chinese"
+)
+```
+
+### 模型列表
+
+| 简称 | 完整名称 | 说明 |
+|------|---------|------|
+| `chinese` | `shibing624/text2vec-base-chinese` | 中文通用(默认) |
+| `multilingual` | `shibing624/text2vec-base-multilingual` | 多语言 |
+| `paraphrase` | `shibing624/text2vec-base-chinese-paraphrase` | 中文长文本 |
+| `sentence` | `shibing624/text2vec-base-chinese-sentence` | 中文短句子 |
+
+---
+
+## 接口说明
+
+```python
+compare_phrases(
+    phrase_a: str,           # 第一个短语
+    phrase_b: str,           # 第二个短语
+    model_name: str = "chinese"  # 模型(可选)
+) -> Dict[str, Any]
+```
+
+**返回格式:**
+```python
+{
+    "说明": "基于向量模型计算的语义相似度为 高 (0.86)",
+    "相似度": 0.855
+}
+```
+
+---
+
+## 运行示例
+
+```bash
+python lib/text_embedding.py
+```
+
+**输出:**
+```
+示例 1: 默认模型(chinese)
+相似度: 0.855
+说明: 基于向量模型计算的语义相似度为 高 (0.86)
+
+示例 2: 使用默认模型
+相似度: 0.486
+说明: 基于向量模型计算的语义相似度为 较低 (0.49)
+
+示例 3: 不相关的短语
+相似度: 0.187
+说明: 基于向量模型计算的语义相似度为 低 (0.19)
+
+示例 4: 多语言模型(multilingual)
+相似度: 0.950
+说明: 基于向量模型计算的语义相似度为 极高 (0.95)
+
+============================================================
+支持的模型:
+------------------------------------------------------------
+  chinese         -> shibing624/text2vec-base-chinese
+  multilingual    -> shibing624/text2vec-base-multilingual
+  paraphrase      -> shibing624/text2vec-base-chinese-paraphrase
+  sentence        -> shibing624/text2vec-base-chinese-sentence
+```
+
+---
+
+## 使用场景
+
+### 场景 1: 中文短文本(默认)
+```python
+result = compare_phrases("深度学习", "神经网络")
+# 使用 chinese 模型
+```
+
+### 场景 2: 多语言文本
+```python
+result = compare_phrases("Hello", "Hi", model_name="multilingual")
+result = compare_phrases("こんにちは", "你好", model_name="multilingual")
+```
+
+### 场景 3: 中文长文本
+```python
+long_text_1 = "这是一段很长的文本..."
+long_text_2 = "这是另一段很长的文本..."
+result = compare_phrases(long_text_1, long_text_2, model_name="paraphrase")
+```
+
+### 场景 4: 中文短句子
+```python
+result = compare_phrases("你好", "您好", model_name="sentence")
+```
+
+---
+
+## 默认算分逻辑
+
+**余弦相似度(基于 BERT 向量)**
+
+```
+输入: "深度学习" vs "神经网络"
+    ↓
+BERT 模型转换为向量
+    ↓
+计算余弦相似度
+    ↓
+返回: 0.486
+```
+
+---
+
+## 与 semantic_similarity 对比
+
+| 特性 | semantic_similarity | text_embedding |
+|------|---------------------|----------------|
+| **算分方法** | LLM 判断 | BERT 向量 |
+| **返回格式** | `{说明, 相似度}` | `{说明, 相似度}` ✅ |
+| **速度** | 慢(需要调用 AI) | 快 |
+| **成本** | 有 token 成本 | **零成本** |
+| **模型数量** | 1 个 | **4 个** |
+| **代码行数** | 508 行 | **163 行** |
+
+---
+
+## 常见问题
+
+### Q1: 第一次运行会下载模型吗?
+**A**: 是的,第一次使用某个模型时会自动下载(约 400MB),之后就很快了。
+
+### Q2: 可以同时使用多个模型吗?
+**A**: 可以!代码会自动缓存已加载的模型。
+```python
+# 第一次调用会下载 chinese 模型
+result1 = compare_phrases("文本1", "文本2")
+
+# 第一次调用会下载 multilingual 模型
+result2 = compare_phrases("Hello", "Hi", model_name="multilingual")
+
+# 第二次调用直接使用缓存的模型,速度很快
+result3 = compare_phrases("文本3", "文本4")
+```
+
+### Q3: 哪个模型最好?
+**A**:
+- 中文短文本:`chinese`(默认)
+- 多语言:`multilingual`
+- 中文长文本(段落级别):`paraphrase`
+- 中文短句子:`sentence`
+
+### Q4: 如何选择模型?
+**A**: 不确定就用默认的 `chinese`,99% 的情况都够用!
+
+---
+
+## 总结
+
+**只需要记住:**
+
+```python
+from lib.text_embedding import compare_phrases
+
+# 基础用法(99% 的情况)
+result = compare_phrases("文本A", "文本B")
+
+# 切换模型
+result = compare_phrases("文本A", "文本B", model_name="multilingual")
+```
+
+**支持 4 种模型:**
+- `chinese` - 默认
+- `multilingual` - 多语言
+- `paraphrase` - 长文本
+- `sentence` - 短句子
+
+就这么简单!

+ 194 - 0
examples/DEFAULT_SCORING_SUMMARY.md

@@ -0,0 +1,194 @@
+# 默认算分逻辑 - 快速总结
+
+## 一句话回答
+
+**默认算分逻辑是:AI 直接判断语义相似度**
+
+---
+
+## 详细说明
+
+### `semantic_similarity.py`
+```python
+from lib.semantic_similarity import compare_phrases
+
+result = await compare_phrases("深度学习", "神经网络")
+# 使用: AI 直接判断(唯一方法)
+# 返回: {"说明": "...", "相似度": 0.85}
+```
+
+### `text_embedding.py` 的 `compare_phrases()`
+```python
+from lib.text_embedding import compare_phrases
+
+result = await compare_phrases("深度学习", "神经网络")
+# 使用: AI 直接判断(默认,与 semantic_similarity 相同)
+# 返回: {"说明": "...", "相似度": 0.85}
+```
+
+**两者默认行为完全一致!**
+
+---
+
+## 工作流程
+
+```
+输入: "深度学习" vs "神经网络"
+  ↓
+发送给 AI 的 Prompt:
+  "请计算以下两个文本的语义相似度,输出 0-1 之间的分数"
+  ↓
+AI 理解语义
+  ↓
+AI 返回:
+  {
+    "说明": "两者都是人工智能领域的核心概念,深度学习基于神经网络...",
+    "相似度": 0.85
+  }
+```
+
+---
+
+## text_embedding 的额外功能
+
+除了默认的 AI 判断,还支持:
+
+```python
+# 方法 1: AI 直接判断(默认)⭐
+result = await compare_phrases("A", "B")
+# 或明确指定
+result = await compare_phrases("A", "B", method="ai_direct")
+
+# 方法 2: 余弦相似度(基于向量)
+result = await compare_phrases("A", "B", method="cosine")
+
+# 方法 3: 欧氏距离
+result = await compare_phrases("A", "B", method="euclidean")
+
+# 方法 4: 曼哈顿距离
+result = await compare_phrases("A", "B", method="manhattan")
+
+# 方法 5: 点积
+result = await compare_phrases("A", "B", method="dot_product")
+```
+
+---
+
+## 准确度对比
+
+```
+ai_direct (默认)   ⭐⭐⭐⭐⭐ 最准确
+cosine             ⭐⭐⭐⭐
+euclidean          ⭐⭐⭐
+manhattan          ⭐⭐⭐
+dot_product        ⭐⭐⭐
+```
+
+---
+
+## 速度对比(已有缓存)
+
+```
+dot_product        ⚡⚡⚡⚡⚡ 最快
+manhattan          ⚡⚡⚡⚡
+euclidean          ⚡⚡⚡⚡
+cosine             ⚡⚡⚡
+ai_direct          ⚡⚡⚡⚡⚡ (缓存命中后极快)
+```
+
+---
+
+## 推荐使用
+
+### 场景 1: 日常使用(99% 的情况)
+```python
+# 不传 method 参数,使用默认值
+result = await compare_phrases("深度学习", "神经网络")
+```
+**原因**: 准确度最高,有缓存,第二次极快
+
+---
+
+### 场景 2: 批量计算
+```python
+# 如果要计算大量相似度
+result = await compare_phrases("A", "B", method="cosine", dim=128)
+```
+**原因**: 向量生成后,计算速度快
+
+---
+
+### 场景 3: 与 semantic_similarity 兼容
+```python
+# 直接替换导入,无需修改代码
+from lib.text_embedding import compare_phrases  # 改这里
+result = await compare_phrases("A", "B")  # 其他代码不变
+```
+
+---
+
+## 常见问题
+
+### Q1: 为什么默认用 AI 判断?
+**A**: 因为准确度最高,且有缓存机制,第二次调用极快。
+
+### Q2: AI 判断会不会很慢?
+**A**:
+- 首次调用: 需要 1-3 秒(调用 AI)
+- 第二次调用: 几乎瞬间(从缓存读取)
+
+### Q3: 什么时候用其他方法?
+**A**:
+- 批量计算相似度 → 用 `cosine`
+- 需要极快速度 → 用向量方法
+- 其他情况 → 用默认的 `ai_direct`
+
+### Q4: 如何切换算分方法?
+**A**:
+```python
+# 默认(AI 判断)
+result = await compare_phrases("A", "B")
+
+# 切换到余弦相似度
+result = await compare_phrases("A", "B", method="cosine")
+```
+
+---
+
+## 运行示例
+
+```bash
+# 查看详细说明
+cat examples/scoring_logic_explanation.md
+
+# 运行交互式演示
+python examples/demo_scoring_methods.py
+
+# 运行对比示例
+python examples/compare_with_semantic_similarity.py
+```
+
+---
+
+## 核心结论
+
+1. ✅ **默认算分逻辑**: AI 直接判断语义相似度
+2. ✅ **与 semantic_similarity 完全一致**: 返回格式和算分方法都相同
+3. ✅ **99% 情况用默认值就好**: 不需要指定 method 参数
+4. ✨ **额外功能**: 支持多种向量算分方法(可选)
+5. 🚀 **有缓存机制**: 第二次调用极快
+
+---
+
+## 快速参考
+
+```python
+# 最简单的用法(推荐)⭐
+from lib.text_embedding import compare_phrases
+
+result = await compare_phrases("深度学习", "神经网络")
+print(result['相似度'])  # 0.85
+print(result['说明'])     # AI 给出的详细理由
+```
+
+就这么简单!

+ 361 - 0
examples/README_text_embedding.md

@@ -0,0 +1,361 @@
+# text_embedding 使用说明
+
+## 这是什么?
+
+`text_embedding.py` 是一个**文本语义分析工具**,做两件事:
+
+1. **文本向量化** - 把文字变成数字向量
+2. **相似度计算** - 判断两段文字有多相似
+
+## 为什么需要它?
+
+传统的文字比较只能看字面:
+- "深度学习" vs "神经网络" → 完全不同 ❌
+
+使用语义分析可以理解含义:
+- "深度学习" vs "神经网络" → 相似度 0.85 ✅
+- "深度学习" vs "今天吃饭" → 相似度 0.05 ✅
+
+---
+
+## 快速开始
+
+### 安装依赖
+```bash
+pip install numpy
+# agents 和 lib.client 需要在项目中配置
+```
+
+### 基础使用
+
+```python
+import asyncio
+from lib.text_embedding import encode, similarity
+
+async def main():
+    # 1. 文本向量化
+    vector = await encode("人工智能很有趣")
+    print(vector.shape)  # (1536,) - 1536个数字
+
+    # 2. 计算相似度
+    result = await similarity("深度学习", "神经网络")
+    print(result['similarity'])  # 0.85
+
+asyncio.run(main())
+```
+
+---
+
+## 三种使用方式
+
+### 方式1: 直接调用函数(推荐)
+
+**文件:** `examples/example_text_embedding_basic.py`
+
+```python
+from lib.text_embedding import encode, similarity
+
+# 单个文本转向量
+vector = await encode("你好世界", dim=128)
+
+# 批量转换
+vectors = await encode(["文本1", "文本2", "文本3"], dim=128)
+
+# 计算相似度(AI直接判断,最准确)
+result = await similarity("深度学习", "神经网络")
+print(result['similarity'])  # 0.85
+```
+
+**运行:**
+```bash
+python examples/example_text_embedding_basic.py
+```
+
+---
+
+### 方式2: 使用 SentenceModel 类
+
+**文件:** `examples/example_text_embedding_model.py`
+
+```python
+from lib.text_embedding import SentenceModel
+
+# 创建模型
+model = SentenceModel(dim=128)
+
+# 文本向量化
+vector = await model.encode("机器学习")
+vectors = await model.encode(["文本1", "文本2"])
+
+# 计算相似度
+score = await model.similarity("深度学习", "神经网络")
+print(score)  # 0.85
+```
+
+**运行:**
+```bash
+python examples/example_text_embedding_model.py
+```
+
+---
+
+### 方式3: 实际应用场景
+
+**文件:** `examples/example_text_embedding_usecase.py`
+
+包含三个实际应用:
+
+#### 应用1: 语义搜索
+从大量文档中找出与查询最相关的内容
+
+```python
+query = "什么是深度学习?"
+documents = ["文档1", "文档2", ...]
+
+# 找出最相关的文档
+for doc in documents:
+    score = await model.similarity(query, doc)
+    # 按相似度排序
+```
+
+#### 应用2: 文本聚类
+把意思相近的文本自动分组
+
+```python
+texts = ["AI很强大", "深度学习很好", "今天吃饭", "晚餐美味"]
+# 自动找出相似的文本对(如:"AI很强大" 和 "深度学习很好")
+```
+
+#### 应用3: 重复检测
+识别意思相同但表述不同的文本
+
+```python
+q1 = "如何学习Python?"
+q2 = "怎样学好Python?"
+# 检测相似度 > 0.7 的问题,视为重复
+```
+
+**运行:**
+```bash
+python examples/example_text_embedding_usecase.py
+```
+
+---
+
+## API 接口说明
+
+### 0. `compare_phrases()` - 兼容 semantic_similarity.py 的接口 ⭐
+
+**返回格式与 `semantic_similarity.compare_phrases()` 完全一致**
+
+```python
+await compare_phrases(
+    phrase_a,          # 第一个短语
+    phrase_b,          # 第二个短语
+    model_name='openai/gpt-4.1-mini',
+    temperature=0.0,
+    method="ai_direct",  # 计算方法
+    use_cache=True
+)
+```
+
+**返回格式:**
+```python
+{
+    "说明": "简明扼要说明理由",
+    "相似度": 0.85  # 0-1之间的分数
+}
+```
+
+**例子:**
+```python
+# 与 semantic_similarity 完全兼容
+result = await compare_phrases("深度学习", "神经网络")
+print(result['相似度'])  # 0.85
+print(result['说明'])     # "两者都是AI领域的核心概念..."
+
+# 额外支持多种计算方法
+result = await compare_phrases("文本1", "文本2", method="cosine")
+```
+
+**与 semantic_similarity 的区别:**
+- ✅ 返回格式完全一致
+- ✅ 支持 AI 直接判断(与 semantic_similarity 相同)
+- ✨ 额外支持多种向量计算方法(cosine, euclidean 等)
+
+---
+
+### 1. `encode()` - 文本向量化
+
+```python
+await encode(
+    text,              # 单个文本或文本列表
+    dim=1536,          # 向量维度
+    model_name='openai/gpt-4.1-mini',  # 模型
+    use_cache=True,    # 是否使用缓存
+    return_dict=False  # 是否返回完整信息
+)
+```
+
+**返回:**
+- `return_dict=False`: numpy 数组(默认)
+- `return_dict=True`: 完整字典(含语义摘要)
+
+**例子:**
+```python
+# 返回向量
+vector = await encode("你好")  # numpy 数组 (1536,)
+
+# 返回完整信息
+result = await encode("你好", return_dict=True)
+print(result['semantic_summary'])  # 语义摘要
+print(result['embedding'])         # 向量
+```
+
+---
+
+### 2. `similarity()` - 相似度计算
+
+```python
+await similarity(
+    text_a,            # 第一个文本
+    text_b,            # 第二个文本
+    method="ai_direct",  # 计算方法
+    model_name='openai/gpt-4.1-mini',
+    use_cache=True
+)
+```
+
+**计算方法:**
+- `ai_direct`: AI 直接判断(最准确,推荐)
+- `cosine`: 余弦相似度(基于向量)
+- `euclidean`: 欧氏距离
+- `manhattan`: 曼哈顿距离
+- `dot_product`: 点积
+
+**返回:**
+```python
+{
+    "similarity": 0.85,          # 相似度分数 (0-1)
+    "method": "ai_direct",       # 使用的方法
+    "explanation": "两者高度相关..."  # 说明
+}
+```
+
+---
+
+### 3. `SentenceModel` - 模型类
+
+```python
+model = SentenceModel(
+    model_name='openai/gpt-4.1-mini',
+    dim=1536,
+    use_cache=True
+)
+
+# 向量化
+vector = await model.encode("文本")
+vectors = await model.encode(["文本1", "文本2"])
+
+# 相似度(直接返回分数)
+score = await model.similarity("文本A", "文本B")
+print(score)  # 0.85
+```
+
+---
+
+## 参数说明
+
+### 向量维度 `dim`
+- 向量的长度(数字个数)
+- 默认: `1536`(与 OpenAI embeddings 兼容)
+- 建议: 测试时用 `128` 或 `256`,节省时间
+
+### 模型 `model_name`
+```python
+'openai/gpt-4.1-mini'        # 默认,速度快
+'anthropic/claude-sonnet-4.5' # 质量高
+'google/gemini-2.5-pro'      # Google 模型
+```
+
+### 缓存 `use_cache`
+- `True`: 相同输入会从缓存读取(速度快 10-100倍)
+- `False`: 每次都调用 AI(用于测试)
+
+---
+
+## 与 text2vec 的对比
+
+| 特性 | text2vec | text_embedding.py |
+|------|----------|-------------------|
+| 文本向量化 | ✅ BERT 模型 | ✅ AI Agent 生成 |
+| 相似度计算 | ✅ 余弦距离 | ✅ AI 判断 + 多种方法 |
+| 缓存机制 | ❌ 无 | ✅ 自动缓存 |
+| 多模型支持 | ❌ 固定模型 | ✅ GPT/Claude/Gemini |
+| API 风格 | `encode()`, `similarity()` | ✅ 完全兼容 + 扩展 |
+| 中文支持 | ✅ | ✅ |
+
+---
+
+## 常见问题
+
+### Q1: 为什么要用 `await` 和 `async`?
+因为调用 AI 需要时间,使用异步可以提高效率。
+
+```python
+# 错误 ❌
+result = similarity("A", "B")
+
+# 正确 ✅
+result = await similarity("A", "B")
+
+# 必须在 async 函数中
+async def main():
+    result = await similarity("A", "B")
+
+asyncio.run(main())
+```
+
+### Q2: 向量维度选多大?
+- **测试**: 128 或 256(速度快)
+- **生产**: 1536(质量高,与 OpenAI 兼容)
+
+### Q3: 使用哪种相似度计算方法?
+- **推荐**: `ai_direct`(最准确)
+- **快速**: `cosine`(基于向量,速度快但需要生成向量)
+
+### Q4: 缓存文件在哪?
+在 `cache/text_embedding/` 目录下,可以手动删除。
+
+---
+
+## 完整示例运行
+
+```bash
+# 示例1: 基础用法
+python examples/example_text_embedding_basic.py
+
+# 示例2: SentenceModel 类
+python examples/example_text_embedding_model.py
+
+# 示例3: 实际应用场景
+python examples/example_text_embedding_usecase.py
+
+# 模块自带示例
+python lib/text_embedding.py
+```
+
+---
+
+## 总结
+
+**简单来说:**
+- **`encode()`** → 把文字变成数字
+- **`similarity()`** → 判断两段文字有多像
+- **`SentenceModel`** → 封装好的类,更方便使用
+
+**什么时候用:**
+- 语义搜索(在大量文档中找相关内容)
+- 文本聚类(自动分组相似内容)
+- 重复检测(找出意思相同的文本)
+- 推荐系统(找相似的文章/商品)

+ 149 - 0
examples/compare_with_semantic_similarity.py

@@ -0,0 +1,149 @@
+#!/usr/bin/env python3
+"""
+对比 semantic_similarity 和 text_embedding 两个模块的接口
+"""
+import asyncio
+
+
+async def main():
+    print("=" * 70)
+    print("对比 semantic_similarity 和 text_embedding 两个模块")
+    print("=" * 70)
+    print()
+
+    # ========== 1. 导入方式对比 ==========
+    print("1. 导入方式")
+    print("-" * 70)
+
+    print("# semantic_similarity 模块")
+    print("from lib.semantic_similarity import compare_phrases")
+    print()
+
+    print("# text_embedding 模块(兼容接口)")
+    print("from lib.text_embedding import compare_phrases")
+    print()
+
+    # ========== 2. 基本使用对比 ==========
+    print("2. 基本使用(完全兼容)")
+    print("-" * 70)
+
+    print("""
+# 两个模块的基本用法完全相同
+result = await compare_phrases("深度学习", "神经网络")
+
+# 返回格式完全一致
+{
+    "说明": "简明扼要说明理由",
+    "相似度": 0.85
+}
+    """)
+
+    # ========== 3. 实际对比 ==========
+    print("3. 实际效果对比")
+    print("-" * 70)
+
+    phrase_a = "机器学习"
+    phrase_b = "人工智能"
+
+    print(f"\n测试短语: 【{phrase_a}】 vs 【{phrase_b}】\n")
+
+    # 使用 text_embedding 模块(因为它兼容 semantic_similarity)
+    from lib.text_embedding import compare_phrases as compare_phrases_embed
+
+    result = await compare_phrases_embed(phrase_a, phrase_b)
+
+    print("text_embedding.compare_phrases() 结果:")
+    print(f"  相似度: {result['相似度']}")
+    print(f"  说明: {result['说明']}")
+    print()
+
+    # ========== 4. 功能对比 ==========
+    print("4. 功能对比")
+    print("-" * 70)
+
+    comparison = """
+┌─────────────────────────────────────────────────────────────────┐
+│                         功能对比表                               │
+├─────────────────────────┬─────────────────┬─────────────────────┤
+│ 功能                    │ semantic_sim.   │ text_embedding      │
+├─────────────────────────┼─────────────────┼─────────────────────┤
+│ 返回格式                │ {说明, 相似度}   │ {说明, 相似度} ✅    │
+│ AI 直接判断             │ ✅               │ ✅                   │
+│ 余弦相似度 (向量)       │ ❌               │ ✅                   │
+│ 欧氏距离 (向量)         │ ❌               │ ✅                   │
+│ 曼哈顿距离 (向量)       │ ❌               │ ✅                   │
+│ 文本向量化 (encode)     │ ❌               │ ✅                   │
+│ 批量处理                │ ❌               │ ✅                   │
+│ 缓存机制                │ ✅               │ ✅                   │
+│ 多模型支持              │ ✅               │ ✅                   │
+└─────────────────────────┴─────────────────┴─────────────────────┘
+    """
+    print(comparison)
+
+    # ========== 5. 使用场景推荐 ==========
+    print("5. 使用场景推荐")
+    print("-" * 70)
+
+    recommendations = """
+【推荐使用 semantic_similarity】
+  - 只需要简单的相似度判断
+  - 专注于语义分析
+  - 不需要向量化功能
+
+【推荐使用 text_embedding】
+  - 需要文本向量化(encode)
+  - 需要多种相似度计算方法
+  - 需要批量处理文本
+  - 需要兼容 semantic_similarity 的代码
+  - 想要更多的灵活性
+
+【无缝迁移】
+  如果你之前使用 semantic_similarity.compare_phrases(),
+  可以直接替换为 text_embedding.compare_phrases(),
+  代码无需任何修改!
+
+  # 旧代码
+  from lib.semantic_similarity import compare_phrases
+  result = await compare_phrases("A", "B")
+
+  # 新代码(只需改导入)
+  from lib.text_embedding import compare_phrases
+  result = await compare_phrases("A", "B")
+    """
+    print(recommendations)
+
+    # ========== 6. 扩展功能演示 ==========
+    print("6. text_embedding 的扩展功能演示")
+    print("-" * 70)
+
+    print("\n6.1 使用不同的计算方法:")
+    methods = ["ai_direct", "cosine", "euclidean"]
+    for method in methods:
+        result = await compare_phrases_embed(
+            phrase_a, phrase_b,
+            method=method,
+            dim=128
+        )
+        print(f"  {method:15s}: 相似度 = {result['相似度']:.3f}")
+
+    print("\n6.2 文本向量化:")
+    from lib.text_embedding import encode
+    vector = await encode("测试文本", dim=128)
+    print(f"  向量维度: {vector.shape}")
+    print(f"  向量前5个值: {vector[:5]}")
+
+    print("\n6.3 批量处理:")
+    from lib.text_embedding import SentenceModel
+    model = SentenceModel(dim=128)
+    texts = ["文本1", "文本2", "文本3"]
+    vectors = await model.encode(texts)
+    print(f"  批量转换 {len(texts)} 个文本")
+
+    print()
+    print("=" * 70)
+    print("对比完成!")
+    print("=" * 70)
+
+
+if __name__ == "__main__":
+    asyncio.run(main())

+ 243 - 0
examples/demo_scoring_methods.py

@@ -0,0 +1,243 @@
+#!/usr/bin/env python3
+"""
+演示不同算分方法的效果
+"""
+import asyncio
+from lib.text_embedding import compare_phrases
+import time
+
+
+async def demo_default_method():
+    """演示默认算分方法"""
+    print("=" * 70)
+    print("1. 默认算分方法: ai_direct")
+    print("=" * 70)
+    print()
+
+    print("默认情况下,compare_phrases() 使用 AI 直接判断语义相似度")
+    print("这与 semantic_similarity.py 的方法完全相同\n")
+
+    phrase_a = "深度学习"
+    phrase_b = "神经网络"
+
+    print(f"测试短语: 【{phrase_a}】 vs 【{phrase_b}】\n")
+
+    # 不指定 method,使用默认值 ai_direct
+    result = await compare_phrases(phrase_a, phrase_b)
+
+    print("返回结果:")
+    print(f"  相似度: {result['相似度']}")
+    print(f"  说明: {result['说明']}")
+    print()
+
+    print("工作原理:")
+    print("  1. AI 读取两个短语")
+    print("  2. AI 理解它们的语义")
+    print("  3. AI 直接给出相似度分数和理由")
+    print()
+
+
+async def demo_all_methods():
+    """演示所有算分方法"""
+    print("=" * 70)
+    print("2. 对比所有算分方法")
+    print("=" * 70)
+    print()
+
+    test_pairs = [
+        ("深度学习", "神经网络"),
+        ("机器学习", "人工智能"),
+        ("Python编程", "Java开发"),
+        ("今天吃饭", "深度学习"),
+    ]
+
+    methods = {
+        "ai_direct": "AI 直接判断(默认)",
+        "cosine": "余弦相似度",
+        "euclidean": "欧氏距离",
+        "manhattan": "曼哈顿距离",
+        "dot_product": "点积相似度",
+    }
+
+    for pair_idx, (phrase_a, phrase_b) in enumerate(test_pairs, 1):
+        print(f"\n测试 {pair_idx}: 【{phrase_a}】 vs 【{phrase_b}】")
+        print("-" * 70)
+
+        results = []
+        for method, description in methods.items():
+            result = await compare_phrases(
+                phrase_a, phrase_b,
+                method=method,
+                dim=128  # 使用较小维度加快测试
+            )
+            results.append((method, description, result['相似度']))
+
+        # 按相似度排序
+        results.sort(key=lambda x: x[2], reverse=True)
+
+        for method, description, score in results:
+            bar = "█" * int(score * 30)  # 可视化
+            print(f"  {description:25s} {score:.3f} {bar}")
+
+        print()
+
+
+async def demo_speed_comparison():
+    """演示不同方法的速度对比"""
+    print("=" * 70)
+    print("3. 速度对比(缓存机制演示)")
+    print("=" * 70)
+    print()
+
+    phrase_a = "测试文本A"
+    phrase_b = "测试文本B"
+
+    print(f"测试短语: 【{phrase_a}】 vs 【{phrase_b}】\n")
+
+    # 第一次调用(无缓存)
+    print("第一次调用(无缓存):")
+    start = time.time()
+    result1 = await compare_phrases(phrase_a, phrase_b)
+    time1 = time.time() - start
+    print(f"  耗时: {time1:.2f} 秒")
+    print(f"  相似度: {result1['相似度']}")
+    print()
+
+    # 第二次调用(有缓存)
+    print("第二次调用(有缓存):")
+    start = time.time()
+    result2 = await compare_phrases(phrase_a, phrase_b)
+    time2 = time.time() - start
+    print(f"  耗时: {time2:.2f} 秒")
+    print(f"  相似度: {result2['相似度']}")
+    print(f"  加速比: {time1/time2:.1f}x")
+    print()
+
+    print("结论:")
+    print("  - 首次调用需要请求 AI,耗时较长")
+    print("  - 缓存命中后,速度极快(几乎瞬间)")
+    print("  - 生产环境中,缓存大幅降低成本和延迟")
+    print()
+
+
+async def demo_accuracy_vs_speed():
+    """演示准确度 vs 速度的权衡"""
+    print("=" * 70)
+    print("4. 准确度 vs 速度权衡")
+    print("=" * 70)
+    print()
+
+    test_cases = [
+        ("深度学习", "神经网络", "高度相关"),
+        ("机器学习", "人工智能", "相关"),
+        ("Python", "Java", "弱相关"),
+        ("编程", "吃饭", "不相关"),
+    ]
+
+    print("测试不同语义关系的短语对:\n")
+
+    for phrase_a, phrase_b, relation in test_cases:
+        print(f"【{phrase_a}】 vs 【{phrase_b}】 (预期: {relation})")
+
+        # AI 直接判断(最准确)
+        result_ai = await compare_phrases(phrase_a, phrase_b, method="ai_direct")
+
+        # 余弦相似度(次准确)
+        result_cosine = await compare_phrases(phrase_a, phrase_b, method="cosine", dim=128)
+
+        print(f"  AI 判断:    {result_ai['相似度']:.3f} - {result_ai['说明'][:40]}...")
+        print(f"  余弦相似度: {result_cosine['相似度']:.3f}")
+
+        # 对比差异
+        diff = abs(result_ai['相似度'] - result_cosine['相似度'])
+        print(f"  差异:       {diff:.3f}")
+        print()
+
+    print("结论:")
+    print("  - AI 直接判断: 准确度最高,能给出详细理由")
+    print("  - 余弦相似度: 速度更快,但可能不如 AI 准确")
+    print("  - 建议: 默认使用 AI 直接判断,批量计算时考虑余弦")
+    print()
+
+
+async def demo_method_selection_guide():
+    """演示如何选择算分方法"""
+    print("=" * 70)
+    print("5. 算分方法选择指南")
+    print("=" * 70)
+    print()
+
+    print("┌─────────────────────────────────────────────────────────┐")
+    print("│ 场景                         │ 推荐方法                │")
+    print("├─────────────────────────────────────────────────────────┤")
+    print("│ 日常使用,追求准确度          │ ai_direct (默认)  ⭐    │")
+    print("│ 批量计算,已有向量            │ cosine                  │")
+    print("│ 需要详细解释原因              │ ai_direct (默认)        │")
+    print("│ 对成本敏感,大量计算          │ cosine                  │")
+    print("│ 与 semantic_similarity 兼容   │ ai_direct (默认)        │")
+    print("│ 需要稳定可复现的结果          │ cosine/euclidean        │")
+    print("└─────────────────────────────────────────────────────────┘")
+    print()
+
+    print("使用建议:")
+    print()
+    print("1️⃣  99% 的情况,直接用默认值(不传 method 参数)")
+    print("   result = await compare_phrases('A', 'B')  # 使用 ai_direct")
+    print()
+    print("2️⃣  批量计算时,可以考虑 cosine")
+    print("   result = await compare_phrases('A', 'B', method='cosine')")
+    print()
+    print("3️⃣  不确定时,用默认值就对了!")
+    print()
+
+
+async def main():
+    """运行所有演示"""
+
+    print("\n")
+    print("╔══════════════════════════════════════════════════════════════════╗")
+    print("║             默认算分逻辑演示 - text_embedding.py                ║")
+    print("╚══════════════════════════════════════════════════════════════════╝")
+    print()
+
+    # 1. 默认方法
+    await demo_default_method()
+
+    input("按回车继续下一个演示...")
+    print("\n")
+
+    # 2. 对比所有方法
+    await demo_all_methods()
+
+    input("按回车继续下一个演示...")
+    print("\n")
+
+    # 3. 速度对比
+    await demo_speed_comparison()
+
+    input("按回车继续下一个演示...")
+    print("\n")
+
+    # 4. 准确度 vs 速度
+    await demo_accuracy_vs_speed()
+
+    input("按回车继续下一个演示...")
+    print("\n")
+
+    # 5. 选择指南
+    await demo_method_selection_guide()
+
+    print("=" * 70)
+    print("所有演示完成!")
+    print("=" * 70)
+    print()
+    print("核心结论:")
+    print("  ✅ 默认使用 ai_direct(不需要指定 method 参数)")
+    print("  ✅ 与 semantic_similarity.py 完全兼容")
+    print("  ✅ 有缓存机制,第二次调用极快")
+    print("  ✨ 支持多种算分方法,按需选择")
+    print()
+
+
+if __name__ == "__main__":
+    asyncio.run(main())

+ 135 - 0
examples/example_compare_phrases.py

@@ -0,0 +1,135 @@
+#!/usr/bin/env python3
+"""
+演示 text_embedding.compare_phrases() 接口
+返回格式与 semantic_similarity.compare_phrases() 完全一致
+"""
+import asyncio
+from lib.text_embedding import compare_phrases
+
+
+async def main():
+    print("=" * 60)
+    print("text_embedding.compare_phrases() 接口演示")
+    print("返回格式与 semantic_similarity.compare_phrases() 一致")
+    print("=" * 60)
+    print()
+
+    # ========== 示例 1: 基本使用 ==========
+    print("示例 1: 基本使用")
+    print("-" * 60)
+
+    result = await compare_phrases("深度学习", "神经网络")
+
+    print(f"短语A: 深度学习")
+    print(f"短语B: 神经网络")
+    print(f"\n返回结果:")
+    print(f"  相似度: {result['相似度']}")
+    print(f"  说明: {result['说明']}")
+    print()
+
+    # ========== 示例 2: 对比不同的短语对 ==========
+    print("示例 2: 对比不同的短语对")
+    print("-" * 60)
+
+    phrase_pairs = [
+        ("机器学习", "人工智能"),
+        ("深度学习", "今天吃饭"),
+        ("Python编程", "程序设计"),
+        ("北京", "上海"),
+    ]
+
+    for phrase_a, phrase_b in phrase_pairs:
+        result = await compare_phrases(phrase_a, phrase_b)
+        print(f"\n【{phrase_a}】 vs 【{phrase_b}】")
+        print(f"  相似度: {result['相似度']:.3f}")
+        print(f"  说明: {result['说明']}")
+
+    print()
+
+    # ========== 示例 3: 使用不同的计算方法 ==========
+    print("示例 3: 使用不同的计算方法")
+    print("-" * 60)
+
+    phrase_a = "自然语言处理"
+    phrase_b = "文本分析"
+
+    methods = {
+        "ai_direct": "AI 直接判断(推荐)",
+        "cosine": "余弦相似度(基于向量)",
+        "euclidean": "欧氏距离相似度",
+    }
+
+    print(f"\n短语A: {phrase_a}")
+    print(f"短语B: {phrase_b}\n")
+
+    for method, description in methods.items():
+        result = await compare_phrases(
+            phrase_a, phrase_b,
+            method=method,
+            dim=128  # 使用较小维度加快测试
+        )
+        print(f"{description:30s}")
+        print(f"  相似度: {result['相似度']:.3f}")
+        print(f"  说明: {result['说明']}")
+        print()
+
+    # ========== 示例 4: 与 semantic_similarity 的对比 ==========
+    print("示例 4: 与 semantic_similarity.compare_phrases() 的对比")
+    print("-" * 60)
+
+    print("\n两个接口返回的数据格式完全一致:")
+    print("""
+    {
+        "说明": "相似度判断的理由",
+        "相似度": 0.85
+    }
+    """)
+
+    print("\n主要区别:")
+    print("  semantic_similarity:")
+    print("    - 只支持 AI 直接判断")
+    print("    - 专注于语义相似度分析")
+    print()
+    print("  text_embedding.compare_phrases:")
+    print("    - 支持 AI 直接判断 + 多种向量方法")
+    print("    - 可以选择不同的计算方法")
+    print("    - 返回格式完全兼容")
+    print()
+
+    # ========== 示例 5: 实际应用 - 批量比较 ==========
+    print("示例 5: 实际应用 - 批量比较")
+    print("-" * 60)
+
+    target = "机器学习"
+    candidates = [
+        "深度学习算法",
+        "神经网络模型",
+        "数据分析",
+        "今天天气",
+        "人工智能"
+    ]
+
+    print(f"\n目标短语: {target}")
+    print(f"候选短语: {len(candidates)} 个\n")
+
+    results = []
+    for candidate in candidates:
+        result = await compare_phrases(target, candidate)
+        results.append((candidate, result['相似度'], result['说明']))
+
+    # 按相似度排序
+    results.sort(key=lambda x: x[1], reverse=True)
+
+    print("相似度排名:")
+    for i, (phrase, score, explanation) in enumerate(results, 1):
+        print(f"\n  {i}. {phrase} (相似度: {score:.3f})")
+        print(f"     说明: {explanation}")
+
+    print()
+    print("=" * 60)
+    print("示例完成!")
+    print("=" * 60)
+
+
+if __name__ == "__main__":
+    asyncio.run(main())

+ 58 - 0
examples/example_text_embedding_basic.py

@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+"""
+text_embedding 基础使用示例
+"""
+import asyncio
+from lib.text_embedding import encode, similarity
+
+
+async def main():
+    print("=" * 60)
+    print("示例1: 文本向量化")
+    print("=" * 60)
+
+    # 把文字变成数字向量
+    text = "人工智能正在改变世界"
+    vector = await encode(text, dim=128)
+
+    print(f"文本: {text}")
+    print(f"向量形状: {vector.shape}")  # (128,) 表示128个数字
+    print(f"向量前10个数字: {vector[:10]}")
+    print()
+
+    print("=" * 60)
+    print("示例2: 批量转换多个文本")
+    print("=" * 60)
+
+    texts = [
+        "深度学习很有趣",
+        "机器学习很强大",
+        "今天天气不错"
+    ]
+
+    vectors = await encode(texts, dim=128)
+
+    for i, (text, vec) in enumerate(zip(texts, vectors)):
+        print(f"{i+1}. {text} -> {vec.shape}")
+    print()
+
+    print("=" * 60)
+    print("示例3: 计算相似度")
+    print("=" * 60)
+
+    # 方法1: AI直接判断(最准确)
+    result = await similarity("深度学习", "神经网络", method="ai_direct")
+    print(f"深度学习 vs 神经网络")
+    print(f"  相似度: {result['similarity']:.3f}")
+    print(f"  说明: {result.get('explanation', '')}")
+    print()
+
+    # 方法2: 基于向量计算
+    result = await similarity("深度学习", "今天吃饭", method="cosine", dim=128)
+    print(f"深度学习 vs 今天吃饭")
+    print(f"  相似度: {result['similarity']:.3f}")
+    print()
+
+
+if __name__ == "__main__":
+    asyncio.run(main())

+ 66 - 0
examples/example_text_embedding_model.py

@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+"""
+使用 SentenceModel 类(类似 text2vec 的用法)
+"""
+import asyncio
+from lib.text_embedding import SentenceModel
+
+
+async def main():
+    print("=" * 60)
+    print("使用 SentenceModel 类")
+    print("=" * 60)
+
+    # 创建模型(只需要创建一次)
+    model = SentenceModel(
+        model_name='openai/gpt-4.1-mini',
+        dim=128,  # 向量维度
+        use_cache=True  # 启用缓存
+    )
+
+    # 1. 文本向量化
+    print("\n1. 单个文本向量化")
+    vector = await model.encode("机器学习很有趣")
+    print(f"向量维度: {vector.shape}")
+
+    # 2. 批量向量化
+    print("\n2. 批量向量化")
+    texts = ["文本1", "文本2", "文本3"]
+    vectors = await model.encode(texts)
+    print(f"转换了 {len(vectors)} 个文本")
+
+    # 3. 计算相似度
+    print("\n3. 计算相似度")
+    score = await model.similarity("深度学习", "神经网络")
+    print(f"相似度分数: {score:.3f}")
+
+    # 4. 实际应用:找出最相似的文本
+    print("\n4. 实际应用:找出最相似的文本")
+    query = "人工智能"
+    candidates = [
+        "机器学习算法",
+        "深度神经网络",
+        "今天天气很好",
+        "自然语言处理",
+        "晚上吃什么饭"
+    ]
+
+    print(f"\n查询文本: {query}")
+    print(f"候选文本: {candidates}")
+    print("\n相似度排名:")
+
+    # 计算所有候选文本的相似度
+    scores = []
+    for candidate in candidates:
+        score = await model.similarity(query, candidate)
+        scores.append((candidate, score))
+
+    # 按相似度排序
+    scores.sort(key=lambda x: x[1], reverse=True)
+
+    for i, (text, score) in enumerate(scores, 1):
+        print(f"  {i}. {text:20s} -> {score:.3f}")
+
+
+if __name__ == "__main__":
+    asyncio.run(main())

+ 84 - 0
examples/example_text_embedding_simple.py

@@ -0,0 +1,84 @@
+#!/usr/bin/env python3
+"""
+text_embedding 简单使用示例(基于 similarities 库)
+"""
+from lib.text_embedding import compare_phrases, similarity, encode, SentenceModel
+
+
+def main():
+    print("=" * 60)
+    print("text_embedding 使用示例(基于 similarities 向量模型)")
+    print("=" * 60)
+    print()
+
+    # ========== 示例 1: compare_phrases(推荐,兼容 semantic_similarity)==========
+    print("示例 1: compare_phrases() - 兼容 semantic_similarity.py")
+    print("-" * 60)
+
+    result = compare_phrases("如何更换花呗绑定银行卡", "花呗更改绑定银行卡")
+    print(f"短语A: 如何更换花呗绑定银行卡")
+    print(f"短语B: 花呗更改绑定银行卡")
+    print(f"\n返回结果:")
+    print(f"  相似度: {result['相似度']:.3f}")
+    print(f"  说明: {result['说明']}")
+    print()
+
+    # ========== 示例 2: 直接获取相似度分数 ==========
+    print("示例 2: similarity() - 直接获取相似度分数")
+    print("-" * 60)
+
+    score = similarity("深度学习", "神经网络")
+    print(f"深度学习 vs 神经网络")
+    print(f"相似度: {score:.3f}")
+    print()
+
+    # ========== 示例 3: 文本向量化 ==========
+    print("示例 3: encode() - 文本向量化")
+    print("-" * 60)
+
+    embedding = encode("人工智能很有趣")
+    print(f"文本: 人工智能很有趣")
+    print(f"向量维度: {embedding.shape}")
+    print(f"向量前5个值: {embedding[:5]}")
+    print()
+
+    # ========== 示例 4: 批量处理 ==========
+    print("示例 4: 批量文本处理")
+    print("-" * 60)
+
+    texts = ["深度学习", "机器学习", "人工智能"]
+    embeddings = encode(texts)
+    print(f"批量转换 {len(texts)} 个文本:")
+    for i, (text, emb) in enumerate(zip(texts, embeddings), 1):
+        print(f"  {i}. {text} -> {emb.shape}")
+    print()
+
+    # ========== 示例 5: 使用 SentenceModel 类 ==========
+    print("示例 5: SentenceModel 类")
+    print("-" * 60)
+
+    model = SentenceModel()
+
+    # 相似度
+    score = model.similarity("Python编程", "程序设计")
+    print(f"相似度: {score:.3f}")
+
+    # 完整结果
+    result = model.compare_phrases("机器学习", "人工智能")
+    print(f"完整结果: {result}")
+    print()
+
+    print("=" * 60)
+    print("示例完成!")
+    print("=" * 60)
+    print()
+    print("核心要点:")
+    print("  ✅ 使用真正的向量模型(不是 LLM)")
+    print("  ✅ 返回格式与 semantic_similarity.py 兼容")
+    print("  ✅ 默认算分: 基于向量的余弦相似度")
+    print("  ✅ 速度快,成本低")
+    print()
+
+
+if __name__ == "__main__":
+    main()

+ 151 - 0
examples/example_text_embedding_usecase.py

@@ -0,0 +1,151 @@
+#!/usr/bin/env python3
+"""
+text_embedding 实际应用场景示例
+"""
+import asyncio
+from lib.text_embedding import SentenceModel
+import numpy as np
+
+
+async def usecase_1_semantic_search():
+    """
+    应用场景1: 语义搜索
+    - 用户输入一个查询
+    - 从大量文本中找出最相关的内容
+    """
+    print("=" * 60)
+    print("应用场景1: 语义搜索")
+    print("=" * 60)
+
+    model = SentenceModel(dim=128)
+
+    # 文档库(比如知识库、文章库)
+    documents = [
+        "深度学习是机器学习的一个重要分支",
+        "神经网络模拟人脑的结构和功能",
+        "自然语言处理用于理解和生成人类语言",
+        "计算机视觉让机器能够理解图像",
+        "今天天气晴朗,适合出门散步",
+        "晚餐吃了美味的意大利面",
+    ]
+
+    # 用户查询
+    query = "什么是深度学习?"
+
+    print(f"\n用户查询: {query}")
+    print(f"\n文档库中有 {len(documents)} 篇文档")
+    print("\n搜索结果(按相关度排序):")
+
+    # 计算查询与每篇文档的相似度
+    results = []
+    for doc in documents:
+        score = await model.similarity(query, doc)
+        results.append((doc, score))
+
+    # 排序并展示前3个最相关的
+    results.sort(key=lambda x: x[1], reverse=True)
+
+    for i, (doc, score) in enumerate(results[:3], 1):
+        print(f"\n  Top {i} (相似度: {score:.3f})")
+        print(f"  {doc}")
+
+
+async def usecase_2_text_clustering():
+    """
+    应用场景2: 文本聚类
+    - 把相似的文本分组
+    """
+    print("\n" + "=" * 60)
+    print("应用场景2: 文本聚类(相似内容分组)")
+    print("=" * 60)
+
+    model = SentenceModel(dim=128)
+
+    texts = [
+        "机器学习算法很强大",
+        "深度神经网络效果很好",
+        "今天吃了火锅",
+        "晚餐很美味",
+        "AI技术发展迅速",
+        "明天去爬山",
+    ]
+
+    print(f"\n待分组文本: {texts}")
+
+    # 简单聚类:找出相似度 > 0.6 的文本对
+    print("\n相似文本对(相似度 > 0.6):")
+
+    similar_pairs = []
+    for i in range(len(texts)):
+        for j in range(i + 1, len(texts)):
+            score = await model.similarity(texts[i], texts[j])
+            if score > 0.6:
+                similar_pairs.append((texts[i], texts[j], score))
+
+    for text1, text2, score in similar_pairs:
+        print(f"\n  相似度: {score:.3f}")
+        print(f"  - {text1}")
+        print(f"  - {text2}")
+
+
+async def usecase_3_duplicate_detection():
+    """
+    应用场景3: 重复/相似内容检测
+    - 识别意思相同但表述不同的文本
+    """
+    print("\n" + "=" * 60)
+    print("应用场景3: 重复内容检测")
+    print("=" * 60)
+
+    model = SentenceModel(dim=128)
+
+    # 用户提交的问题列表
+    questions = [
+        "如何学习Python编程?",
+        "怎样才能学好Python?",
+        "Python入门教程有哪些?",
+        "今天天气怎么样?",
+        "北京今天的天气如何?",
+    ]
+
+    print(f"\n问题列表:")
+    for i, q in enumerate(questions, 1):
+        print(f"  {i}. {q}")
+
+    # 检测重复(相似度 > 0.7 视为重复)
+    print("\n检测到的重复问题(相似度 > 0.7):")
+
+    threshold = 0.7
+    duplicates = []
+
+    for i in range(len(questions)):
+        for j in range(i + 1, len(questions)):
+            score = await model.similarity(questions[i], questions[j])
+            if score > threshold:
+                duplicates.append((i+1, j+1, questions[i], questions[j], score))
+
+    for idx1, idx2, q1, q2, score in duplicates:
+        print(f"\n  问题{idx1} 和 问题{idx2} 相似 (相似度: {score:.3f})")
+        print(f"  - {q1}")
+        print(f"  - {q2}")
+
+
+async def main():
+    """运行所有应用场景示例"""
+
+    # 场景1: 语义搜索
+    await usecase_1_semantic_search()
+
+    # 场景2: 文本聚类
+    await usecase_2_text_clustering()
+
+    # 场景3: 重复检测
+    await usecase_3_duplicate_detection()
+
+    print("\n" + "=" * 60)
+    print("所有示例完成!")
+    print("=" * 60)
+
+
+if __name__ == "__main__":
+    asyncio.run(main())

+ 353 - 0
examples/scoring_logic_explanation.md

@@ -0,0 +1,353 @@
+# 默认算分逻辑说明
+
+## 两个模块的默认算分逻辑对比
+
+### 1. `semantic_similarity.py` 的默认算分逻辑
+
+#### 默认方法
+**AI 直接判断**(唯一方法)
+
+#### 工作原理
+```
+用户输入: "深度学习" vs "神经网络"
+    ↓
+发送给 AI 的 Prompt:
+    从语意角度,判断【深度学习】和【神经网络】的相似度,从0-1打分,输出json格式
+    ```json
+    {
+      "说明": "简明扼要说明理由",
+      "相似度": 0.0,
+    }
+    ```
+    ↓
+AI 理解语义后返回:
+    {
+      "说明": "两者都是人工智能领域的核心概念,深度学习是基于神经网络的...",
+      "相似度": 0.85
+    }
+```
+
+#### 特点
+- ✅ **优点**: AI 深度理解语义,准确度高
+- ✅ **优点**: 能理解上下文、隐含关系
+- ⚠️ **缺点**: 需要调用 AI,速度较慢(首次)
+- ⚠️ **缺点**: 有 token 成本
+
+---
+
+### 2. `text_embedding.py` 的默认算分逻辑
+
+#### 默认方法
+**AI 直接判断** (`method="ai_direct"`)
+
+与 `semantic_similarity.py` 完全相同!
+
+#### 工作原理(默认)
+```
+用户输入: "深度学习" vs "神经网络"
+    ↓
+发送给 AI 的 Prompt:
+    请计算以下两个文本的语义相似度,输出 0-1 之间的分数。
+
+    文本A:【深度学习】
+    文本B:【神经网络】
+
+    输出格式:
+    ```json
+    {
+      "similarity": 0.0,
+      "method": "semantic_analysis",
+      "explanation": "相似度判断的理由"
+    }
+    ```
+    ↓
+AI 返回结果后,转换为兼容格式:
+    {
+      "说明": "相似度判断的理由",
+      "相似度": 0.85
+    }
+```
+
+#### 额外支持的算分方法
+
+除了默认的 AI 直接判断,还支持基于向量的计算方法:
+
+---
+
+## 详细算分方法对比
+
+### 方法 1: `ai_direct` (默认,推荐)⭐
+
+**原理**: AI 直接理解语义并打分
+
+**优点**:
+- ✅ 准确度最高
+- ✅ 能理解复杂的语义关系
+- ✅ 能理解上下文、同义词、隐含意义
+
+**缺点**:
+- ⚠️ 需要调用 AI(但有缓存,第二次很快)
+- ⚠️ 有 token 成本
+
+**适用场景**:
+- 需要高准确度的语义分析
+- 文本有复杂的语义关系
+- 不在意首次调用的时间成本
+
+**示例**:
+```python
+result = await compare_phrases("深度学习", "神经网络", method="ai_direct")
+# 相似度: 0.85
+# 说明: "两者都是AI领域的核心概念..."
+```
+
+---
+
+### 方法 2: `cosine` (余弦相似度)
+
+**原理**:
+1. 先把两段文字转换成向量(数字数组)
+2. 计算两个向量的夹角
+3. 夹角越小 → 相似度越高
+
+**数学公式**:
+```
+相似度 = cos(θ) = (A·B) / (|A| × |B|)
+
+其中:
+- A, B 是两个向量
+- A·B 是点积
+- |A|, |B| 是向量的模(长度)
+```
+
+**取值范围**: -1 到 1
+- 1: 完全相同
+- 0: 无关
+- -1: 完全相反
+
+**优点**:
+- ✅ 计算速度快(向量生成后)
+- ✅ 数学方法,结果稳定
+- ✅ 不受向量长度影响
+
+**缺点**:
+- ⚠️ 需要先生成向量(首次需要调用 AI)
+- ⚠️ 对语义的理解不如 AI 直接判断
+
+**适用场景**:
+- 需要批量计算相似度
+- 需要结果稳定可复现
+- 已经有向量,不想再调用 AI
+
+**示例**:
+```python
+result = await compare_phrases("深度学习", "神经网络", method="cosine", dim=128)
+# 相似度: 0.78
+# 说明: "基于 cosine 方法计算的向量相似度"
+```
+
+---
+
+### 方法 3: `euclidean` (欧氏距离)
+
+**原理**:
+1. 把文字转换成向量(多维空间中的点)
+2. 计算两点之间的直线距离
+3. 距离越近 → 相似度越高
+
+**数学公式**:
+```
+距离 = √[(a1-b1)² + (a2-b2)² + ... + (an-bn)²]
+
+相似度 = 1 / (1 + 距离)  # 归一化到 0-1
+```
+
+**取值范围**: 0 到 1
+- 1: 完全相同(距离=0)
+- 0: 完全不同(距离→∞)
+
+**优点**:
+- ✅ 直观(就是空间距离)
+- ✅ 计算简单
+
+**缺点**:
+- ⚠️ 受向量长度影响
+- ⚠️ 高维空间中可能不够准确
+
+**适用场景**:
+- 需要直观的距离度量
+- 向量长度有意义的场景
+
+**示例**:
+```python
+result = await compare_phrases("深度学习", "神经网络", method="euclidean", dim=128)
+# 相似度: 0.65
+# 说明: "基于 euclidean 方法计算的向量相似度"
+```
+
+---
+
+### 方法 4: `manhattan` (曼哈顿距离)
+
+**原理**:
+类似走城市街道,只能沿坐标轴方向移动
+
+**数学公式**:
+```
+距离 = |a1-b1| + |a2-b2| + ... + |an-bn|
+
+相似度 = 1 / (1 + 距离)  # 归一化到 0-1
+```
+
+**取值范围**: 0 到 1
+
+**优点**:
+- ✅ 对噪声不敏感
+- ✅ 计算快
+
+**缺点**:
+- ⚠️ 不适合高维空间
+
+**适用场景**:
+- 数据有噪声
+- 需要对异常值鲁棒
+
+**示例**:
+```python
+result = await compare_phrases("深度学习", "神经网络", method="manhattan", dim=128)
+# 相似度: 0.62
+# 说明: "基于 manhattan 方法计算的向量相似度"
+```
+
+---
+
+### 方法 5: `dot_product` (点积)
+
+**原理**:
+计算两个向量的点积,用 sigmoid 归一化
+
+**数学公式**:
+```
+点积 = a1×b1 + a2×b2 + ... + an×bn
+
+相似度 = 1 / (1 + e^(-点积))  # sigmoid 归一化
+```
+
+**取值范围**: 0 到 1
+
+**优点**:
+- ✅ 计算最快
+- ✅ 考虑向量长度(方向+幅度)
+
+**缺点**:
+- ⚠️ 受向量长度影响大
+
+**适用场景**:
+- 向量长度有意义
+- 需要极快的计算速度
+
+**示例**:
+```python
+result = await compare_phrases("深度学习", "神经网络", method="dot_product", dim=128)
+# 相似度: 0.71
+# 说明: "基于 dot_product 方法计算的向量相似度"
+```
+
+---
+
+## 方法选择指南
+
+### 📊 准确度排名
+```
+ai_direct > cosine > euclidean ≈ manhattan ≈ dot_product
+```
+
+### ⚡ 速度排名(向量已生成)
+```
+dot_product > manhattan > euclidean > cosine >> ai_direct
+```
+
+### 💰 成本排名
+```
+ai_direct (需要调用 AI) >> 向量方法 (首次需要生成向量)
+```
+
+---
+
+## 实际测试对比
+
+```python
+# 测试短语
+phrase_a = "深度学习"
+phrase_b = "神经网络"
+
+# 不同方法的结果(示例)
+┌──────────────┬──────────┬────────────────────────────┐
+│ 方法         │ 相似度   │ 说明                       │
+├──────────────┼──────────┼────────────────────────────┤
+│ ai_direct    │ 0.850    │ AI 深度理解,最准确        │
+│ cosine       │ 0.780    │ 向量夹角,次准确           │
+│ euclidean    │ 0.650    │ 欧氏距离                   │
+│ manhattan    │ 0.620    │ 曼哈顿距离                 │
+│ dot_product  │ 0.710    │ 点积                       │
+└──────────────┴──────────┴────────────────────────────┘
+```
+
+---
+
+## 默认选择建议
+
+### 如果你不确定用哪个,建议:
+
+**1. 默认使用 `ai_direct`** ⭐
+```python
+# 不传 method 参数,默认就是 ai_direct
+result = await compare_phrases("深度学习", "神经网络")
+```
+
+**原因**:
+- ✅ 准确度最高
+- ✅ 有缓存机制,第二次很快
+- ✅ 与 semantic_similarity 完全一致
+
+---
+
+**2. 批量计算时可以考虑 `cosine`**
+```python
+# 如果要计算大量相似度,可以先生成所有向量
+model = SentenceModel(dim=128)
+
+# 生成向量(只需一次)
+vectors = await model.encode(all_texts)
+
+# 然后用 cosine 快速计算
+for i in range(len(all_texts)):
+    for j in range(i+1, len(all_texts)):
+        result = await compare_phrases(
+            all_texts[i], all_texts[j],
+            method="cosine"
+        )
+```
+
+---
+
+## 总结
+
+### `semantic_similarity.py`
+- **唯一方法**: AI 直接判断
+- **返回格式**: `{说明, 相似度}`
+
+### `text_embedding.py` 的 `compare_phrases()`
+- **默认方法**: AI 直接判断(与 semantic_similarity 相同)
+- **返回格式**: `{说明, 相似度}` (完全兼容)
+- **额外功能**: 支持 5 种计算方法
+  - `ai_direct` - AI 判断(默认)⭐
+  - `cosine` - 余弦相似度
+  - `euclidean` - 欧氏距离
+  - `manhattan` - 曼哈顿距离
+  - `dot_product` - 点积
+
+### 推荐
+- **日常使用**: 默认 `ai_direct`,不需要指定 method
+- **批量计算**: 考虑 `cosine`
+- **完全兼容**: 可以直接替换 `semantic_similarity.compare_phrases()`

+ 163 - 0
lib/text_embedding.py

@@ -0,0 +1,163 @@
+#!/usr/bin/env python3
+"""
+文本相似度计算模块
+基于 similarities 库(真正的向量模型,不使用 LLM)
+"""
+
+from typing import Dict, Any
+
+# 支持的模型列表
+SUPPORTED_MODELS = {
+    "chinese": "shibing624/text2vec-base-chinese",           # 默认,中文通用
+    "multilingual": "shibing624/text2vec-base-multilingual", # 多语言(中英韩日德意等)
+    "paraphrase": "shibing624/text2vec-base-chinese-paraphrase",  # 中文长文本
+    "sentence": "shibing624/text2vec-base-chinese-sentence",      # 中文短句子
+}
+
+# 延迟导入 similarities,避免初始化时就加载模型
+_similarity_models = {}  # 存储多个模型实例
+
+
+def _get_similarity_model(model_name: str = "shibing624/text2vec-base-chinese"):
+    """
+    获取或初始化相似度模型(支持多个模型)
+
+    Args:
+        model_name: 模型名称
+
+    Returns:
+        BertSimilarity 模型实例
+    """
+    global _similarity_models
+
+    # 如果是简称,转换为完整名称
+    if model_name in SUPPORTED_MODELS:
+        model_name = SUPPORTED_MODELS[model_name]
+
+    # 如果模型已加载,直接返回
+    if model_name in _similarity_models:
+        return _similarity_models[model_name]
+
+    # 加载新模型
+    try:
+        from similarities import BertSimilarity
+        print(f"正在加载模型: {model_name}...")
+        _similarity_models[model_name] = BertSimilarity(model_name_or_path=model_name)
+        print("模型加载完成!")
+        return _similarity_models[model_name]
+    except ImportError:
+        raise ImportError(
+            "请先安装 similarities 库: pip install -U similarities torch"
+        )
+
+
+def compare_phrases(
+    phrase_a: str,
+    phrase_b: str,
+    model_name: str = "chinese"
+) -> Dict[str, Any]:
+    """
+    比较两个短语的语义相似度(兼容 semantic_similarity.py 的接口)
+
+    返回格式与 semantic_similarity.compare_phrases() 一致:
+    {
+        "说明": "基于向量模型计算的语义相似度",
+        "相似度": 0.85
+    }
+
+    Args:
+        phrase_a: 第一个短语
+        phrase_b: 第二个短语
+        model_name: 模型名称,可选:
+            简称:
+            - "chinese" (默认) - 中文通用模型
+            - "multilingual" - 多语言模型(中英韩日德意等)
+            - "paraphrase" - 中文长文本模型
+            - "sentence" - 中文短句子模型
+
+            完整名称:
+            - "shibing624/text2vec-base-chinese"
+            - "shibing624/text2vec-base-multilingual"
+            - "shibing624/text2vec-base-chinese-paraphrase"
+            - "shibing624/text2vec-base-chinese-sentence"
+
+    Returns:
+        {
+            "说明": str,      # 相似度说明
+            "相似度": float    # 0-1之间的相似度分数
+        }
+
+    Examples:
+        >>> # 使用默认模型
+        >>> result = compare_phrases("如何更换花呗绑定银行卡", "花呗更改绑定银行卡")
+        >>> print(result['相似度'])  # 0.855
+
+        >>> # 使用多语言模型
+        >>> result = compare_phrases("Hello", "Hi", model_name="multilingual")
+
+        >>> # 使用长文本模型
+        >>> result = compare_phrases("长文本1...", "长文本2...", model_name="paraphrase")
+    """
+    model = _get_similarity_model(model_name)
+    score = float(model.similarity(phrase_a, phrase_b))
+
+    # 生成说明
+    if score >= 0.9:
+        level = "极高"
+    elif score >= 0.7:
+        level = "高"
+    elif score >= 0.5:
+        level = "中等"
+    elif score >= 0.3:
+        level = "较低"
+    else:
+        level = "低"
+
+    explanation = f"基于向量模型计算的语义相似度为 {level} ({score:.2f})"
+
+    return {
+        "说明": explanation,
+        "相似度": score
+    }
+
+
+if __name__ == "__main__":
+    print("=" * 60)
+    print("text_embedding - 文本相似度计算")
+    print("=" * 60)
+    print()
+
+    # 示例 1: 默认模型
+    print("示例 1: 默认模型(chinese)")
+    result = compare_phrases("如何更换花呗绑定银行卡", "花呗更改绑定银行卡")
+    print(f"相似度: {result['相似度']:.3f}")
+    print(f"说明: {result['说明']}")
+    print()
+
+    # 示例 2: 短句子
+    print("示例 2: 使用默认模型")
+    result = compare_phrases("深度学习", "神经网络")
+    print(f"相似度: {result['相似度']:.3f}")
+    print(f"说明: {result['说明']}")
+    print()
+
+    # 示例 3: 不相关
+    print("示例 3: 不相关的短语")
+    result = compare_phrases("编程", "吃饭")
+    print(f"相似度: {result['相似度']:.3f}")
+    print(f"说明: {result['说明']}")
+    print()
+
+    # 示例 4: 多语言模型
+    print("示例 4: 多语言模型(multilingual)")
+    result = compare_phrases("Hello", "Hi", model_name="multilingual")
+    print(f"相似度: {result['相似度']:.3f}")
+    print(f"说明: {result['说明']}")
+    print()
+
+    print("=" * 60)
+    print("支持的模型:")
+    print("-" * 60)
+    for key, value in SUPPORTED_MODELS.items():
+        print(f"  {key:15s} -> {value}")
+    print("=" * 60)

+ 201 - 71
script/data_processing/match_inspiration_features.py

@@ -12,6 +12,7 @@ import asyncio
 from pathlib import Path
 from typing import Dict, List
 import sys
+from datetime import datetime
 
 # 添加项目根目录到路径
 project_root = Path(__file__).parent.parent.parent
@@ -20,9 +21,62 @@ sys.path.insert(0, str(project_root))
 from lib.semantic_similarity import compare_phrases
 
 # 全局并发限制
-MAX_CONCURRENT_REQUESTS = 20
+MAX_CONCURRENT_REQUESTS = 100
 semaphore = None
 
+# 进度跟踪
+class ProgressTracker:
+    """进度跟踪器"""
+    def __init__(self, total: int):
+        self.total = total
+        self.completed = 0
+        self.start_time = datetime.now()
+        self.last_update_time = datetime.now()
+        self.last_completed = 0
+
+    def update(self, count: int = 1):
+        """更新进度"""
+        self.completed += count
+        current_time = datetime.now()
+
+        # 每秒最多更新一次,或者达到总数时更新
+        if (current_time - self.last_update_time).total_seconds() >= 1.0 or self.completed >= self.total:
+            self.display()
+            self.last_update_time = current_time
+            self.last_completed = self.completed
+
+    def display(self):
+        """显示进度"""
+        if self.total == 0:
+            return
+
+        percentage = (self.completed / self.total) * 100
+        elapsed = (datetime.now() - self.start_time).total_seconds()
+
+        # 计算速度和预估剩余时间
+        if elapsed > 0:
+            speed = self.completed / elapsed
+            if speed > 0:
+                remaining = (self.total - self.completed) / speed
+                eta_str = f", 预计剩余: {int(remaining)}秒"
+            else:
+                eta_str = ""
+        else:
+            eta_str = ""
+
+        bar_length = 40
+        filled_length = int(bar_length * self.completed / self.total)
+        bar = '█' * filled_length + '░' * (bar_length - filled_length)
+
+        print(f"\r  进度: [{bar}] {self.completed}/{self.total} ({percentage:.1f}%){eta_str}", end='', flush=True)
+
+        # 完成时换行
+        if self.completed >= self.total:
+            print()
+
+# 全局进度跟踪器
+progress_tracker = None
+
 
 def get_semaphore():
     """获取全局信号量"""
@@ -35,6 +89,7 @@ def get_semaphore():
 async def match_single_pair(
     feature_name: str,
     persona_name: str,
+    persona_feature_level: str,
     category_mapping: Dict = None,
     model_name: str = None
 ) -> Dict:
@@ -44,6 +99,7 @@ async def match_single_pair(
     Args:
         feature_name: 要匹配的特征名称
         persona_name: 人设特征名称
+        persona_feature_level: 人设特征层级(灵感点/关键点/目的点)
         category_mapping: 特征分类映射字典
         model_name: 使用的模型名称
 
@@ -51,6 +107,7 @@ async def match_single_pair(
         单个匹配结果,格式:
         {
             "人设特征名称": "xxx",
+            "人设特征层级": "灵感点",
             "特征类型": "标签",
             "特征分类": ["分类1", "分类2"],
             "匹配结果": {
@@ -59,14 +116,18 @@ async def match_single_pair(
             }
         }
     """
+    global progress_tracker
     sem = get_semaphore()
     async with sem:
-        print(f"      匹配: {feature_name} <-> {persona_name}")
         similarity_result = await compare_phrases(
             phrase_a=feature_name,
             phrase_b=persona_name,
         )
 
+        # 更新进度
+        if progress_tracker:
+            progress_tracker.update(1)
+
         # 判断该特征是标签还是分类
         feature_type = "分类"  # 默认为分类
         categories = []
@@ -104,6 +165,7 @@ async def match_single_pair(
 
         return {
             "人设特征名称": persona_name,
+            "人设特征层级": persona_feature_level,
             "特征类型": feature_type,
             "特征分类": unique_categories,
             "匹配结果": similarity_result
@@ -121,7 +183,7 @@ async def match_feature_with_persona(
 
     Args:
         feature_name: 要匹配的特征名称
-        persona_features: 人设特征列表
+        persona_features: 人设特征列表(包含"特征名称"和"人设特征层级")
         category_mapping: 特征分类映射字典
         model_name: 使用的模型名称
 
@@ -130,7 +192,13 @@ async def match_feature_with_persona(
     """
     # 创建所有匹配任务
     tasks = [
-        match_single_pair(feature_name, persona_feature["特征名称"], category_mapping, model_name)
+        match_single_pair(
+            feature_name,
+            persona_feature["特征名称"],
+            persona_feature["人设特征层级"],
+            category_mapping,
+            model_name
+        )
         for persona_feature in persona_features
     ]
 
@@ -161,7 +229,6 @@ async def match_single_feature(
     feature_name = feature_item.get("特征名称", "")
     feature_weight = feature_item.get("权重", 1.0)
 
-    print(f"    特征: {feature_name} (权重: {feature_weight})")
     match_results = await match_feature_with_persona(
         feature_name=feature_name,
         persona_features=persona_features,
@@ -176,29 +243,28 @@ async def match_single_feature(
     }
 
 
-async def process_single_inspiration_point(
-    inspiration_point: Dict,
+async def process_single_point(
+    point: Dict,
+    point_type: str,
     persona_features: List[Dict],
     category_mapping: Dict = None,
     model_name: str = None
 ) -> Dict:
     """
-    处理单个灵感点的特征匹配(并发执行)
+    处理单个点(灵感点/关键点/目的点)的特征匹配(并发执行)
 
     Args:
-        inspiration_point: 灵感点数据
-        persona_features: 人设灵感特征列表
+        point: 点数据(灵感点/关键点/目的点)
+        point_type: 点类型("灵感点"/"关键点"/"目的点")
+        persona_features: 人设特征列表
         category_mapping: 特征分类映射字典
         model_name: 使用的模型名称
 
     Returns:
-        包含 how 步骤列表的灵感点数据
+        包含 how 步骤列表的点数据
     """
-    point_name = inspiration_point.get("名称", "")
-    feature_list = inspiration_point.get("特征列表", [])
-
-    print(f"  处理灵感点: {point_name}")
-    print(f"    特征数量: {len(feature_list)}")
+    point_name = point.get("名称", "")
+    feature_list = point.get("特征列表", [])
 
     # 并发匹配所有特征
     tasks = [
@@ -207,14 +273,20 @@ async def process_single_inspiration_point(
     ]
     feature_match_results = await asyncio.gather(*tasks)
 
-    # 构建 how 步骤
+    # 构建 how 步骤(根据点类型生成步骤名称)
+    step_name_mapping = {
+        "灵感点": "灵感特征分别匹配人设特征",
+        "关键点": "关键特征分别匹配人设特征",
+        "目的点": "目的特征分别匹配人设特征"
+    }
+
     how_step = {
-        "步骤名称": "灵感特征分别匹配人设特征",
+        "步骤名称": step_name_mapping.get(point_type, f"{point_type}特征分别匹配人设特征"),
         "特征列表": list(feature_match_results)
     }
 
-    # 返回更新后的灵感点
-    result = inspiration_point.copy()
+    # 返回更新后的点
+    result = point.copy()
     result["how步骤列表"] = [how_step]
 
     return result
@@ -224,7 +296,7 @@ async def process_single_task(
     task: Dict,
     task_index: int,
     total_tasks: int,
-    persona_inspiration_features: List[Dict],
+    all_persona_features: List[Dict],
     category_mapping: Dict = None,
     model_name: str = None
 ) -> Dict:
@@ -235,7 +307,7 @@ async def process_single_task(
         task: 任务数据
         task_index: 任务索引(从1开始)
         total_tasks: 总任务数
-        persona_inspiration_features: 人设灵感特征列表
+        all_persona_features: 所有人设特征列表(包含三种层级)
         category_mapping: 特征分类映射字典
         model_name: 使用的模型名称
 
@@ -243,30 +315,35 @@ async def process_single_task(
         包含 how 解构结果的任务
     """
     post_id = task.get("帖子id", "")
-    print(f"\n处理任务 [{task_index}/{total_tasks}]: {post_id}")
+    print(f"\n[{task_index}/{total_tasks}] 处理帖子: {post_id}")
 
-    # 获取灵感点列表
+    # 获取 what 解构结果
     what_result = task.get("what解构结果", {})
-    inspiration_list = what_result.get("灵感点列表", [])
-
-    print(f"  灵感点数量: {len(inspiration_list)}")
-
-    # 并发处理所有灵感点
-    tasks = [
-        process_single_inspiration_point(
-            inspiration_point=inspiration_point,
-            persona_features=persona_inspiration_features,
-            category_mapping=category_mapping,
-            model_name=model_name
-        )
-        for inspiration_point in inspiration_list
-    ]
-    updated_inspiration_list = await asyncio.gather(*tasks)
 
     # 构建 how 解构结果
-    how_result = {
-        "灵感点列表": list(updated_inspiration_list)
-    }
+    how_result = {}
+
+    # 处理灵感点、关键点和目的点
+    for point_type in ["灵感点", "关键点", "目的点"]:
+        point_list_key = f"{point_type}列表"
+        point_list = what_result.get(point_list_key, [])
+
+        if point_list:
+            # 并发处理所有点
+            tasks = [
+                process_single_point(
+                    point=point,
+                    point_type=point_type,
+                    persona_features=all_persona_features,
+                    category_mapping=category_mapping,
+                    model_name=model_name
+                )
+                for point in point_list
+            ]
+            updated_point_list = await asyncio.gather(*tasks)
+
+            # 添加到 how 解构结果
+            how_result[point_list_key] = list(updated_point_list)
 
     # 更新任务
     updated_task = task.copy()
@@ -293,27 +370,57 @@ async def process_task_list(
     Returns:
         包含 how 解构结果的任务列表
     """
-    # 获取标签特征列表
-    persona_inspiration_features = persona_features_dict.get("灵感点", [])
-    print(f"人设标签特征数量: {len(persona_inspiration_features)}")
-
-    # 从分类映射中提取所有唯一的分类作为分类特征(仅从灵感点中提取)
-    category_features = []
-    if category_mapping:
-        all_categories = set()
-        # 只从灵感点中提取分类
-        if "灵感点" in category_mapping:
-            for _, feature_data in category_mapping["灵感点"].items():
+    global progress_tracker
+
+    # 合并三种人设特征(灵感点、关键点、目的点)
+    all_features = []
+
+    for feature_type in ["灵感点", "关键点", "目的点"]:
+        # 获取该类型的标签特征
+        type_features = persona_features_dict.get(feature_type, [])
+
+        # 为每个特征添加层级信息
+        for feature in type_features:
+            feature_with_level = feature.copy()
+            feature_with_level["人设特征层级"] = feature_type
+            all_features.append(feature_with_level)
+
+        print(f"人设{feature_type}标签特征数量: {len(type_features)}")
+
+        # 从分类映射中提取该类型的分类特征
+        if category_mapping and feature_type in category_mapping:
+            type_categories = set()
+            for _, feature_data in category_mapping[feature_type].items():
                 categories = feature_data.get("所属分类", [])
-                all_categories.update(categories)
+                type_categories.update(categories)
+
+            # 转换为特征格式并添加层级信息
+            for cat in sorted(type_categories):
+                all_features.append({
+                    "特征名称": cat,
+                    "人设特征层级": feature_type
+                })
+
+            print(f"人设{feature_type}分类特征数量: {len(type_categories)}")
 
-        # 转换为特征格式
-        category_features = [{"特征名称": cat} for cat in sorted(all_categories)]
-        print(f"人设分类特征数量: {len(category_features)}")
+    print(f"总特征数量(三种类型的标签+分类): {len(all_features)}")
 
-    # 合并标签特征和分类特征
-    all_features = persona_inspiration_features + category_features
-    print(f"总特征数量(标签+分类): {len(all_features)}")
+    # 计算总匹配任务数(灵感点、关键点和目的点)
+    total_match_count = 0
+    for task in task_list:
+        what_result = task.get("what解构结果", {})
+        for point_type in ["灵感点", "关键点", "目的点"]:
+            point_list = what_result.get(f"{point_type}列表", [])
+            for point in point_list:
+                feature_count = len(point.get("特征列表", []))
+                total_match_count += feature_count * len(all_features)
+
+    print(f"处理灵感点、关键点和目的点特征")
+    print(f"总匹配任务数: {total_match_count:,}")
+    print()
+
+    # 初始化全局进度跟踪器
+    progress_tracker = ProgressTracker(total_match_count)
 
     # 并发处理所有任务
     tasks = [
@@ -321,7 +428,7 @@ async def process_task_list(
             task=task,
             task_index=i,
             total_tasks=len(task_list),
-            persona_inspiration_features=all_features,
+            all_persona_features=all_features,
             category_mapping=category_mapping,
             model_name=model_name
         )
@@ -384,19 +491,42 @@ async def main():
     print("\n完成!")
 
     # 打印统计信息
-    total_inspiration_points = sum(
-        len(task["how解构结果"]["灵感点列表"])
-        for task in updated_task_list
-    )
-    total_features = sum(
-        len(point["特征列表"])
-        for task in updated_task_list
-        for point in task["how解构结果"]["灵感点列表"]
-    )
+    total_inspiration_points = 0
+    total_key_points = 0
+    total_purpose_points = 0
+    total_inspiration_features = 0
+    total_key_features = 0
+    total_purpose_features = 0
+
+    for task in updated_task_list:
+        how_result = task.get("how解构结果", {})
+
+        # 统计灵感点
+        inspiration_list = how_result.get("灵感点列表", [])
+        total_inspiration_points += len(inspiration_list)
+        for point in inspiration_list:
+            total_inspiration_features += len(point.get("特征列表", []))
+
+        # 统计关键点
+        key_list = how_result.get("关键点列表", [])
+        total_key_points += len(key_list)
+        for point in key_list:
+            total_key_features += len(point.get("特征列表", []))
+
+        # 统计目的点
+        purpose_list = how_result.get("目的点列表", [])
+        total_purpose_points += len(purpose_list)
+        for point in purpose_list:
+            total_purpose_features += len(point.get("特征列表", []))
+
     print(f"\n统计:")
     print(f"  处理的帖子数: {len(updated_task_list)}")
     print(f"  处理的灵感点数: {total_inspiration_points}")
-    print(f"  处理的特征数: {total_features}")
+    print(f"  处理的灵感点特征数: {total_inspiration_features}")
+    print(f"  处理的关键点数: {total_key_points}")
+    print(f"  处理的关键点特征数: {total_key_features}")
+    print(f"  处理的目的点数: {total_purpose_points}")
+    print(f"  处理的目的点特征数: {total_purpose_features}")
 
 
 if __name__ == "__main__":

+ 53 - 0
test_model_cache.py

@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+"""
+测试模型缓存机制
+"""
+from lib.text_embedding import compare_phrases
+
+print("=" * 60)
+print("测试模型缓存机制")
+print("=" * 60)
+print()
+
+# 第一次调用 - 会加载模型
+print("第一次调用 compare_phrases(会加载模型):")
+result1 = compare_phrases("深度学习", "神经网络")
+print(f"相似度: {result1['相似度']:.3f}")
+print()
+
+# 第二次调用 - 不会加载模型(使用缓存)
+print("第二次调用 compare_phrases(使用缓存,不会重新加载):")
+result2 = compare_phrases("机器学习", "人工智能")
+print(f"相似度: {result2['相似度']:.3f}")
+print()
+
+# 第三次调用 - 不会加载模型(使用缓存)
+print("第三次调用 compare_phrases(使用缓存,不会重新加载):")
+result3 = compare_phrases("Python", "Java")
+print(f"相似度: {result3['相似度']:.3f}")
+print()
+
+# 切换到多语言模型 - 第一次会加载
+print("切换到多语言模型(第一次会加载):")
+result4 = compare_phrases("Hello", "Hi", model_name="multilingual")
+print(f"相似度: {result4['相似度']:.3f}")
+print()
+
+# 再次使用多语言模型 - 不会加载(使用缓存)
+print("再次使用多语言模型(使用缓存,不会重新加载):")
+result5 = compare_phrases("Good", "Great", model_name="multilingual")
+print(f"相似度: {result5['相似度']:.3f}")
+print()
+
+# 切换回中文模型 - 不会加载(之前已加载)
+print("切换回中文模型(使用缓存,不会重新加载):")
+result6 = compare_phrases("编程", "开发")
+print(f"相似度: {result6['相似度']:.3f}")
+print()
+
+print("=" * 60)
+print("总结:")
+print("  - 每个模型只在第一次使用时加载一次")
+print("  - 后续调用直接使用缓存的模型")
+print("  - 可以自由切换不同模型,已加载的模型会保留在内存中")
+print("=" * 60)