[Bug]: ag-ui get_default_workflow_factory shares the initial_state dict across every AGUIChatWorkflow it produces

用户在 LlamaIndex 的 AG-UI 协议模块中使用 get_default_workflow_factory 创建多个 AGUIChatWorkflow 实例时,不同的工作流实例本应拥有独立的初始状态。但实际由于 initial_state 参数在传入时是同一字典引用,导致泄漏。

[Bug]: ag-ui get_default_workflow_factory shares the initial_state dict across every AGUIChatWorkflow it produces

[Bug]: ag-ui get_default_workflow_factory shares the initial_state dict across every AGUIChatWorkflow it produces

快速结论:此 Bug 导致通过 get_default_workflow_factory 创建的所有 AGUIChatWorkflow 实例共享同一个 initial_state 字典对象,造成跨工作流的意外状态泄露。优先排查 AGUIChatWorkflow.__init__ 中是否使用直接赋值而非深拷贝,并在工厂函数内部对 initial_statecopy.deepcopy

问题场景

用户在 LlamaIndex 的 AG-UI 协议模块中使用 get_default_workflow_factory 创建多个 AGUIChatWorkflow 实例时,不同的工作流实例本应拥有独立的初始状态。但实际由于 initial_state 参数在传入时是同一字典引用,导致泄漏。

报错原文


a.initial_state IS b.initial_state: True

# Direct leak: mutate a -> visible on b and on the operator dict.
a.initial_state["secret_for_alice"] = "API-KEY-ALICE-12345"
print("b.initial_state['secret_for_alice']:", b.initial_state.get("secret_for_alice"))
# Output: API-KEY-ALICE-12345

原因分析

get_default_workflow_factory 定义的内层 workflow_factory() 闭包捕获了操作符的 initial_state 字典,并以引用方式传给每个 AGUIChatWorkflow 实例。同时 AGUIChatWorkflow.__init__ 通过 self.initial_state = initial_state or {} 直接存储引用,而非深拷贝。此外,chat 步骤中对 self.initial_state 的浅拷贝 state = self.initial_state.copy() 也导致嵌套可变对象(如 items: []user: {"roles": []})跨请求别名共享。

环境排查

  • LlamaIndex 版本:确认使用的版本,GitHub Issue 中涉及版本为 llama-index-protocols-ag-ui==0.3.1
  • 确认是否存在相关 Issue #22066 中的 AGUIChatWorkflow.aggregate_tool_calls 类似问题。
  • Python 环境是否安装了 llama-index-protocols-ag-ui 及相关依赖。

解决步骤

  1. 确认 Bug 位置:检查 llama_index/protocols/ag_ui/router.py 中的 get_default_workflow_factory 函数,确认闭包中 initial_state 是否为直接引用。
  2. 检查 AGUIChatWorkflow.__init__llama_index/protocols/ag_ui/agent.py 中找到 self.initial_state = initial_state or {},确认是否为直接赋值。
  3. 修改 router.py 中的工厂函数:initial_state 传入前使用 copy.deepcopy(initial_state) 包装,确保每个工作流获得独立副本。
  4. 修改 agent.py 中的 chat 步骤:state = self.initial_state.copy() 替换为 state = copy.deepcopy(self.initial_state),避免嵌套可变对象别名问题。
  5. 可优先尝试:如果无法修改源代码,考虑在调用 get_default_workflow_factory 时为每个工作流传入独立的 initial_state 副本(如 copy.deepcopy(shared))。

验证方法

运行 Issue 中提供的复现代码,检查 a.initial_state is b.initial_state 是否为 False,且对其中一个工作流的 initial_state 进行修改不会影响另一个工作流或原始操作符的字典。

参考来源

run-llama/llama_index #22069

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

celebrityanime
celebrityanime
文章: 11188

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注