bug(python-sdk): Streaming tool calls are missing `id` and `type` fields in generation output, causing UI to incorrectly show “not called”

用户通过 langfuse.openai.AsyncOpenAI 或同步客户端包装器执行流式( stream=True )ChatCompletion 请求,且模型触发工具调用时。Langfuse UI 中 Tools 选项卡下所有工具均显示 "not called",尽管工具已被成功调用。

bug(python-sdk): Streaming tool calls are missing `id` and `type` fields in generation output, causing UI to incorrectly show "not called"

bug(python-sdk): Streaming tool calls are missing `id` and `type` fields in generation output, causing UI to incorrectly show “not called”

快速结论:该报错发生在使用 Langfuse 的 OpenAI 包装器进行流式 ChatCompletion 调用时。由于 Python SDK 的流式积累逻辑未正确保留工具调用(tool_calls)中的 `id` 和 `type` 字段,导致 Langfuse UI 将已成功调用的工具错误显示为 “not called”。优先检查 `langfuse-python` 版本并应用 Issue 中提出的补丁。

问题场景

用户通过 langfuse.openai.AsyncOpenAI 或同步客户端包装器执行流式(stream=True)ChatCompletion 请求,且模型触发工具调用时。Langfuse UI 中 Tools 选项卡下所有工具均显示 “not called”,尽管工具已被成功调用。

报错原文

# 原始 trace payload 中缺少 id 和 type 字段
"output": {
    "role": "assistant",
    "tool_calls": [
        {
            "function": {
                "name": "ReadFile",
                "arguments": "{\"path\": \"test.txt\"}"
            }
        }
    ]
}

# 非流式场景的正确输出
"output": {
    "role": "assistant",
    "tool_calls": [
        {
            "id": "call_123456789", 
            "type": "function",
            "function": {
                "name": "ReadFile",
                "arguments": "{\"path\": \"test.txt\"}"
            }
        }
    ]
}

原因分析

根本原因位于 langfuse/openai.py 中的 _extract_streamed_openai_response 方法(langfuse-python v3.14.5)。在流式工具调用 delta 的积累逻辑中(约第 663-700 行),代码仅提取了 function 属性:

  • tool_call_chunk = getattr(delta.get("tool_calls", None)[0], "function", None)

该行完全忽略了原始 delta 对象中的 idtype 字段,导致最终 Generation 输出缺失这两个关键字段。

此外,Issue #12490 报告了另一个相关流式 bug:当非空的 content 块在 tool_calls 块之前到达时,get_response_for_chat() 中的短路逻辑会直接丢弃 tool_calls。后端 PR #10847 已修复归一化逻辑以正确保留 idtype,但前提是 Python SDK 正确发送这些字段。

环境排查

  • 确认 langfuse-python 版本(报错时为 v3.14.5,建议升级到最新版或确认当前版本是否存在该问题)。
  • 确认 Langfuse 服务版本(自托管时为 v3.155.1)。
  • 确认使用的 OpenAI 客户端类型(Async/Sync)及流式标志(stream=True)。
  • 检查 Langfuse trace payload 中 tool_calls 是否缺少 idtype 字段。

解决步骤

  1. 定位源代码:找到 langfuse/openai.py 中的 _extract_streamed_openai_response 函数。
  2. 修改积累逻辑:在函数内部,将原始 delta 对象中的 idtype 字段提取出来并附加到累积的 tool_calls 数组中。参考代码:
    raw_tc = delta.get("tool_calls", None)[0]
    tool_call_chunk = getattr(raw_tc, "function", None)
    tc_id = getattr(raw_tc, "id", None)
    tc_type = getattr(raw_tc, "type", None)
    然后将 tc_idtc_type 合并到累积的 tool_calls 对象中。
  3. 可优先尝试:由于 Issue 提交者已本地验证该修改有效,可直接应用上述补丁。
  4. 等待官方修复:该 Issue 已被标记为未确认 bug 且已僵化。如果不想手动补丁,建议持续关注 langfuse-python 仓库的更新。

验证方法

修改后,执行一次流式 ChatCompletion 请求并触发工具调用。通过 Langfuse API 或 Trace 列表检查 Generation 的 raw payload,确认 output 中的 tool_calls 数组包含 idtype 字段。然后在 Langfuse UI 中打开该 Trace 的 Tools 选项卡,确认工具不再显示 “not called”,而是显示正确的调用状态。

参考来源

langfuse/langfuse #12491

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

celebrityanime
celebrityanime
文章: 9045

发表回复

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