docs: 里程碑3.1 InferenceEngine 交付报告与进度账本
This commit is contained in:
@@ -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..d93cc77,58 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)
|
||||
|
||||
@@ -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` | approximate(4 字符≈1 token)+ tiktoken 可选懒加载回落 |
|
||||
| Prompt 注册表 | `src/genesis/inference/prompt_registry.py` | register / get / list_versions / render(jinja2) |
|
||||
| LLM 客户端 | `src/genesis/inference/client.py` | LLMClient Protocol + HttpLLMClient(OpenAI 兼容) |
|
||||
| 编排引擎 | `src/genesis/inference/engine.py` | InferenceEngine:chat / 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),超时→LLMTimeoutError,4xx 不重试→LLMNetworkError,2xx 结构损坏→LLMResponseError,3xx 不误判成功。
|
||||
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`)为 v2,v1 仅代码内注册。
|
||||
- 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**(无 Critical;2 项 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: 客户端响应结构损坏归入 LLMResponseError;3xx 不再误判成功)。
|
||||
|
||||
## 6. 提交清单
|
||||
|
||||
```
|
||||
c2fad77 feat: 推理引擎数据模型与异常层(types/exceptions)及 httpx/jinja2 依赖
|
||||
71d38b9 feat: Token 估算(approximate 内置 / tiktoken 可选回落)
|
||||
59c1ea7 feat: PromptRegistry 注册/版本/渲染(jinja2)
|
||||
add7b15 feat: HttpLLMClient(httpx + 重试退避/超时/鉴权)
|
||||
8bc5e5e feat: InferenceEngine chat/chat_structured 全流程 + 文档补丁(补丁1/2/3)
|
||||
14062d1 fix: 客户端响应结构损坏归入 LLMResponseError;3xx 不再误判成功
|
||||
```
|
||||
|
||||
## 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)
|
||||
Reference in New Issue
Block a user