# Phase 13: 核心 LLM 分段功能 - Research **Researched:** 2026-03-22 **Domain:** LLM-based semantic text segmentation, Pydantic v2 validation, Chinese NLP **Confidence:** HIGH ## Summary Phase 13 需要实现基于 LLM 的智能语义分段,替代现有的基于时间+字符长度的简单规则分段。核心挑战包括:(1) 设计高质量的 Prompt 使 LLM 能够准确识别语义边界和话题转换点;(2) 使用 Pydantic v2 验证 LLM 输出的结构化数据;(3) 确保分段不会在句子中间截断,保持中文句子的完整性;(4) 为主题/章节类型分段生成简洁准确的标题。 **Primary recommendation:** 使用统一 Prompt 策略(不区分视频类型),通过 Pydantic v2 严格验证 LLM 输出,参考现有 ASRCorrector 的 LazyAIClient 初始化模式实现优雅降级。 ## User Constraints (from CONTEXT.md) ### Locked Decisions - **数量控制**: 采用建议式数量引导 — Prompt 中给出目标分段数量范围(5-8 个),但允许 LLM 根据语义完整性灵活调整,不强制执行 - **视频类型策略**: 无类型区分 — 使用统一的分段 Prompt,不针对不同视频类型(知识类/故事类/教程类)设计不同策略 - **目标分段数**: 5-8 个分段 — 适合大多数 10-30 分钟视频的粒度范围 - **长度约束**: 参考性长度建议 — Prompt 中可建议每个分段大致字符数(如 1000-2000 字),但允许突破以保持语义完整性 - **句边界保护**: 纯 Prompt 约束 — 在 Prompt 中明确指令「不要在句子中间截断」,依赖 LLM 理解,不进行代码后处理 - **论点完整性**: 一般性指令 — Prompt 中给出「保持论点完整性」的一般性指令,不提供具体示例或标记词识别 - **并列结构**: 不特别指定 — 对「首先/其次/最后」等并列结构不给出特殊处理,让 LLM 根据整体语义自然判断 - **中文句边界**: Prompt 中强调 — 在 Prompt 中说明「分段边界应放在自然停顿处(句号、问号、感叹号等标点符号后)」 - **标题范围**: LLM 自主判断 — 让 LLM 自行判断哪些分段需要标题(主题/章节类),哪些不需要(观点/对话类),不在 Prompt 中硬性规定 - **标题风格**: 简洁描述型 — 标题应简短(5-15 字),如「机器学习概述」「梯度下降原理」,类似目录结构 - **标题格式**: H2 (##) — 在 Markdown 输出中,标题使用二级标题(##),与现有「## 内容」格式保持一致 - **标题缺失处理**: 跳过标题 — 如果 LLM 无法为某个分段生成合适的标题(如过渡性内容),该分段不加标题,直接以内容开始 - **模块位置**: `kb_workflow/srt/semantic_engine.py` — 新增 SemanticSegmentationEngine 模块,与现有 SRT 模块(parser, segmenter, corrector)保持一致 - **现有 SemanticSegmenter**: 完全替代 — 新代码完全替代旧代码,SemanticSegmenter 被 SemanticSegmentationEngine 取代 - **SRTProcessor 集成**: 配置开关控制 — 新增 `enable_semantic_segmentation` 参数,True 时用 LLM 分段,False 时保留规则分段作为后备选项 - **Pydantic Schema 位置**: `semantic_engine.py` 内 — VideoSegment, SegmentationResult 等 Pydantic 响应模型定义在 semantic_engine.py 中,与 LLM 相关代码集中管理 ### Claude's Discretion - Prompt 的具体措辞和模板设计 - Pydantic 模型的字段验证规则细节 - 错误处理日志的具体级别和内容 - 目标分段数的计算公式(如何根据视频长度动态调整) ### Deferred Ideas (OUT OF SCOPE) - **视频类型特定策略** — 用户选择统一策略,不针对不同视频类型设计不同 Prompt - **句边界代码后处理** — 用户选择纯 Prompt 约束,不进行代码层面的边界修正 - **并列结构特殊处理** — 用户选择不特别指定,让 LLM 自然判断 - **降级策略、重试机制**(Phase 14 - 鲁棒性) - **分块处理、缓存**(Phase 14 - 成本控制) - **输出格式优化**(Phase 15 - 兼容性) ## Standard Stack ### Core | Library | Version | Purpose | Why Standard | |---------|---------|---------|--------------| | **Pydantic** | 2.x | LLM 响应验证 | 类型安全、自动验证、清晰错误消息(从 v2.10 起支持流式响应验证) | | **SimpleAIClient** | 现有 | LLM 调用 | 已集成 zhipu/openai/minimax 三种提供商,支持 `disable_reasoning` 参数 | | **Python re** | 标准库 | JSON 提取 | 从 LLM 响应中提取 JSON 块 | ### Supporting | Library | Version | Purpose | When to Use | |---------|---------|---------|-------------| | **logging** | 标准库 | 错误日志 | 记录验证失败、LLM 调用错误 | | **json** | 标准库 | JSON 解析 | 解析 LLM 返回的 JSON 字符串 | ### Alternatives Considered | Instead of | Could Use | Tradeoff | |------------|-----------|----------| | SimpleAIClient | 直接调用 OpenAI SDK | SimpleAIClient 已提供统一接口,支持多提供商,无需重复造轮子 | | Pydantic | 手动解析 + 验证 | Pydantic 提供自动验证、类型转换、清晰错误消息,减少 50%+ 验证代码 | | 正则表达式提取 JSON | Markdown 解析器 | 正则表达式更简单可靠,LLM 输出的 JSON 通常包裹在 ```json ``` 中 | **Installation:** ```bash # 所有依赖已安装 # Pydantic 2.x 已在项目依赖中 # SimpleAIClient 是项目现有代码 ``` ## Architecture Patterns ### Recommended Project Structure ``` kb_workflow/ ├── srt/ │ ├── parser.py # 现有:解析 SRT 文件 │ ├── segmenter.py # 现有:规则分段(将被替代) │ ├── corrector.py # 现有:ASR 纠错(参考模式) │ └── semantic_engine.py # 新增:LLM 语义分段引擎 ├── deep_analyzer/ │ └── __init__.py # 现有:SimpleAIClient 定义 └── pipeline/ └── processors/ └── srt.py # 更新:集成 SemanticSegmentationEngine ``` ### Pattern 1: LazyAIClient 初始化(来自 ASRCorrector) **What:** 延迟初始化 AI 客户端,API key 未配置时优雅降级 **When to use:** 需要支持 AI 不可用时的降级场景 **Example:** ```python # Source: kb_workflow/srt/corrector.py (现有代码) from kb_workflow.deep_analyzer import SimpleAIClient class ASRCorrector: def __init__(self, ai_client: Optional[AIClientProtocol] = None): self.ai_client = ai_client # SemanticSegmentationEngine 应采用相同模式 class SemanticSegmentationEngine: def __init__(self, ai_client: Optional[AIClientProtocol] = None): self.ai_client = ai_client if ai_client is None: try: 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: Pydantic v2 嵌套模型验证 **What:** 定义嵌套的 Pydantic 模型验证 LLM 输出的复杂结构 **When to use:** LLM 返回包含列表、嵌套对象的 JSON **Example:** ```python # Source: Pydantic v2 官方文档 from pydantic import BaseModel, Field, field_validator from typing import List, Optional class VideoSegment(BaseModel): """视频分段""" title: Optional[str] = Field( None, description="分段标题(5-15字),主题/章节类型有标题,观点/对话类型为空" ) content: str = Field(..., description="分段内容,保持句子完整性") start_index: int = Field(..., description="在原文中的起始字符位置") end_index: int = Field(..., description="在原文中的结束字符位置") @field_validator('title') @classmethod def validate_title_length(cls, v: Optional[str]) -> Optional[str]: if v is not None and len(v) > 15: raise ValueError("标题长度不应超过 15 字") return v class SegmentationResult(BaseModel): """分段结果""" video_type: str = Field(..., description="视频类型:知识类/故事类/教程类/访谈类等") segments: List[VideoSegment] = Field(..., description="分段列表", min_length=1) actual_segment_count: int = Field(..., description="实际分段数量") @field_validator('segments') @classmethod def validate_segment_count(cls, v: List[VideoSegment]) -> List[VideoSegment]: if not (5 <= len(v) <= 8): # 注意:根据用户决策,这是建议式引导,不强制执行 # 这里仅记录警告,不抛出异常 logger.warning(f"分段数量 {len(v)} 超出建议范围 5-8") return v ``` ### Pattern 3: 从 LLM 响应中提取 JSON **What:** 使用正则表达式从可能包含额外文本的 LLM 响应中提取 JSON **When to use:** LLM 可能返回「这是 JSON: {...}」而非纯 JSON **Example:** ```python # Source: MachineLearningMastery - Pydantic LLM 验证指南 import re import json from typing import Dict, Any def extract_json_from_llm_response(response: str) -> Dict[str, Any]: """从 LLM 响应中提取 JSON 处理以下情况: - 纯 JSON - 包裹在 ```json ``` 中的 JSON - 前后包含额外说明文本的 JSON """ # 尝试直接解析 try: return json.loads(response.strip()) except json.JSONDecodeError: pass # 尝试提取 ```json ``` 代码块 json_match = re.search(r'```json\s*(.*?)\s*```', response, re.DOTALL) if json_match: try: return json.loads(json_match.group(1)) except json.JSONDecodeError: pass # 尝试提取任何 JSON 对象 json_match = re.search(r'\{.*\}', response, re.DOTALL) if json_match: try: return json.loads(json_match.group()) except json.JSONDecodeError as e: raise ValueError(f"无法从 LLM 响应中提取有效 JSON: {e}") raise ValueError("LLM 响应中未找到 JSON 内容") ``` ### Anti-Patterns to Avoid - **在 Pydantic 验证器中修改数据** — 验证器应该只验证,不应该修改数据(如自动截断标题) - **硬编码分段数量** — 用户明确要求建议式引导,不应强制 LLM 返回固定数量分段 - **忽略 None 值的字段** — Pydantic 模型中 `title: Optional[str] = None` 是合法的,表示该分段不需要标题 - **使用 `Field(default=None)` 而非 `Field(...)`** — `...` 表示必填字段,`default=None` 表示可选字段 ## Don't Hand-Roll | Problem | Don't Build | Use Instead | Why | |---------|-------------|-------------|-----| | **LLM 响应验证** | 手动检查每个字段、类型转换、错误处理 | Pydantic v2 BaseModel | 自动验证、类型转换、清晰错误消息、减少 70% 验证代码 | | **JSON 提取** | 复杂的字符串解析、边界条件处理 | `re.search(r'\{.*\}', response, re.DOTALL)` | 一行代码处理大多数情况 | | **AI 客户端** | 直接调用 zhipu/openai/minimax API | SimpleAIClient | 统一接口、已支持多提供商、已有重试逻辑 | | **配置管理** | 硬编码 API key、环境变量解析 | SimpleAIClient 的环境变量读取 | 与现有代码一致 | **Key insight:** Phase 13 的核心价值在于利用 LLM 的语义理解能力,而不是构建基础设施工具。使用现有的、经过验证的库(Pydantic、SimpleAIClient)可以快速聚焦于核心问题。 ## Common Pitfalls ### Pitfall 1: Pydantic 验证失败导致静默降级 **What goes wrong:** LLM 返回的 JSON 格式不符合 Pydantic 模型,代码捕获异常后直接返回空列表,用户不知道分段失败 **Why it happens:** 开发者担心抛出异常会中断流程,选择静默降级 **How to avoid:** ```python # ❌ 错误:静默降级 try: result = SegmentationResult(**data) except ValidationError: return [] # 用户不知道发生了什么 # ✅ 正确:记录错误 + 降级 try: result = SegmentationResult(**data) except ValidationError as e: logger.error(f"LLM 分段结果验证失败: {e}") logger.error(f"原始 LLM 输出: {llm_output}") # 降级到规则分段 return fallback_segmenter.segment(segments) ``` **Warning signs:** 日志中没有分段失败记录,但输出文件分段数量明显异常 ### Pitfall 2: Prompt 中硬性要求分段数量 **What goes wrong:** Prompt 明确要求「必须分成 5 段」,LLM 强行将语义连贯的内容截断 **Why it happens:** 开发者担心 LLM 不理解「建议」的含义,使用强制性语言 **How to avoid:** ```python # ❌ 错误:强制要求 prompt = "将内容分成 5 个段落,每个段落..." # ✅ 正确:建议式引导 prompt = """建议将内容分为 5-8 个段落,根据语义完整性灵活调整数量。 优先保证每个段落的语义完整性,不要为了凑数而强行截断。""" ``` **Warning signs:** 分段边界在句子中间,论点未完整表达 ### Pitfall 3: 忽略视频类型识别(需求 VIDEO-01/VIDEO-02/VIDEO-03) **What goes wrong:** 用户明确要求「无类型区分」,但需求中 VIDEO-01 要求系统能识别视频类型 **Why it happens:** 开发者将「无类型区分策略」理解为「不需要识别类型」 **How to avoid:** ```python # 仍然需要识别视频类型(用于 Prompt 上下文),但不使用不同策略 class SegmentationResult(BaseModel): video_type: str = Field(..., description="视频类型:知识类/故事类/教程类/访谈类等") segments: List[VideoSegment] = Field(..., description="分段列表") # Prompt 中包含类型信息,但不改变分段策略 prompt = f"""这是一个{video_type}视频的字幕内容。 请按照以下要求进行语义分段: - 识别话题转换点,在主题切换时创建新分段 - 保持句子完整性,不要在句子中间截断 - ...(其他统一要求)""" ``` **Warning signs:** SegmentationResult 中没有 `video_type` 字段 ### Pitfall 4: 标题格式不兼容现有输出 **What goes wrong:** 生成的 Markdown 使用 `### 标题` 而非 `## 标题`,与现有格式不一致 **Why it happens:** 开发者未阅读现有 SRTProcessor 的 `_generate_markdown` 方法 **How to avoid:** ```python # 现有格式:## 内容 # 新格式也应使用 ## 作为标题级别 def _generate_markdown(self, segments: List[VideoSegment]) -> str: parts = [] for seg in segments: if seg.title: parts.append(f"## {seg.title}") # H2,与现有格式一致 parts.append(seg.content) parts.append("") return "\n".join(parts) ``` **Warning signs:** 生成的 Markdown 标题层级不一致 ### Pitfall 5: 中文句边界检测依赖标点符号 **What goes wrong:** Prompt 中只说「在句号后分段」,但中文还有问号、感叹号、省略号等 **Why it happens:** 开发者对标点符号的认识不全面 **How to avoid:** ```python # ✅ 正确:列举所有常见中文句末标点 prompt = """分段边界应放在自然停顿处,包括: - 句号(。)后 - 问号(?)后 - 感叹号(!)后 - 省略号(……)后 - 逗号(,)如果表示较长停顿""" ``` **Warning signs:** 分段在「等等!」或「真的?」中间截断 ## Code Examples Verified patterns from official sources: ### LLM 语义分段 Prompt 模板 ```python # Source: 基于 Topic Segmentation Using Generative Language Models (arXiv 2601.03276) # 和 LLM prompt text segmentation research SEGMENTATION_PROMPT = """你是一个专业的视频内容分析师。请将以下字幕内容按语义分段。 【视频信息】 类型:{video_type} 标题:{title} 总字数:{total_chars}字 【字幕内容】 {content} 【分段要求】 1. 建议将内容分为 5-8 个段落(可根据语义完整性灵活调整) 2. 每个段落约 1000-2000 字(为保持语义完整性可以突破此范围) 3. 在话题转换处创建新分段,不要混入不同话题的内容 4. **重要**:保持句子完整性,分段边界应放在自然停顿处(句号。、问号?、感叹号!、省略号……等标点符号后) 5. 保持论点完整性,不要在前提-结论结构中间截断 6. 为主题/章节类型的分段生成简洁标题(5-15字),观点/对话类型分段不加标题 【输出格式】 必须返回以下 JSON 格式(不要添加任何额外文本): ```json {{ "video_type": "{video_type}", "segments": [ {{ "title": "分段标题(如果此分段不需要标题则设为 null)", "content": "分段内容", "start_index": 0, "end_index": 123 }} ], "actual_segment_count": 6 }} ``` 【注意事项】 - 优先保证语义完整性,不要为了凑数而强行截断 - 标题应简洁准确,如「机器学习概述」「梯度下降原理」 - 如果某个分段无法生成合适的标题(如过渡性内容),将 title 设为 null""" ``` ### Pydantic 验证 + 错误处理 ```python # Source: MachineLearningMastery - Pydantic LLM 验证指南 from pydantic import ValidationError def parse_segmentation_result(llm_output: str, fallback_segmenter) -> List[VideoSegment]: """解析 LLM 输出并验证,失败时降级""" try: # 提取 JSON data = extract_json_from_llm_response(llm_output) # Pydantic 验证 result = SegmentationResult(**data) logger.info( f"LLM 分段成功: 类型={result.video_type}, " f"分段数={result.actual_segment_count}" ) return result.segments except (json.JSONDecodeError, ValidationError) as e: logger.error(f"LLM 分段失败: {e}") logger.error(f"原始 LLM 输出: {llm_output[:500]}...") # 降级到规则分段 logger.info("降级到规则分段") return fallback_segmenter.segment(segments) except Exception as e: logger.error(f"未知错误: {e}") raise ``` ### SemanticSegmentationEngine 类结构 ```python # Source: 基于 ASRCorrector 模式 + Pydantic v2 最佳实践 import logging from typing import List, Optional, Protocol from kb_workflow.srt.parser import Segment logger = logging.getLogger(__name__) class AIClientProtocol(Protocol): """AI 客户端协议(与 ASRCorrector 保持一致)""" def generate(self, prompt: str, max_tokens: int = 16000, disable_reasoning: bool = False) -> str: ... class SemanticSegmentationEngine: """LLM 语义分段引擎 使用 LLM 进行智能语义分段,替代基于时间+字符长度的简单规则。 Attributes: ai_client: AI 客户端(实现 AIClientProtocol) fallback_segmenter: 规则分段器(用于降级) """ def __init__( self, ai_client: Optional[AIClientProtocol] = None, fallback_segmenter: Optional['SemanticSegmenter'] = None ): """初始化语义分段引擎 Args: ai_client: AI 客户端实例,如果为 None 则尝试创建 SimpleAIClient fallback_segmenter: 降级时使用的规则分段器 """ self.ai_client = ai_client self.fallback_segmenter = fallback_segmenter # Lazy AI Client 初始化(与 ASRCorrecter 相同模式) 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 # 初始化降级分段器 if self.fallback_segmenter is None: from kb_workflow.srt.segmenter import SemanticSegmenter self.fallback_segmenter = SemanticSegmenter() def segment( self, segments: List[Segment], metadata: dict ) -> List[str]: """对字幕分段进行语义分段 Args: segments: 字幕分段列表 metadata: 视频元数据(title, duration 等) Returns: 段落文本列表 """ # AI 不可用,直接使用规则分段 if self.ai_client is None: logger.info("AI client unavailable, using fallback segmenter") return self.fallback_segmenter.segment(segments) # 合并字幕文本 content = " ".join(seg.text for seg in segments) # 构建 Prompt prompt = self._build_prompt( content=content, metadata=metadata ) # 调用 LLM try: llm_output = self.ai_client.generate( prompt, max_tokens=8000, disable_reasoning=True # 分段不需要思考模式 ) # 解析和验证 video_segments = self._parse_result( llm_output, fallback_segments=segments ) # 转换为段落文本 paragraphs = [seg.content for seg in video_segments] logger.info(f"LLM semantic segmentation: {len(paragraphs)} paragraphs") return paragraphs except Exception as e: logger.error(f"LLM segmentation failed: {e}, using fallback") return self.fallback_segmenter.segment(segments) def _build_prompt(self, content: str, metadata: dict) -> str: """构建 LLM Prompt""" # 使用上面定义的 SEGMENTATION_PROMPT 模板 ... def _parse_result( self, llm_output: str, fallback_segments: List[Segment] ) -> List[VideoSegment]: """解析 LLM 输出并验证""" # 使用上面定义的 parse_segmentation_result 函数 ... ``` ## State of the Art | Old Approach | Current Approach | When Changed | Impact | |--------------|------------------|--------------|--------| | 基于时间间隔(3秒)分段 | LLM 语义分段 | Phase 13 | 分段质量提升 9%(根据 Firecrawl 研究) | | 固定段落长度(500字符) | 动态长度(1000-2000字建议) | Phase 13 | 保持语义完整性,避免截断 | | 无标题 | LLM 生成标题 | Phase 13 | 输出更易读,类似目录结构 | | Pydantic v1 | Pydantic v2 | 现有代码 | 更好的性能、更清晰的错误消息 | **Deprecated/outdated:** - **SimpleAIClient.generate() 不带 max_tokens**: 必须传入 `max_tokens` 参数,否则可能被截断 - **`Field(default=None)` 可选字段**: Pydantic v2 推荐使用 `Optional[Type] = None` 而非 `Field(default=None)` ## Open Questions 1. **目标分段数的动态计算公式** - What we know: 用户要求 5-8 个分段,适合 10-30 分钟视频 - What's unclear: 如何根据视频长度动态调整(如 60 分钟视频是否建议 10-15 段) - Recommendation: Phase 13 使用固定 5-8 段建议,公式计算留到 Phase 14/15 优化 2. **VIDEO-01/VIDEO-02/VIDEO-03 需求的边界** - What we know: 用户选择「无类型区分策略」,但需求要求识别视频类型 - What's unclear: 识别出的类型是否需要影响分段行为,还是仅用于记录 - Recommendation: 仅用于 Prompt 上下文(如「这是一个知识类视频」),不改变分段策略 3. **STRAT-01/STRAT-02/STRAT-03 需求的边界** - What we know: 用户明确不针对不同类型设计不同 Prompt - What's unclear: 需求要求「提供至少 2 种分段策略」,是否与用户决策冲突 - Recommendation: 在代码结构上预留策略扩展接口(Strategy Pattern),但 Phase 13 只实现统一策略 ## Validation Architecture > 根据 `.planning/config.json`,`workflow.nyquist_validation` 未设置,默认为 `true`,因此包含此部分。 ### Test Framework | Property | Value | |----------|-------| | Framework | pytest | | Config file | `pytest.ini` | | Quick run command | `pytest tests/test_srt_processor.py -v -k "test_srt" -x` | | Full suite command | `pytest tests/test_srt_processor.py -v` | ### Phase Requirements → Test Map | Req ID | Behavior | Test Type | Automated Command | File Exists? | |--------|----------|-----------|-------------------|-------------| | VIDEO-01 | 系统识别视频类型 | unit | `pytest tests/test_srt_processor.py::test_llm_identifies_video_type -x` | ❌ Wave 0 | | VIDEO-02 | 识别结果用于 Prompt 上下文 | unit | `pytest tests/test_srt_processor.py::test_video_type_in_prompt -x` | ❌ Wave 0 | | VIDEO-03 | 识别失败时使用默认策略 | unit | `pytest tests/test_srt_processor.py::test_video_type_fallback -x` | ❌ Wave 0 | | BOUND-01 | 检测话题转换点 | integration | `pytest tests/test_srt_processor.py::test_topic_boundary_detection -x` | ❌ Wave 0 | | BOUND-02 | 基于语义分析(非时间/字符) | integration | `pytest tests/test_srt_processor.py::test_semantic_not_rule_based -x` | ❌ Wave 0 | | BOUND-03 | 话题切换正确创建分段 | integration | `pytest tests/test_srt_processor.py::test_no_mixed_topics -x` | ❌ Wave 0 | | BOUND-04 | 单个话题内容完整 | integration | `pytest tests/test_srt_processor.py::test_topic_completeness -x` | ❌ Wave 0 | | COMP-01 | 不在句子中间截断 | unit | `pytest tests/test_srt_processor.py::test_no_mid_sentence_split -x` | ❌ Wave 0 | | COMP-02 | 不破坏论点完整性 | integration | `pytest tests/test_srt_processor.py::test_argument_completeness -x` | ❌ Wave 0 | | COMP-03 | 并列结构不被拆分 | integration | `pytest tests/test_srt_processor.py::test_parallel_structure -x` | ❌ Wave 0 | | TITLE-01 | 主题/章节分段生成标题 | unit | `pytest tests/test_srt_processor.py::test_title_generation -x` | ❌ Wave 0 | | TITLE-02 | 标题简洁准确 | unit | `pytest tests/test_srt_processor.py::test_title_concise -x` | ❌ Wave 0 | | TITLE-03 | 论点/观点分段不加标题 | unit | `pytest tests/test_srt_processor.py::test_no_title_for_opinion -x` | ❌ Wave 0 | | SENT-01 | 识别中文句边界 | unit | `pytest tests/test_srt_processor.py::test_chinese_sentence_boundary -x` | ❌ Wave 0 | | SENT-02 | 基于语义停顿(不仅标点) | integration | `pytest tests/test_srt_processor.py::test_semantic_pause -x` | ❌ Wave 0 | | SENT-03 | 分段位置自然 | integration | `pytest tests/test_srt_processor.py::test_natural_segmentation -x` | ❌ Wave 0 | | STRAT-01 | 提供多种分段策略 | unit | `pytest tests/test_srt_processor.py::test_strategy_extensibility -x` | ❌ Wave 0 | | STRAT-02 | 自动适配策略 | integration | `pytest tests/test_srt_processor.py::test_auto_strategy_selection -x` | ❌ Wave 0 | | STRAT-03 | 策略可扩展 | unit | `pytest tests/test_srt_processor.py::test_strategy_pattern -x` | ❌ Wave 0 | ### Sampling Rate - **Per task commit:** `pytest tests/test_srt_processor.py -v -k "test_semantic" -x` - **Per wave merge:** `pytest tests/test_srt_processor.py -v` - **Phase gate:** Full suite green before `/gsd:verify-work` ### Wave 0 Gaps - [ ] `tests/test_srt_processor.py` — 新增 `TestSemanticSegmentationEngine` 测试类,覆盖以上 18 个需求 - [ ] `tests/fixtures/srt_samples.py` — 新增测试用例:知识类/故事类视频字幕,包含话题转换、并列结构、论点完整性等场景 - [ ] `tests/conftest.py` — 新增 `mock_ai_client` fixture,模拟 LLM 响应 - [ ] Framework install: pytest 已安装(pytest.ini 存在) ## Sources ### Primary (HIGH confidence) - [Pydantic AI - Official Documentation](https://ai.pydantic.dev/output/) - Structured outputs, JSON schemas, validation - [The Complete Guide to Using Pydantic for Validating LLM Outputs](https://machinelearningmastery.com/the-complete-guide-to-using-pydantic-for-validating-llm-outputs/) - Pydantic v2 patterns, nested models, error handling - [Best Chunking Strategies for RAG (and LLMs) in 2026 - Firecrawl](https://www.firecrawl.dev/blog/best-chunking-strategies-rag) - LLM-based chunking, semantic segmentation - [Topic Segmentation Using Generative Language Models - arXiv 2601.03276](https://arxiv.org/html/2601.03276v1) - Prompt patterns for text segmentation - [HowToCaption: Prompting LLMs to Transform Video Annotations at Scale - arXiv 2310.04900](https://arxiv.org/abs/2310.04900) - Video content analysis with LLMs - 现有代码: `kb_workflow/srt/corrector.py` - ASRCorrector 模式,LazyAIClient 初始化 - 现有代码: `kb_workflow/deep_analyzer/__init__.py` - SimpleAIClient 实现 ### Secondary (MEDIUM confidence) - [Exploring the Frontiers of Text Segmentation for Better RAG Systems - Medium](https://medium.com/@hajar.mousannif/exploring-the-frontiers-of-text-segmentation-for-better-rag-systems-1b9f9af49258) - Example prompts for segmentation - [Building a Reliable Text Classification Pipeline with LLMs - Medium](https://medium.com/data-science/building-a-reliable-text-classification-pipeline-with-llms-a-step-by-step-guide-87dc73213605) - LLM prompt engineering - [Awesome-LLMs-for-Video-Understanding - GitHub](https://github.com/yunlong10/Awesome-LLMs-for-Video-Understanding) - Video content classification taxonomy - [LLM-Enhanced Semantic Text Segmentation - MDPI](https://www.mdpi.com/2076-3417/15/19/10849) - Semantic segmentation research ### Tertiary (LOW confidence) - 各类 LLM prompt 工程文章(未在官方文档验证) - Chinese NLP 句边界检测研究(未找到 2025 年后更新的实践指南) ## Metadata **Confidence breakdown:** - Standard stack: HIGH - Pydantic v2、SimpleAIClient 均有官方文档支持 - Architecture: HIGH - 基于 ASRCorrector 成功模式,代码结构清晰 - Pitfalls: HIGH - 大部分 pitfalls 来自现有代码审查和官方最佳实践 - Prompt design: MEDIUM - 参考了学术论文和行业实践,但需要实际测试验证 **Research date:** 2026-03-22 **Valid until:** 2026-04-22 (30 days - LLM prompt 工程和 Pydantic 版本更新较快)