Mustache templates silently render an empty string for any non-`dict` `Mapping` (`ChainMap`, `UserDict`, `os.environ`), contradicting the de

LangChain Mustache 模板在传入非 dict 类型的 Mapping(如 ChainMap、UserDict、MappingProxyType、os.environ)时会静默渲染为空字符串,优先确认传入的数据类型,并升级到包含修复的版本或临时改用 dict 包装数据。

快速结论:LangChain Mustache 模板在传入非 dict 类型的 Mapping(如 ChainMap、UserDict、MappingProxyType、os.environ)时会静默渲染为空字符串,优先确认传入的数据类型,并升级到包含修复的版本或临时改用 dict 包装数据。

适用环境:langchain-core 包,涉及 Mustache 模板渲染功能(langchain_core.prompts.PromptTemplate,template_format=”mustache”)。Issue 已确认在 master 分支上存在该问题,影响 Python 标准库中所有非 dict 的 Mapping 类型。

最快修复方案:暂无确认的一步修复方案。Issue 中已定位根因并提出修复方案(将 `_get_key` 中的 `isinstance(resolved_scope, dict)` 改为 `isinstance(resolved_scope, Mapping)`),但需等待官方 PR 合并或自行修改源码。

注意事项:临时绕过方案(如将传入数据转为 dict)可能带来额外内存复制;自行修改源码需注意保留 CVE-2025-65106 加固逻辑中对任意对象遍历的拦截。

问题场景

在使用 LangChain 的 PromptTemplate 且设置 template_format="mustache" 时,若模板变量传入的值是 ChainMapUserDictMappingProxyTypeos.environ 这类非 dict 的 Mapping 对象,模板会静默渲染为空字符串,不会抛出任何异常或警告。

报错原文

# 无错误堆栈,问题表现为静默失败
print(repr(p.format(user={"name": "Alice"})))                    # 'Hello Alice'  ✓
print(repr(p.format(user=ChainMap({"name": "Alice"}))))          # 'Hello '       ✗
print(repr(p.format(user=UserDict({"name": "Alice"}))))          # 'Hello '       ✗
print(repr(p.format(user=MappingProxyType({"name": "Alice"}))))  # 'Hello '       ✗
print(repr(q.format(env=os.environ)))                            # 'Home='        ✗

原因分析

根本原因位于 langchain_core/utils/mustache.py_get_key 函数中,其类型分派使用具体类型 dict 而非抽象基类 Mapping。当传入非 dict 的 Mapping 对象时,`isinstance(resolved_scope, dict)` 返回 False,代码落入 else 分支并抛出 TypeError,但该异常被外层的 except (AttributeError, KeyError, IndexError, ValueError, TypeError) 捕获,与”键不存在”的情况无法区分,最终静默返回空字符串。这与模块公开 API 声明的 Mapping[str, Any] 类型契约矛盾。

环境排查

  • 确认 langchain-core 版本为最新 master 分支(Issue 中已确认当前版本存在问题)
  • 检查传入模板的数据类型是否为 dict 子类:isinstance(data, dict)
  • 确认是否为非 dict 的 Mapping 类型:from collections.abc import Mapping; isinstance(data, Mapping)
  • 注意 os.environ 类型为 _Environ,不是 dict 子类

解决步骤

  1. 优先尝试:在调用 format() 前将非 dict 的 Mapping 数据显式转换为 dict,如 format(user=dict(user_data)),作为临时绕过方案
  2. 检查是否有包含该修复的新版本 langchain-core 发布,升级到最新版本
  3. 如有能力,可按照 Issue 中提出的修复方案自行修改源码:将 langchain_core/utils/mustache.py_get_key 函数的 isinstance(resolved_scope, dict) 改为 isinstance(resolved_scope, Mapping)(需从 collections.abc 导入 Mapping)
  4. 修改源码时需确保保留对任意对象遍历的拦截逻辑(即 else 分支),以维持 CVE-2025-65106 加固有效性
  5. 添加针对 ChainMapUserDictMappingProxyType 的单元测试,验证修复正确性

验证方法

修复后重新运行 Issue 中的复现代码,确认所有 Mapping 类型(包括 ChainMap、UserDict、MappingProxyType、os.environ)都能正确渲染出预期的值(如 ‘Hello Alice’、’Home=/home/user’),而不是输出空字符串。同时确认使用普通 dict 和 list/tuple 的现有功能不受影响。

参考来源

langchain-ai/langchain #39678

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 18936

发表回复

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