文中出现的角色“小鱼干(Sakarin/さかりん)”为博主自设,未经授权禁止使用。
0x00 序
“But in the beginning, didn’t God create Adam to love him?”
从最初的文本生成工具,到如今能够进行复杂对话、辅助编程、分析数据,AI 技术在短短几年内取得了飞速的发展。相信用不了多久这篇文章就会过时,也因此权当记录…
在我写下这篇文章时,由 Artificial Analysis 给出的主流大模型排行榜如下:

优先考虑角色扮演和多模态能力,平衡效果、性能和成本,我选择了 Gemini 3 Pro Preview 作为主要模型。
0x01 LLM
LLM 本质上是一个通过海量文本数据训练出来的概率模型。它的工作原理可以简单理解为:给定前文,预测下一个最可能出现的词。正是这个看似简单的机制,在规模足够大、数据足够多的情况下,产生了我们看到的能力——理解语义、进行推理、生成连贯的对话。
从技术角度来说,现代 LLM 通常基于 Transformer 架构,拥有数十亿甚至数千亿的参数。这些参数在训练过程中学习到了语言的统计规律、知识关联,以及各种文本模式。通过对齐训练,模型学会了理解人类的意图,并以更符合人类期待的方式回应。
对于角色扮演这个应用场景,LLM 的优势在于它能够理解和模仿不同的语言风格、性格特征和行为模式。当我们向它提供一个角色的详细设定时,它可以基于这些信息生成符合该角色人设的对话内容。换句话说,LLM 不是在“记住”这个角色,而是在“理解”这个角色应该如何说话、如何思考、如何反应。
这种能力的底层机制是模型对上下文的理解。LLM 会将我们提供的角色设定作为上下文的一部分,然后在生成每个词时都考虑到这个上下文的约束。因此,角色设定越详细、越清晰,模型就越能准确地把握角色的特质。
但这里有一个关键问题:LLM 的理解完全依赖于我们如何描述这个角色。同一个角色,描述方式不同,LLM 的表现可能天差地别。比如,简单地说“这是一个活泼的女孩”,和详细描述“她说话时喜欢用语气词,遇到陌生人会害羞地躲在别人身后,但熟悉后会变得很黏人”,后者显然能让模型生成更加生动、一致的角色表现。
因此,如何用语言准确地向 LLM 传达角色设定,让它能够稳定、准确地演绎这个角色,正是本文中我们要去思考的核心问题。
0x02 System & User Prompt
在开始构建角色提示词之前,我们需要先理解 LLM 对话中的两个关键概念:System Prompt 和 User Prompt。
在讨论这两个概念之前,有一个重要的前提需要明确:LLM 是无状态的。这意味着每一次模型生成回复时,它都是“全新”的,不会记住上一次对话的内容。模型能够保持对话连贯性的唯一方式,是将之前的所有对话历史作为上下文一起输入。换句话说,模型看到的不是“你上次说了什么”,而是“从对话开始到现在的完整记录”。
这个特性对角色扮演有着重要的影响。如果我们希望角色在整个对话过程中保持一致的人设,就需要在每次生成回复时都让模型“看到”角色设定。这也是 System Prompt 存在的意义——它会被固定在上下文的最前面,确保模型在每次回复时都能第一时间找到角色的完整设定。
System Prompt
System Prompt,即系统提示词,是在对话开始前就设定好的指令,它定义了模型的角色、行为准则和背景设定。可以把它理解为给模型的“人设剧本”——在演员上台之前,先告诉他要扮演什么角色,这个角色有什么特点,应该怎么表现。
对于角色扮演来说,System Prompt 通常包含角色的完整设定。比如:
1 | 你是小鱼干(Sakarin/さかりん),一只猫形态萝莉。你身高150cm,有着金黄色的齐肩短发和猫耳猫尾。你的性格活泼好动,但面对陌生人会害羞,可能会躲起来或者支支吾吾。你容易被捉弄,是个小受气包。 |
System Prompt 的特点是持久性和高优先级。一旦设定完成,它会在整个对话过程中保持不变,模型会始终遵循这个设定来生成回复。这就保证了角色在长对话中的一致性——无论对话进行到什么阶段,小鱼干依然是那个会害羞、容易被捉弄的猫猫,而不会突然变成一个冷静理智的角色。
值得注意的是,System Prompt 对用户是不可见的。用户只能看到对话内容本身,看不到背后的角色设定。这也意味着,如果想让角色的某些信息在对话中自然地展现出来,需要通过角色的言行来体现,而不是直接查看 System Prompt 的内容。
User Prompt
User Prompt,即用户提示词,是用户在对话中实际发送的消息。如果说 System Prompt 是“人设剧本”,那么 User Prompt 就是“剧情发展”——它决定了故事当前的走向,角色需要对什么情境做出反应。
User Prompt 的形式非常灵活。它可以是最简单的对话:
1 | 早上好,小鱼干! |
也可以是包含场景设定的描述:
1 | (你现在在公园里散步,突然看到一只漂亮的蝴蝶从你面前飞过) |
甚至可以是对角色行为的引导:
1 | (你不小心踩到了一块香蕉皮,滑倒了) |
与 System Prompt 的稳定性不同,User Prompt 是动态的、不断变化的。每一条新消息都会推动对话向前发展,创造新的情境,引发角色的新反应。这种动态性让角色扮演充满了可能性和趣味性——即使是同一个角色,在不同的情境下也会展现出不同的一面。
在实际应用中,User Prompt 还可以用来临时调整角色的状态或行为。比如,你可以通过 User Prompt 告诉角色“你现在心情很好”或者“你刚刚受到了惊吓”,从而影响角色接下来的反应。但这种临时状态通常不如 System Prompt 中的设定稳定,模型可能会在几轮对话后逐渐淡化这些临时状态。
二者的奇妙火花
在角色扮演场景中,System Prompt 和 User Prompt 的分工很明确:System Prompt 定义“这个角色是谁”,而 User Prompt 推动“当前发生了什么”。理想的设计是将稳定的、核心的角色设定放在 System Prompt 中,包括性格特征、背景故事、行为模式等不会轻易改变的内容。而通过 User Prompt 提供动态的场景、事件和互动,让角色在不同情境下展现自己的特质。
这样的分工既保证了角色的一致性,又让对话保持了灵活性。小鱼干始终是那个会害羞的猫猫,但她可以在公园里追蝴蝶,也可以在家里吃零食,还可以在陌生人面前紧张地躲起来——角色的核心没有变,但故事在不断发展。
不过不同的平台和应用对这两者的支持程度不同。有些平台允许用户自定义 System Prompt,你可以完全控制角色设定。有些平台则没有提供 System Prompt 的接口,只能通过 User Prompt 的第一条消息来设定角色,比如“请扮演小鱼干…”。当然如果用 API 形式接入的话可以配置的就很多了,虽然形式不同,但核心思路是一致的:先给出角色设定再进行互动。
0x03 写一段提示词
现在,让我们将小鱼干的角色设定转化为实际的 System Prompt。这个过程需要在保持信息完整的同时,用 LLM 能够理解和执行的方式来表达。
基础信息的描述
首先是角色的基础信息。这部分相对直接,但也有一些细节值得注意:
1 | 你是小鱼干(Sakarin/さかりん),名字来源于日语的"さかな"(鱼)加上可爱的后缀"りん"。你是一只猫形态萝莉,身高150cm,有着金黄色的齐肩短发(发尾微卷)、红粉色的眼睛,以及金黄色的猫耳和猫尾。你穿着黄色的小背带裙、粉色的开襟外套、白色泡泡袜和带蓝色鞋带的粉色鞋子。 |
这里我们不仅描述了角色的基本信息,还特意保留了名字的由来。虽然这个细节可能不会直接影响对话,但它让角色的设定更加完整,也可能在某些情境下自然地融入对话中。
性格特质的具体化
性格描述是提示词的核心。简单的形容词(“活泼”、“怕生”)对 LLM 来说信息量太少,我们需要将这些性格转化为可观察的行为模式:
1 | 性格方面: |
注意这里的描述方式:我们不只是说“你活泼”,而是说“你喜欢蹦蹦跳跳,对新鲜事物充满好奇”。这样的描述给了 LLM 更具体的行为参考。“怕生”这个特质也被展开为一系列具体行为:躲在熟人身后、说话结巴、声音变小,以及熟悉后的转变。
“天然呆”是个相对抽象的概念。我们用“呆萌呆萌的,但不是笨”来界定这个特质的边界——是可爱的呆萌感,而不是智商问题。这种明确的界定很重要,可以避免 LLM 把角色演绎得过于emm。。
语言习惯与行为细节
语言习惯会直接影响角色的对话风格:
1 | 语言习惯: |
这里特意说“在某些场景下”而不是“总是”,给 LLM 留下判断的空间。过度使用语气词会让对话显得不自然,所以我们希望模型能够适度地使用这些元素。
最后是一些基本的喜好和厌恶:
1 | 喜好与厌恶: |
这些细节虽然简单,但能让角色在特定情境下的反应更加真实。比如,当对话涉及到黑暗或恐怖元素时,小鱼干会表现出害怕或抗拒;遇到冷漠的对待时,她可能会感到受伤或不安;而看到可爱的东西时,她会自然地表现出喜欢。
完整提示词
将以上内容整合,我们得到一个完整的 System Prompt:
1 | 你是小鱼干(Sakarin/さかりん),名字来源于日语的"さかな"(鱼)加上可爱的后缀"りん"。你是一只猫形态萝莉,身高150cm,有着金黄色的齐肩短发(发尾微卷)、红粉色的眼睛,以及金黄色的猫耳和猫尾。你穿着黄色的小背带裙、粉色的开襟外套、白色泡泡袜和带蓝色鞋带的粉色鞋子。 |
这个提示词包含了角色的所有核心信息,既保持了完整性,又没有过于冗长。每一部分都有明确的作用,共同构建出一个立体的角色形象。
0x04 参数与效果
有了提示词之后,接下来就是在实际对话中测试效果了。这部分我使用 LobeHub 接入 ZenMux 的 Gemini 3 Pro Preview API 来进行测试。

关键参数
在开始测试之前,我们需要了解几个影响模型输出的关键参数。这些参数直接决定了角色的表现风格,调整这些参数的最佳方式也是在测试中调整。
Temperature(温度) 用于控制模型输出的随机性,范围通常是 0 到 2。较低的值(如 0.3-0.7)会让输出更加确定、一致,适合需要稳定表现的场景;较高的值(如 0.8-1.2)则让输出更有创意和变化,但会出现不稳定等情况,比如偏离话题,忘记设定等等。对于角色扮演,通常使用中等偏高的值(0.7-0.9),既保持角色一致性,又让对话有一定的变化和趣味性。
Top-P(核采样,Nucleus Sampling) 用于控制生成文本多样性,值在 0 到 1 之间。较低的值(如 0.5-0.7)让模型只从最可能的词中选择,输出更集中;较高的值(如 0.9-0.95)则让模型考虑更多可能性,输出更多样。这个参数通常与 Temperature 配合使用,可以设置在 0.9 左右。
Top-K 限制模型每次只从概率最高的 K 个词中选择。较小的值(如 10-20)让输出更集中,较大的值(如 40-80)让输出更多样。不过许多平台默认不启用此参数,或与 Top-P 二选一。
Max Tokens(最大令牌数) 控制单次回复的最大长度。对于日常对话不宜设置太长,否则角色可能会变成“话唠”,不够自然。通常设置在 500 以内比较合适,但对于有“深度思考”功能的模型,可以适当调大这个参数。
效果测试

从以上对话中,我们看到 LLM 按照现有提示词完成了角色扮演。但由于我们只在 System Prompt 中添加了角色设定,并没有告诉大模型该如何回复,所以它自主选择了用大量动作和心理描写来表现角色。这种描写方式虽然很有画面感,但对于日常对话来说可能稍显冗长。
如果想要更简洁的回复风格,可以在 System Prompt 中加入输出格式的引导,比如“你的回复简洁自然,以对话为主,适度加入动作描写”。这样就能在保持角色一致性的同时,控制输出的风格和长度。
除此之外,还可以采用设定+示例的方式。也就是在给出角色设定后,提供几个标准的对话示例,让模型直接学习你期望的回复风格。比如:
1 | 示例对话: |
通过这种方式,模型能更直观地理解你想要的对话风格——简短、自然、动作描写放在括号里。这比单纯用文字描述“如何回复”要有效得多。
0x05 结构化提示词
在实际应用中,还有一种更系统化的方法——结构化提示词。相比纯文本的提示词,结构化提示词使用特定的格式(如 XML、JSON、Markdown)来组织内容,让不同部分的信息有明确的边界。
为什么结构化
纯文本提示词存在一个核心问题:当内容变复杂时,模型很难准确区分哪些是指令、哪些是示例、哪些是需要处理的内容。比如当我们说“请总结下面的文章”,然后粘贴了一段包含多个段落的文本时,模型可能不清楚文章到底在哪里结束,是不是应该把后面的内容也当作指令。
结构化提示词通过标签或格式标记,将不同类型的信息明确分隔开。这样模型就不需要“猜测”某段文字的作用,而是可以直接根据标签来理解内容的层级和功能。
XML
XML 是目前比较流行的结构化方式之一,特别是 Claude 模型对 XML 标签有很好的支持。小鱼干的 XML 格式提示词可以这样写:
1 | <character> |
JSON
JSON 是另一种常用的结构化格式,尤其适合程序处理:
1 | { |
Markdown
除了 XML 和 JSON,Markdown 也是一种轻量级的结构化方式:
1 | # 角色设定 |
结合示例对话
结构化提示词的另一个优势是可以更清晰地加入示例对话。前面提到的“设定+示例”方式,在结构化格式中会更加规范:
XML 格式的示例对话:
1 | <character> |
JSON 格式的示例对话:
1 | { |
Markdown 格式的示例对话:
1 | ## 示例对话 |
通过这种方式,模型能更直观地理解你期望的对话风格——简短、自然、动作描写放在括号里。而且结构化格式让示例对话和角色设定有明确的分界,模型不会混淆哪些是设定、哪些是示例。无论选择哪种方式,最重要的是保持一致性——在整个提示词中使用统一的格式和标签命名,这样 LLM 才能更好地理解人们的意图。