LangChain 官方项目标识

LangChain

Stars

面向 Agent 与 LLM 应用的开源 Python 框架,通过统一的模型、消息、工具、检索与中间件接口连接不同提供商和组件,为可组合、可扩展的智能体工程提供核心基础设施。

Agent EngineeringPython · LangChain CoreModels · Tools · Retrieval
MESSAGE TRANSLATION · OBSERVATIONAL PURITY

读取派生属性,不应该改写原始消息

`content_blocks` 可以规范化 provider 内容,但每次读取都必须从同一个未被污染的源消息出发。

BEFORE · READ WITH SIDE EFFECTSmessage.content"hello"
content_blocksREAD #1
[{"type": "text", …}]SOURCE MUTATED
AFTER · DERIVED VIEW
SOURCEmessage.content→ local derive →VIEWcontent_blocks
{ type: "custom", index: 3 }copy · lift indexsource keeps index ✓
READ #1 = READ #2 · SOURCE UNCHANGED
隐式写入

字符串与 index 在读取中被改写

Bedrock Converse 消息的 `AIMessage.content_blocks` 看似只是读取派生表示,实际却会改写源 `message.content`:字符串会被替换成文本块列表,未知字典块的 `index` 会被 `pop()` 移除。第一次读取已经污染原始消息,连续两次读取还可能返回不同结果。

接口契约

派生视图必须保持源消息只读

`content_blocks` 是只读属性,调用方应能安全地重复读取,并继续序列化、持久化原始 provider 内容。修复边界不在于深拷贝整个消息,而是让字符串转换只使用局部列表,并在提升未知块的 `index` 前复制该字典,从最小范围切断写回源对象的路径。

局部隔离

本地列表与 copy-before-pop 切断写回

字符串内容只在局部列表中转换,不再写回 `message.content`;处理未知字典块时先复制对象,再从副本提升 `index`。参数化回归覆盖 `AIMessage` / `AIMessageChunk`、字符串、自定义块及连续读取,直接锁定派生视图与源对象之间的只读边界。

行为结果

重复读取一致,原始内容保持完整

读取 `content_blocks` 不再改变原始字符串或删除未知块的 `index`;同一消息的连续读取保持一致,后续序列化与持久化仍能获得完整的 provider 原始内容。两类消息对象与两条原地修改路径均由回归测试覆盖。

CONTRIBUTION SHIPPEDIssue #39821 已转化为 LangChain 上游修复

维护者通过 PR #40022 合并修复,并在最终提交中以 Co-authored-by 明确保留 Zhewen Tan(@tandede)的共同作者署名。

  • Issue #39821 最小复现与根因定位
  • PR #40022 合入 master
  • Merge Commit 共同作者署名
查看合并提交