AIMessage.content_blocks mutates Bedrock Converse message content

该报错发生在 LangChain 中通过 Bedrock Converse 模型提供商读取 AIMessage.content_blocks 属性时,翻译器直接修改了原始消息内容,导致源消息被污染、连续两次读取返回不同结果。优先检查是否使用了 bedrock_converse 作为 model_pr

快速结论:该报错发生在 LangChain 中通过 Bedrock Converse 模型提供商读取 AIMessage.content_blocks 属性时,翻译器直接修改了原始消息内容,导致源消息被污染、连续两次读取返回不同结果。优先检查是否使用了 bedrock_converse 作为 model_provider,并确保 langchain-core 已更新到包含修复的版本。

适用环境:langchain-core 包;使用 Bedrock Converse 模型提供商(model_provider: "bedrock_converse")的场景;涉及 AIMessageAIMessageChunk

最快修复方案:升级 langchain-core 到包含修复的最新版本。Issue 确认的修复方式是在 bedrock_converse.py_convert_to_v1_from_converse() 函数中,对字符串内容使用局部列表转换、对未识别块进行浅拷贝后再移动 index 字段,避免修改原始消息内容。尚未确认具体修复版本号。

注意事项:修复仅针对 Bedrock Converse 翻译器,其他模型提供商的翻译器未受影响;如果遇到类似问题但不在该场景下,可能是其他原因。

问题场景

用户在使用 LangChain 且模型提供商为 Bedrock Converse(model_provider: "bedrock_converse")时,读取 AIMessage.content_blocks 属性会导致原始消息内容被修改。具体表现为:当 message.content 是字符串时,第一次读取后会被替换为文本块列表;当内容包含带 index 字段的未识别字典块时,读取操作会从原始字典中移除该字段。这导致连续两次调用 content_blocks 返回不同的值。

报错原文

AIMessage.content_blocks mutates Bedrock Converse message content
No exception is raised.
original: hello
content after reads: [{'type': 'text', 'text': 'hello'}]
first read: [{'type': 'text', 'text': 'hello'}]
second read: [{'type': 'text', 'text': 'hello'}]

原因分析

问题出在 libs/core/langchain_core/messages/block_translators/bedrock_converse.py 文件的 _convert_to_v1_from_converse() 函数中,存在两处直接修改原始消息内容的位置:

1. 字符串内容修改(约 162-163 行):

if isinstance(message.content, str):
    message.content = [{"type": "text", "text": message.content}]

2. 未识别块的修改(约 276-277 行):

if "index" in new_block["value"]:
    new_block["index"] = new_block["value"].pop("index")

其中 new_block["value"] 引用的是 message.content 中的原始块,调用 .pop("index") 会直接删除原始消息内容中的 index 字段。已知问题在于 Bedrock Converse 翻译器在构建标准化内容块时被设计为“非修改性”操作,但实现中违反了这一约束;其他模型提供商的翻译器均保持了源消息不变。

环境排查

  • 确认 langchain-core 的当前版本,检查是否已包含修复提交(提交信息涉及“preserving original content”且修复了 bedrock_converse.py)。
  • 确认用于复现的 Python 版本(Issue 未明确给出具体版本号)。
  • 确认 response_metadata 中的 model_provider 是否为 "bedrock_converse"。需要确认 AIMessageAIMessageChunk 两个类的行为。

解决步骤

  1. 升级 langchain-core:将 langchain-core 升级到最新版本,该问题已被修复并合并进主分支。
  2. 验证修复效果(可优先尝试):如果升级后问题仍存在,可先尝试在读取 content_blocks 之前对消息内容执行 deepcopy 作为临时规避方案。已确认修复方案采用了局部变量和浅拷贝方式,因此升级是最直接的解决途径。
  3. 检查回归覆盖:修复提交中包含了对 AIMessageAIMessageChunk 的回归测试,覆盖了以下场景:字符串内容在读取后保持不变、带 index 的未识别块保留原始 index、连续两次读取结果一致。如果升级后仍有异常,可对照这些测试场景检查代码。
  4. 检查自定义代码:确认自己的代码中是否有对 message.content 的直接或间接修改,特别是在调用 content_blocks 前后。

验证方法

使用 Issue 中的复现代码验证问题已解决:

from copy import deepcopy
from langchain_core.messages import AIMessage

for content in [
    "hello",
    [{"type": "custom", "payload": "value", "index": 3}],
]:
    message = AIMessage(
        content=content,
        response_metadata={"model_provider": "bedrock_converse"},
    )
    original = deepcopy(message.content)
    first = message.content_blocks
    second = message.content_blocks

    print("original:", original)
    print("content after reads:", message.content)
    print("first read:", first)
    print("second read:", second)

正确行为应为:message.content 在读取 content_blocks 前后保持不变,且 firstsecond 返回值相同。

参考来源

langchain-ai/langchain #39821

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 21235

发表回复

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