test(13-03): add content completeness protection tests

- 添加 TestSentenceBoundaryProtection 测试类(COMP-01)
  - test_sentence_boundary_protection: 验证分段边界在标点符号后
  - test_sentence_boundary_in_prompt: 验证 Prompt 包含句边界指令

- 添加 TestArgumentCompleteness 测试类(COMP-02)
  - test_argument_completeness: 验证论点结构完整性
  - test_argument_completeness_in_prompt: 验证 Prompt 包含论点完整性指令

- 添加 TestParallelStructurePreservation 测试类(COMP-03)
  - test_parallel_structure_preserved: 验证并列结构不被错误拆分
  - test_no_special_handling_for_parallel_in_prompt: 验证遵守用户决策(不特别指定并列结构处理)

所有测试通过(29/29),semantic_engine.py 已包含所需的内容完整性保护指令:
- 第 337 行:保持句子完整性,列举所有中文句末标点(。?!……)
- 第 340 行:保持论点完整性,不在前提-结论结构中间截断
- 不包含并列结构特殊处理(符合用户决策)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-22 00:26:14 +08:00
parent 759503f48a
commit adc1aa3b1d
+214
View File
@@ -513,3 +513,217 @@ class TestPydanticValidationExtended:
result = SegmentationResult(**data)
assert result.segments[0].title is None
# =============================================================================
# Test Content Completeness Protection (COMP-01, COMP-02, COMP-03)
# =============================================================================
class TestSentenceBoundaryProtection:
"""测试句边界保护功能 - COMP-01: 不在句子中间截断"""
def test_sentence_boundary_protection(self):
"""Test: 分段边界应在标点符号后,不在句子中间截断"""
from kb_workflow.srt.parser import Segment
# Sample segments with clear sentence boundaries
segments = [
Segment(id=1, start_time=0.0, end_time=3.0, text="机器学习是人工智能的一个分支。"),
Segment(id=2, start_time=3.0, end_time=6.0, text="它使用算法来解析数据、从中学习。"),
Segment(id=3, start_time=6.0, end_time=9.0, text="机器学习的目标是让计算机能够自动学习!"),
]
# Mock AI client
mock_client = Mock()
mock_client.api_key = "test-key"
mock_response = """```json
{
"video_type": "知识类",
"segments": [
{
"title": "机器学习概述",
"content": "机器学习是人工智能的一个分支。它使用算法来解析数据、从中学习。",
"start_index": 0,
"end_index": 35
},
{
"title": null,
"content": "机器学习的目标是让计算机能够自动学习!",
"start_index": 36,
"end_index": 55
}
],
"actual_segment_count": 2
}
```"""
mock_client.generate.return_value = mock_response
# Create engine and segment
engine = SemanticSegmentationEngine(ai_client=mock_client)
metadata = {"title": "机器学习介绍", "duration": 9.0}
paragraphs = engine.segment(segments, metadata)
# Verify segmentation occurred
assert len(paragraphs) == 2
# Verify sentence boundaries - each paragraph should end with punctuation
import re
sentence_endings = r'[。?!……]$'
for para in paragraphs:
para_stripped = para.strip()
assert re.search(sentence_endings, para_stripped), \
f"段落应以标点符号结尾: {para[:50]}..."
def test_sentence_boundary_in_prompt(self):
"""Test: SEGMENTATION_PROMPT 包含句边界保护指令"""
engine = SemanticSegmentationEngine()
# Get the prompt template
content = "测试内容"
metadata = {"title": "测试", "duration": 10.0, "video_type": "知识类"}
prompt = engine._build_prompt(content, metadata)
# Verify prompt contains sentence boundary instructions
assert "句号" in prompt or "。" in prompt
assert "问号" in prompt or "?" in prompt
assert "感叹号" in prompt or "!" in prompt
assert "省略号" in prompt or "……" in prompt
assert "不要在句子中间截断" in prompt or "保持句子完整性" in prompt
class TestArgumentCompleteness:
"""测试论点完整性保护 - COMP-02: 不破坏论点完整性"""
def test_argument_completeness(self):
"""Test: 论点结构应保持完整,前提-结论不被拆分"""
from kb_workflow.srt.parser import Segment
# Sample segments with premise-conclusion structures
segments = [
Segment(id=1, start_time=0.0, end_time=4.0, text="首先,让我们理解什么是深度学习。"),
Segment(id=2, start_time=4.0, end_time=8.0, text="深度学习是机器学习的一个子集。"),
Segment(id=3, start_time=8.0, end_time=12.0, text="因此,深度学习能够处理更复杂的数据模式。"),
]
# Mock AI client
mock_client = Mock()
mock_client.api_key = "test-key"
mock_response = """```json
{
"video_type": "知识类",
"segments": [
{
"title": "深度学习简介",
"content": "首先,让我们理解什么是深度学习。深度学习是机器学习的一个子集。因此,深度学习能够处理更复杂的数据模式。",
"start_index": 0,
"end_index": 50
}
],
"actual_segment_count": 1
}
```"""
mock_client.generate.return_value = mock_response
# Create engine and segment
engine = SemanticSegmentationEngine(ai_client=mock_client)
metadata = {"title": "深度学习介绍", "duration": 12.0}
paragraphs = engine.segment(segments, metadata)
# Verify segmentation occurred
assert len(paragraphs) == 1
# Verify argument completeness - premise and conclusion together
first_para = paragraphs[0]
assert "首先" in first_para
assert "因此" in first_para
def test_argument_completeness_in_prompt(self):
"""Test: SEGMENTATION_PROMPT 包含论点完整性指令"""
engine = SemanticSegmentationEngine()
# Get the prompt template
content = "测试内容"
metadata = {"title": "测试", "duration": 10.0, "video_type": "知识类"}
prompt = engine._build_prompt(content, metadata)
# Verify prompt contains argument completeness instructions
assert "论点完整性" in prompt or "保持论点" in prompt
assert "前提" in prompt or "结论" in prompt or "不要截断" in prompt
class TestParallelStructurePreservation:
"""测试并列结构保护 - COMP-03: 并列结构不被错误拆分"""
def test_parallel_structure_preserved(self):
"""Test: 并列结构(首先/其次/最后)应保持完整"""
from kb_workflow.srt.parser import Segment
# Sample segments with parallel structures
segments = [
Segment(id=1, start_time=0.0, end_time=4.0, text="首先,我们需要收集数据。"),
Segment(id=2, start_time=4.0, end_time=8.0, text="其次,我们清洗和预处理数据。"),
Segment(id=3, start_time=8.0, end_time=12.0, text="最后,我们训练模型并进行评估。"),
]
# Mock AI client
mock_client = Mock()
mock_client.api_key = "test-key"
mock_response = """```json
{
"video_type": "教程类",
"segments": [
{
"title": "数据收集",
"content": "首先,我们需要收集数据。",
"start_index": 0,
"end_index": 14
},
{
"title": "数据预处理",
"content": "其次,我们清洗和预处理数据。",
"start_index": 15,
"end_index": 30
},
{
"title": "模型训练",
"content": "最后,我们训练模型并进行评估。",
"start_index": 31,
"end_index": 45
}
],
"actual_segment_count": 3
}
```"""
mock_client.generate.return_value = mock_response
# Create engine and segment
engine = SemanticSegmentationEngine(ai_client=mock_client)
metadata = {"title": "数据处理流程", "duration": 12.0}
paragraphs = engine.segment(segments, metadata)
# Verify segmentation occurred
assert len(paragraphs) == 3
# Verify each parallel point is complete in its segment
assert "首先" in paragraphs[0]
assert "其次" in paragraphs[1]
assert "最后" in paragraphs[2]
def test_no_special_handling_for_parallel_in_prompt(self):
"""Test: SEGMENTATION_PROMPT 不包含并列结构特殊处理
遵守用户决策:让 LLM 自然判断
"""
engine = SemanticSegmentationEngine()
# Get the prompt template
content = "测试内容"
metadata = {"title": "测试", "duration": 10.0, "video_type": "知识类"}
prompt = engine._build_prompt(content, metadata)
# Verify prompt does NOT have specific instructions for parallel structures
# (per user decision to let LLM naturally judge)
# The prompt should not have special handling like "保持并列结构完整"
assert "保持并列结构完整" not in prompt
assert "并列结构不拆分" not in prompt