185 lines
6.7 KiB
Markdown
185 lines
6.7 KiB
Markdown
---
|
|
phase: 14-robustness-cost
|
|
plan: 01
|
|
type: execute
|
|
wave: 1
|
|
depends_on: []
|
|
files_modified:
|
|
- kb_workflow/srt/semantic_engine.py
|
|
autonomous: true
|
|
requirements:
|
|
- ROBUST-01
|
|
- ROBUST-03
|
|
must_haves:
|
|
truths:
|
|
- "LLM 调用失败时系统自动降级到规则分段,不影响整体流程"
|
|
- "AI 客户端不可用时(未配置 API key)使用规则分段"
|
|
- "LLM 响应解析失败时降级到规则分段"
|
|
artifacts:
|
|
- path: "kb_workflow/srt/semantic_engine.py"
|
|
provides: "UnifiedSegmentationStrategy.segment() 带重试和降级逻辑"
|
|
exports: ["segment", "_is_recoverable_error"]
|
|
key_links:
|
|
- from: "UnifiedSegmentationStrategy.segment()"
|
|
to: "规则分段器"
|
|
via: "fallback_segmenter.segment()"
|
|
pattern: "self.fallback_segmenter.segment"
|
|
- from: "UnifiedSegmentationStrategy.segment()"
|
|
to: "SimpleAIClient.generate()"
|
|
via: "LLM API 调用"
|
|
pattern: "self.ai_client.generate"
|
|
---
|
|
|
|
<objective>
|
|
实现 LLM 调用的优雅降级策略,确保 AI 不可用时系统仍能正常运行。
|
|
|
|
Purpose: 提高系统稳定性,避免 LLM 故障导致整个处理流程失败。
|
|
Output: 带重试和降级逻辑的 UnifiedSegmentationStrategy.segment() 方法。
|
|
</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
|
|
@kb_workflow/srt/corrector.py
|
|
@kb_workflow/deep_analyzer/__init__.py
|
|
</context>
|
|
|
|
<interfaces>
|
|
<!-- Key types and contracts from semantic_engine.py -->
|
|
|
|
From kb_workflow/srt/semantic_engine.py:
|
|
```python
|
|
class UnifiedSegmentationStrategy:
|
|
def __init__(
|
|
self,
|
|
ai_client: Optional[AIClientProtocol] = None,
|
|
fallback_segmenter: Optional['SemanticSegmenter'] = None
|
|
):
|
|
# Lazy AI Client 初始化
|
|
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
|
|
|
|
def segment(
|
|
self,
|
|
segments: List,
|
|
metadata: dict
|
|
) -> List['VideoSegment']:
|
|
# AI 不可用,直接使用规则分段
|
|
if self.ai_client is None:
|
|
logger.info("AI client unavailable, using fallback segmenter")
|
|
paragraphs = self.fallback_segmenter.segment(segments)
|
|
return [
|
|
VideoSegment(title=None, content=para, start_index=0, end_index=0)
|
|
for para in paragraphs
|
|
]
|
|
|
|
# 调用 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)
|
|
return video_segments
|
|
except Exception as e:
|
|
logger.error(f"LLM segmentation failed: {e}, using fallback")
|
|
paragraphs = self.fallback_segmenter.segment(segments)
|
|
return [VideoSegment(title=None, content=para, start_index=0, end_index=0) for para in paragraphs]
|
|
```
|
|
|
|
From kb_workflow/deep_analyzer/__init__.py (SimpleAIClient 重试模式):
|
|
- SimpleAIClient 已有内置重试逻辑 (max_retries=3)
|
|
- 使用 requests 库进行 HTTP 调用
|
|
- 可能抛出的异常: ConnectionError, Timeout, HTTPError
|
|
</interfaces>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto" tdd="true">
|
|
<name>Task 1: 实现可恢复错误检测和重试逻辑</name>
|
|
<files>kb_workflow/srt/semantic_engine.py</files>
|
|
<behavior>
|
|
- 添加 _is_recoverable_error() 方法判断错误类型
|
|
- 可恢复错误: ConnectionError, Timeout, HTTPError with status 429/500/502/503/504
|
|
- 不可恢复错误: 其他 HTTPError (4xx), JSONDecodeError, ValidationError
|
|
- 重试逻辑: 仅对可恢复错误重试 1 次
|
|
- 重试延迟: 立即重试(无延迟)
|
|
- 最后一次失败或不可恢复错误: 降级到规则分段
|
|
</behavior>
|
|
<action>
|
|
在 UnifiedSegmentationStrategy 类中添加:
|
|
|
|
1. _is_recoverable_error() 静态方法:
|
|
- 导入 requests.exceptions (ConnectionError, Timeout, HTTPError)
|
|
- 判断异常类型和状态码
|
|
- 返回 bool
|
|
|
|
2. 修改 segment() 方法的 LLM 调用部分:
|
|
- 添加 for 循环 (max_attempts = 2)
|
|
- 在 try-except 中捕获异常
|
|
- 检查是否可恢复且还有重试机会
|
|
- 可恢复: logger.info 重试, continue
|
|
- 不可恢复或最后一次: logger.warning 降级原因, break
|
|
|
|
3. 改进日志记录:
|
|
- 重试: info 级别, "LLM call failed (attempt 1/2): {error}, retrying..."
|
|
- 降级: warning 级别, "{error_type}: {error_message}, 降级到规则分段"
|
|
|
|
遵守用户决策: 重试 1 次, 仅可恢复错误重试, 立即重试。
|
|
</action>
|
|
<verify>
|
|
<automated>pytest tests/test_semantic_robustness.py::test_llm_failure_fallback -x</automated>
|
|
</verify>
|
|
<done>
|
|
- _is_recoverable_error() 方法正确识别可恢复/不可恢复错误
|
|
- LLM 调用失败时重试 1 次(可恢复错误)或直接降级(不可恢复错误)
|
|
- 降级时记录具体的错误类型和消息 (warning 级别)
|
|
- AI 不可用时 (ai_client is None) 直接使用规则分段,无重试
|
|
</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
## 整体验证标准
|
|
|
|
1. **功能验证**: LLM 调用失败时系统仍能返回分段结果(使用规则分段)
|
|
2. **重试验证**: 可恢复错误(网络错误、超时、限流)触发重试
|
|
3. **降级验证**: 不可恢复错误(API 错误、解析失败)直接降级,不重试
|
|
4. **日志验证**: 降级时记录具体原因,便于问题诊断
|
|
|
|
运行完整测试套件:
|
|
```bash
|
|
python3 -m pytest tests/test_semantic_robustness.py::test_llm_failure_fallback -v -x
|
|
```
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
1. LLM 调用失败时自动降级到规则分段,不中断处理流程
|
|
2. 可恢复错误(网络、超时、限流)重试 1 次后降级
|
|
3. 不可恢复错误(API 错误、解析失败)直接降级,不浪费配额
|
|
4. AI 客户端未配置时直接使用规则分段,无 LLM 调用
|
|
5. 降级时记录 warning 级别日志,包含错误类型和原因
|
|
6. 所有测试通过
|
|
</success_criteria>
|
|
|
|
<output>
|
|
执行完成后创建 `.planning/phases/14-robustness-cost/14-01-SUMMARY.md`
|
|
</output>
|