写作归档

情绪状态机实现

类型
文章
日期
2026/10/15
阅读
5 分钟
字数
1,353

1. 情绪状态机

这篇文章,我们来讨论一个情绪连续性的问题。

前面我们提到过这样一个场景:用户昨晚刚和 AI Agent 吵过架,第二天又发来一句 早安。没有情绪系统时,AI Agent 可能立刻回复 早安!今天天气不错!,像是在处理一段全新的对话。引入情绪系统后,它则可能只回一句 ……早。,因为昨晚产生的情绪还没有消失。

两种回复的差异并不只是 Prompt 写法造成的,更重要的是,系统是否维护了能够跨越多轮对话的情绪状态。

LLM 本身没有情绪,每次回复都依赖当前收到的上下文。Prompt 中写着 你现在很生气,它就会按照生气的状态回复;换成 你现在很开心,它又会表现得开心。

真正需要解决的问题是:当前应该处于什么情绪,由谁来决定? 这个判断不能只交给 LLM,而要由应用层的调度逻辑负责。这个调度逻辑,我们称之为情绪状态机。

应用层维护一份独立于 LLM 的情绪状态,根据用户行为更新它,并在每次生成回复前把当前情绪写入对话上下文。

2. 有限状态机

有限状态机(Finite State Machine,FSM)是计算机科学中常见的建模方式,由三个要素组成:

  • 状态集合:系统可能处于的所有状态,例如开心、生气和平静
  • 转移条件:触发状态切换的事件或条件,例如用户道歉后,状态从生气转为平静
  • 当前状态:系统在某一时刻所处的唯一状态

FSM 有一个明确的约束:系统在任何时刻只能处于一个离散状态。在这篇文章里,FSM 只负责维护 Agent 当前的主导情绪,例如 calm 或 angry。情绪强度、亲密度和进入状态的时间是附加的连续变量,它们会影响回复的表现,但不属于有限状态集合本身。

我们在使用一个以 FSM 为核心、带有连续变量的情绪状态模型。这样既保留了有限状态机可预测的优点,也能表达“同样是生气,但程度不同”这种实际需求

为什么使用 FSM,而不是直接让 LLM 判断当前情绪?这里主要是基于如下考虑

  1. 可预测:状态转移遵循确定的规则,不会因 LLM 的随机性而在相同条件下得到不同结果。
  2. 可调试:状态与转移条件都是显式数据,出现问题时可以定位到具体规则。
  3. 可持久化:一个表示当前状态的字符串,再加上情绪强度、时间戳等少量数值,就能完整保存到数据库。
  4. 低成本:事件识别可以交给 LLM,状态转移则通过普通逻辑判断完成,不需要为每次转移额外调用 LLM

3. AI 伴侣的情绪模型设计

下面以“小薇”为例,设计一套包含六种 Agent 主导情绪的模型。用户自己的情绪需要单独记录,不能因为用户难过,就直接把 Agent 的状态改成难过。

我们的情绪状态定义如下:

状态含义表现特征Prompt 风格
平静(Calm)默认状态正常语气,温柔日常基础人设 Prompt
开心(Happy)被夸奖、收到礼物语气活泼,主动撒娇甜蜜模式 Prompt
生气(Angry)被忽视、争吵、记错事语气冷淡或暴躁冷战/暴怒 Prompt
难过(Sad)Agent 自身受到冷落或冲突影响语气低沉,敏感脆弱自我表达 Prompt
害羞(Shy)表白、亲密互动说话磕磕巴巴,颜文字增多娇羞模式 Prompt
吃醋(Jealous)出现暧昧或潜在竞争关系语气酸酸的,旁敲侧击醋意模式 Prompt

模型一共包含 6 种情绪状态。其中,平静是默认状态,其余 5 种状态需要由具体事件触发

每种情绪都应该有明确的进入和退出条件。

实际设计时,不能只列出几个示例状态,还要为没有特殊规则的情况定义默认行为:没有匹配到转移条件时,保持当前状态。这样转移函数才是完整的,普通闲聊也不会让情绪无故跳转

type AgentMood = 'calm' | 'happy' | 'angry' | 'sad' | 'shy' | 'jealous'
type EmotionEvent =
  | 'praise' | 'argument' | 'apology' | 'intimate'
  | 'rival' | 'gift' | 'neglect' | 'neutral'

const transitionRules: Record<AgentMood, Partial<Record<EmotionEvent, AgentMood>>> = {
  calm:   { praise: 'happy', argument: 'angry', intimate: 'shy', rival: 'jealous', gift: 'happy', neglect: 'sad' },
  happy:  { argument: 'angry', intimate: 'shy', rival: 'jealous', neglect: 'sad' },
  angry:  { apology: 'calm', gift: 'happy', rival: 'jealous' },
  sad:    { apology: 'calm', praise: 'happy', intimate: 'shy' },
  shy:    { argument: 'angry', praise: 'happy' },
  jealous:{ apology: 'calm', argument: 'angry', gift: 'happy' },
}

function resolveMood(currentMood: AgentMood, event: EmotionEvent): AgentMood {
  return transitionRules[currentMood][event] ?? currentMood
}

这里的代码只展示主导情绪的转移,强度和亲密度应该在同一个规则函数中单独计算。不同情绪可以有不同的衰减时间,例如生气比开心持续得更久;状态也不一定要先回到平静,再进入下一种情绪,生气时收到合适的礼物就可以直接转为开心

4. 情绪路由

可以利用 langGraph 的条件路由来实现情绪路

订阅后解锁剩余内容

已免费试看前 30%,订阅小册即可阅读全文。

订阅小册
0 条

还没有评论。

发表评论