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 可指定文件类型(如 json、text、csv),不提供时按扩展名推断。

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 片段注入当前文件;被包含文件可访问当前上下文的变量。
  • for 与 if 可与 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,保证可移植性与可调试性。

相关推荐
iiiiii1134 分钟前
大模型批量生成中的左填充 (left padding)与右填充 (right padding):从生成正确性到 GRPO 的混合策略
人工智能·机器学习·语言模型·大模型·llm·attention·注意力
Eloudy2 小时前
从 huggingFace 下载大模型命令备忘
llm·gpu·rdma
lucas_AI3 小时前
不用一行恶意代码,就能教坏你的 AI Agent:SkillPoison 只用了 15 条『成功经验』
llm
lucas_AI3 小时前
把图转成文字再答题,为什么反而错得更狠?图森破了:答案就吊在那一条边上
llm
lucas_AI3 小时前
DeepMind 发布 Genie 4:世界模型会「出声」了,一句话实时改写世界
人工智能·llm
lucas_AI4 小时前
为什么大模型总敢一本正经地胡说?研究者关掉了它脑内的 8 个「自信开关」
人工智能·llm
blackappleD17 小时前
百度 Unlimited OCR 2 拆解:SR-SWA 如何让百页文档的 KV 缓存不再涨
人工智能·llm
吴凡wudianmei18 小时前
从0搭一个AI Agent(一):为什么你需要的不是“调一次API”
llm·openai·agent
lucas_AI18 小时前
0.8B 干翻 235B:阿里 OvisOCR3 把文档解析、KIE、跨页表格全塞进一个能本地跑的小模型
llm