这个坑值得记一笔。LangGraph 0.2 用条件边返回 [Send('worker', {'item': x}) for x in items],四个分片并发跑完,最终 state 里只剩最后一条,日志显示每次写入都把前一次覆盖了,改串行能保留数据但分片失去意义。

刚开始盯着「多个分支写同一个 key 没有合并规则」,折腾了半个多小时,排掉了。

真正麻烦的地方在于,几个原因的现象几乎一样。state 字段没配 reducer 默认就是覆盖;Send 的 payload 被当成完整 state 传入;checkpointer 并发写同一个 thread 冲突。

给列表字段加 Annotated 合并函数

python -c "from typing import Annotated;import operator;from typing_extensions import TypedDict;class S(TypedDict): items: Annotated[list, operator.add];print(S.__annotations__)"

然后分片节点只返回自己那一条结果

python -c "print({'items':['chunk-1']})"

接着用 graph.stream 看每一步写入

python run_graph.py --stream values --thread t1

最后核对 state 的条数与去重

python -c "import json;s=json.load(open('state.json'));print(len(s['items']),len(set(s['items'])))"

同事提醒我看一下最近一次发布,时间点确实对得上。

改完先别撤,确认这几项。四个分片结果全部保留,state 里列表长度为 4 且没有重复,再跑一次也不会累加旧数据。

提醒一点。reducer 只在同一个 superstep 内合并,跨轮对话的历史仍要自己做去重和裁剪。报错文案容易误导,真正的原因往往在相邻那一层的日志里。

作者 9823189