Handlebars 模板 #

概述 #

Semantic Kernel 支持 Handlebars 模板引擎,提供更强大的模板功能,包括条件渲染、循环、辅助函数等。

基本使用 #

启用 Handlebars #

csharp
using Microsoft.SemanticKernel.PromptTemplates.Handlebars;

var function = kernel.CreateFunctionFromPrompt(
    promptTemplate: """
        你好,{{name}}!
        
        你的兴趣有:
        {{#each interests}}
        - {{this}}
        {{/each}}
        """,
    templateFormat: "handlebars",
    promptTemplateFactory: new HandlebarsPromptTemplateFactory()
);

var result = await kernel.InvokeAsync(
    function,
    new KernelArguments
    {
        ["name"] = "小明",
        ["interests"] = new[] { "编程", "阅读", "运动" }
    }
);

从文件加载 #

text
Prompts/
└── UserProfile/
    ├── config.json
    └── skprompt.txt

config.json:

json
{
    "schema": 1,
    "description": "生成用户简介",
    "template_format": "handlebars",
    "input_variables": [
        {
            "name": "user",
            "description": "用户信息对象",
            "required": true
        }
    ]
}

skprompt.txt:

text
用户简介:

姓名:{{user.name}}
年龄:{{user.age}}

兴趣爱好:
{{#each user.interests}}
- {{this}}
{{/each}}

个人简介:
{{user.bio}}

变量语法 #

简单变量 #

handlebars
你好,{{name}}!
你今年{{age}}岁。

对象属性 #

handlebars
用户信息:
- 姓名:{{user.name}}
- 邮箱:{{user.email}}
- 城市:{{user.address.city}}

数组访问 #

handlebars
第一个兴趣:{{interests.0}}
第二个兴趣:{{interests.1}}

条件渲染 #

if 条件 #

handlebars
{{#if isPremium}}
感谢您成为高级会员!
{{else}}
升级到高级会员享受更多功能。
{{/if}}
csharp
var result = await kernel.InvokeAsync(
    function,
    new KernelArguments
    {
        ["isPremium"] = true
    }
);

多条件 #

handlebars
{{#if (eq level "gold")}}
金牌会员特权
{{else if (eq level "silver")}}
银牌会员特权
{{else}}
普通会员
{{/if}}

复杂条件 #

handlebars
{{#if (and (gt age 18) (lt age 60))}}
您是成年工作人群
{{else if (gte age 60)}}
您已退休
{{else}}
您是未成年人
{{/if}}

循环 #

each 循环 #

handlebars
产品列表:
{{#each products}}
{{@index}}. {{name}} - ¥{{price}}
{{/each}}
csharp
var arguments = new KernelArguments
{
    ["products"] = new[]
    {
        new { name = "产品A", price = 99 },
        new { name = "产品B", price = 199 },
        new { name = "产品C", price = 299 }
    }
};

循环索引 #

handlebars
{{#each items}}
{{@index}}: {{this}}
{{/each}}

嵌套循环 #

handlebars
{{#each categories}}
分类:{{name}}
{{#each items}}
  - {{name}}
{{/each}}
{{/each}}

循环中的条件 #

handlebars
{{#each users}}
{{#if active}}
- {{name}} (活跃)
{{else}}
- {{name}} (不活跃)
{{/if}}
{{/each}}

内置辅助函数 #

比较函数 #

handlebars
{{#if (eq status "active")}}激活{{/if}}
{{#if (ne status "deleted")}}未删除{{/if}}
{{#if (gt score 60)}}及格{{/if}}
{{#if (gte score 90)}}优秀{{/if}}
{{#if (lt age 18)}}未成年{{/if}}
{{#if (lte count 0)}}无库存{{/if}}

逻辑函数 #

handlebars
{{#if (and isMember hasCredit)}}可以购买{{/if}}
{{#if (or isAdmin isModerator)}}有管理权限{{/if}}
{{#if (not isBanned)}}可以发言{{/if}}

字符串函数 #

handlebars
大写:{{upper name}}
小写:{{lower name}}
长度:{{length text}}
截取:{{substring text 0 10}}

数组函数 #

handlebars
数组长度:{{length items}}
第一个:{{first items}}
最后一个:{{last items}}

自定义辅助函数 #

注册辅助函数 #

csharp
var handlebarsFactory = new HandlebarsPromptTemplateFactory();

handlebarsFactory.RegisterHelper("formatDate", (context, arguments) =>
{
    if (arguments[0] is DateTime date)
    {
        return date.ToString("yyyy-MM-dd");
    }
    return arguments[0]?.ToString() ?? "";
});

handlebarsFactory.RegisterHelper("currency", (context, arguments) =>
{
    if (arguments[0] is double amount)
    {
        return $"¥{amount:N2}";
    }
    return arguments[0]?.ToString() ?? "";
});

var function = kernel.CreateFunctionFromPrompt(
    promptTemplate: """
        订单信息:
        日期:{{formatDate orderDate}}
        金额:{{currency amount}}
        """,
    templateFormat: "handlebars",
    promptTemplateFactory: handlebarsFactory
);

复杂辅助函数 #

csharp
handlebarsFactory.RegisterHelper("stars", (context, arguments) =>
{
    if (arguments[0] is int rating)
    {
        return new string('★', rating) + new string('☆', 5 - rating);
    }
    return "";
});

handlebarsFactory.RegisterHelper("truncate", (context, arguments) =>
{
    var text = arguments[0]?.ToString() ?? "";
    var maxLength = arguments.Length > 1 ? Convert.ToInt32(arguments[1]) : 50;
    
    if (text.Length <= maxLength)
        return text;
    
    return text.Substring(0, maxLength) + "...";
});

实战示例 #

示例 1:产品推荐 #

csharp
var template = """
    根据用户信息推荐产品:
    
    用户:{{user.name}}
    预算:¥{{user.budget}}
    兴趣:
    {{#each user.interests}}
    - {{this}}
    {{/each}}
    
    {{#if (gt user.budget 1000)}}
    推荐高端产品线
    {{else if (gt user.budget 500)}}
    推荐中端产品线
    {{else}}
    推荐性价比产品线
    {{/if}}
    """;

var function = kernel.CreateFunctionFromPrompt(
    template,
    templateFormat: "handlebars",
    promptTemplateFactory: new HandlebarsPromptTemplateFactory()
);

var result = await kernel.InvokeAsync(function, new KernelArguments
{
    ["user"] = new
    {
        name = "小明",
        budget = 800,
        interests = new[] { "电子产品", "运动", "阅读" }
    }
});

示例 2:报告生成 #

csharp
var template = """
    # 销售报告
    
    ## 概述
    - 报告日期:{{formatDate reportDate}}
    - 总销售额:{{currency totalSales}}
    - 订单数量:{{orderCount}}
    
    ## 分类销售
    {{#each categories}}
    ### {{name}}
    - 销售额:{{currency sales}}
    - 占比:{{percentage}}%
    {{/each}}
    
    ## 热销产品
    {{#each topProducts}}
    {{@index}}. {{name}} - 销量:{{sold}}
    {{/each}}
    
    {{#if (gt alerts.length 0)}}
    ## 预警
    {{#each alerts}}
    - {{this}}
    {{/each}}
    {{/if}}
    """;

示例 3:多语言模板 #

csharp
var template = """
    {{#if (eq language "zh")}}
    你好,{{user.name}}!
    欢迎使用我们的服务。
    {{else if (eq language "en")}}
    Hello, {{user.name}}!
    Welcome to our service.
    {{else if (eq language "ja")}}
    こんにちは、{{user.name}}さん!
    サービスへようこそ。
    {{/if}}
    """;

模板继承 #

Partials(部分模板) #

csharp
var handlebarsFactory = new HandlebarsPromptTemplateFactory();

handlebarsFactory.RegisterPartial("userCard", """
    <div class="user-card">
      <h3>{{name}}</h3>
      <p>{{email}}</p>
    </div>
    """);

handlebarsFactory.RegisterPartial("productCard", """
    <div class="product-card">
      <h4>{{name}}</h4>
      <p>价格:¥{{price}}</p>
    </div>
    """);

var template = """
    {{> userCard}}
    
    推荐产品:
    {{#each products}}
    {{> productCard}}
    {{/each}}
    """;

最佳实践 #

1. 保持模板简洁 #

handlebars
好的做法:
{{#each items}}
- {{name}}: {{value}}
{{/each}}

避免:
{{#each items}}{{#if @first}}{{name}}{{else}}, {{name}}{{/if}}{{/each}}

2. 使用 Partials 复用 #

csharp
// 定义可复用的部分
handlebarsFactory.RegisterPartial("address", """
    {{street}}
    {{city}}, {{state}} {{zip}}
    {{country}}
    """);

// 在多处使用
var template = """
    发货地址:
    {{> address address=shippingAddress}}
    
    账单地址:
    {{> address address=billingAddress}}
    """;

3. 合理使用条件 #

handlebars
清晰的条件:
{{#if (and (gt age 0) (lt age 150))}}
有效年龄
{{/if}}

避免过深的嵌套:
{{#if condition1}}
  {{#if condition2}}
    {{#if condition3}}
      过于复杂
    {{/if}}
  {{/if}}
{{/if}}

4. 数据预处理 #

csharp
// 在传递给模板前处理数据
var templateData = new
{
    user = new
    {
        name = user.Name,
        // 预处理数据
        displayName = $"{user.FirstName} {user.LastName}",
        isActive = user.Status == "active",
        memberSince = user.CreatedAt.ToString("yyyy-MM-dd")
    }
};

下一步 #

现在你已经掌握了 Handlebars 模板,接下来学习 OpenAI 连接器,了解如何连接 OpenAI 服务!

最后更新:2026-04-04