432 lines
13 KiB
Markdown
432 lines
13 KiB
Markdown
# RDAIReaderView 架构设计
|
||
|
||
**文档状态:** Draft 0.1
|
||
**最后更新:** 2026-07-25
|
||
**目标版本:** RDAIReaderView 1.0
|
||
|
||
## 1. 架构目标
|
||
|
||
RDAIReaderView 必须满足四个架构目标:
|
||
|
||
1. 不改变 RDPDFReaderView、RDEpubReaderView 和 RDSpeechReaderView 的核心职责。
|
||
2. iOS 15 用户继续获得稳定阅读、基础 NLP 和 TTS;Foundation Models 仅作为可选增强。
|
||
3. 所有生成结果都能追溯到稳定原文位置。
|
||
4. AI Provider、索引实现和 UI 可替换,公共数据模型保持稳定。
|
||
|
||
## 2. 总体分层
|
||
|
||
```text
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ Host App / RDAIReaderViewUI │
|
||
│ AI 面板、摘要、问答、人物卡片、关系图、引用跳转 │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ RDAIReaderView │
|
||
│ Query Service / Summary Service / Character Service │
|
||
├───────────────────────┬─────────────────────────────────────┤
|
||
│ NaturalLanguage │ FoundationModels │
|
||
│ 分句/语言/实体/检索 │ 结构化生成/工具调用/拒答 │
|
||
├───────────────────────┴─────────────────────────────────────┤
|
||
│ Index & Storage │
|
||
│ Passage / EntityMention / Citation / Artifact / Job │
|
||
├───────────────────────┬─────────────────────────────────────┤
|
||
│ RDPDFReaderView/AI │ RDEpubReaderView/AI │
|
||
│ 页码/范围/矩形/OCR │ href/CFI/范围/章节 │
|
||
├───────────────────────┴─────────────────────────────────────┤
|
||
│ RDPDFReaderView / RDEpubReaderView / RDSpeechReaderView │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
依赖方向只能从上到下。阅读器核心不能反向依赖 RDAIReaderView。
|
||
|
||
## 3. CocoaPods 模块设计
|
||
|
||
建议新增:
|
||
|
||
```ruby
|
||
pod 'RDAIReaderView/Core'
|
||
pod 'RDAIReaderView/NaturalLanguage'
|
||
pod 'RDAIReaderView/FoundationModels'
|
||
pod 'RDAIReaderView/UI'
|
||
pod 'RDPDFReaderView/AI'
|
||
pod 'RDEpubReaderView/AI'
|
||
```
|
||
|
||
### 3.1 Core
|
||
|
||
- 最低 iOS 15。
|
||
- 只依赖 Foundation、SQLite3/CryptoKit 等系统能力。
|
||
- 包含公共协议、数据模型、索引调度、存储和查询编排。
|
||
- 不导入 UIKit、PDFKit、DTCoreText 或 FoundationModels。
|
||
|
||
### 3.2 NaturalLanguage
|
||
|
||
- 最低 iOS 15。
|
||
- 依赖 Core 和 NaturalLanguage。
|
||
- 提供语言识别、分句、实体候选、关键词和语义评分。
|
||
- iOS 17+ 可选使用 `NLContextualEmbedding`;资源不可用时降级。
|
||
|
||
### 3.3 FoundationModels
|
||
|
||
- 源码使用 `@available(iOS 26.0, *)` 隔离。
|
||
- 依赖 Core 和系统 FoundationModels。
|
||
- 需要支持 Foundation Models 的 Xcode 工具链。
|
||
- 不被基础 Pod 默认引入,避免旧工具链客户无法编译。
|
||
|
||
### 3.4 UI
|
||
|
||
- 最低 iOS 15。
|
||
- 依赖 Core,可选识别 FoundationModels 可用性。
|
||
- UI 不直接构造 Prompt,也不直接访问数据库。
|
||
|
||
### 3.5 Reader Adapters
|
||
|
||
- `RDPDFReaderView/AI` 依赖 RDAIReaderView/Core。
|
||
- `RDEpubReaderView/AI` 依赖 RDAIReaderView/Core。
|
||
- Adapter 只负责内容快照、定位转换、跳转和高亮。
|
||
|
||
## 4. 建议目录
|
||
|
||
```text
|
||
Sources/RDAIReaderView/
|
||
├── RDAIReaderView.podspec
|
||
├── Core/
|
||
│ ├── Contracts/
|
||
│ ├── Models/
|
||
│ ├── Indexing/
|
||
│ ├── Retrieval/
|
||
│ ├── Storage/
|
||
│ └── Services/
|
||
├── NaturalLanguage/
|
||
│ ├── Analysis/
|
||
│ ├── Embeddings/
|
||
│ └── Retrieval/
|
||
├── FoundationModels/
|
||
│ ├── Availability/
|
||
│ ├── Generation/
|
||
│ ├── Prompts/
|
||
│ ├── Schemas/
|
||
│ └── Tools/
|
||
├── UI/
|
||
│ ├── Assistant/
|
||
│ ├── Citations/
|
||
│ └── Characters/
|
||
└── Tests/
|
||
|
||
Sources/RDPDFReaderView/AI/
|
||
Sources/RDEpubReaderView/AI/
|
||
```
|
||
|
||
## 5. 核心数据流
|
||
|
||
### 5.1 建立索引
|
||
|
||
```text
|
||
ContentProvider
|
||
↓ 读取资源快照
|
||
Text Snapshot + Stable Locator
|
||
↓
|
||
Language Detection
|
||
↓
|
||
Paragraph/Sentence Chunking
|
||
↓
|
||
Entity Mentions + Keywords + Embeddings
|
||
↓
|
||
Transactional Storage
|
||
↓
|
||
Index Checkpoint
|
||
```
|
||
|
||
每次数据库事务只提交一个资源或一组有界片段。应用退出时,最多重做当前事务,不重做整本书。
|
||
|
||
### 5.2 问答
|
||
|
||
```text
|
||
User Question
|
||
↓
|
||
Language / Intent / Spoiler Scope
|
||
↓
|
||
Hybrid Retrieval
|
||
↓
|
||
Access + Read-Progress Filter
|
||
↓
|
||
Context Budget Builder
|
||
↓
|
||
Foundation Models Structured Generation
|
||
↓
|
||
Citation Validator
|
||
↓
|
||
Answer or Evidence-Insufficient Refusal
|
||
```
|
||
|
||
检索由代码执行。首版不让模型自由遍历整本数据库,只有需要多轮查找时才使用受限 Tool Calling。
|
||
|
||
### 5.3 人物关系
|
||
|
||
```text
|
||
Entity Mentions
|
||
↓
|
||
Alias Candidate Grouping
|
||
↓
|
||
Chunk-level Structured Extraction
|
||
↓
|
||
Evidence Validation
|
||
↓
|
||
Relationship Merge
|
||
↓
|
||
confirmed / possible / conflicting
|
||
```
|
||
|
||
代码只能自动合并完全相同的标准化名称和明确别名。代词消解、同名人物合并和隐含关系必须保持低置信度,等待更多证据或用户确认。
|
||
|
||
## 6. 稳定定位模型
|
||
|
||
### 6.1 通用定位
|
||
|
||
`RDAILocator` 包含:
|
||
|
||
- `documentIdentifier`
|
||
- `resourceIdentifier`
|
||
- `utf16Range`
|
||
- `sourceHash`
|
||
- 格式专属 Anchor
|
||
|
||
文本范围统一使用 UTF-16,与现有 RDSpeechReaderView、NSString 和 EPUB 搜索范围保持一致。
|
||
|
||
### 6.2 PDF Anchor
|
||
|
||
```text
|
||
pageIndex
|
||
normalizedRects
|
||
textSource: native / ocr
|
||
readingOrder
|
||
```
|
||
|
||
PDF Adapter 从现有 `RDPDFReaderTextRun` 构建连续页文本和 UTF-16 范围。每个 Passage 必须保留与 run 的映射,不能在 AI 层重新拼接后丢失矩形。
|
||
|
||
扫描 PDF 使用现有 `speechTextRuns(at:)`/OCR 能力,但商用实现应增加独立的 AI OCR 调度入口,避免页面导航取消请求时同时取消后台索引。
|
||
|
||
### 6.3 EPUB Anchor
|
||
|
||
```text
|
||
normalizedHref
|
||
cfi
|
||
rangeCFI
|
||
rangeAnchor
|
||
progressionFallback
|
||
```
|
||
|
||
优先级:
|
||
|
||
1. `rangeCFI`
|
||
2. `cfi + UTF-16 range`
|
||
3. `rangeAnchor`
|
||
4. `href + progression`
|
||
|
||
屏幕页码只用于展示,不能作为持久化引用主键。
|
||
|
||
## 7. 文本快照与分块
|
||
|
||
### 7.1 不修改原文
|
||
|
||
索引保存两份文本信息:
|
||
|
||
- `sourceText`:原始文本,用于引用与范围映射。
|
||
- `searchText`:规范化副本,用于检索。
|
||
|
||
禁止使用规范化文本范围直接驱动阅读器高亮。
|
||
|
||
### 7.2 分块策略
|
||
|
||
- 先按资源和章节边界划分。
|
||
- 再按段落划分。
|
||
- 超长段落使用 `NLTokenizer(unit: .sentence)`。
|
||
- 中文目标 600-900 字;英文目标 300-600 词。
|
||
- 片段之间保留 1-2 句重叠。
|
||
- 表格、代码、脚注和标题保留语义类型,避免与正文无差别拼接。
|
||
|
||
### 7.3 内容哈希
|
||
|
||
建议使用 SHA-256:
|
||
|
||
```text
|
||
documentHash = hash(ordered resource identifiers + resource hashes)
|
||
resourceHash = hash(source text + format-specific stable metadata)
|
||
passageHash = hash(resource hash + UTF-16 range + source text)
|
||
```
|
||
|
||
书籍更新时按资源哈希增量失效。
|
||
|
||
## 8. 检索架构
|
||
|
||
首版采用 Hybrid Retrieval:
|
||
|
||
```text
|
||
finalScore =
|
||
0.45 * lexicalScore +
|
||
0.40 * semanticScore +
|
||
0.10 * proximityScore +
|
||
0.05 * headingBoost
|
||
```
|
||
|
||
权重是初始值,必须通过评测集调优,不作为永久常量。
|
||
|
||
检索步骤:
|
||
|
||
1. 规范化查询并识别语言。
|
||
2. 关键词倒排召回 Top 30。
|
||
3. 语义相似度重排。
|
||
4. 合并高度重叠 Passage。
|
||
5. 按已读范围、文档授权和最大上下文过滤。
|
||
6. 返回 Top 3-4,并保留评分解释。
|
||
|
||
若语义模型资源不可用,使用纯词法检索,不阻塞问答入口;UI 可提示结果质量可能降低。
|
||
|
||
## 9. Foundation Models 编排
|
||
|
||
### 9.1 Provider 抽象
|
||
|
||
Core 只依赖 `RDAIGenerativeProvider`。Apple 实现位于 FoundationModels 子模块,未来可增加 Core ML、MLX 或经用户授权的云端实现。
|
||
|
||
### 9.2 会话策略
|
||
|
||
- 摘要、问答、人物关系使用不同 instructions 和独立会话。
|
||
- 同一会话只处理一个并发请求。
|
||
- 用户切换书籍、变更阅读范围或取消时终止任务。
|
||
- 达到上下文阈值前主动新建会话,不等待系统抛错。
|
||
- 记录 Prompt 版本、模型可用性分类、耗时和 token 数,不记录原文。
|
||
|
||
### 9.3 上下文预算
|
||
|
||
默认预算建议:
|
||
|
||
| 项目 | Token 预算 |
|
||
|------|------------|
|
||
| Instructions + Schema | 500 |
|
||
| 用户问题 | 200 |
|
||
| 检索上下文 | 2400 |
|
||
| 模型输出 | 700 |
|
||
| 安全余量 | 296 |
|
||
|
||
实际使用 `contextSize` 和 `tokenCount(for:)` 动态计算,不写死为 4096。
|
||
|
||
### 9.4 引用验证
|
||
|
||
生成后执行确定性校验:
|
||
|
||
1. Citation ID 必须存在于本次上下文。
|
||
2. Citation 必须属于当前文档和允许阅读范围。
|
||
3. 引用文本必须能在 Passage 原文中匹配。
|
||
4. 每个事实项至少有一个有效引用。
|
||
5. 删除无效项后答案为空,则返回 evidence insufficient。
|
||
|
||
## 10. 存储设计
|
||
|
||
建议使用 SQLite,Schema 初稿:
|
||
|
||
```text
|
||
documents
|
||
resources
|
||
passages
|
||
passage_fts
|
||
embeddings
|
||
entity_mentions
|
||
entities
|
||
entity_aliases
|
||
relationships
|
||
relationship_evidence
|
||
artifacts
|
||
index_jobs
|
||
schema_metadata
|
||
```
|
||
|
||
关键原则:
|
||
|
||
- FTS 和关系表通过 Passage ID 关联原文。
|
||
- 向量数据按模型标识符、revision 和语言分区。
|
||
- 生成结果不覆盖人工编辑内容。
|
||
- 每个 Artifact 保存 Prompt/模型/输入哈希。
|
||
- 索引表支持按文档级联删除。
|
||
|
||
## 11. 并发与生命周期
|
||
|
||
建议采用 Swift Concurrency:
|
||
|
||
- `RDAIIndexCoordinator`:actor,管理索引队列和 checkpoint。
|
||
- `RDAIStore`:actor,串行化数据库写入。
|
||
- `RDAIRetriever`:Sendable 服务,可并发读取快照。
|
||
- Reader Adapter:`@MainActor`,仅提取 UI/阅读器状态和执行跳转。
|
||
- Foundation Models Session:由单请求 actor 或服务隔离。
|
||
|
||
优先级:
|
||
|
||
1. 用户当前问答所需 Passage。
|
||
2. 当前章节。
|
||
3. 相邻章节。
|
||
4. 已读范围。
|
||
5. 其余获准内容。
|
||
|
||
发生内存警告时:
|
||
|
||
- 取消低优先级 embedding 任务。
|
||
- 卸载 contextual embedding。
|
||
- 清理内存 Passage/向量缓存。
|
||
- 保留已提交数据库和当前用户请求。
|
||
|
||
## 12. 可用性与降级
|
||
|
||
```text
|
||
Foundation Models available
|
||
├─ 是 → 完整生成能力
|
||
└─ 否
|
||
├─ Natural Language available → 索引、实体、基础检索
|
||
└─ 语言/资源不支持 → 关键词检索与基础分段
|
||
```
|
||
|
||
降级状态是公共 API 的一部分,UI 不根据 Error 字符串猜测原因。
|
||
|
||
## 13. 安全与隐私
|
||
|
||
- 默认 Provider 为设备端 Provider。
|
||
- Core 不包含网络代码。
|
||
- 云端 Provider 若未来增加,必须是单独 Pod,并要求宿主显式配置。
|
||
- 日志只记录文档匿名哈希、阶段、耗时、错误类别和计数。
|
||
- 禁止记录 Prompt、Passage、用户问题和模型回答全文。
|
||
- 导出诊断包前再次脱敏。
|
||
- 删除书籍时由宿主调用 `removeDocument`,同时删除索引、关系和生成缓存。
|
||
|
||
## 14. 可观测性
|
||
|
||
本地指标:
|
||
|
||
- 索引耗时、资源数、片段数、失败类别。
|
||
- 检索 P50/P95、召回数量和降级模式。
|
||
- 生成耗时、取消率、错误类别和引用校验失败率。
|
||
- Foundation Models availability 分布。
|
||
- 缓存命中率和数据库大小。
|
||
|
||
商用版本默认只汇总数值。任何远程遥测必须由宿主决定,并遵守其隐私政策。
|
||
|
||
## 15. 架构决策记录
|
||
|
||
实施时至少补充以下 ADR:
|
||
|
||
- ADR-001:独立 RDAIReaderView 而非嵌入阅读器核心。
|
||
- ADR-002:UTF-16 作为跨模块文本范围。
|
||
- ADR-003:本地 SQLite 和增量资源哈希。
|
||
- ADR-004:检索先行、生成后置、引用强校验。
|
||
- ADR-005:Foundation Models 可选依赖和运行时降级。
|
||
- ADR-006:已读范围作为默认安全边界。
|
||
|
||
## 16. 已知技术风险
|
||
|
||
| 风险 | 影响 | 缓解 |
|
||
|------|------|------|
|
||
| 中文小说实体识别不足 | 人物漏识别或误合并 | 规则候选 + 结构化模型提取 + 证据与置信度 |
|
||
| OCR 阅读顺序错误 | 摘要和引用错误 | 保留 readingOrder、双栏测试、允许宿主提供文本 |
|
||
| PDF OCR 请求被页面导航取消 | 后台索引不完整 | AI 使用独立调度队列与缓存 |
|
||
| EPUB 重排后范围变化 | 引用跳转漂移 | CFI/rangeCFI 优先,文本哈希校验 |
|
||
| 系统模型更新 | Prompt 质量回归 | Prompt 版本化、模型版本分层评测 |
|
||
| 上下文不足 | 回答遗漏 | 检索压缩、分层摘要、新会话 |
|
||
| 同名人物 | 错误关系合并 | 不自动合并低置信候选,保留冲突 |
|
||
|