[Bug] merge_dicts concatenates identical string metadata fields across streaming chunks (model_name, finish_reason doubled)

用户通过 langchain_openrouter.ChatOpenRouter 调用模型 deepseek/deepseek-v4-pro-20260423 ,并使用 .stream("Hello") 方法手动聚合块。当 AI 提供商(OpenRouter)发送两个包含相同 model_name

[Bug] merge_dicts concatenates identical string metadata fields across streaming chunks (model_name, finish_reason doubled)

[Bug] merge_dicts concatenates identical string metadata fields across streaming chunks (model_name, finish_reason doubled)

快速结论:该 bug 在使用 LangChain 的 .stream().astream() 方法并从 AI 提供商(如 OpenRouter)接收多个终端块时触发。优先排查 langchain-core_merge.py 文件的 merge_dicts 函数版本。

问题场景

用户通过 langchain_openrouter.ChatOpenRouter 调用模型 deepseek/deepseek-v4-pro-20260423,并使用 .stream("Hello") 方法手动聚合块。当 AI 提供商(OpenRouter)发送两个包含相同 model_namefinish_reason 的终端块时,response_metadata 中的这些字符串字段值会直接拼接(doubled),而非去重。

报错原文

print(final.response_metadata.get("model_name"))
# Output:  "deepseek/deepseek-v4-pro-20260423deepseek/deepseek-v4-pro-20260423"
# Expected: "deepseek/deepseek-v4-pro-20260423"

print(final.response_metadata.get("finish_reason"))
# Output:  "stopstop"
# Expected: "stop"

原因分析

根本原因在于 langchain-corelibs/core/langchain_core/utils/_merge.py 文件中,merge_dicts 函数在合并相同字符串值时缺少去重逻辑。当 AIMessageChunk.__add__ 聚合块时,会调用 merge_dicts,但该函数仅对 idoutput_versionmodel_provider 三个键做了相等值跳过处理,而 model_namefinish_reasonobjectsystem_fingerprintformat 等字段则直接执行 merged[right_k] += right_v,导致相同字符串被拼接。

环境排查

  • 确认使用的 langchain-core 版本是否包含修复(参考 Issue 中建议的 PR 修改)。
  • 检查 libs/core/langchain_core/utils/_merge.pymerge_dicts 函数的 allowlist 是否已扩展。
  • 如果使用 .invoke() 方法,此 bug 不会出现(只有 streaming 才会触发)。

解决步骤

  1. 优先尝试:升级 langchain-core 到包含此修复的版本(查看 langchain-ai/langchain #38366 的 PR 记录,确认修复已合并的版本号)。
  2. 手动修复建议:若未更新,可自行修改 merge_dicts 函数,在 allowlist 中添加缺失的键:
# 修改前(仅跳过3个键)
if (right_k == "index" and merged[right_k].startswith("lc_")) or (
    right_k in {"id", "output_version", "model_provider"}
    and merged[right_k] == right_v
):
    continue
merged[right_k] += right_v
# 修改后(扩展 allowlist)
if (right_k == "index" and merged[right_k].startswith("lc_")) or (
    right_k in {
        "id", "output_version", "model_provider",
        "model_name", "finish_reason", "native_finish_reason",
        "object", "system_fingerprint", "format",
    }
    and merged[right_k] == right_v
):
    continue
merged[right_k] += right_v
  1. 保存修改后,重新安装或重启应用以使更改生效。

验证方法

运行 Issue 中给出的重现代码,检查 final.response_metadata.get("model_name")final.response_metadata.get("finish_reason") 是否输出正确值(不再包含重复字符串)。例如:

model_name: deepseek/deepseek-v4-pro-20260423(而非两次拼接)
finish_reason: stop(而非 "stopstop")

参考来源

langchain-ai/langchain #38366

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

celebrityanime
celebrityanime
文章: 10679

发表回复

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