diff --git a/.planning/phases/14-robustness-cost/14-RESEARCH.md b/.planning/phases/14-robustness-cost/14-RESEARCH.md
new file mode 100644
index 0000000..8fea69b
--- /dev/null
+++ b/.planning/phases/14-robustness-cost/14-RESEARCH.md
@@ -0,0 +1,434 @@
+# Phase 14: 鲁棒性与成本控制 - Research
+
+**Research Date:** 2026-03-23
+**Domain:** LLM 容错处理、缓存优化、文本分块
+**Confidence:** HIGH
+
+## Summary
+
+本阶段专注于提高 LLM 语义分段的稳定性和成本效率。基于用户决策,实现轻量级的重试机制、智能缓存和长文本分块处理。核心原则是"快速失败,优雅降级"——AI 不可用时立即使用规则分段,保证系统可用性。
+
+**Primary Recommendation:** 复用 ASRCorrector 的分批处理模式和 SimpleAIClient 的重试逻辑,避免引入新依赖,保持代码一致性。
+
+
+## User Constraints (from CONTEXT.md)
+
+### Locked Decisions
+
+#### 重试策略
+- **重试次数**: 重试 1 次 — 失败后立即降级到规则分段,简单快速,避免浪费配额
+- **重试条件**: 仅可恢复错误触发重试 — 网络错误/超时/限流重试,API 错误(如 400)直接降级
+- **重试延迟**: 立即重试 — 失败后立即重试,大多数情况下网络抖动是瞬时的
+- **不可恢复错误**: API 错误(4xx)、解析失败、验证失败等直接降级,不重试
+
+#### 分块处理
+- **分块阈值**: 5000 字符(约 10-15 分钟字幕)— 与 ASRCorrector 的 batch_size 一致,保持代码模式统一
+- **分块方式**: 按句子边界分割 — 在句号、问号、感叹号等标点符号后分割,保持语义完整性
+- **结果合并**: 直接拼接各分块结果 — 每个分块独立分段后直接拼接,简单快速
+- **分块策略**: 长字幕按句子边界分成多个 5000 字符以内的块,每块独立调用 LLM 分段
+
+#### 缓存机制
+- **缓存键**: 字幕内容哈希(SHA256)— 精确匹配,相同内容一定命中
+- **缓存存储**: 本地文件系统 — 存储在 `.planning/cache/semantic/` 目录,简单持久化
+- **缓存 TTL**: 永久有效 — 字幕内容不变,分段结果应该一致,手动清理过期缓存
+- **缓存内容**: 完整的 SegmentationResult(JSON 格式),包含 video_type 和 segments
+
+#### 日志详细程度
+- **降级日志**: 记录原因 + 降级方式 — 如 "API key 未配置,降级到规则分段"
+- **日志级别**: 区分级别
+ - 降级:warning 级别
+ - 重试:info 级别
+ - 成功:debug 级别
+- **重试日志**: 记录重试原因和次数
+- **缓存日志**: 记录缓存命中/未命中,使用 debug 级别
+
+### Claude's Discretion
+
+- 具体的重试逻辑实现细节
+- 缓存文件命名规则和目录结构
+- 分块算法的具体实现(句子边界检测)
+- 日志消息的具体措辞和格式
+
+### Deferred Ideas (OUT OF SCOPE)
+
+- **缓存清理命令**: 自动清理过期缓存的功能 — 延后到未来版本,当前手动删除缓存文件
+- **缓存压缩**: 压缩缓存文件以节省空间 — 延后到缓存文件较大时再考虑
+- **分块智能合并**: 检测相邻分段语义相似度并合并 — 增加复杂度,当前直接拼接足够
+
+
+
+## Phase Requirements
+
+| ID | Description | Research Support |
+|----|-------------|-----------------|
+| ROBUST-01 | LLM 调用失败时自动降级到简单规则分段 | 重试策略实现,异常时调用 fallback_segmenter |
+| ROBUST-02 | LLM 响应解析失败时自动重试或降级,有日志记录 | 区分可恢复/不可恢复错误,解析失败直接降级 |
+| ROBUST-03 | AI 不可用时自动使用简单规则分段 | Lazy AI Client 初始化,None 时直接使用规则分段 |
+| ROBUST-04 | 降级过程有日志记录,便于问题诊断 | 分级日志:降级 warning,重试 info,成功 debug |
+| COST-01 | 长视频字幕自动分块处理,避免上下文窗口溢出 | 复用 ASRCorrector 分批模式,5000 字符阈值 |
+| COST-02 | 相同内容使用缓存结果,避免重复 LLM 调用 | SHA256 哈希缓存键,本地文件系统存储 |
+| COST-03 | 提供配置开关,用户可选择是否启用 LLM 分段 | SRTProcessor 已有 enable_semantic_segmentation 参数 |
+
+
+## Standard Stack
+
+### Core
+| Library | Version | Purpose | Why Standard |
+|---------|---------|---------|--------------|
+| hashlib (built-in) | - | 内容哈希计算 | Python 标准库,无需额外依赖 |
+| logging (built-in) | - | 分级日志记录 | Python 标准库,已在项目中使用 |
+| json (built-in) | - | 缓存序列化 | Python 标准库,已在项目中使用 |
+| pathlib (built-in) | - | 路径操作 | Python 标准库,跨平台兼容 |
+
+### Supporting
+| Library | Version | Purpose | When to Use |
+|---------|---------|---------|-------------|
+| pydantic | v2 | 响应验证 | 已在项目中使用,验证 SegmentationResult |
+| requests | 2.32.5+ | HTTP 请求 | 已通过 SimpleAIClient 隐式依赖 |
+
+### Alternatives Considered
+| Instead of | Could Use | Tradeoff |
+|------------|-----------|----------|
+| 简单重试循环 | tenacity 库 | tenacity 功能丰富但增加依赖,简单场景手写即可 |
+| 文件系统缓存 | redis/sqlite | Redis 需要额外服务,sqlite 增加复杂度,文件系统最简单 |
+| 手动分块 | langchain TextSplitter | langchain 体积大,ASRCorrector 模式已足够 |
+
+**Installation:**
+```bash
+# 无需安装新依赖,全部使用 Python 标准库或已有依赖
+```
+
+## Architecture Patterns
+
+### Recommended Project Structure
+```
+kb_workflow/srt/
+├── semantic_engine.py # 现有文件,添加重试、分块、缓存
+├── cache/ # 新增目录
+│ ├── __init__.py
+│ └── semantic_cache.py # 缓存管理器
+└── corrector.py # 参考分批处理模式(已有)
+```
+
+### Pattern 1: Lazy Initialization with Fallback(已有模式)
+**What:** 延迟初始化 AI Client,失败时使用规则分段
+**When to use:** AI 依赖可能不可用的场景
+**Example:**
+```python
+# Source: kb_workflow/srt/semantic_engine.py:99-114
+if self.ai_client is None:
+ try:
+ from kb_workflow.deep_analyzer import SimpleAIClient
+ self.ai_client = SimpleAIClient()
+ if not self.ai_client.api_key:
+ logger.info("AI API key not configured")
+ self.ai_client = None
+ except Exception as e:
+ logger.warning(f"Failed to initialize AI client: {e}")
+ self.ai_client = None
+```
+
+### Pattern 2: Batch Processing with Sentence Boundary Detection(复用模式)
+**What:** 按句子边界分割长文本,每批独立处理
+**When to use:** 文本超过 LLM 上下文窗口
+**Example:**
+```python
+# Source: kb_workflow/srt/corrector.py:125-136
+# 按句子分割(简单分割,基于句号、问号、感叹号)
+sentences = []
+current = ""
+for char in text:
+ current += char
+ if char in '。!?\n':
+ sentences.append(current)
+ current = ""
+
+# 添加最后一个不完整的句子
+if current:
+ sentences.append(current)
+```
+
+### Pattern 3: Content-Based Hashing(新增)
+**What:** 使用 SHA256 哈希内容作为缓存键
+**When to use:** 需要精确匹配相同内容
+**Example:**
+```python
+import hashlib
+
+def compute_content_hash(content: str) -> str:
+ """计算内容的 SHA256 哈希"""
+ return hashlib.sha256(content.encode('utf-8')).hexdigest()
+```
+
+### Pattern 4: Retry with Distinguishable Errors(新增)
+**What:** 区分可恢复和不可恢复错误,仅对可恢复错误重试
+**When to use:** API 调用可能因临时故障失败
+**Example:**
+```python
+import requests
+from requests.exceptions import ConnectionError, Timeout, HTTPError
+
+def is_recoverable_error(error: Exception) -> bool:
+ """判断是否为可恢复错误"""
+ if isinstance(error, (ConnectionError, Timeout)):
+ return True
+ if isinstance(error, HTTPError):
+ status_code = error.response.status_code
+ # 网络错误、超时、限流重试
+ return status_code in (429, 500, 502, 503, 504)
+ return False
+
+def call_llm_with_retry(prompt: str, max_retries: int = 1):
+ """带重试的 LLM 调用"""
+ for attempt in range(max_retries + 1):
+ try:
+ return llm_client.generate(prompt)
+ except Exception as e:
+ if attempt < max_retries and is_recoverable_error(e):
+ logger.info(f"LLM call failed (attempt {attempt + 1}): {e}, retrying...")
+ continue
+ # 最后一次失败或不可恢复错误,抛出异常
+ raise
+```
+
+### Anti-Patterns to Avoid
+- **不区分错误类型的盲目重试**: 所有错误都重试会导致浪费配额,应区分可恢复/不可恢复错误
+- **固定延迟重试**: 应立即重试(网络抖动是瞬时的),不要使用指数退避
+- **缓存键包含可变元数据**: 缓存键应仅基于内容哈希,不应包含视频 ID 或时间戳
+- **过度复杂的分块合并**: 直接拼接各分块结果即可,无需检测语义相似度
+
+## Don't Hand-Roll
+
+| Problem | Don't Build | Use Instead | Why |
+|---------|-------------|-------------|-----|
+| 内容哈希 | 自定义哈希算法 | hashlib.sha256() | 标准库函数,安全可靠 |
+| 日志分级 | print 语句 | logging 模块 | 已在项目中使用,支持分级和输出控制 |
+| JSON 序列化 | 手动拼接字符串 | json.dump()/json.load() | 标准库函数,处理转义和格式 |
+| 路径操作 | 字符串拼接 | pathlib.Path | 跨平台兼容,自动处理路径分隔符 |
+| 重试装饰器 | 复杂的装饰器 | 简单 for 循环 | 简单场景(1 次重试)无需额外抽象 |
+
+**Key insight:** Python 标准库提供了所需的全部基础设施,无需引入新依赖。重试、缓存、分块都是简单模式,过度工程化会增加维护成本。
+
+## Common Pitfalls
+
+### Pitfall 1: 不区分可恢复/不可恢复错误
+**What goes wrong:** 所有 LLM 调用失败都重试,包括 API 错误(如 400 Bad Request),导致浪费配额和时间
+**Why it happens:** 简单的 try-except 捕获所有异常,统一重试
+**How to avoid:** 使用 `is_recoverable_error()` 函数判断错误类型,仅对网络错误、超时、限流进行重试
+**Warning signs:** 看到 "重试 400 错误" 的日志
+
+### Pitfall 2: 缓存键冲突
+**What goes wrong:** 不同内容的哈希意外相同(哈希碰撞),导致返回错误的缓存结果
+**Why it happens:** 使用弱哈希算法或包含可变元数据(如时间戳)
+**How to avoid:** 使用 SHA256 强哈希,缓存键仅基于内容
+**Warning signs:** 缓存命中后分段结果与内容不符
+
+### Pitfall 3: 分块边界破坏语义
+**What goes wrong:** 在句子或段落中间分割,破坏内容完整性
+**Why it happens:** 仅按字符数分割,不考虑句子边界
+**How to avoid:** 复用 ASRCorrector 的分批模式,在标点符号(。!?\n)后分割
+**Warning signs:** 分块后某些分段以不完整的句子开头
+
+### Pitfall 4: 缓存目录不存在导致写入失败
+**What goes wrong:** 首次运行时缓存目录不存在,导致文件写入失败
+**Why it happens:** 假设目录已存在,未创建父目录
+**How to avoid:** 使用 `pathlib.Path.mkdir(parents=True, exist_ok=True)` 创建目录
+**Warning signs:** FileNotFoundError 或 PermissionError
+
+### Pitfall 5: 降级日志信息不足
+**What goes wrong:** 降级时仅记录 "降级到规则分段",无法诊断具体原因
+**Why it happens:** 捕获异常后未记录原始错误信息
+**How to avoid:** 记录具体错误类型和消息,如 "ConnectionError: 请求超时,降级到规则分段"
+**Warning signs:** 无法定位降级原因
+
+## Code Examples
+
+Verified patterns from official sources:
+
+### 可恢复错误检测
+```python
+# Source: WebSearch 2026 - Python Retry Best Practices
+from requests.exceptions import ConnectionError, Timeout, HTTPError
+
+def is_recoverable_error(error: Exception) -> bool:
+ """判断是否为可恢复错误
+
+ 可恢复错误:网络错误、超时、限流
+ 不可恢复错误:API 错误(4xx)、解析失败、验证失败
+ """
+ if isinstance(error, (ConnectionError, Timeout)):
+ return True
+ if isinstance(error, HTTPError):
+ status_code = error.response.status_code
+ # 429 Too Many Requests, 5xx Server Error
+ return status_code in (429, 500, 502, 503, 504)
+ return False
+```
+
+### 内容哈希缓存键
+```python
+# Source: Python standard library documentation
+import hashlib
+
+def compute_cache_key(content: str) -> str:
+ """计算内容的 SHA256 哈希作为缓存键"""
+ return hashlib.sha256(content.encode('utf-8')).hexdigest()
+```
+
+### 缓存读写
+```python
+# Source: Python standard library documentation
+import json
+from pathlib import Path
+
+def load_cache(cache_key: str, cache_dir: Path) -> dict | None:
+ """从文件加载缓存"""
+ cache_file = cache_dir / f"{cache_key}.json"
+ if not cache_file.exists():
+ return None
+ try:
+ return json.loads(cache_file.read_text(encoding='utf-8'))
+ except (json.JSONDecodeError, IOError) as e:
+ logger.warning(f"Failed to load cache: {e}")
+ return None
+
+def save_cache(cache_key: str, data: dict, cache_dir: Path):
+ """保存缓存到文件"""
+ cache_dir.mkdir(parents=True, exist_ok=True)
+ cache_file = cache_dir / f"{cache_key}.json"
+ try:
+ cache_file.write_text(json.dumps(data, ensure_ascii=False), encoding='utf-8')
+ except IOError as e:
+ logger.warning(f"Failed to save cache: {e}")
+```
+
+### 按句子边界分割
+```python
+# Source: kb_workflow/srt/corrector.py:125-136
+def split_by_sentences(text: str, max_length: int = 5000) -> list[str]:
+ """按句子边界分割文本
+
+ 在句号、问号、感叹号后分割,保持语义完整性。
+ """
+ sentences = []
+ current = ""
+ for char in text:
+ current += char
+ if char in '。!?\n':
+ sentences.append(current)
+ current = ""
+
+ if current:
+ sentences.append(current)
+
+ # 按最大长度分批
+ batches = []
+ current_batch = []
+ current_length = 0
+
+ for sentence in sentences:
+ if current_length + len(sentence) > max_length:
+ if current_batch:
+ batches.append(''.join(current_batch))
+ current_batch = [sentence]
+ current_length = len(sentence)
+ else:
+ current_batch.append(sentence)
+ current_length += len(sentence)
+
+ if current_batch:
+ batches.append(''.join(current_batch))
+
+ return batches
+```
+
+## State of the Art
+
+| Old Approach | Current Approach | When Changed | Impact |
+|--------------|------------------|--------------|--------|
+| 盲目重试所有错误 | 区分可恢复/不可恢复错误 | 2026-03-23 (Phase 14) | 减少配额浪费,提高响应速度 |
+| 无缓存 | SHA256 内容哈希缓存 | 2026-03-23 (Phase 14) | 相同内容避免重复 LLM 调用 |
+| 长文本直接调用 | 分块处理(5000字符) | 2026-03-23 (Phase 14) | 避免上下文窗口溢出 |
+| 简单 print 日志 | 分级 logging | 已在项目中使用 | 便于问题诊断和日志过滤 |
+
+**Deprecated/outdated:**
+- **无区分的重试**: 所有错误都重试的模式已被淘汰,应根据错误类型决定是否重试
+- **基于时间戳的缓存**: 缓存键包含时间戳会导致相同内容缓存不命中,应仅基于内容哈希
+
+## Open Questions
+
+1. **分块后的分段索引如何计算?**
+ - What we know: 每个分块独立分段,结果直接拼接
+ - What's unclear: VideoSegment.start_index 和 end_index 是相对于原文还是分块?
+ - Recommendation: 相对于原文,需要在分块时记录每个分块的起始偏移量,分段后累加偏移量
+
+2. **缓存文件是否需要版本控制?**
+ - What we know: 缓存永久有效,手动清理
+ - What's unclear: 如果 SegmentationResult 结构变化,旧缓存会加载失败
+ - Recommendation: 在缓存 JSON 中添加 version 字段,加载时验证版本
+
+3. **分块处理的顺序是否影响结果?**
+ - What we know: 每个分块独立调用 LLM,结果直接拼接
+ - What's unclear: 分块间是否有上下文依赖(如跨分块的论点)
+ - Recommendation: 假设分块间独立,直接拼接。如果出现问题,在 Phase 15 考虑智能合并
+
+## Validation Architecture
+
+### Test Framework
+| Property | Value |
+|----------|-------|
+| Framework | pytest (python3 -m pytest) |
+| Config file | pytest.ini (已存在) |
+| Quick run command | `python3 -m pytest tests/test_semantic_robustness.py -v -x` |
+| Full suite command | `python3 -m pytest tests/ -v` |
+
+### Phase Requirements → Test Map
+| Req ID | Behavior | Test Type | Automated Command | File Exists? |
+|--------|----------|-----------|-------------------|-------------|
+| ROBUST-01 | LLM 调用失败时自动降级 | unit | `pytest tests/test_semantic_robustness.py::test_llm_failure_fallback -x` | ❌ Wave 0 |
+| ROBUST-02 | 解析失败时重试或降级 | unit | `pytest tests/test_semantic_robustness.py::test_parse_failure_retry -x` | ❌ Wave 0 |
+| ROBUST-03 | AI 不可用时使用规则分段 | unit | `pytest tests/test_semantic_robustness.py::test_ai_unavailable_fallback -x` | ❌ Wave 0 |
+| ROBUST-04 | 降级日志记录 | unit | `pytest tests/test_semantic_robustness.py::test_fallback_logging -x` | ❌ Wave 0 |
+| COST-01 | 长文本分块处理 | unit | `pytest tests/test_semantic_robustness.py::test_long_text_chunking -x` | ❌ Wave 0 |
+| COST-02 | 缓存命中避免重复调用 | unit | `pytest tests/test_semantic_robustness.py::test_cache_hit -x` | ❌ Wave 0 |
+| COST-03 | 配置开关控制 | integration | `pytest tests/test_srt_processor.py::test_semantic_segmentation_toggle -x` | ❌ Wave 0 |
+
+### Sampling Rate
+- **Per task commit:** `python3 -m pytest tests/test_semantic_robustness.py -v -x`
+- **Per wave merge:** `python3 -m pytest tests/ -v`
+- **Phase gate:** Full suite green before `/gsd:verify-work`
+
+### Wave 0 Gaps
+- [ ] `tests/test_semantic_robustness.py` — 覆盖 ROBUST-01, ROBUST-02, ROBUST-03, ROBUST-04, COST-01, COST-02
+- [ ] `tests/test_srt_processor.py` — 覆盖 COST-03(配置开关)
+- [ ] `tests/conftest.py` — 共享 fixtures(mock LLM client, 样本字幕数据)
+- [ ] 框架安装: 无需安装,pytest 已配置
+
+**Mock Strategy:** 使用 unittest.mock.patch 模拟 SimpleAIClient.generate(),测试不同失败场景(网络错误、解析失败、超时等)
+
+## Sources
+
+### Primary (HIGH confidence)
+- **kb_workflow/srt/semantic_engine.py** — 现有代码模式,UnifiedSegmentationStrategy, Lazy AI Client 初始化
+- **kb_workflow/srt/corrector.py** — 分批处理模式(_correct_long_text),按句子分割
+- **kb_workflow/deep_analyzer/__init__.py** — SimpleAIClient 重试逻辑(max_retries=3)
+- **Python Standard Library** — hashlib, logging, json, pathlib
+
+### Secondary (MEDIUM confidence)
+- [Tenacity Official Repository](https://github.com/jd/tenacity) — 重试库参考(最终决定手写简单重试)
+- [Python Retry Best Practices with Tenacity](https://medium.com/@isuru-perera/how-i-stopped-worrying-about-api-failures-python-retry-with-tenacity-03cf839b4ceb) — 重试最佳实践
+- [How to Retry Failed Python Requests in 2026](https://oxylabs.io/blog/python-requests-retry) — 可恢复错误类型
+
+### Tertiary (LOW confidence)
+- [nnsplit - Semantic Text Segmentation](https://github.com/xinmeiyang/nnsplit) — 句子边界检测参考(最终决定复用 ASRCorrector 模式)
+- [PySBD: Pragmatic Sentence Boundary Disambiguation](https://www.researchgate.net/publication/347234862_PySBD_Pragmatic_Sentence_Boundary_Disambiguation) — 句子边界检测研究(最终决定使用简单标点符号分割)
+
+## Metadata
+
+**Confidence breakdown:**
+- Standard stack: HIGH - 全部使用 Python 标准库或已有依赖
+- Architecture: HIGH - 基于现有代码模式(semantic_engine.py, corrector.py)
+- Pitfalls: HIGH - 基于用户决策和常见错误模式
+
+**Research date:** 2026-03-23
+**Valid until:** 2026-04-23 (30 days, 稳定技术栈)