This repository has been archived on 2026-08-07. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
kb-skills/.planning/phases/14-robustness-cost/14-02-PLAN.md
T

241 lines
7.3 KiB
Markdown

---
phase: 14-robustness-cost
plan: 02
type: execute
wave: 1
depends_on: []
files_modified:
- kb_workflow/srt/semantic_engine.py
autonomous: true
requirements:
- ROBUST-02
- ROBUST-04
must_haves:
truths:
- "LLM 响应解析失败时自动重试或降级"
- "降级过程记录详细日志,包含错误类型和原因"
- "Pydantic 验证失败时直接降级(不可恢复错误)"
artifacts:
- path: "kb_workflow/srt/semantic_engine.py"
provides: "_parse_result() 带解析失败处理"
exports: ["_parse_result"]
key_links:
- from: "_parse_result()"
to: "extract_json_from_llm_response()"
via: "JSON 提取"
pattern: "extract_json_from_llm_response"
- from: "_parse_result()"
to: "SegmentationResult"
via: "Pydantic 验证"
pattern: "SegmentationResult(**data)"
---
<objective>
增强 LLM 响应解析的错误处理,区分解析失败类型并采取不同策略。
Purpose: 提高 LLM 输出格式不稳定时的容错能力,记录详细日志便于诊断。
Output: 改进的 _parse_result() 方法,带详细的错误日志和重试逻辑。
</objective>
<execution_context>
@/home/starmen1265/.claude/get-shit-done/workflows/execute-plan.md
@/home/starmen1265/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/phases/14-robustness-cost/14-CONTEXT.md
@.planning/phases/14-robustness-cost/14-RESEARCH.md
@.planning/phases/14-robustness-cost/14-VALIDATION.md
@.planning/ROADMAP.md
@.planning/REQUIREMENTS.md
@.planning/STATE.md
@kb_workflow/srt/semantic_engine.py
@.planning/phases/14-robustness-cost/14-01-PLAN.md
</context>
<interfaces>
<!-- Key types and contracts from semantic_engine.py -->
From kb_workflow/srt/semantic_engine.py:
```python
def extract_json_from_llm_response(response: str) -> dict:
"""从 LLM 响应中提取 JSON
处理以下情况:
- 纯 JSON
- 包裹在 ```json ``` 中的 JSON
- 前后包含额外说明文本的 JSON
Raises:
ValueError: 无法提取有效 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 内容")
class SegmentationResult(BaseModel):
video_type: str
segments: List[VideoSegment]
actual_segment_count: int
def _parse_result(
self,
llm_output: str,
fallback_segments: List
) -> List[VideoSegment]:
"""解析 LLM 输出并验证
Raises:
Exception: 解析或验证失败时
"""
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("降级到规则分段")
raise
except Exception as e:
logger.error(f"未知错误: {e}")
raise
```
关键观察:
- extract_json_from_llm_response() 可能抛出 ValueError (无法提取 JSON)
- SegmentationResult(**data) 可能抛出 ValidationError (Pydantic 验证失败)
- 当前实现: 所有解析失败都抛出异常,由 segment() 方法的 try-except 捕获并降级
</interfaces>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: 改进解析失败的错误处理和日志</name>
<files>kb_workflow/srt/semantic_engine.py</files>
<behavior>
- 区分 JSONDecodeError (无法提取 JSON) 和 ValidationError (Pydantic 验证失败)
- JSONDecodeError 是可恢复错误(可能 LLM 输出格式问题),可以重试
- ValidationError 是不可恢复错误(数据结构错误),直接降级
- 所有解析失败都记录详细日志:
- 错误类型 (JSONDecodeError/ValidationError/ValueError)
- 错误消息
- LLM 输出前 500 字符(用于诊断)
</behavior>
<action>
修改 UnifiedSegmentationStrategy._parse_result() 方法:
1. 拆分 except 块,区分不同的错误类型:
```python
except json.JSONDecodeError as e:
# JSON 解析失败(可恢复)
logger.error(
f"JSON 解析失败: {e}\n"
f"LLM 输出片段: {llm_output[:500]}..."
)
# 抛出特定异常,由 segment() 决定是否重试
raise
except ValidationError as e:
# Pydantic 验证失败(不可恢复)
logger.error(
f"Pydantic 验证失败: {e}\n"
f"LLM 输出片段: {llm_output[:500]}..."
)
# 直接降级,不重试
raise
except ValueError as e:
# 无法提取 JSON(可恢复)
logger.error(
f"JSON 提取失败: {e}\n"
f"LLM 输出片段: {llm_output[:500]}..."
)
raise
```
2. 在 segment() 方法中,修改 LLM 调用部分的重试逻辑:
- 对 JSONDecodeError 和 ValueError 进行重试
- 对 ValidationError 不重试,直接降级
- 使用 _is_recoverable_error() 的模式,创建 _is_recoverable_parse_error()
3. 统一日志格式:
- 重试: info 级别
- 降级: warning 级别,包含 "降级到规则分段"
遵守用户决策: 解析失败直接降级(不重试),但 JSONDecodeError 可以重试 1 次。
</action>
<verify>
<automated>pytest tests/test_semantic_robustness.py::test_parse_failure_retry -x</automated>
</verify>
<done>
- JSONDecodeError 和 ValueError 触发重试 1 次
- ValidationError 直接降级,不重试
- 所有解析失败都记录详细日志(错误类型 + LLM 输出片段)
- 测试覆盖各种解析失败场景
</done>
</task>
</tasks>
<verification>
## 整体验证标准
1. **JSON 解析失败**: JSONDecodeError 触发重试 1 次,仍失败则降级
2. **Pydantic 验证失败**: ValidationError 直接降级,不重试
3. **JSON 提取失败**: ValueError 触发重试 1 次,仍失败则降级
4. **日志完整性**: 所有解析失败都记录错误类型和 LLM 输出片段
运行完整测试套件:
```bash
python3 -m pytest tests/test_semantic_robustness.py::test_parse_failure_retry -v -x
```
</verification>
<success_criteria>
1. JSONDecodeError 重试 1 次后降级
2. ValidationError 直接降级,不重试
3. 所有解析失败都记录 warning 级别日志
4. 日志包含错误类型、错误消息、LLM 输出前 500 字符
5. 所有测试通过
</success_criteria>
<output>
执行完成后创建 `.planning/phases/14-robustness-cost/14-02-SUMMARY.md`
</output>