docs: 里程碑3.1 InferenceEngine 交付报告与进度账本

This commit is contained in:
lhl
2026-08-09 08:36:33 +08:00
parent 14062d1954
commit 1eb07db123
2 changed files with 78 additions and 0 deletions
+8
View File
@@ -12,3 +12,11 @@ M2.5 Task 11: complete (commits 539945b..1e3f702 + log bc79945, review approved)
M2.5 Task 12: complete (commit 7592516, review approved; minor: assert msg tweak for brief typo)
M2.5 Task 13: complete (commit d93cc77, review approved; minor: inline comments in test, enum-to-enum assert fine given literal-assert exists)
M2.5 FINAL: 整体评审通过(base 81c6b6c..d93cc7758 passed,无 skip; Minor backlog unchanged (progress dedup done this edit; log 范式步骤 "整体迭代"→"反馈迭代" for Task13 row; delivery report docs/milestone2-5-mixed-parser-review.md pending creation)
M3.1 IE Task 1: dispatch (base 2fbff07)
M3.1 IE Task 1: complete (commit c2fad77, review clean; Minor backlog: types.py unused Any import, test_inference_errors.py unused pytest import, __init__.py missing trailing newline — all verbatim from brief)
M3.1 IE Task 2: complete (commit 71d38b9, review clean; Minor: unused pytest import in token test, weak fake-encoder discrimination, check _AI_USAGE_LOG mid-table blank line)
M3.1 IE Task 3: complete (commit 59c1ea7, review clean; Minor: unused Prompt import in prompt_registry, duplicate jinja2 import)
M3.1 IE Task 4: complete (commit per git log, review clean; Minor backlog: retry_backoff consumed via time.sleep affects latency in real calls, client not closed via __enter__ context manager)
M3.1 IE Task 4: complete (commit add7b15, review clean; Minor: 5xx chain message redundancy, test comment mismatch 0.01, un-typed 3xx/malformed-JSON JSONDecodeError passthrough - leave to Task5/engine fold)
M3.1 IE Task 5: complete (commit 8bc5e5e, review clean 3 deviations all justified; Minor: for-loop var name in failed chat, test import hygiene, raw-template leak known tradeoff, api-design patch +source column slight overreach)
M3.1 IE final review: base 2fbff07..8bc5e5e -> With fixes; fixed 2 Important (LLMResponseError wrap for malformed 2xx, explicit 2xx check re 3xx); Issue3 chat_structured no model fallback confirmed intentional per plan L1142 (v1 single-model, prod passes explicit model); Minors logged (LLMResponseError now live, truncation in chat_structured, prompt renderer duplicate import, prompts-dir load not v1, no context manager, last-error only)
+70
View File
@@ -0,0 +1,70 @@
# 里程碑 3.1 InferenceEngine 交付报告
## 1. 概述
完成 `agent-runtime-design.md` §2 定义的推理引擎(InferenceEngine),为多 Agent 协作提供统一 LLM 调用入口:模型选择/降级、重试、超时、Token 管理、Prompt 注册表与结构化输出。全程 TDD、零真实网络、覆盖率红线 100% 达成。
- **评审对象**`docs` 阶段(spec + plan)经 plan-design-review 批准后,实施提交范围 `2fbff07..HEAD`(共 6 个 commit
- **验收结论**With fixes → 2 项 Important 已修复 → 重新验证 **Ready**117 passed / 100% 覆盖)
## 2. 交付内容
| 模块 | 文件 | 说明 |
|------|------|------|
| 数据模型 | `src/genesis/inference/types.py` | TokenUsage / ChatMessage / ChatResult / StructuredResult / Prompt |
| 异常体系 | `src/genesis/inference/exceptions.py` | LLMError 五类:Network / Timeout / NotConfigured / ResponseError |
| Token 估算 | `src/genesis/inference/token.py` | approximate4 字符≈1 token+ tiktoken 可选懒加载回落 |
| Prompt 注册表 | `src/genesis/inference/prompt_registry.py` | register / get / list_versions / renderjinja2 |
| LLM 客户端 | `src/genesis/inference/client.py` | LLMClient Protocol + HttpLLMClientOpenAI 兼容) |
| 编排引擎 | `src/genesis/inference/engine.py` | InferenceEnginechat / chat_structured |
| 测试 | `tests/test_inference_{types,errors,token,prompt_registry,client,engine}.py` + `tests/inference_helpers.py` | 全部离线用例 |
## 3. 关键设计决策
1. **httpx 选型**`httpx.Client(timeout=..., transport=...)` 支持 transport 注入(MockTransport 离线测试);5xx/网络错误指数退避重试(1s/3s/7s),超时→LLMTimeoutError4xx 不重试→LLMNetworkError2xx 结构损坏→LLMResponseError3xx 不误判成功。
2. **结构化重试语义**`chat_structured` 对 JSON 解析失败带错误信息重试(retry_count+1),重试成功仍为 `status="ok"`(fallback 语义保留给模型降级);最终失败返回 `parse_error` + raw_text,不抛异常(spec §3.4 验收 3)。
3. **异常折叠边界**`chat` 失败降级备用模型(status=fallback),双模型全败 status=failed;仅折叠 LLMError,非 LLM 异常照常冒出。
4. **显式延后(非目标)**
- `chat_structured` 不做模型降级——plan 明确「生产建议显式传主模型,实现已足够 v1」(plan L1142),结构化重试固定主模型。
- Prompt 目录加载(`prompts/{name}/{version}.txt`)为 v2v1 仅代码内注册。
- LLMResponseError 在 v1.0 spec 已定义但无触发点,最终评审后补齐(见 §5)。
## 4. 测试与验证
- 聚焦测试:各模块 RED→GREEN 全绿(types 8 / token 7 / registry 6 +1 / client 9 / engine 16
- 全量回归:`python -m pytest -q`**117 passed / 覆盖率 100.00%785 stmts / 186 br**`fail_under=99` 达成
- 零真实网络:单测全部注入 FakeLLMClient / httpx.MockTransport`DEEPSEEK_API_KEY` 不落代码
- 基线不回退:既有 parsers / data_models / config 全绿保持
## 5. 最终评审(base 2fbff07 → 8bc5e5e)与修正
评审判定 **With fixes**(无 Critical2 项 Important;若干 Minor):
1. **[已修复] 响应结构异常逃逸**:2xx 畸形响应(非 JSON / 缺 choices 字段)抛裸 `KeyError/JSONDecodeError`,逃出 engine 的 `except LLMError`,与「不把异常抛给调用方」承诺冲突。修复:client 内捕获 `(json.JSONDecodeError, KeyError, IndexError, TypeError)``raise LLMResponseError`(spec §3.8 既有类型首次被触发,闭环 api-design §7 LLM_PARSE_ERROR 来源列)。TDD:新增 `test_chat_3xx_no_retry``test_chat_malformed_response_raises_llm_response_error`
2. **[已修复] 3xx 误判成功**:httpx 默认不跟随重定向,301/302 落入成功路径。修复:显式 `200 <= resp.status_code < 300` 判定,非 2xx 一律 LLMNetworkError(不重试)。
3. **[确认为有意] chat_structured 无模型降级**plan 已声明 v1 单模型链,生产显式传主模型,非回归缺陷。
4. **[Minor 挂账 backlog]**`chat` 失败仅保留最后一次模型错误信息;`__init__.py` 缺尾换行;prompt_registry 模块级 jinja2 导入冗余;chat_structured 未做 token 超限检测;HttpLLMClient 无 `__enter__/__exit__`(调用方负责关闭生命周期)。
修复提交 `14062d1`(fix: 客户端响应结构损坏归入 LLMResponseError3xx 不再误判成功)。
## 6. 提交清单
```
c2fad77 feat: 推理引擎数据模型与异常层(types/exceptions)及 httpx/jinja2 依赖
71d38b9 feat: Token 估算(approximate 内置 / tiktoken 可选回落)
59c1ea7 feat: PromptRegistry 注册/版本/渲染(jinja2
add7b15 feat: HttpLLMClienthttpx + 重试退避/超时/鉴权)
8bc5e5e feat: InferenceEngine chat/chat_structured 全流程 + 文档补丁(补丁1/2/3)
14062d1 fix: 客户端响应结构损坏归入 LLMResponseError3xx 不再误判成功
```
## 7. 涉及文件
- 新建:`src/genesis/inference/{types,exceptions,token,prompt_registry,client,engine}.py``tests/inference_helpers.py``tests/test_inference_{types,errors,token,prompt_registry,client,engine}.py`
- 修改:`src/genesis/inference/__init__.py``pyproject.toml`httpx/jinja2 依赖)、`docs/agent-runtime-design.md``docs/api-design.md``docs/config-design.md`
- 文档:spec `docs/superpowers/specs/2026-08-09-inference-engine-design.md`、plan `docs/superpowers/plans/2026-08-09-inference-engine.md`
## 8. 后续工作
- 接入 Parser Agent 自由记述型结构化(待后续里程碑)
- LLMResponseError 已闭环,可为 engine 增加按错误分类的重试选项(api §7 retry/skip/abort UX