[Bug]: FunctionAgent.structured_output_fn is ignored when executed via AgentWorkflow

用户通过 FunctionAgent 设置 structured_output_fn 回调,并期望在 agent 执行完毕后自动触发。在直接调用 agent.run() 时行为正常;但当该 agent 被放入 AgentWorkflow 并用 workflow.run() 驱动时,回调从未被调用。如

[Bug]: FunctionAgent.structured_output_fn is ignored when executed via AgentWorkflow

[Bug]: FunctionAgent.structured_output_fn is ignored when executed via AgentWorkflow

快速结论:该问题发生在将 FunctionAgent 放入 AgentWorkflow 中运行时——虽已在 FunctionAgent 上设置了 structured_output_fn 回调,但 AgentWorkflow 的完成处理中仅检查了自身(workflow 级别)的 structured_output_fn,忽略了 agent 级别的回调。优先排查是否在 workflow 运行代码中误用了 workflow.run(),且未手动将回调传递到 workflow。

问题场景

用户通过 FunctionAgent 设置 structured_output_fn 回调,并期望在 agent 执行完毕后自动触发。在直接调用 agent.run() 时行为正常;但当该 agent 被放入 AgentWorkflow 并用 workflow.run() 驱动时,回调从未被调用。如果回调附加到 workflow 实例上(即 AgentWorkflowstructured_output_fn 参数),则运行正常。这是一个 API 承诺与实际行为不一致的问题。

报错原文

# 无显式报错,但 structured_output_fn 回调未触发
# 在 AgentWorkflow 中 agent 完成后,回调函数 print("Structured output callback invoked") 未被打印
# 而在 agent.run() 下正常打印

原因分析

AgentWorkflow 的完成处理代码(multi_agent_workflow.py)中,当 agent 产生无工具调用(即 agent 已结束)时,流程仅检查 self.structured_output_fn(即 workflow 级别的回调),从未检查 agent.structured_output_fn。尽管 FunctionAgentstructured_output_fnbase_agent.py 中定义的模型字段(API 声称支持),但 workflow 路径直接忽略了它。

反观直接调用 agent.run() 时(base_agent.py 第 568 行附近),agent 自己的 structured_output_fn 会被正常调用,因此直接路径工作,但 workflow 路径不工作。

注意:以下解决方案在 Issue 中被认定为正确修复,但并未被最终合入(维护者通过关联线程处理了另一种修复方式)。请根据你的代码版本酌情参考。

环境排查

  • 确认 LlamaIndex 版本是否为 0.14.22(Issue 报告的版本)
  • 检查 FunctionAgent 对象是否拥有 structured_output_fn 属性:hasattr(agent, 'structured_output_fn')
  • 确认 AgentWorkflow 对象是否也设置了 structured_output_fn——如果有,则 workflow 级别优先,是正常行为
  • 确认 agent.run() 单独调用时回调是否触发——用于区分是代码级 bug 还是环境配置问题

解决步骤

  1. 优先尝试:structured_output_fn 直接传递给 AgentWorkflow 的构造函数:workflow = AgentWorkflow(agents=[agent], structured_output_fn=structured_output_fn)。这是 Issue 中的确认的
  2. 如果必须保持每个 agent 独立的回调,需要手动修改源码(或等待 LlamaIndex 更新)。在 multi_agent_workflow.py 的完成处理(if not ev.tool_calls 分支中)找到以下类似代码:
  3. # 在完成 agent 后,获取当前 agent 对象
    agent = self.agents[ev.current_agent_name]
    ...
    if self.structured_output_fn is not None:
        output.structured_response = await self.structured_output_fn(messages)
  4. 将上述判断修改为“当 workflow 级别的 structured_output_fn 未设置时,使用 agent 级别的作为回退”:
  5. effective_fn = self.structured_output_fn or agent.structured_output_fn
    if effective_fn is not None:
        if inspect.iscoroutinefunction(effective_fn):
            output.structured_response = await effective_fn(messages)
        else:
            output.structured_response = cast(Dict[str, Any], effective_fn(messages))
  6. 注意:修改后需保留异常捕获和 AgentStreamStructuredOutput 流事件写入(原代码中的 ctx.write_event_to_stream)。
  7. 重新安装或手动替换修改后的文件,测试 workflow.run() 逻辑。

验证方法

  • 运行复现脚本:设置 print("Structured output callback invoked") 在回调中,通过 workflow.run() 提交一条简单消息(如 “My name is Charlie”),确认控制台输出了该日志
  • 同时确保当 workflow 级别也设置了 structured_output_fn 时,workflow 级别回调仍然优先触发,且 agent 级别回调未被调用(回归测试)
  • 单独使用 agent.run() 运行同一 agent,确认回调仍然正常触发

参考来源

run-llama/llama_index #22159

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

celebrityanime
celebrityanime
文章: 11201

发表回复

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