13 KiB
RDAIReaderView AI 系统设计合同
文档状态: Draft 0.1
最后更新: 2026-07-25
目标版本: RDAIReaderView 1.0
1. 系统分类
RDAIReaderView 是一个本地优先的 Retrieval-Augmented Generation 阅读系统,包含:
- 确定性 NLP:语言识别、分句、实体候选、词法检索。
- 本地语义检索:Natural Language embeddings。
- 生成式任务:摘要、书内问答、人物卡片和人物关系。
- 引用约束:生成内容必须映射到 PDF/EPUB 原文。
系统不是通用聊天机器人,也不把模型自身知识作为书籍事实来源。
2. 框架选择
2.1 主框架
- Apple Natural Language:iOS 15+ 基础分析和检索。
- Apple Foundation Models:支持设备上的生成式增强。
- Vision:扫描 PDF OCR,继续复用 RDPDFReaderView 现有能力。
2.2 选择理由
- 与当前纯 Swift/UIKit/CocoaPods 架构一致。
- 默认设备端处理,不需要新增服务端和书籍上传链路。
- Natural Language 可覆盖不支持 Apple Intelligence 的设备。
- Foundation Models 支持 structured generation 和 tool calling。
- 系统 API 可与现有 PDF/EPUB 定位直接结合。
2.3 未选择的首版方案
| 方案 | 首版不采用原因 |
|---|---|
| LangChain/LlamaIndex | 主要面向 Python/服务端,增加不必要基础设施 |
| 云端 LLM | 引入内容上传、成本、隐私、版权和网络可用性问题 |
| ONNX Runtime 自带模型 | 需要自行选择、量化、分发和维护语言模型 |
| 自训练 Foundation Models Adapter | 模型版本绑定和 entitlement 增加发布复杂度 |
Core 保留 RDAIGenerativeProvider,以后可以增加其他 Provider,不把 Apple 实现写死在公共业务层。
3. 模型可用性合同
调用 Foundation Models 前必须检查:
- API 在当前系统可用。
SystemLanguageModel.default.availability为 available。- 当前 Locale 被支持。
- 当前请求未超过并发限制。
- 当前任务的上下文预算可满足。
不可用原因映射:
| Apple 状态 | RDAI 状态 | UI 行为 |
|---|---|---|
| deviceNotEligible | .deviceNotEligible |
隐藏生成操作,保留基础分析 |
| appleIntelligenceNotEnabled | .appleIntelligenceNotEnabled |
说明可在系统设置中开启 |
| modelNotReady | .modelNotReady |
展示模型准备中,可稍后重试 |
| unsupported locale | .languageUnsupported |
保留检索,关闭生成 |
| unknown | .unknown |
通用不可用状态,允许重试 |
禁止通过静态设备型号列表推断可用性,运行时状态是唯一依据。
参考:
4. 输入与上下文策略
4.1 唯一事实来源
模型可以使用:
- 本次请求提供的 Passage。
- Passage 的章节标题、页码/资源信息。
- 用户当前问题。
- 非内容性规则,例如输出语言和防剧透范围。
模型不得把训练知识、其他书籍、互联网知识或先前书籍会话作为当前书籍事实来源。
4.2 上下文预算
运行时读取模型 contextSize,并使用 tokenCount(for:) 估算。
初始预算比例:
- 12%:instructions 和 schema。
- 5%:用户问题。
- 60%:检索 Passage。
- 17%:输出。
- 6%:安全余量。
若预算不足,按以下顺序处理:
- 删除低分 Passage。
- 缩短 Passage 到完整句子边界。
- 使用预计算的有引用片段摘要。
- 创建新会话。
- 仍不足则返回
contextLimitExceeded。
不得静默截断引用或生成半个结构化对象。
参考:Managing the context window
5. Prompt 资产管理
Prompt 作为版本化代码资产保存:
FoundationModels/Prompts/
├── summary_v1.swift
├── answer_v1.swift
├── characters_v1.swift
└── relationships_v1.swift
每个 Prompt 定义:
identifierversionminimumModelProfileinstructions- 输入构造器
- 输出 schema
- 评测集标签
修改 Prompt 必须:
- 增加版本号。
- 跑完整离线评测集。
- 与上一版本对比准确率、拒答、引用和延迟。
- 更新缓存失效策略。
6. 通用 Instructions
所有任务共享以下不可省略规则:
你是书内阅读助手。
只使用提供的原文片段,不使用外部知识补充书中事实。
每个事实性结论必须引用一个或多个有效片段 ID。
证据不足时返回 insufficientEvidence,不猜测。
不得引用允许阅读范围之外的内容。
区分原文明确事实与可能推断。
使用用户当前语言回答。
实际实现使用简洁英文或经评测验证的目标语言 instructions;以上文字表达语义合同,不要求逐字使用。
7. 结构化输出
7.1 摘要 Schema
@Generable
struct GeneratedSummary {
var overview: String
@Guide(.maximumCount(6))
var points: [GeneratedStatement]
}
@Generable
struct GeneratedStatement {
var text: String
@Guide(.minimumCount(1), .maximumCount(3))
var passageIDs: [String]
}
规则:
overview只能概括已提供 Passage。- 每个 point 必须有 Passage ID。
- brief 最多 3 点,standard 最多 6 点。
7.2 问答 Schema
@Generable
enum GeneratedAnswerStatus {
case answered
case insufficientEvidence
}
@Generable
struct GeneratedAnswer {
var status: GeneratedAnswerStatus
var answer: String
@Guide(.maximumCount(6))
var statements: [GeneratedStatement]
}
若 status == insufficientEvidence:
statements必须为空。answer只说明当前已读内容没有足够依据。- 不推荐用户从互联网获取答案,除非宿主未来明确增加该产品能力。
7.3 人物 Schema
@Generable
struct GeneratedCharacter {
var displayName: String
@Guide(.maximumCount(6))
var aliases: [String]
var description: String
@Guide(.minimumCount(1), .maximumCount(6))
var evidencePassageIDs: [String]
}
人物必须在 Passage 中有明确名称或可验证别名。纯代词不能单独创建人物。
7.4 关系 Schema
@Generable
enum GeneratedRelationshipStatus {
case confirmed
case possible
case conflicting
}
@Generable
struct GeneratedRelationship {
var sourceName: String
var targetName: String
var label: String
var status: GeneratedRelationshipStatus
@Guide(.minimumCount(1), .maximumCount(5))
var evidencePassageIDs: [String]
}
关系标签应简短,例如“师徒”“同事”“敌对”“亲属”。描述性事件放在人物事件中,不无限创建关系类型。
8. 任务设计
8.1 章节摘要
输入:
- 当前章节 Passage,或已读范围内的章节片段摘要。
- 目标长度。
- 用户 Locale。
流程:
- 章节能放入上下文时直接生成。
- 超长章节分块生成带引用局部摘要。
- 聚合局部摘要时保留原 Passage ID。
- 运行引用验证。
禁止只把局部摘要文本作为最终事实来源而丢失原始 Passage ID。
8.2 书内问答
流程:
- 识别问题语言和实体词。
- Hybrid Retrieval 召回 30 个候选。
- 重排并过滤到 3-4 个 Passage。
- 直接把 Passage 放入 Prompt。
- 生成结构化答案。
- 验证引用和阅读范围。
- 无有效事实项时拒答。
首版优先使用代码检索,不默认使用 Tool Calling,这样召回过程更确定、可测试、节省 token。
8.3 人物卡片
流程:
- Natural Language 提供人物候选及出现位置。
- 按名称和明确别名聚合候选。
- 检索候选周边 Passage。
- Foundation Models 生成结构化人物信息。
- 代码校验所有别名和证据。
- 低置信别名保持独立候选。
8.4 人物关系
采用两阶段:
- Chunk-level extraction:从局部 Passage 提取关系候选。
- Document-level merge:按人物 ID、关系标签和时间顺序合并。
合并规则:
- 相同关系 + 相同方向:合并证据。
- 对称关系可由受控词典决定是否双向展示。
- 新证据否定旧关系:状态变为 conflicting。
- 隐含动机、情感和立场默认 possible。
- 任何关系没有有效证据时不入库。
9. Tool Calling
仅在单次检索无法回答、且评测证明多轮查找有明显收益时启用。最多提供三个工具:
searchBook(query, scope, limit)
getPassages(ids)
getCharacterEvidence(name, scope, limit)
要求:
- 工具只读。
- 工具强制应用文档和已读范围过滤。
- 参数有严格长度和数量上限。
- 返回内容有 token 上限。
- 每个请求最大 Tool 调用次数为 3。
- 检测重复参数调用并终止循环。
- 工具调用和结果 ID进入本地 trace,但不记录原文。
不提供跳页、删除、购买、网络请求等副作用工具。
参考:Expanding generation with tool calling
10. 确定性后处理
模型输出必须经过:
- Schema 解码。
- Passage ID 存在性校验。
- 阅读范围校验。
- Quote/Locator 构造。
- 重复 statement 合并。
- 空文本和长度校验。
- 敏感内容与系统错误映射。
- Artifact 元数据补齐。
模型不能直接构造页码、CFI、CGRect 或数据库 ID;这些字段全部由代码通过 Passage ID解析。
11. 安全与产品规则
- 不将 AI 输出表示为作者原话。
- UI 明确标记“AI 生成”。
- possible/conflicting 关系必须视觉区分。
- 用户问题涉及未读内容时,默认拒绝并提示防剧透设置。
- 原文包含违法或敏感内容时,遵循系统模型 guardrails;不能绕过。
- 输入和输出触发系统安全限制时,返回稳定、非技术性的不可生成状态。
- 不要求模型提供医学、法律或金融建议;如果书中包含相关内容,只能解释“书中写了什么”。
发布前必须复核 Apple Foundation Models acceptable use requirements 和最新 App Review Guidelines。
12. 关键失败模式
| 失败模式 | 检测 | 处理 |
|---|---|---|
| 模型编造人物或关系 | Passage ID/名称验证 | 删除无效项,无结果则拒答 |
| 引用存在但不支持结论 | 人工评测 + LLM judge | Prompt 调整,低分结果进入回归集 |
| 同名人物合并 | 别名证据检查 | 保持独立,标记待确认 |
| 未读内容泄漏 | Scope validator | 阻断输出并记录安全计数 |
| OCR 错字导致错误事实 | OCR source 标记和置信策略 | 降低置信度,展示 OCR 来源 |
| Prompt 在系统更新后退化 | 模型版本分桶评测 | 版本化 Prompt 和缓存 |
| 上下文溢出 | tokenCount/contextSize | 重建上下文或分层摘要 |
| Tool 循环 | 调用次数和参数去重 | 终止并降级为现有证据回答 |
| 用户快速重复请求 | request actor + cancellation | 取消旧任务或排队 |
13. 评测维度
| 维度 | 定义 | 1.0 门槛 |
|---|---|---|
| Citation validity | 引用能否恢复到原文 | ≥ 99% |
| Context faithfulness | 事实是否由引用支持 | ≥ 98% |
| Refusal accuracy | 无证据时是否拒答 | ≥ 95% |
| Spoiler safety | 是否只使用允许范围 | 100% |
| Schema validity | 结构化输出是否通过校验 | ≥ 99.5% |
| Character precision | 人物是否真实出现 | ≥ 97% |
| Relationship evidence | 关系是否至少有一条证据 | 100% |
| Alias precision | 自动合并别名是否正确 | ≥ 98% |
| Retrieval recall@5 | 正确证据是否在 Top 5 | ≥ 90% |
| Answer usefulness | 人工 1-5 分平均值 | ≥ 4.0 |
14. 评测方法
- 代码指标:Schema、引用 ID、范围、阅读权限、延迟和拒答格式。
- 人工标注:人物、别名、关系、引用支持度、剧透边界。
- LLM judge:只用于语气、完整性和引用支持度的辅助评估;必须先与人工评分校准。
- 生产抽样:只上传宿主允许的匿名数值和用户显式反馈;不上传书籍原文。
评测集和完整方法见 RDAIReaderView-TEST-PLAN.md。
15. 发布检查清单
- 所有 Prompt 有 identifier 和 version。
- 每个生成任务使用
@Generable。 - 每个事实输出经过 Citation Validator。
- 防剧透 Scope 在检索前和生成后各检查一次。
- Foundation Models 不可用路径已真机验证。
- 上下文预算使用运行时 API 计算。
- 模型版本变化不会复用旧缓存。
- 评测集达到所有 1.0 门槛。
- 日志不包含原文、问题或完整回答。
- Apple 最新 acceptable use 与审核要求已复核。