Files
ZNJJ-api-server/docs/assignment6-compat.md
T
Eric Wang 20e151b097 feat(services): register workflow-native driver keys in field registry
Workflow reconciliation (see previous commit) showed the 20261022
state variable really stores person identity under driver{i}ID /
driver{i}Phonenumber (x2), while the API get_info group keys
(sfzmhm{i}/sjhm{i}) have zero references in any workflow version -
the legacy group read always returned empty for workflow-produced data.

- registry: +4 keys (driver1/2ID, driver1/2Phonenumber) in
  human1/human2 groups, SENSITIVE, documented as synonymous with
  sfzmhm{i}/sjhm{i}; 24 -> 28 specs
- driver{i}License deliberately NOT registered: the sandbox reads
  state.hphm{i} and only renames the output for confirmation prompts -
  it is not a state key, set_info rejects it as unknown (workflow
  never consumes it)
- intentional diff documented: acdhuman1/2 group output now includes
  the driver keys (legacy FastGPT output did not) - fixes the legacy
  'workflow person data unreadable by group' gap; synonym merging
  (driver1ID vs sfzmhm1) deferred pending caller confirmation
- tests: registry size 28, driver keys present with sensitive level,
  License alias excluded

Verified: 230 unit tests
2026-10-22 23:40:27 +08:00

98 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 作业 6 兼容差异清单:LangGraph 业务状态 vs FastGPT 现状
> 范围:`/set_info`、`/get_info`、`/delete_session`、`/chat` 四个接口在
> `AGENT_BACKEND=langgraph` 下接入应用服务 + repository 后的行为差异。
> FastGPT 模式(`AGENT_BACKEND=fastgpt`)保留旧实现,不受影响。
## 接口响应契约(保持不变)
| 项 | 现状(FastGPT) | LangGraph(作业 6) |
|---|---|---|
| 请求/响应模型 | `ProcessRequest/Response_*` | 相同(endpoint 未改模型) |
| `get_info` 分组名 | `all` / `acdinfo` / `acdhuman1` / `acdhuman2` | 相同 |
| `get_info` 布尔外部表示 | `True→"1"`,`False→"0"`,未知→`""` | 相同(`to_external_string`) |
| `get_info` 未知 key | 返回 JSON 空串 `'""'` | **保持** `'""'`(现状兼容) |
| `includeInputInfo` 字段 | 触发 FastGPT 辅助对话 | 继续接受但**忽略**——新后端零辅助对话 |
## 有意的行为差异(新后端收紧)
| 项 | FastGPT 现状 | LangGraph | 理由 |
|---|---|---|---|
| `set_info` 未知 key | 任意 key 写入 state 变量 | **拒绝**(500 + "入参不规范:未知或受保护的字段 key") | 白名单保护;任意写入会污染图输入。上线前需审计旧调用方是否依赖任意 key 写入 |
| `set_info` 图内部键(`stage_code` 等) | 可写(state 是裸 dict) | **拒绝**(`INTERNAL_FIELD_KEYS` 保护) | 内部状态只允许图自己推进 |
| `set_info` 字段值 | 任意字符串原样存 | 按注册表类型解析(bool/int 严格),无法解析拒绝 | 保留 空/False/0/未知 区分,杜绝 `bool("0")` 陷阱 |
| 图表单键与业务键 | FastGPT state 为裸 dict,无映射概念 | 建立双向映射(作业 6):表单六键(`has_injury` 等)<-> acd 业务键(`ywrysw` 等);`bjrjs`/`ywmtc` 无表单来源,仅 `set_info` 可写 | 图的表单语义与 get_info 业务分组需要同一份事实 |
| LLM 调用 | set/get 走辅助对话 + 事后删记录 | **零 LLM 调用**(测试 spy 保证) | 成本与延迟;删除 race 消失 |
| 重复 `delete_session` | FastGPT SDK 行为未固定 | **幂等成功**(业务状态删除天然幂等;checkpoint 清理重复触发但缺失静默容忍) | 行为固定为测试 |
## 图表单键 <-> 业务键映射(作业 6 建立)
| 图表单键(accident_fields) | 业务键(acdinfo 分组) |
|---|---|
| `has_injury` | `ywrysw` |
| `has_non_motor_vehicle_hit` | `ywfjdc` |
| `is_on_scene` | `sfsgxc` |
| `vehicle_count` | `jdcsl` |
| `accident_time` | `sgfssj` |
| `accident_cause` | `sgyy` |
- chat 方向:repository 业务键经映射注入图为表单键(图只认表单语义)。
- 写回方向:图产出的表单键差量经映射落 repository 业务键,get_info 分组即可读到。
- `bjrjs`(报警人是否驾驶员)、`ywmtc`(是否撞摩托车)无表单来源:
不进入注入映射,仅支持 set_info 直写、get_info 直读。
## 与 workflow 20261022 的字段对账(2026-10-22 核对)
核对来源:`workflow/20261022/事故信息采集2025118.json`(已与 main@c7ca781 同步)
及历史版本 20250419—20261021。
| 注册表内容 | 对账结果 |
|---|---|
| 图表单六键(`has_injury` 等,FORM_FIELDS 白名单) | **一致**。workflow `form` 全局变量(bNJkeXot)初始即这六键;「更新表单」code 节点白名单语义(只遍历表单已有字段、无效值/同值筛除)与本服务 `_merge_form` 相同 |
| acd 业务八键(`ywrysw` 等) | **语义一致,出处不同**。八键全部出自 **20250419 版** workflow 的提取 schema(含 `sgyy` 事故原因);20251015 起 workflow 已弃用,API 代码自 a1a4bce 起沿用为对外契约。新后端注册表保留 = 兼容旧契约 |
| 人员分组键(`xm1/sfzmhm1/sfzmwh1/sjwh1/csbw1` 等每组 8 键) | **任何 workflow 版本都不存在**。系 API 服务端自定义契约(get_info 分组)。`sfzmwh/sjwh/csbw` 的全量覆盖是契约要求,与 workflow 无关 |
| 作业 6 表单键<->业务键映射(`has_injury`->`ywrysw` 等) | workflow 中**无此映射**——两侧键名从未在同一系统共存(workflow 只用表单键,API 只用业务键)。映射是迁移时按中文语义建立的桥(对照 20250419 提取 schema 的 desc 字段),属本服务新增语义,已双向测试固定 |
### 对账发现的一个真实差异
20261022 workflow 的 `state` 变量中人员信息键为
`driver1ID / driver1Phonenumber`(×2,sandbox 另把 `hphm1/2`
车牌改名 `driver{i}License` 输出给确认提示词——该名不是 state 键),
与 API `get_info` 分组键(`sfzmhm1/sjwh1/sjhm1` 等)**不同名**。
旧 FastGPT 实现按 API 分组键读 state,这些键在 workflow state 中
本就读空——属于既有行为。
**处理(2026-10-22 已落地)**:注册表把 workflow 原生键
`driver{i}ID / driver{i}Phonenumber`(×2,同义 sfzmhm/sjhm)
登记进 human1/human2 分组——
- set/get_info 单键直读写 driver 系键与旧 API 行为一致;
- **有意差异**:`acdhuman1/2` 分组输出现包含 driver 系键
(旧 FastGPT 分组输出没有它们)。调用方按 JSON 取键,多键无害;
这修正了旧实现"workflow 真实人员数据无法分组读到"的问题;
- `driver{i}License` 非 state 键,对其 set_info 按未知键拒绝
(workflow 不消费它);
- 同义键(driver1ID vs sfzmhm1)暂不合并:合并需调用方确认
实际使用侧后作为后续优化,已列入审计项。
## 待审计项(作业 6-7 要求的后续工作)
- [ ] 审计现有调用方是否存在对 `set_info` 任意 key 写入的依赖
(如动态自定义键)。存在则在注册表补登记或提供逃生口。
**对账新增**:workflow 20261022 state 人员键
(`driver1ID`/`driver1License`/`driver1Phonenumber` ×2)
与 API 分组键不同名——确认线上调用方实际使用哪套键名,
必要时注册表补别名。
- [x] ~~流式 `chat` 的 `formUpdate` 差量写回 repository~~
(完整版已实现:FormUpdate 事件捕获后经映射写回,见 `app_service.stream`)。
- [ ] `get_info` 返回值中的敏感字段(证件号/手机号)回显边界:
注册表已记录 `SensitiveLevel`,访问控制随作业 9 落地。
## 验证
- `test/services/test_fields_registry.py`:注册表完整性、类型/敏感级别、
外部表示、`bool("0")` 防线。
- `test/services/test_app_service.py`:四接口组合(set→get→chat 注入→
差量写回→分组读→删除→无泄漏),set/get/delete 零模型调用 spy,
重复删除幂等。
- `test/api/test_assignment6_endpoints.py`:HTTP 层验收演示链路。