This commit is contained in:
2026-01-13 23:02:07 +08:00
parent a1e42127e6
commit 804baa64b2
71 changed files with 658 additions and 925 deletions

View File

@@ -0,0 +1,206 @@
# 词典查询模块化架构
本目录包含词典查询系统的**多阶段 LLM 调用**实现,将查询过程拆分为 4 个独立的 LLM 调用,每个阶段之间有代码层面的数据验证,只要有一环失败,直接返回错误。
## 目录结构
```
dictionary/
├── index.ts # 主导出文件
├── orchestrator.ts # 主编排器,串联所有阶段
├── types.ts # 类型定义
├── stage1-inputAnalysis.ts # 阶段1输入解析与语言识别
├── stage2-semanticMapping.ts # 阶段2跨语言语义映射决策
├── stage3-standardForm.ts # 阶段3standardForm 生成与规范化
└── stage4-entriesGeneration.ts # 阶段4释义与词条生成
```
## 工作流程
```
用户输入
[阶段1] 输入分析 → 代码验证 → 失败则返回错误
[阶段2] 语义映射 → 代码验证 → 失败则保守处理(不映射)
[阶段3] 标准形式 → 代码验证 → 失败则返回错误
[阶段4] 词条生成 → 代码验证 → 失败则返回错误
最终结果
```
## 各阶段详细说明
### 阶段 1输入分析
**文件**: `stage1-inputAnalysis.ts`
**目的**:
- 判断输入是否有效
- 判断是「单词」还是「短语」
- 识别输入语言
**返回**: `InputAnalysisResult`
**代码验证**:
- `isValid` 必须是 boolean
- 输入为空或无效时立即返回错误
### 阶段 2语义映射
**文件**: `stage2-semanticMapping.ts`
**目的**:
- 决定是否启用"语义级查询"
- **严格条件**:只有输入符合"明确、基础、可词典化的语义概念"且语言不一致时才映射
- 不符合条件则**直接失败**(快速失败)
**返回**: `SemanticMappingResult`
**代码验证**:
- `shouldMap` 必须是 boolean
- 如果 `shouldMap=true`,必须有 `mappedQuery`
- 如果不应该映射,**抛出异常**(不符合条件直接失败)
- **失败则直接返回错误响应**,不继续后续阶段
**映射条件**(必须同时满足):
a) 输入语言 ≠ 查询语言
b) 输入是明确、基础、可词典化的语义概念(如常见动词、名词、形容词)
**不符合条件的例子**
- 复杂句子:"我喜欢吃苹果"
- 专业术语
- 无法确定语义的词汇
### 阶段 3标准形式生成
**文件**: `stage3-standardForm.ts`
**目的**:
- 确定最终词条的"标准形"(整个系统的锚点)
- 修正拼写错误
- 还原为词典形式(动词原形、辞书形等)
- **如果进行了语义映射**:基于映射结果生成标准形式,同时参考原始输入的语义上下文
**参数**:
- `inputText`: 用于生成标准形式的文本(可能是映射后的结果)
- `queryLang`: 查询语言
- `originalInput`: (可选)原始用户输入,用于语义参考
**返回**: `StandardFormResult`
**代码验证**:
- `standardForm` 不能为空
- `confidence` 必须是 "high" | "medium" | "low"
- 失败时使用原输入作为标准形式
**特殊逻辑**:
- 当进行了语义映射时(即提供了 `originalInput`),阶段 3 会:
1. 基于 `inputText`(映射结果)生成标准形式
2. 参考 `originalInput` 的语义上下文,确保标准形式符合用户的真实查询意图
3. 例如:原始输入 "吃"(中文)→ 映射为 "to eat"(英语)→ 标准形式 "eat"
### 阶段 4词条生成
**文件**: `stage4-entriesGeneration.ts`
**目的**:
- 生成真正的词典内容
- 根据类型生成单词或短语条目
**返回**: `EntriesGenerationResult`
**代码验证**:
- `entries` 必须是非空数组
- 每个条目必须有 `definition``example`
- 单词条目必须有 `partOfSpeech`
- **失败则抛出异常**(核心阶段)
## 使用方式
### 基本使用
```typescript
import { lookUp } from "@/lib/server/bigmodel/dictionaryActions";
const result = await lookUp({
text: "hello",
queryLang: "English",
definitionLang: "中文"
});
```
### 高级使用(直接调用编排器)
```typescript
import { executeDictionaryLookup } from "@/lib/server/bigmodel/dictionary";
const result = await executeDictionaryLookup(
"hello",
"English",
"中文"
);
```
### 单独测试某个阶段
```typescript
import { analyzeInput } from "@/lib/server/bigmodel/dictionary";
const analysis = await analyzeInput("hello");
console.log(analysis);
```
## 设计优势
### 1. 代码层面的数据验证
每个阶段完成后都有严格的类型检查和数据验证,确保数据质量。
### 2. 快速失败
只要有一个阶段失败,立即返回错误,不浪费后续的 LLM 调用。
### 3. 可观测性
每个阶段都有 console.log 输出,方便调试和追踪问题。
### 4. 模块化
每个阶段独立文件,可以单独测试、修改或替换。
### 5. 容错性
非核心阶段阶段2、3失败时有降级策略不会导致整个查询失败。
## 日志示例
```
[阶段1] 开始输入分析...
[阶段1] 输入分析完成: { isValid: true, inputType: 'word', inputLanguage: 'English' }
[阶段2] 开始语义映射...
[阶段2] 语义映射完成: { shouldMap: false }
[阶段3] 开始生成标准形式...
[阶段3] 标准形式生成完成: { standardForm: 'hello', confidence: 'high' }
[阶段4] 开始生成词条...
[阶段4] 词条生成完成: { entries: [...] }
[完成] 词典查询成功
```
## 扩展建议
### 添加缓存
对阶段1、3的结果进行缓存避免重复调用 LLM。
### 添加指标
记录每个阶段的耗时和成功率,用于性能优化。
### 并行化
某些阶段可以并行执行(如果有依赖关系允许的话)。
### A/B 测试
为某个阶段创建不同版本的实现,进行效果对比。
## 注意事项
- 每个阶段都是独立的 LLM 调用,会增加总耗时
- 需要控制 token 使用量,避免成本过高
- 错误处理要完善,避免某个阶段卡住整个流程
- 日志记录要清晰,方便问题排查