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

7.3 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
14-robustness-cost 02 execute 1
kb_workflow/srt/semantic_engine.py
true
ROBUST-02
ROBUST-04
truths artifacts key_links
LLM 响应解析失败时自动重试或降级
降级过程记录详细日志,包含错误类型和原因
Pydantic 验证失败时直接降级(不可恢复错误)
path provides exports
kb_workflow/srt/semantic_engine.py _parse_result() 带解析失败处理
_parse_result
from to via pattern
_parse_result() extract_json_from_llm_response() JSON 提取 extract_json_from_llm_response
from to via pattern
_parse_result() SegmentationResult Pydantic 验证 SegmentationResult(**data)
增强 LLM 响应解析的错误处理,区分解析失败类型并采取不同策略。

Purpose: 提高 LLM 输出格式不稳定时的容错能力,记录详细日志便于诊断。 Output: 改进的 _parse_result() 方法,带详细的错误日志和重试逻辑。

<execution_context> @/home/starmen1265/.claude/get-shit-done/workflows/execute-plan.md @/home/starmen1265/.claude/get-shit-done/templates/summary.md </execution_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

From kb_workflow/srt/semantic_engine.py:

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 捕获并降级
Task 1: 改进解析失败的错误处理和日志 kb_workflow/srt/semantic_engine.py - 区分 JSONDecodeError (无法提取 JSON) 和 ValidationError (Pydantic 验证失败) - JSONDecodeError 是可恢复错误(可能 LLM 输出格式问题),可以重试 - ValidationError 是不可恢复错误(数据结构错误),直接降级 - 所有解析失败都记录详细日志: - 错误类型 (JSONDecodeError/ValidationError/ValueError) - 错误消息 - LLM 输出前 500 字符(用于诊断) 修改 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 次。
pytest tests/test_semantic_robustness.py::test_parse_failure_retry -x - JSONDecodeError 和 ValueError 触发重试 1 次 - ValidationError 直接降级,不重试 - 所有解析失败都记录详细日志(错误类型 + LLM 输出片段) - 测试覆盖各种解析失败场景 ## 整体验证标准
  1. JSON 解析失败: JSONDecodeError 触发重试 1 次,仍失败则降级
  2. Pydantic 验证失败: ValidationError 直接降级,不重试
  3. JSON 提取失败: ValueError 触发重试 1 次,仍失败则降级
  4. 日志完整性: 所有解析失败都记录错误类型和 LLM 输出片段

运行完整测试套件:

python3 -m pytest tests/test_semantic_robustness.py::test_parse_failure_retry -v -x

<success_criteria>

  1. JSONDecodeError 重试 1 次后降级
  2. ValidationError 直接降级,不重试
  3. 所有解析失败都记录 warning 级别日志
  4. 日志包含错误类型、错误消息、LLM 输出前 500 字符
  5. 所有测试通过 </success_criteria>
执行完成后创建 `.planning/phases/14-robustness-cost/14-02-SUMMARY.md`