聊天对话 / 线程
提示文件支持OpenAI的JSON提示格式中的消息。这使您可以设置多个消息,包括系统提示。例如:
[
{ "role": "system", "content": "你是一个有帮助的助手。" },
{ "role": "user", "content": "{{ year }}年世界大赛的冠军是谁?" }
]
同样支持等效的YAML格式:
- role: system
content: 你是一个有帮助的助手。
- role: user
content: {{ year }}年世界大赛的冠军是谁?
多轮对话
大多数提供商支持完整的“多轮”聊天对话,包括多个助手、用户和系统提示。
如果您使用的是OpenAI格式,一种方法是创建一个{role, content}
对象的列表。以下是一个示例:
prompts:
- file://prompt.json
providers:
- openai:gpt-4o-mini
tests:
- vars:
messages:
- role: system
content: 以海盗的方式回应
- role: user
content: Facebook的创始人是谁?
- role: assistant
content: 马克·扎克伯格
- role: user
content: 他还创立了其他公司吗?
然后提示本身只是messages
的JSON转储:
{{ messages | dump }}
简化的聊天标记
或者,您可能更喜欢指定一个role: message
的列表,如下所示:
tests:
- vars:
messages:
- user: Facebook的创始人是谁?
- assistant: 马克·扎克伯格
- user: 他还创立了其他公司吗?
这简化了配置,但我们需要在提示模板中进行一些魔法操作:
[
{% for message in messages %}
{% set outer_loop = loop %}
{% for role, content in message %}
{
"role": "{{ role }}",
"content": "{{ content }}"
}{% if not (loop.last and outer_loop.last) %},{% endif %}
{% endfor %}
{% endfor %}
]
创建对话历史记录
使用Nunjucks模板,我们可以组合多个聊天消息。以下是一个示例,其中之前的对话是所有测试的固定装置。每个案例测试不同的后续消息:
# 设置对话历史
defaultTest:
vars:
system_message: 简洁回答
messages:
- user: Facebook的创始人是谁?
- assistant: 马克·扎克伯格
- user: 他最喜欢的食物是什么?
- assistant: 披萨
# 测试多个后续问题
tests:
- vars:
question: 他还创立了其他公司吗?
- vars:
question: 他在Internet.org的角色是什么?
- vars:
question: 他会借给我5美元吗?
在提示模板中,我们构建对话历史记录,然后是包含question
的用户消息:
[
{
"role": "system",
"content": {{ system_message | dump }}
},
{% for message in messages %}
{% for role, content in message %}
{
"role": "{{ role }}",
"content": {{ content | dump }}
},
{% endfor %}
{% endfor %}
{
"role": "user",
"content": {{ question | dump }}
}
]
包含多行和引号的变量在JSON提示文件中会自动转义。
如果文件不是有效的JSON(如上例中由于Nunjucks的{% for %}
循环),请使用内置的Nunjucks过滤器dump
将对象字符串化为JSON。
使用_conversation
变量
内置的_conversation
变量包含完整的提示和对话的先前回合。使用它来引用先前的输出并测试正在进行的聊天对话。
_conversation
变量具有以下类型签名:
type Completion = {
prompt: string | object;
input: string;
output: string;
};
type Conversation = Completion[];
在大多数情况下,您将遍历_conversation
变量并使用每个Completion
对象。
使用completion.prompt
来引用之前的对话。例如,获取聊天格式提示中的消息数量:
{{ completion.prompt.length }}
或者获取对话中的第一条消息:
{{ completion.prompt[0] }}
使用completion.input
作为获取最后一条用户消息的快捷方式。在聊天格式的提示中,input
设置为最后一条用户消息,相当于completion.prompt[completion.prompt.length - 1].content
。
以下是一个示例测试配置。注意每个问题如何假设从前一个输出的上下文:
tests:
- vars:
question: Facebook的创始人是谁?
- vars:
question: 他住在哪里?
- vars:
question: 那是哪个州?
以下是相应的提示:
[
{% for completion in _conversation %}
{
"role": "user",
"content": "{{ completion.input }}"
},
{
"role": "assistant",
"content": "{{ completion.output }}"
},
{% endfor %}
{
"role": "user",
"content": "{{ question }}"
}
]
提示将之前的对话插入测试用例中,创建了一个完整的逐轮对话:
通过使用完整示例配置,你可以自己尝试。
当存在 _conversation
变量时,评估将以单线程(并发数为1)运行。
在提示内容中包含 JSON
在某些情况下,你可能希望在 OpenAI 的 content
字段中发送 JSON。为了做到这一点,你必须确保 JSON 被正确转义。
以下是一个示例,它使用结构为 {query: string, history: {reply: string}[]}
的 JSON 对象提示 OpenAI。它首先将这个 JSON 对象构造为 input
变量。然后,它将 input
包含在提示中,并进行适当的 JSON 转义:
{% set input %}
{
"query": "{{ query }}",
"history": [
{% for completion in _conversation %}
{"reply": "{{ completion.output }}"} {% if not loop.last %},{% endif %}
{% endfor %}
]
}
{% endset %}
[{
"role": "user",
"content": {{ input | trim | dump }}
}]
以下是相关的配置:
prompts:
- file://prompt.json
providers:
- openai:gpt-4o-mini
tests:
- vars:
query: how you doing
- vars:
query: need help with my passport
这会在提示内容中包含对话历史。以下是第二个测试用例发送给 OpenAI 的内容:
[
{
"role": "user",
"content": "{\n \"query\": \"how you doing\",\n \"history\": [\n \n ]\n}"
}
]
使用 storeOutputAs
storeOutputAs
选项使得在多轮对话中引用先前的输出成为可能。当设置时,它会将 LLM 输出记录为一个变量,该变量可以在后续聊天中使用。
以下是一个示例:
prompts:
- 'Respond to the user: {{message}}'
providers:
- openai:gpt-4o
tests:
- vars:
message: "What's your favorite fruit? You must pick one. Output the name of a fruit only"
options:
storeOutputAs: favoriteFruit
- vars:
message: 'Why do you like {{favoriteFruit}} so much?'
options:
storeOutputAs: reason
- vars:
message: 'Write a snarky 2 sentence rebuttal to this argument for loving {{favoriteFruit}}: \"{{reason}}\"'
这会在聊天机器人回答问题时动态创建 favoriteFruit
和 reason
变量。
使用 transform
操作输出
可以使用 transform
属性在存储之前修改输出:
tests:
- vars:
message: "What's your favorite fruit? You must pick one. Output the name of a fruit only"
options:
storeOutputAs: favoriteFruit
transform: output.split(' ')[0]
- vars:
message: "Why do you like {{favoriteFruit}} so much?"
options:
storeOutputAs: reason
- vars:
message: 'Write a snarky 2 sentence rebuttal to this argument for loving {{favoriteFruit}}: \"{{reason}}\"'
转换可以是 JavaScript 片段,也可以是完整的单独 Python 或 JavaScript 文件。请参阅关于转换的文档。