feat(agent): use native parallel nodes and early reply streaming
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
# LangGraph 原生并行与流式输出
|
||||
|
||||
文本模型使用 ChatOpenAI,业务图嵌入 FastAPI。对外仍使用原来的
|
||||
stage_code / text_delta / formUpdate / done / error SSE 契约。
|
||||
|
||||
## 图内并行
|
||||
|
||||
事故采集阶段:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
P[normalize_input] --> R[collect:生成并校验回复]
|
||||
P --> X[extract_accident_fields:提取候选字段]
|
||||
R --> M[merge_collect]
|
||||
X --> M
|
||||
M --> C[应用服务事务提交]
|
||||
```
|
||||
|
||||
条件边只在采集阶段选中两个分支;welcome、拍照、人员核实走自己的分支。
|
||||
通过 `add_edge(["collect", "extract_accident_fields"], "merge_collect")`
|
||||
保证两个分支都完成后,汇合节点只运行一次。
|
||||
|
||||
`normalize_input` 固定服务器参考时间并清空本轮临时通道。回复节点只更新
|
||||
回复、阶段和对话簿记;提取节点只写 `extracted_accident_fields`;汇合节点
|
||||
更新 accident_fields / turn_patch,再清空候选通道。两条分支都读取本轮开始时
|
||||
的快照,不需要为并发写同一字段增加合并 reducer。
|
||||
|
||||
人员核实的提取提示词当前依赖本轮模型回复,并负责声明人员切换。
|
||||
本次保留它的串行依赖与提示词,仍能在抽取完成前发送完整回复。
|
||||
|
||||
## 原生流与校验
|
||||
|
||||
后端使用 LangChain `astream_events(version="v2")`,其生命周期管理负责
|
||||
消费期间的任务调度,以及流关闭后的取消与等待。
|
||||
|
||||
| 原生事件 | 条件 | 应用服务适配 |
|
||||
|---|---|---|
|
||||
| on_chain_stream | name=validated_reply_tokens | TextDelta |
|
||||
| on_chain_end | name=validated_reply | ReplyFinished,刷新分句器 |
|
||||
| on_chain_end | 根 accident_turn 正常结束 | 已提交结果,可发送 FormUpdate |
|
||||
|
||||
`validated_reply_tokens` 是原生 RunnableGenerator,封装现有模型文本迭代器,
|
||||
等待完整合法的 state 前缀后才产出第一段文本。原始 ChatOpenAI 的 model 事件
|
||||
仍可被 callbacks 追踪,但公开文本只消费受控回复 Runnable 的事件。
|
||||
原生 messages 流包含校验前 token,单纯按模型或节点过滤不能替代前缀校验。
|
||||
|
||||
`validated_reply` 是原生 RunnableLambda。完整回复通过格式、阶段转换和可选
|
||||
时间依据校验后,其正常 on_chain_end 才表示回复结束。模型结束事件本身
|
||||
不能证明这些业务校验通过,因此不作为刷新最后一句的依据。
|
||||
|
||||
字段提取保留 complete / ainvoke,显式 stream=False,避免事件追踪 callback
|
||||
把该调用隐式切换为流式。辅助模型输出不会映射为 TextDelta。
|
||||
|
||||
## 回复结束与事务完成
|
||||
|
||||
ReplyFinished 仅是后端中立适配层的内部标记,不新增公开 SSE 事件。
|
||||
它立即刷新 useTextChunk 的剩余完整回复,覆盖有/无字段差量和
|
||||
needFormUpdate=false 的情况。
|
||||
|
||||
文本可以早于提取和业务事务完成到达客户端;FormUpdate 与 done 仍在事务
|
||||
成功后出现。完整回复失败、图失败、业务提交失败时,发送 error 而不发送 done。
|
||||
已经输出的文字不可撤回,客户端仍以 done 判断本轮成功。
|
||||
|
||||
取消流时必须等图分支与模型关闭后才释放会话锁。持久化模式继续从业务提交
|
||||
快照恢复;并行分支产生的未提交 checkpoint 不成为业务成功状态。
|
||||
|
||||
## 验证
|
||||
|
||||
`test/backends/test_native_parallel_streaming.py` 使用事件屏障验证:
|
||||
|
||||
- 回复和抽取同时运行,汇合与提交等待两者完成。
|
||||
- 抽取阻塞时已经收到完整正文和 ReplyFinished。
|
||||
- 分句器最后一句及时刷新;公开 SSE 类型、文本顺序和终止事件保持兼容。
|
||||
- 抽取 JSON 不泄漏,原生节点和汇合在事件流中可见。
|
||||
- 断开取消剩余抽取,SQLite 未提交状态可恢复并重试。
|
||||
- 完整回复校验失败和业务提交失败均不产生虚假成功。
|
||||
- ChatOpenAI 的真实 HTTP mock 路径保留普通提取与流式回复的请求参数。
|
||||
|
||||
官方接口参考:
|
||||
|
||||
- https://docs.langchain.com/oss/python/langgraph/streaming
|
||||
- https://docs.langchain.com/oss/python/langgraph/use-graph-api
|
||||
Reference in New Issue
Block a user