Semantic Kernel 收紧模板参数编码规则:复杂类型默认触发异常

在此前版本的 Semantic Kernel 中,如果模板参数类型是 string,系统会自动执行编码;但对于自定义类型、匿名类型或集合,则不会应用编码。
随着最新改动上线,我们引入了更严格的规则:如果启用了自动编码(默认行为),当参数中使用复杂类型时将直接抛出异常。这样可以强制开发者为复杂类型手动处理编码,并为这些变量显式关闭自动编码,从而实现更安全的模板渲染。尤其是在使用 Handlebars 或 Liquid 这类模板引擎时,这一改动有助于落实安全最佳实践。
本文将说明旧方案存在的问题、新行为,以及如何更新代码以符合这些变更。关于 Semantic Kernel 中模板渲染的更多细节,请参阅官方文档。
复杂类型的编码
自动编码本质上是一道安全防线:它会转义字符串中的特殊字符,以防止模板注入等常见漏洞。但当参数是复杂类型(例如自定义对象、匿名类型或集合)时,SDK 无法可靠判断应如何对嵌套属性或集合元素进行编码;贸然处理可能导致数据损坏或防护不完整。
为了解决这个问题,SDK 现在会在这类场景中抛出异常,强制开发者显式进行手动编码和相关配置。
最新版本的变化与潜在报错
从最新的 .NET 与 Python Semantic Kernel 包开始,在启用编码的前提下渲染模板时,如果使用复杂类型且未做正确配置,就会抛出异常。这可以避免无意中的不安全渲染,并要求相关场景更新代码。
如果你的代码在 Handlebars 或 Liquid 模板中使用了复杂参数(例如包含用户输入属性的对象),就会遇到这一变化。异常信息会提示你手动编码数据,并为相关输入变量设置 AllowDangerouslySetContent 为 true。这一调整在保留高级用法灵活性的同时,执行了更严格、更安全的规则,降低漏洞风险。
如何更新你的代码
要解决这个问题,你需要对复杂类型中可能不安全的数据执行手动编码,并在 prompt template 配置中为这些参数显式关闭自动编码,即设置 AllowDangerouslySetContent 为 true。
.NET 示例
以下是变更前的代码示例:
var arguments = new KernelArguments()
{
{ "customer", new
{
firstName = userInput.FirstName,
lastName = userInput.LastName,
}
}
};
var templateFactory = new LiquidPromptTemplateFactory();
var promptTemplateConfig = new PromptTemplateConfig()
{
TemplateFormat = "liquid"
};
var promptTemplate = templateFactory.Create(promptTemplateConfig);
// The following line will throw an exception now, because of the complex type passed as argument and enabled encoding
var renderedPrompt = await promptTemplate.RenderAsync(kernel, arguments);
变更后的代码:
var arguments = new KernelArguments()
{
{ "customer", new
{
// Perform encoding for each property of complex type
firstName = HttpUtility.HtmlEncode(userInput.FirstName),
lastName = HttpUtility.HtmlEncode(userInput.LastName),
}
}
};
var templateFactory = new LiquidPromptTemplateFactory();
var promptTemplateConfig = new PromptTemplateConfig()
{
TemplateFormat = "liquid",
InputVariables = new()
{
// We set AllowDangerouslySetContent to 'true' because each property of this argument is encoded manually
new() { Name = "customer", AllowDangerouslySetContent = true },
}
};
var promptTemplate = templateFactory.Create(promptTemplateConfig);
// No exception, because we disabled encoding for arguments due to manual encoding
var renderedPrompt = await promptTemplate.RenderAsync(kernel, arguments);
Python 示例
以下是变更前的代码示例:
arguments = {
"customer": {
"first_name": user_input.first_name,
"last_name": user_input.last_name,
}
}
prompt_template_config = PromptTemplateConfig(
template_format="handlebars"
)
prompt_template = HandlebarsPromptTemplate(prompt_template_config=prompt_template_config)
# The following line will throw an exception now, because of the complex type passed as argument and enabled encoding
rendered_prompt = await prompt_template.render(kernel, arguments)
变更后的代码:
arguments = {
"customer": {
# Perform encoding for each property of the complex type
"first_name": escape(user_input.first_name),
"last_name": escape(user_input.last_name),
}
}
prompt_template_config = PromptTemplateConfig(
template=template,
template_format="handlebars",
input_variables=[
# We set allow_dangerously_set_content to True because each property of this argument is encoded manually
InputVariable(name="customer", allow_dangerously_set_content=True),
]
)
prompt_template = HandlebarsPromptTemplate(prompt_template_config=prompt_template_config)
# No exception, because we disabled encoding for arguments due to manual encoding
rendered_prompt = await prompt_template.render(kernel, arguments)
在这次更新中:
- 使用
HttpUtility.HtmlEncode(或模板引擎对应的等效方法)等方式,对属性进行手动编码,净化用户输入。 - 在
PromptTemplateConfig中增加InputVariables,并为已自行完成编码的复杂参数设置AllowDangerouslySetContent = true。这会告诉 SDK:跳过该变量的自动编码。
对于 Handlebars 或其他受支持模板,也应做类似调整。请务必测试渲染输出,确认编码生效且不影响功能。
总结
Semantic Kernel 这次更新为模板参数引入了更严格的编码规则:在自动编码开启时,复杂类型会触发异常,以强制手动净化与显式配置。这显著提升了模板渲染安全性,能够更有效地防止潜在漏洞。
我们始终欢迎你的反馈。如果你有任何意见、问题或想进一步讨论,欢迎前往 GitHub 的讨论区与我们及社区交流。也欢迎支持我们——如果你喜欢 Semantic Kernel,欢迎在 GitHub 给项目点个 star。
分类
作者

高级软件工程师

