Skip to main content

聊天对话 / 线程

提示文件支持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 }}
}
]
info

包含多行和引号的变量在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 }}"
}
]

提示将之前的对话插入测试用例中,创建了一个完整的逐轮对话:

多轮对话评估

通过使用完整示例配置,你可以自己尝试。

info

当存在 _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}}\"'

这会在聊天机器人回答问题时动态创建 favoriteFruitreason 变量。

使用 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 文件。请参阅关于转换的文档