POML 模板引擎(Template Engine)

POML 模板引擎(Template Engine)

参考官方文档:microsoft.github.io/poml/stable...

概览

POML 的模板引擎让你在提示中使用"变量、表达式、循环、条件、文件包含"等动态能力,从而构建可复用、可组合的复杂提示。


表达式(Expressions)

  • 基本用法:使用双花括号 {{ }} 在内容位置插入变量或表达式结果。
poml 复制代码
<poml>
  <p>Hello, {{ name }}!</p>
</poml>
  • 属性中的表达式:也可用于属性值。
poml 复制代码
<poml>
  <task caption="Task #{{ index }}">This is task No. {{ index }}.</task>
</poml>
  • 支持的表达式(JavaScript 语法):
    • 变量:{{variableName}}
    • 算术:{{a + b}}{{x * y}}{{count / total}}
    • 字符串拼接:{{firstName + " " + lastName}}
    • 数组访问:{{myArray[0]}}
    • 对象属性:{{myObject.property}}
    • 函数调用:{{myFunction(arg1, arg2)}}(若函数在上下文中可用)
    • 三元运算:{{condition ? A : B}}
    • 循环变量:{{loop.index}} 等(见下文)

提示:属性中的表达式会先求值再进行类型自动转换(见"类型自动转换")。


let 变量与数据导入(Let Expressions)

<let> 用于定义变量、导入外部数据,并在模板内复用。

1) 从字面量设置变量

  • 内容作为字面量:
poml 复制代码
<poml>
  <let name="greeting">Hello, world!</let>
  <p>{{ greeting }}</p>
</poml>
  • 使用 value 属性(会按 JS 表达式求值,注意字符串需要引号):
poml 复制代码
<poml>
  <let name="greeting" value="'Hello, world!'" />
  <p>{{ greeting }}</p>
</poml>

2) 从文件导入数据(命名变量)

  • users.json 的内容导入到 users 变量:
poml 复制代码
<poml>
  <let name="users" src="users.json" />
  <p>First user: {{ users[0].name }}</p>
</poml>

type 可指定文件类型(如 jsontextcsv),不提供时按扩展名推断。

3) 从文件导入(不命名)

  • 直接把 JSON 顶层的键注入到当前上下文:
poml 复制代码
<poml>
  <let src="config.json" />
  <p>API Key: {{ apiKey }}</p>
</poml>

config.json 示例:

json 复制代码
{ "apiKey": "your_api_key" }

4) 使用内联 JSON 与类型标注

poml 复制代码
<poml>
  <let name="person">{ "name": "Alice", "age": 30 }</let>
  <p>Name: {{ person.name }}, Age: {{ person.age }}</p>

  <let name="count" type="integer">5</let>
  <p>Count: {{ count }}</p>
</poml>

5) 基于表达式设置变量

poml 复制代码
<poml>
  <let name="base" value="10" />
  <let name="increment" value="5" />
  <let name="total" value="{{ base + increment }}" />
  <p>Total: {{ total }}</p> <!-- 输出:15 -->
</poml>

类型自动转换(Type-Autocasting in Attributes)

  • 组件属性会根据其定义的类型自动转换:
    • Boolean:"true"1"1"{{true}}true"false"0"0"{{false}}false
    • Number:"123"45.6{{anyNumber}}{{myNumber+1.3}} → 相应数值
    • Object:尝试解析为 JSON 对象,例如:
      • data='{"name":"John","age":30}'
      • data="{{{name: 'John', age: 30}}}"(三花括号语法,直接提供对象字面量)
    • String:不做转换

示例(概念演示):

poml 复制代码
<poml>
  <let name="boolVar" type="boolean" value="true"/>
  <let name="numVar"  type="number"  value="42"/>
  <let name="objVar"  type="object"  value="{{ { key: 'value' } }}"/>
  <MyComponent
    boolProp="{{ boolVar }}"
    numProp="{{ numVar }}"
    objProp="{{ objVar }}"
    stringProp="hello"
  />
</poml>

for 循环(For Attribute)

  • 语法:for="itemName in listExpr"
poml 复制代码
<poml>
  <list>
    <item for="item in ['apple', 'banana', 'cherry']">{{ item }}</item>
  </list>
</poml>

循环变量(Loop Variables)

  • loop.index:当前索引(从 0 开始)
  • loop.length:总长度
  • loop.first:是否第一项(true/false)
  • loop.last:是否最后一项(true/false)
poml 复制代码
<poml>
  <let name="all_demos" value='[
    { "input": "What is your name?", "output": "My name is POML." },
    { "input": "What can you do?",  "output": "I can generate prompts." }
  ]'/>
  <examples>
    <example for="example in all_demos" chat="false"
             caption="Example {{ loop.index + 1 }}" captionStyle="header">
      <input>{{ example.input }}</input>
      <output>{{ example.output }}</output>
    </example>
  </examples>
</poml>

条件渲染(If Condition)

  • 使用 if 属性按条件渲染元素:
poml 复制代码
<poml>
  <let name="isVisible" value="true"/>
  <let name="isHidden"  value="{{ !isVisible }}"/>
  <p if="isVisible">This paragraph is visible.</p>
  <p if="isHidden">This paragraph is hidden.</p>
</poml>

if 的值可直接写变量名(按布尔解释)或任意表达式。


文件包含(Include Files)

  • 使用 <include src="..." /> 将其他 POML 片段注入当前文件;被包含文件可访问当前上下文的变量。
  • forif 可与 include 同用:
poml 复制代码
<poml>
  <include src="row.poml" for="i in [1,2,3]" />
  <include src="footer.poml" if="showFooter" />
</poml>

路径 src 相对于当前 POML 文件;避免循环包含。


实战组合示例

  • 目标:从 JSON 读取人员列表,循环渲染为多行,页脚按条件包含。

目录结构:

  • people.json
  • row.poml
  • main.poml

people.json

json 复制代码
[
  { "name": "Alice", "role": "PM" },
  { "name": "Bob",   "role": "Engineer" }
]

row.poml

poml 复制代码
<p><b>{{ person.name }}</b> - {{ person.role }}</p>

main.poml

poml 复制代码
<poml>
  <let name="people" src="people.json" />
  <let name="showFooter" value="true" />

  <section>
    <include src="row.poml" for="person in people" />
  </section>

  <footer if="showFooter">
    <p>Total: {{ people.length }}</p>
  </footer>
</poml>

实践建议与常见坑

  • 字符串字面量在 value 中必须加引号;内容写法则按字面量处理。
  • 对象型属性可用 JSON 字符串或三花括号对象字面量:
    • data='{"name":"John","age":30}'
    • data="{{{name: 'John', age: 30}}}"
  • 文件路径相对当前 .poml;注意编码与格式(如 JSON 的逗号与引号)。
  • 循环与条件可叠加在 include 上,便于模块化拆分。
  • 谨慎使用自定义函数调用;优先使用纯表达式与 let,保证可移植性与可调试性。

相关推荐
boooooooom2 小时前
尝尝咸淡:从朴素 RAG 到 Graph RAG——一个烹饪问答系统的三层检索升级之路
前端·后端·llm
武子康5 小时前
33B 音画模型塞进 Apple Silicon,h3.c 重写了哪些 Runtime 职责
人工智能·llm·agent
知几蜗牛5 小时前
一张图看懂AI、机器学习、深度学习和生成式AI之间的关系
llm
XLYcmy5 小时前
小红书 算法一面 十一
google·meta·llm·负载均衡·token·moe·glam
谢白羽6 小时前
Mooncake在LLM的kv cache offload
人工智能·llm·论文·agent·mooncake
牧艺1 天前
DeepSeek Harness 上手:一切皆插件的 Agent 运行时,核心流程怎么走
llm·agent·deepseek
魔术师Grace1 天前
模型“开源”了,就能直接拿来做 Agent 吗?
llm·aigc·agent
夫子3961 天前
【第三部分:第一个 Agent 应用】10. 不使用框架,手写一个最小 Agent
llm·agent·ai编程
武子康1 天前
模型分数涨了,它真的学会了吗?LittleLearner 拆开了三种可能
人工智能·llm·agent
要有锋芒_不要疯忙1 天前
Transformer 是什么?--LLM知识(一)
llm