fix(backends): make streamed replies and session state consistent
- Validate stage prefixes before forwarding model tokens. Invalid prefixes may use the existing repair budget; once output starts, validation failure aborts the turn without appending a regenerated reply. Bound the token queue and close inner streams when consumption stops. - Replace delete-time lock eviction with reference-counted session locks covering holders and waiters. Serialize set/get with chat/stream/delete and release cancelled waiters without replacing a live lock. - Store person synonyms under workflow-native driver keys and expose consistent alias views to single/group reads and graph prompt injection. - Separate committed field patches from public formUpdate visibility. Commit callbacks keep repository fields synchronized even when updates are hidden or the consumer closes after graph completion. - Disable OpenAI SDK automatic retries. Own bounded retry attempts in the application, use 1/2/4 second backoff, retry streams only before text is emitted, enforce attempt timeouts, and close upstream/client resources. - Translate FastGPT SDK max_retries (total attempts) from the configured extra-retry count, and verify the real SDK loop uses four attempts. - Document the per-LLM budget and streaming failure semantics without claiming the whole multi-call HTTP turn has the same timeout. Validation: 267 offline tests passed, including actual SDK requests through MockTransport, stream repair/abort, timeout/close, lock races, aliases and formUpdate visibility; existing four dependency deprecation warnings.
This commit is contained in:
@@ -71,22 +71,42 @@
|
||||
这修正了旧实现"workflow 真实人员数据无法分组读到"的问题;
|
||||
- `driver{i}License` 非 state 键,对其 set_info 按未知键拒绝
|
||||
(workflow 不消费它);
|
||||
- 同义键(driver1ID vs sfzmhm1)暂不合并:合并需调用方确认
|
||||
实际使用侧后作为后续优化,已列入审计项。
|
||||
- 同义键统一存储:`sfzmhm{i}` 与 `driver{i}ID` 共用后者,
|
||||
`sjhm{i}` 与 `driver{i}Phonenumber` 共用后者。单键和分组读取
|
||||
继续提供两套键名;图输入同时注入一致的别名视图,避免旧 driver 值
|
||||
遮盖 API 键的新值。同一批差量包含相互冲突的别名值时拒绝提交。
|
||||
|
||||
## 待审计项(作业 6-7 要求的后续工作)
|
||||
|
||||
- [ ] 审计现有调用方是否存在对 `set_info` 任意 key 写入的依赖
|
||||
(如动态自定义键)。存在则在注册表补登记或提供逃生口。
|
||||
**对账新增**:workflow 20261022 state 人员键
|
||||
(`driver1ID`/`driver1License`/`driver1Phonenumber` ×2)
|
||||
与 API 分组键不同名——确认线上调用方实际使用哪套键名,
|
||||
必要时注册表补别名。
|
||||
workflow 人员键 `driver{i}ID` / `driver{i}Phonenumber` 及对应
|
||||
API 别名均已登记并统一存储;`driver{i}License` 只是车牌的
|
||||
输出名称,外部写车牌继续使用 `hphm{i}`。
|
||||
- [x] ~~流式 `chat` 的 `formUpdate` 差量写回 repository~~
|
||||
(完整版已实现:FormUpdate 事件捕获后经映射写回,见 `app_service.stream`)。
|
||||
(图提交时即同步业务字段;FormUpdate 是否返回不影响写回)。
|
||||
- [ ] `get_info` 返回值中的敏感字段(证件号/手机号)回显边界:
|
||||
注册表已记录 `SensitiveLevel`,访问控制随作业 9 落地。
|
||||
|
||||
## 流式、并发与字段一致性约定
|
||||
|
||||
- 阶段前缀先缓冲并按当前节点的转换规则校验,非法前缀不推送;
|
||||
未输出时仍可使用一次修复预算。已开始输出后,全文格式或时间依据
|
||||
校验失败会以错误终止,不在同一流中拼接修复答案,不提交本轮业务字段。
|
||||
已经到达客户端的正文不可撤回;客户端只在收到 done 后将一轮视为成功。
|
||||
- 会话锁引用包括持有者与等待者,只有最后一个使用者退出才回收。
|
||||
chat、stream、set、get、delete 全部按同一会话串行;不同会话独立。
|
||||
取消流时先关闭内部生成器、取消图任务,再释放会话锁。
|
||||
- needFormUpdate 只决定对外是否返回差量。图提交时通过内部回调同步
|
||||
repository,关闭差量显示或消费者在提交后断开不会丢失业务字段。
|
||||
- SDK 自动重试关闭,由应用层统一控制;默认首次尝试加 3 次重试,
|
||||
每次尝试总超时 60 秒,退避 1、2、4 秒。单次 LLM 调用理论预算
|
||||
4×60+1+2+4=247 秒(另有响应关闭的清理时间)。FastGPT SDK 的
|
||||
max_retries 实际代表总尝试数,适配层传入 4 以表达额外重试 3 次;
|
||||
其 timeout 是 HTTP SDK 超时,不将它等同于整个多节点请求总期限。
|
||||
流式首个文本 token 前可重试,发出文本后失败则终止,不重放。
|
||||
该预算并非整个多次 LLM 调用的聊天回合总超时。
|
||||
|
||||
## 验证
|
||||
|
||||
- `test/services/test_fields_registry.py`:注册表完整性、类型/敏感级别、
|
||||
|
||||
Reference in New Issue
Block a user