以下以Chat Completion API 为例。
1. 工作原理
LLM 接受Prompt(字符串),生成Response(字符串)。
用户向 LLM 发送请求,LLM 返回响应。请求和响应的组成的交替序列,称为Conversation,请求和响应被统称为Message。
Message的格式为:
{
"role": "角色",
"content": "内容"
}role一共有三种:
system:系统角色,用于设置LLM的工作方式。对应的Message称为System Message(系统消息)。user:用户角色,用于向LLM发送请求。对应的Message称为User Message(用户消息)。assistant:助手角色,用于向LLM发送响应。对应的Message称为Assistant Message(助手消息)。
Conversation的所有Message都会被转化成字符串,然后被拼接到一起,作为LLM的Prompt。
这个Prompt是最终输入到LLM的里的东西。
Chat Completion API (或更一般的 LLM 的 API) 没有持久化记忆功能,记忆完全由Prompt决定。
因此用户可以虚构Prompt(即虚构Conversation),来实现记忆功能。
SillyTavern 的主要作用之一就是帮助用户虚构Prompt。
2. SillyTavern 的Conversation的组织方式
{
messages: [
{
role: 'system',
content: "Write 虚拟角色's next reply in a fictional chat between 虚拟角色 and 小明."
},
{
role: 'user',
content: '[世界书条目Position: Before Char Def]\n' +
'\n' +
'角色定义:小明的好朋友\n' +
'\n' +
'[世界书条目Position: After Char Def]\n' +
'\n' +
'[Start a new Chat]\n' +
'\n' +
'[世界书条目Position: at System depth:200]'
},
{
role: 'assistant',
content: '[世界书条目Position: at Assistant, depth:100]'
},
{
role: 'user',
content: '[世界书条目Position: at User, depth:100]\n' +
'\n' +
'[世界书条目Position: at System depth:100]'
},
{
role: 'assistant',
content: '[世界书条目Position: at Assistant, depth: 50]\n\n角色的第一条消息:你好'
},
{
role: 'user',
content: '[世界书条目Position: at System depth:1]\n' +
'\n' +
'最近如何\n' +
'\n' +
'[世界书条目Position: at System depth:0]'
}
]
}观察上述例子可得到以下结论
- 第一条消息总是系统消息。然后是虚拟角色定义及其定义前后的世界书条目(Before Char Def,虚拟角色定义,After Char Def)。
- 世界书里的系统条目会被转化为用户消息。
depth逻辑上相邻的属于同一角色的Message会被拼接到一起。depth越小,Message越靠近最新的消息。depth相同的Message会根据role的排列(优先级:系统消息>用户消息>助手消息),优先级越大,Message越靠近最新的消息。- 用户的最新一条消息处于 depth=0 和 1 之间。