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,保证可移植性与可调试性。

相关推荐
hojyn7 小时前
LLM评估系列(二):LLM 乱输出难控?五篇顶会论文教你用 LLM 评估器破解五大关键场景
llm
hojyn7 小时前
别再先分块了!Late Chunking:长上下文嵌入模型如何终结 RAG 检索不准的魔咒?
llm
常先森7 小时前
【解密源码】 RAGFlow 切分最佳实践-navie 分词器原理
架构·llm
RockHopper202510 小时前
海德格尔的“形式指示” vs LLM 的提示工程
llm·提示工程
AI大模型10 小时前
【LM Studio篇】不懂编程也能学会!几分钟教你在本地部署大模型
程序员·llm·agent
钢蛋11 小时前
LangGraph 编排教程指南:从入门到精通的完整学习路径
langchain·llm
mCell14 小时前
Agent ReAct and Loop
langchain·llm·agent
大模型教程1 天前
“锤子”RAG已过时!让AI自带“工具选择大脑”的MCP智能体来了
程序员·llm·agent
大模型教程1 天前
告别“人工客服”!用Dify+知识库,打造你的24小时智能问答专家
程序员·llm·agent
智泊AI1 天前
一文讲清:预训练(Pre-Training)、微调(Fine-Tuning)是什么?
llm