feat(agent): domain events and transition whitelist validation (assignment 3)

Architecture (mirrors workflow/20261016 chatNode structure):
- events.py: client markers parsed to typed ClientEvent (sources
  verified against workflow JSON); plain text like '拍好了' is not an event
- transitions.py: LEGAL_TRANSITIONS whitelist drafted from chatNode
  prompts and Condition edges (16 entries, each with source_ref);
  is_legal_transition rejects unlisted/terminal-violating moves
- graph.py: multi-node graph (collect/single_photo/dual_photo/...
  matching workflow chatNodes), route_by_stage conditional edges,
  _fake_llm_propose simulates LLM stage-code proposals (assignment 4
  replaces with real LLM); code only keeps context bookkeeping
  (no_reply_count) and validation
- state.py: expanded domain fields (pending_question, accident/
  person fields, clarify/no-reply counts, turn_patch, state_version)

Key finding: 单车拍照#6/双车拍照#7 are browser_addon branches ending
at 0000, so 2005/2015 allow both 300x (direct) and 0000.

Verified: pytest 87 passed (24 transition/event tests newly green).
Known limit: stage proposals come from a fake LLM; per-stage scripts
and real LLM integration are assignments 4-5.
This commit is contained in:
Eric Wang
2026-10-19 16:25:04 +08:00
parent 5d68b731d4
commit 8323d53a70
7 changed files with 582 additions and 68 deletions
+2 -2
View File
@@ -142,12 +142,12 @@ python -m pytest test/agent/test_scaffold.py -q
1. 扩充 state:内部阶段、原始状态码、待回答问题、事故字段、两方人员字段、字段确认状态、澄清计数、无回复计数、本轮 patch、响应文本和业务版本。
2. 使用 Pydantic 校验边界数据;图 state 保持可序列化,不保存 HTTP client、连接、音频和图片 base64。
3. 在 API/应用边界把 `【拍摄完成】`、`【用户无回复】`、`【客户端连续3次拍摄识别失败:原因】` 转成明确事件。图内部按事件类型处理,普通“拍好了”不能当完成事件。
4. 建立带来源的转换表,至少包含 `0000—0005`、`1001/1002`、单车、双车和 `3001/3002`。转换条件必须读取字段和当前问题,不能只判断两个状态码。
4. 图结构对齐工作流节点:事故信息收集、单车拍照、双车拍照、信息确认各为独立节点(对照 `workflow/20261016/事故信息采集2025118.json` 的 chatNode),节点间用条件边按 `stage_code` 路由(对照 Condition#2/#7/#9 等分支)。节点内部的小步推进(拍照步骤、分流判断)由节点内 LLM 提出目标阶段码——模型负责自然语言,代码按白名单(`transitions.LEGAL_TRANSITIONS`)校验,非法提议不写状态(受控修复重试在作业 4-10);白名单条目必须对照工作流提示词与条件边登记来源,不能只凭状态码相像填写。所有 stage_code(含拍照失败 → 0005、连续两次无回复 → 0004)都由节点内 LLM 提议,代码只负责事件解析、无回复计数等上下文簿记与合法性校验,不代替模型决定。
5. 拍照失败通知收到一次就产生 `0005`;客户端已经完成三次统计,服务端不得再累计三次。
6. 连续两次无回复产生 `0004`,中间有效回复如何重置计数必须有测试。
7. 把“本轮输出字段”在每轮开始时清空;历史事故字段继续保留,避免旧 `formUpdate` 在下一轮重复返回。
**交付物:** `events.py`、`transitions.py`、状态模型、规则来源表、参数化转换测试。
**交付物:** `events.py`、`transitions.py`(节点内确定性规则)、按工作流拆分的多节点图(`graph.py`)、状态模型、规则来源表、参数化转换测试。
**验收:** 无模型调用即可走完拍照事件链;在拍照中输入“继续”保持当前步骤;非法跨阶段转换不写状态;明确的转人工事件可以终止当前流程。