本页介绍了在 Playground 、提示中心 和 评估器 中支持的 提示模板 格式。提示模板允许您创建带有动态占位符的可重用提示,这些占位符在运行时被填充。
有关提示工程和提示模板的概述,请参阅 概念 页面。
LangSmith 支持两种提示模板格式,适用于不同复杂度的场景:
格式 语法 最适合 f-string {variable}具有基本变量替换的简单提示 mustache {{variable}}具有循环、条件、嵌套数据或评估器的复杂提示
F-string 语法 适用于简单的提示。Mustache 提供了处理复杂数据结构和逻辑的功能,这对评估器和高级用例很有帮助。
您可以在 UI 中切换格式。LangSmith 会在可能的情况下自动 转换您的模板 ,但某些 mustache 功能(如循环和条件)无法转换为 f-string 格式。
使用 Playground 测试本页的示例。在 Playground 的提示设置 菜单下切换 提示格式 。
F-string 语法
F-string 模板使用 Python 风格的格式化,使用单花括号 {variable}。LangSmith 使用了 Python f-string 语法 的 简化子集 :它只支持基本的变量替换,而不是完整的 Python 表达式和格式化选项。当您拥有扁平的数据结构并且只需要在提示中插入值时,f-string 是理想的选择。
基本变量
变量会根据输入数据中的值进行替换。变量名必须完全匹配(区分大小写):
# 模板
你好, { name } !欢迎来到 { company } 。
# 输入
{
"name" : "Ashley" ,
"company" : "LangChain"
}
# 输出
你好,Ashley!欢迎来到 LangChain。
当模板运行时,LangSmith 会在输入对象中查找每个变量名,并用 name 键的值替换 {name}。
变量名
F-string 变量名被视为简单的字符串标识符。它们不能包含点、括号或特殊字符——只能包含字母数字字符和下划线。
# 模板
你好, { name } !
你的主题是: { topic }
# 输入
{
"name" : "Ashley" ,
"topic" : "LangSmith"
}
# 输出
你好,Ashley!
你的主题是:LangSmith
如果您的输入有嵌套对象,例如 {"user": {"name": "Ashley"}},您不能 在 f-string 格式中使用 {user.name} 访问嵌套值。点号将被视为变量名的一部分(字面上查找名为 "user.name" 的键),而不是路径分隔符。对于嵌套访问,请改用 mustache 格式 。
字面量花括号
有时您需要在输出中包含实际的花括号(例如,在 JSON 示例或代码片段中)。为此,请将花括号加倍 :
# 模板
使用双花括号表示字面量: {{ not_a_variable }}
但单花括号用于变量: { variable }
# 输入
{
"variable" : "value"
}
# 输出
使用双花括号表示字面量: { not_a_variable }
但单花括号用于变量:value
模板解析器将 {{ 视为转义的花括号,而不是变量占位符。只有单花括号 {...} 被视为变量。
LangSmith 的 f-string 实现是有限的,以保持模板简单和可预测。不支持 以下功能:
用于嵌套访问的点表示法: 不能使用 {user.name} 访问嵌套对象。整个字符串 "user.name" 将被视为单个变量名。
格式说明符: 不能使用 {price:.2f} 进行数字格式化或 {rate:.1%} 表示百分比。
表达式: 不能使用 {x + y}、{len(items)} 或 {value if condition else default}。
函数调用: 不能使用 {str.upper()} 或其他方法调用。
循环或条件: 没有控制流结构。
数组索引: 不能使用 {items[0]} 访问数组元素。
对于任何这些高级功能,请改用 mustache 格式 。
Mustache 语法
Mustache 是一种“无逻辑”的模板语言,这意味着它不允许任意代码执行,但确实通过区块提供了结构化的控制流。它被称为“无逻辑”是因为您不能编写复杂的表达式——相反,您需要结构化数据来控制渲染内容。
Mustache 专为复杂的数据结构和动态渲染而设计。它对以下情况至关重要:
评估器: 处理对话历史和上下文。
少样本提示: 遍历示例列表。
嵌套数据: 访问深度嵌套的对象和数组。
条件内容: 根据数据的存在显示不同的文本。
双花括号语法 {{variable}} 将其与 f-string 区分开来。
基本变量
与 f-string 类似,mustache 用值替换变量:
{{!-- 模板 --}}
你好,{{name}}!欢迎来到 {{company}}。
{{!-- 输入 --}}
{
"name": "Ashley",
"company": "LangChain"
}
{{!-- 输出 --}}
你好,Ashley!欢迎来到 LangChain。
{{!-- ... --}} 是 mustache 注释,不会出现在输出中。请参阅 注释 部分。
嵌套对象访问
您可以使用点表示法遍历嵌套对象:
{{!-- 模板 --}}
用户:{{user.name}}
邮箱:{{user.profile.email}}
{{!-- 输入 --}}
{
"user": {
"name": "Billy",
"profile": {
"email": "billy@example.com"
}
}
}
{{!-- 输出 --}}
用户:Billy
邮箱:billy@example.com
模板引擎通过您的数据结构遵循路径 user → profile → email。每个点代表一个嵌套级别。
现实世界的数据通常是嵌套的(例如:API 响应、数据库记录等)。Mustache 允许您自然地处理这些数据,而无需先将其扁平化。
区块是 mustache 的核心功能。区块以 {{#name}} 开始,以 {{/name}} 结束。内部发生的情况取决于值:
数组: 为每个元素重复内容。
对象: 以该对象为上下文渲染一次。
真值: 渲染一次。
假值(false、null、undefined、空数组): 不渲染。
在以下示例中,区块 {{#items}} 遍历 items 数组。对于每次迭代,区块内的变量(如 {{name}} 和 {{price}})会针对当前数组元素进行解析:
{{!-- 模板 --}}
购物清单:
{{#items}}
- {{name}}: ${{price}}
{{/items}}
{{!-- 输入 --}}
{
"items": [
{"name": "Apple", "price": "1.50"},
{"name": "Banana", "price": "0.75"},
{"name": "Orange", "price": "2.00"}
]
}
{{!-- 输出 --}}
购物清单:
- Apple: $1.50
- Banana: $0.75
- Orange: $2.00
区块消除了手动构建重复文本的需要。在评估器中,您将使用区块来遍历对话消息或 少样本示例 。
对于深度嵌套的分层数据,您可以嵌套多个区块来处理具有多个数组和对象级别的复杂结构:
{{!-- 模板 --}}
{{#company}}
公司:{{name}}
{{#departments}}
部门:{{dept_name}}
{{#employees}}
- {{employee_name}} ({{role}})
{{/employees}}
{{/departments}}
{{/company}}
{{!-- 输入 --}}
{
"company": {
"name": "TechCorp",
"departments": [
{
"dept_name": "Engineering",
"employees": [
{"employee_name": "Ashley", "role": "Senior Engineer"},
{"employee_name": "Billy", "role": "Engineer"}
]
},
{
"dept_name": "Sales",
"employees": [
{"employee_name": "Carol", "role": "Sales Manager"}
]
}
]
}
}
{{!-- 输出 --}}
公司:TechCorp
部门:Engineering
- Ashley (Senior Engineer)
- Billy (Engineer)
部门:Sales
- Carol (Sales Manager)
您可以创建任意深度的结构,但为了可读性,考虑在模板化之前将非常深的结构扁平化。这种方法适用于嵌套类别、带有元数据的对话线程或任何分层数据表示。
嵌套循环
您可以嵌套区块来处理多级数据结构:
{{!-- 模板 --}}
{{#categories}}
类别:{{name}}
{{#products}}
- {{title}} ({{price}})
{{/products}}
{{/categories}}
{{!-- 输入 --}}
{
"categories": [
{
"name": "Fruits",
"products": [
{"title": "Apple", "price": "$1.50"},
{"title": "Banana", "price": "$0.75"}
]
},
{
"name": "Vegetables",
"products": [
{"title": "Carrot", "price": "$0.50"},
{"title": "Lettuce", "price": "$1.25"}
]
}
]
}
{{!-- 输出 --}}
类别:Fruits
- Apple ($1.50)
- Banana ($0.75)
类别:Vegetables
- Carrot ($0.50)
- Lettuce ($1.25)
外部区块 {{#categories}} 将上下文设置为每个类别对象。在该上下文中,{{name}} 指的是类别名称,而内部区块 {{#products}} 则遍历该类别的产品。
当您的数据具有层次关系时,请使用嵌套循环——例如,包含产品的类别、包含员工的部门,或包含多次交流的对话线程。
按索引访问数组元素
有时您需要特定的元素而不是循环。使用带数字索引的点表示法:
{{!-- 模板 --}}
第一项:{{items.0}}
第二项:{{items.1}}
最后一项:{{items.2}}
{{!-- 输入 --}}
{
"items": ["Apple", "Banana", "Orange"]
}
{{!-- 输出 --}}
第一项:Apple
第二项:Banana
最后一项:Orange
您必须在编写模板时知道索引。
评估器通常需要对话线程中的第一条用户消息或最后一条 AI 响应。使用 {{all_messages.0}} 获取第一条消息,或在数据中预先计算最后一条消息。
您可以使用区块作为条件。它们仅在值存在、非空且不为 false 时渲染:
{{!-- 模板 --}}
{{#user}}
欢迎回来,{{name}}!
{{/user}}
{{!-- 输入(用户存在) --}}
{
"user": {
"name": "Ashley"
}
}
{{!-- 输出 --}}
欢迎回来,Ashley!
{{!-- 输入(无用户) --}}
{}
{{!-- 输出 --}}
(空 - 区块不渲染)
区块 {{#user}} 检查 user 是否存在且为真值。如果是,则渲染内部内容,并以 user 为上下文(因此 {{name}} 会在 user 内部查找 name)。
仅在用户数据可用时显示可选内容,例如“欢迎回来”消息,或仅在错误存在时显示错误消息。
反向区块
反向区块仅在值不存在、为 false、null、undefined 或空数组时渲染。反向区块通常用于处理空状态,例如缺失数据或空列表。
在以下示例中:
{{#results}} 遍历每个结果,并为每个项目渲染一行。
{{^results}} 仅在结果数组为空或缺失时渲染。
反向区块在没有结果可显示时提供了清晰的回退。
{{!-- 模板 --}}
"{{query}}" 的搜索结果:
{{#results}}
- {{title}} ({{year}})
{{/results}}
{{^results}}
未找到结果。请尝试不同的搜索词。
{{/results}}
{{!-- 输入(有结果)--}}
{
"query": "matrix",
"results": [
{"title": "The Matrix", "year": 1999},
{"title": "The Matrix Reloaded", "year": 2003}
]
}
{{!-- 输出 --}}
"matrix" 的搜索结果:
- The Matrix (1999)
- The Matrix Reloaded (2003)
{{!-- 输入(无结果) --}}
{
"query": "asdlkjasd",
"results": []
}
{{!-- 输出 --}}
"asdlkjasd" 的搜索结果:
未找到结果。请尝试不同的搜索词。
您还可以组合常规区块和反向区块来创建 if/else 逻辑,在变量缺失时提供默认值。
常规区块 {{#username}} 仅在 username 存在时渲染。反向区块 {{^username}} 仅在它不存在时渲染。它们共同创建了一个 if/else 分支。这在用户数据可选时个性化提示,或在未提供自定义指令时显示默认指令时非常有用:
{{!-- 模板 --}}
{{#username}}
你好,{{username}}!
{{/username}}
{{^username}}
你好,访客!
{{/username}}
{{!-- 输入(有用户名) --}}
{"username": "Ashley"}
{{!-- 输出:你好,Ashley! --}}
{{!-- 输入(无用户名) --}}
{}
{{!-- 输出:你好,访客! --}}
这种模式扩展到布尔标志,允许您根据数据条件更改输出格式:
{{!-- 模板 --}}
状态:{{status}}
{{#is_urgent}}
⚠️ 紧急 - 需要立即关注!
{{/is_urgent}}
{{^is_urgent}}
标准优先级
{{/is_urgent}}
{{!-- 输入 --}}
{
"status": "Open",
"is_urgent": true
}
{{!-- 输出 --}}
状态:Open
⚠️ 紧急 - 需要立即关注!
在数据中使用布尔标志来控制哪些内容块渲染。这可以将格式化逻辑保留在应用程序代码之外,而放在模板中。这种方法适用于突出显示重要信息、根据上下文调整语气(正式与非正式),或为不同的用户类型显示不同的指令。
注释用于记录您的模板,而不影响输出。使用 {{! comment }} 或 {{!-- comment --}}:
{{!-- 模板 --}}
你好,{{name}}!
{{! 这是一个注释,不会出现在输出中 }}
欢迎使用我们的服务。
{{!-- 输入 --}}
{
"name": "Ashley"
}
{{!-- 输出 --}}
你好,Ashley!
欢迎使用我们的服务。
使用注释来解释复杂的区块、记录预期的数据结构或说明某些逻辑存在的原因。这有助于协作者理解您的模板。
用于评估器和线程的特殊变量
在构建 评估器 或处理对话式 AI 时,LangSmith 会自动提供以有用方式结构化对话数据的特殊变量。这些变量仅在评估器上下文中可用 ,而不是在常规的 Playground 提示中。
评估器需要整体分析对话——查看跨多条消息的模式,比较第一个问题和最终答案,或检查 AI 对后续问题的响应效果如何。这些变量使得无需手动操作数据即可轻松访问对话结构。
线程消息变量
LangSmith 提供了对话 线程 的三种预结构化视图:
{{!-- 访问线程中的所有消息 --}}
{{#all_messages}}
{{role}}: {{content}}
{{/all_messages}}
{{!-- 访问人机消息对 --}}
{{#human_ai_pairs}}
Human: {{human}}
AI: {{ai}}
{{/human_ai_pairs}}
{{!-- 访问第一条人类消息和最后一条 AI 消息 --}}
{{#first_human_last_ai}}
原始问题:{{first_human}}
最终答案:{{last_ai}}
{{/first_human_last_ai}}
{{!-- 按索引访问特定消息 --}}
第一条消息:{{all_messages.0}}
第二条消息:{{all_messages.1}}
all_messages :按时间顺序排列的每条消息,包含 role(用户/助手/系统)和 content 字段。使用此变量显示完整的对话流程。
human_ai_pairs :消息按问答对分组。每对包含 human(用户消息)和 ai(助手响应)。在评估响应质量时使用此变量。
first_human_last_ai :仅包含初始问题(first_human)和最终答案(last_ai)。使用此变量检查 AI 是否最终回答了原始问题,忽略中间的对话。
带有线程上下文的示例
以下是一个使用线程上下文的实用评估器提示示例:
{{!-- 模板 --}}
评估此对话:
{{#all_messages}}
{{role}}: {{content}}
{{/all_messages}}
AI 有帮助吗?请从 1-5 评分。
{{!-- 输入(由 LangSmith 提供) --}}
{
"all_messages": [
{"role": "user", "content": "What's the weather?"},
{"role": "assistant", "content": "I don't have access to weather data."},
{"role": "user", "content": "Can you tell me a joke instead?"},
{"role": "assistant", "content": "Why did the chicken cross the road?"}
]
}
{{!-- 输出 --}}
评估此对话:
user: What's the weather?
assistant: I don't have access to weather data.
user: Can you tell me a joke instead?
assistant: Why did the chicken cross the road?
AI 有帮助吗?请从 1-5 评分。
该模板使用 mustache 区块 {{#all_messages}} 遍历对话数组。对于每次迭代,区块将上下文设置为该消息对象,因此 {{role}} 和 {{content}} 访问当前消息的属性。循环自动按顺序遍历所有四条消息,将每条显示为 "role: content"。这为评估器 LLM 提供了完整的对话历史来评估帮助性。
在 LangSmith 中创建评估器时,选择要包含哪些线程变量。LangSmith 将自动从正在评估的对话中填充它们。
少样本示例
少样本提示通过示例来教导 LLM。您提供几个展示任务的输入-输出对,然后要求它对新的输入执行相同的任务。
少样本示例 帮助 LLM 理解:
格式期望 (例如,“用 JSON 响应”或“使用这种语气”)
边缘情况 (例如,如何处理模糊输入)
任务细微差别 (例如,“积极”和“非常积极”情感之间的区别)
这对于分类、格式化和风格任务特别有用,因为展示比讲述更清晰。
少样本占位符
在 LangSmith 中,在您希望示例出现的位置使用 {{few_shot_examples}} 占位符:
{{!-- 模板 --}}
你是一个情感分类器。
{{few_shot_examples}}
现在对以下文本进行分类:
文本:{{text}}
情感:
当您在 LangSmith UI 中启用少样本示例(在评估器或提示中心中)时,您需要单独配置示例格式。LangSmith 会自动将那些格式化后的示例注入到您放置 {{few_shot_examples}} 占位符的任何位置。这使您的提示模板保持整洁,并允许您独立管理示例。
配置示例后的输出示例:
你是一个情感分类器。
文本:I love this!
情感:positive
文本:This is terrible.
情感:negative
文本:It's okay.
情感:neutral
现在对以下文本进行分类:
文本:This is amazing!
情感:
在 LangSmith UI 中配置您的少样本示例,以匹配您用于实际任务的格式。这种一致性有助于 LLM 正确泛化。占位符方法将提示结构与示例数据分离,使两者都更易于维护。
格式之间的转换
F-string 到 mustache 对于基本变量总是有效。格式说明符会被转换,但格式化会被移除。
Mustache 到 f-string 仅适用于基本变量。Mustache 的功能,如点表示法、区块、条件和注释,在 f-string 中没有等效项,无法转换:
点表示法: {{user.name}} F-string 会将 "user.name" 视为单个变量名,而不是嵌套访问。
区块/循环: {{#items}}...{{/items}} 在 f-string 中没有等效项。
条件: {{#value}}...{{/value}} 在 f-string 中没有等效项。
反向区块: {{^value}}...{{/value}} 在 f-string 中没有等效项。
注释: {{! comment }} 在 f-string 中没有等效项。
如果您尝试转换具有这些功能的 mustache 模板,LangSmith 将拒绝转换或仅转换简单部分,从而破坏模板的功能。转换后请务必预览。
其他资源