深夜的社区小饭馆里,金牌服务员阿芳正在招待一桌熟客。客人刚落座,她就笑着说:“王先生,还是老样子?水煮鱼微辣、不要香菜对吧?您上次说下周要请客户吃饭,我提前让后厨备好了食材。”阿芳的厉害之处,不只是端菜快——她记住的,是这桌客人从进门到结账之间发生的所有事:谁点的菜、什么口味、菜上到第几道、还有什么没做。这份“记忆”,就是多轮对话里的上下文;而管理这份记忆的整套章法,就是我们要讲的状态管理。 如果阿芳只做一桌生意,靠脑子就够了。可如果同时来了十桌客人,每桌都有临时加菜、退菜、催单,她就必须把小本子、点单纸、后厨挂单墙都利用起来。AI也是如此:一个聊天机器人要应对成千上万的用户,每人说上十几轮,它必须清楚“自己在和谁说话、聊到了哪一步、还能记住多少内容、聊到一半断了怎么接上”。本文会用阿芳的“待客记忆术”当主线,讲透多轮对话中的状态定义、消息存储、上下文窗口、状态机、会话恢复、RAG融合与方案选型。学完之后你会发现——让AI不“失忆”,靠的不是神仙算法,而是一套像餐馆台账一样清晰的管理办法。

岗位关联

对 AI 从业者而言,多轮对话状态管理是聊天机器人、智能客服、RAG 类产品稳定可用的地基。掌握它,你才能把“能对话的Demo”升级成“真正扛得住生产环境的对话系统”。

目录
  1. 可视化演示
  2. 会话状态基础
  3. 消息存储设计
  4. 上下文窗口管理
  5. 状态机流转设计
  6. 会话恢复机制
  7. RAG上下文融合
  8. 方案选型对比
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示对话状态机循环、上下文窗口截断策略和多轮消息流管理。

本节配有交互动效(进入视口后自动加载,约 3KB)。

对话状态机 IDLE→LSTN→NLU→RESP循环驱动对话 意图识别触发状态转移 FSM = (S, Σ, δ, s0, F) 有限状态机管理对话流程

会话状态基础

阿芳接待王先生,不只是端菜那么简单。她脑子里同时装着好几件事:这是几号桌、王先生已点了哪几道菜、水煮鱼做到什么程度、客户聚餐的事推进到哪一步了。这套“接待记忆”如果丢了,她就会端着菜不知所措——这正是无状态AI的困境。所以,做多轮对话的第一步,就是明确“状态”由什么构成。

在技术世界里,我们把“记忆桌台”叫做会话状态(Session State)。它是维持一次连续对话所需的全部必要信息,像一个共享的“便签夹”,前后端都能读写。缺少了它,AI每收到一句话都是“初次见面”,你上一轮说的“我要靠窗座位”,下一轮它就忘得一干二净。

St={m1,m2,⋯ ,mn,u,ct}\displaystyle S_t = \{m_1, m_2, \cdots, m_n, u, c_t\}

1. 历史消息集:把之前每一轮的对话按顺序放进一个集合,这是上下文内容的原材料。

{m1,m2,⋯ ,mn}\displaystyle \{m_1, m_2, \cdots, m_n\}

2. 用户身份:记录当前会话属于谁,用来做个性化回复与权限控制。

u∈UserSet\displaystyle u \in \text{UserSet}

3. 附加上下文变量:保存“进行到一半”的任务,比如购物车、填表进度、订单号等瞬时信息。

ct=var_map\displaystyle c_t = \text{var\_map}

理解了这三件套,阿芳的“记忆术”就有了边界:她不需要记住客人十年前穿的衬衫,只需要记住当下这顿饭的桌台状态。同理,AI的状态管理也讲究“够用即可”——把消息、身份和任务变量管好,就抓住了多轮对话的根基。

消息存储设计

光靠脑子记,阿芳迟早翻车。她的本子上每一条都写得很规矩:桌号、菜名、口味备注、下单时间。后厨和收银台看的是同一套格式。如果一条写着“那个客人要的那个那个”,一条画着涂鸦,整个餐馆就乱了。AI的消息存储也是一样:结构统一,才能被消费。

我们把每条消息建模成一个三元组:角色、内容、时间戳。

M=[m1,m2,⋯ ,mn],mi=(ri,ci,ti)\displaystyle M = [m_1, m_2, \cdots, m_n], \quad m_i = (r_i, c_i, t_i)

1. 消息序列:消息按时间先后组成有序数组,这是窗口管理和截断的基础结构。

M=[m1,m2,⋯ ,mn]\displaystyle M = [m_1, m_2, \cdots, m_n]

2. 角色字段:区分 user(用户)、assistant(助手)、system(系统指令)三种角色,不同角色在拼装请求时去向不同。

ri∈{user,assistant,system}\displaystyle r_i \in \{\text{user}, \text{assistant}, \text{system}\}

3. 内容与时间戳:内容存正文,时间戳用于超时判定和排序。

mi=(ri,ci,ti)\displaystyle m_i = (r_i, c_i, t_i)

存储的物理位置也很关键。前端用 localStorage 或 IndexedDB 做“本地缓冲”,保证页面秒开不白屏;服务端用 Redis 或数据库存“权威账本”,保证用户换个设备也能对上账。两边用会话 ID 关联,通过版本号或时间戳做同步——就像阿芳口头交代给同事的要点,必须和电子系统里的记录保持一致,缺一条都会出岔子。

上下文窗口管理

后厨的挂单墙长度有限,王先生点了三十个菜,总不能全挂出来。阿芳的做法是:刚下的单必须挂上,已经上桌的菜就撕掉,还没做的保留,实在太多就把早期的几道菜并成一张“汇总单”。“汇总单”上写着:三荤两素、微辣、已上两道。Token 就是菜单的篇幅,上下文窗口就是后厨的挂单墙。

大语言模型对输入长度有硬性上限,比如 4K、8K、32K Token——Token 可以简单理解为“文字的计费字数”。超出的部分要么报错,要么被静默截断。所以我们要主动管理窗口:

Xt=[xt−k+1,⋯ ,xt],F(Xt)≤B−r\displaystyle X_t = [x_{t-k+1}, \cdots, x_t], \quad F(X_t) \le B - r

1. 滑动窗口:窗口只保留最近 k 条消息,旧的像上桌的菜一样被“撕掉”。

Xt=[xt−k+1,⋯ ,xt]\displaystyle X_t = [x_{t-k+1}, \cdots, x_t]

2. Token 预算约束:窗口内容的总 Token 数不能超过模型上限减去预留回复空间。

F(Xt)≤B−r\displaystyle F(X_t) \le B - r

3. 最小保留:至少保住 system 指令和最近一轮用户问题,否则对话会失去“基本法”。

k≥2,x1=msystem\displaystyle k \ge 2, \quad x_1 = m_{\text{system}}

实际工程里,“摘要压缩”常用来对付那些不能简单丢弃的早期信息:用大模型把前十轮的关键结论浓缩成一段话,放进窗口头部。订单号、用户偏好这些高价值实体则单独存进附加上下文 c_t,避免随窗口滑出。这样后厨既不会开不出来菜,也不会把王先生“不能吃辣”的重要备注弄丢。

状态机流转设计

阿芳所在的小馆子有一条不成文的规矩:客人坐下先倒茶,再递菜单,等客人点头确认才下单。菜上齐了,客人吃好了,才递账单。如果客人刚进门你就把账单拍在桌上,这顿饭就黄了。多轮对话也一样,聊天的每个阶段必须有章法——这套章法就是状态机。

状态机由三个要素构成:状态集合 S(当前处于哪个阶段)、事件集合 E(发生了什么事)、转移函数 δ(遇到事件后去往哪个状态)。比如一个聊天机器人有四态:等待输入(idle)→ 理解处理(listening)→ 检索知识(searching)→ 生成回复(replying),然后循环,超时则回到初始。

δ:S×E→S,Sk=δ(Si,ej)\displaystyle \delta: S \times E \to S, \quad S_{k} = \delta(S_i, e_j)

1. 状态集合:预先枚举所有合法阶段,防止系统进入“四不像”状态。

S={s1,s2,⋯ ,sp}\displaystyle S = \{s_1, s_2, \cdots, s_p\}

2. 事件集合:定义能引发变化的外部动作,如用户发言、超时、接口返回。

E={e1,e2,⋯ ,eq}\displaystyle E = \{e_1, e_2, \cdots, e_q\}

3. 转移函数:用查表法决定去向;查不到的转移保持原状态并记录日志。

Sk=δ(Si,ej)\displaystyle S_{k} = \delta(S_i, e_j)

在前端聊天组件里,状态机特别适合处理“用户疯狂连点发送”和“流式输出中途断线”这类混乱场景。连点发送时,等回复中的状态直接拦截新事件,避免并发乱序;断线重连时,从“接收中”回到“等待输入”,再触发一次恢复流程。阿芳对此深有体会:规矩定死了,场面再乱也乱不到哪去。

会话恢复机制

晚上八点,王先生中途出门接了个电话。等他回来,发现阿芳去后厨了,换成了新来的小陈。小陈不慌不忙,翻开桌上的点单记录:水煮鱼已上、米饭还没催、还有一道炒时蔬没做。她立刻接上服务:“王先生,菜马上就好。”这就是会话恢复——哪怕人换了、页面刷新了,只要“账本”还在,服务就能无缝续上。

技术上的会话恢复,核心是从持久化存储中加载之前的会话快照。这里的“账本”是 Redis 或数据库,“记录编号”则由用户 ID 和会话 ID 共同算出。

S^=Deserialize(Load(DB,key)),key=hash(u,sid)\displaystyle \hat{S} = \mathrm{Deserialize}\big(\mathrm{Load}(\mathrm{DB}, \mathrm{key})\big), \quad \mathrm{key} = \mathrm{hash}(u, sid)

1. 会话密钥:用户 ID 与会话 ID 组合哈希,确保每条记录能被精确定位。

key=hash(u,sid)\displaystyle \mathrm{key} = \mathrm{hash}(u, sid)

2. 持久化载体:快照存放在 Redis(高速)或 MySQL(可靠),按 key 检索。

DB={Redis,MySQL,⋯ }\displaystyle \mathrm{DB} = \{\mathrm{Redis}, \mathrm{MySQL}, \cdots\}

3. 无损重建:反序列化时对老版本字段做兼容,缺失字段给默认值,而不是抛异常。

S^=Deserialize(Load(DB,key))\displaystyle \hat{S} = \mathrm{Deserialize}\big(\mathrm{Load}(\mathrm{DB}, \mathrm{key})\big)

恢复机制还有一个容易被忽略的环节:前端工作区里的临时变量(比如正在编辑的文本、选中的附件)也要一起快照。小陈光知道“菜还没上齐”还不够,她还知道王先生刚说“再加一份米饭”还没写进单子——把这些补写进去,才算真正无损恢复。

RAG上下文融合

阿芳身上还带着一本“宝典”——上面记着今日特供、招牌菜做法和食材禁忌。当客人问“你们这儿有什么拿手菜”时,她会先翻宝典找到答案,再结合这桌客人的口味偏好,给出定制推荐:“王先生您不吃辣,我推荐清蒸鲈鱼。”这其实就是RAG(检索增强生成)的雏形:拿知识库里的信息,辅助生成更靠谱的回答。

在多轮对话里,发给大模型的提示词不是随便拼的。它通常由三段构成:系统指令、检索知识、对话历史。指令定角色,知识管专业,历史保证连贯。

Xprompt=[Cinst]⊕[Kretr]⊕[Hhist]\displaystyle X_{\text{prompt}} = [C_{\text{inst}}] \oplus [K_{\text{retr}}] \oplus [H_{\text{hist}}]

1. 指令底座:固定角色与行为规范,例如“你是耐心细致的客服助手”。

Cinst\displaystyle C_{\text{inst}}

2. 检索片段注入:根er据用户当前问题从知识库召回 Top-K 相关文档片段。

Kretr=TopK(q)\displaystyle K_{\text{retr}} = \mathrm{TopK}(q)

3. 历史对话拼接:把前文语境放进中后部,模型才能写出前后一致的回答。

Hhist=Xt\displaystyle H_{\text{hist}} = X_t

拼接顺序有讲究:指令在最前,统摄全局;知识紧随其后,给模型“弹药”;历史放在中后段,供模型参照口吻与指代。前端 RAG 聊天组件的职责,就是把这些内容正确组装进请求体,并在回答末尾附上引用来源——阿芳推荐菜时会说“这菜是宝典里第 38 页的招牌做法”,AI 也需要给出可点击的源文档编号。

方案选型对比

社区小馆子,阿芳用手写小本子就能运转;五星级酒店,必须上电子点单系统,因为客流量、并发和审计要求都不同。AI 的状态管理方案也没有“最好”,只有“最合适”。选错了方案,要么杀鸡用牛刀,要么数据丢了还不知道找谁。

常见方案四档对比:第一档是前端内存 Map,零成本但刷新即丢,适合 Demo;第二档是 localStorage/IndexedDB 本地持久化,适合单机小工具;第三档是服务端 Redis + 会话 ID,适合生产级客服系统;第四档是 LangChain Memory 等重量级框架,适合复杂 Agent 场景。怎么选?看三个成本:

Ctotal=αD+βS+γR\displaystyle C_{\text{total}} = \alpha D + \beta S + \gamma R

1. 开发成本 D:实现状态存取、同步、恢复所投入的工程师时间。

D=工时\displaystyle D = \text{工时}

2. 服务器成本 S:存储与带宽的持续开销,服务端方案这部分更高。

S=存储量×单价\displaystyle S = \text{存储量} \times \text{单价}

3. 风险成本 R:上下文丢失导致的用户体验损失与客诉成本。

R=故障概率×单次损失\displaystyle R = \text{故障概率} \times \text{单次损失}

给团队的实在建议是:短命 Demo 用手记,长期生意上系统。当“对话记录不能丢”成为硬指标时,服务端持久化就是必选项。阿芳的小本子撑过了创业期,但餐馆开了分店,她终究还是换了电子系统——选型的本质,是用当下资源换未来确定性。

AI 应用场景

电商客服的“退换货一条龙”

阶段:会话状态机 + 服务端持久化

解决的问题:传统客服机器人只认当前一句,用户说“我要退掉收到的快递”时,它还要重复追问订单号。状态管理让机器人记住用户查过哪个订单、走到哪一步,不用反复确认,退款引导从 5 轮缩短到 2 轮。

具体案例:某电商平台售后机器人使用四态状态机:INIT(等待)→ 查询物流 → 确认收货 → 退款办理。用户每答一句,前端把更新后的会话快照同步到 Redis;用户刷新页面再进,系统根据 userId + 会话 ID 恢复现场,直接显示“您上次处理到退款申请第三步”。RAG 检索售后政策,回答末尾附带政策文档链接。

企业内网“知识管家”问答机器人

阶段:RAG 上下文融合

解决的问题:员工问“怎么报销”,机器人答完后,员工追问“那电子发票呢”——单独把“那电子发票呢”发给大模型会因缺失指代而答非所问。融合历史窗口后,模型才能明白“那”指的是报销流程中的发票环节。

具体案例:某互联网公司内网机器人,前端把最近 6 轮对话存入上下文窗口,后端按“电子发票”检索最新报销政策片段注入提示词,历史与知识混合后生成回答,并在末尾返回政策文档编号,员工点击即查看原文。早期对话做摘要压缩,员工的关键信息(部门、审批人)存入附加上下文。

独立开发者的“写作伙伴”插件

阶段:本地存储 + 会话恢复

解决的问题:浏览器一刷新,写作助手的“记忆”就清空了,用户刚定下的文章大纲、语气偏好全部丢失。用 session 快照 + 本地持久化,能让助手“失忆”成本趋近于零。

具体案例:一个开源 Markdown 写作插件,每轮对话后把消息数组和任务变量序列化存入 localStorage;刷新页面时自动读取快照,还原“正在写第 2 章”的现场。多标签页之间用 BroadcastChannel 同步状态,避免两个页面互相覆盖数据。

Python 演示

python82 行
class ChatSession:    def __init__(self, session_id, max_tokens=120):        self.session_id = session_id        self.max_tokens = max_tokens        self.state = 'idle'        self.messages = []        self.token_count = 0     def update_state(self, event):        if event == 'timeout':            self.state = 'idle'            return        rules = {            ('idle', 'user_input'): 'listening',            ('listening', 'need_knowledge'): 'searching',            ('searching', 'answer_ready'): 'replying',            ('replying', 'user_input'): 'listening',        }        self.state = rules.get((self.state, event), self.state)     def add_message(self, role, content):        tokens = len(content) * 2        while self.token_count + tokens > self.max_tokens and self.messages:            removed = self.messages.pop(0)            self.token_count -= len(removed['content']) * 2        self.messages.append({'role': role, 'content': content})        self.token_count += tokens     def search_and_reply(self, query):        knowledge = {            '报销': '报销需要提交发票与申请表',            '发票': '电子发票与纸质发票均有效',        }        snippet = '已记录,请稍后人工处理'        for key, val in knowledge.items():            if key in query:                snippet = val                break        return snippet + '(当前对话共' + str(len(self.messages)) + '轮)'     def process(self, event, content=None):        self.update_state(event)        if event == 'user_input' and content:            self.add_message('user', content)            self.update_state('need_knowledge')            reply = self.search_and_reply(content)            self.update_state('answer_ready')            self.add_message('assistant', reply)            return reply        return self.state     def save(self):        return {            'session_id': self.session_id,            'max_tokens': self.max_tokens,            'state': self.state,            'messages': self.messages,            'token_count': self.token_count,        }     @classmethod    def restore(cls, payload):        instance = cls(payload['session_id'], payload['max_tokens'])        instance.state = payload['state']        instance.messages = payload['messages']        instance.token_count = payload['token_count']        return instance  def main():    session = ChatSession('table-12', max_tokens=80)    for text in ['报销流程是什么', '那我电子发票呢', '提交到哪里']:        reply = session.process('user_input', text)        print('用户: ' + text)        print('助手: ' + reply)    payload = session.save()    restored = ChatSession.restore(payload)    print('恢复会话 ' + restored.session_id + ' 状态=' + restored.state + ' 消息数=' + str(len(restored.messages)))  if __name__ == '__main__':    main()
目的:演示一个带状态机、令牌预算与持久化恢复的最小多轮对话会话管理器,可独立运行。
  1. self.state = rules.get((self.state, event), self.state)状态机核心:查转移表决定下一个状态;查不到就停在原地,拒绝非法转移。
  2. while self.token_count + tokens > self.max_tokens and self.messages:上下文预算检查:新消息放不下时先清理旧消息,腾出空间。
  3. removed = self.messages.pop(0)移除最早的一条消息,这是“窗口滑动”最朴素的具体操作。
  4. if key in query:简易 RAG 检索:判断用户问题是否命中知识库关键词,命中就采用对应知识。
  5. payload = session.save()快照持久化:把会话对象序列化为可存储的字典,相当于阿芳的点单账本。
  6. restored = ChatSession.restore(payload)会话恢复:从快照重建会话实例,新服务员翻开账本就能继续服务。

常见误区

误区“多轮对话嘛,把之前所有的话都塞给大模型,它一定记得更清楚。模型上限是 8K Token,我就发 7.9K,应该没问题!”

正解上下文窗口就像后厨的挂单墙——单子太多,每道菜都要扫一眼,出菜速度反而变慢。研究表明,塞满长文本后模型的注意力会被稀释,尾部和中间的关键信息被“淹没”,幻觉率上升,成本还随 Token 线性上涨。正确做法是“窗口管理三件套”:保留 system 指令、最近对话和关键任务变量,早期内容用摘要压缩。

为何常见:人的直觉是“信息越多判断越准”,但注意力机制的退化现象反直觉;加上很多人拿超长单轮对话的成功经验,误以为多轮也能照搬。

误区“用户刷新页面,我再请求一次大模型接口就行,反正服务端会自己处理上下文。”

正解大模型本身是“无状态”的,每个请求都像新客人进门。刷新后要恢复的是状态数据,不是重新请求。必须先按用户 ID 和会话 ID 从 Redis/数据库加载快照,把消息数组、状态机当前值、附加上下文都拼装进下一次请求。前端工作区的临时变量也要回填,否则用户觉得“你什么都记得,却忘了我刚才选的附件”。

为何常见:人会把模型拟人化,以为它“记得”上次聊过什么;实际上每个 HTTP 请求都彼此独立,记忆全靠外部存储。

误区“状态管理是服务端开发者的活儿,我只负责写聊天框样式和消息列表,不需要状态机。”

正解前端聊天组件恰恰最容易乱:用户狂点发送造成并发乱序、流式输出中途断线导致 UI 卡死、重连后状态未同步。用 useReducer 或轻量状态机库(如 xstate)管理“可发送/禁发送、接收中/空闲、待同步”等 UI 状态,能拦截非法交互。阿芳的餐馆里,端菜和记账是同一套流程,前端就是“端菜”的角色,也得守规矩。

为何常见:组件库上手太容易,做个聊天框看起来“只是个样式问题”,等到并发 bug 压垮页面才意识到缺少状态约束。

误区“我用 localStorage 保存了所有对话记录,服务端不用存了吧?这样还能省服务器存储钱。”

正解localStorage 容量有限(通常 5-10MB),跨设备不同步,用户清缓存就全没了。生产环境应采用混合架构:本地快照负责秒开和离线兜底,服务端持久化负责权威数据和跨端一致,两者用版本号或时间戳做合并。小陈的本子可以随身带,但餐馆总台的电子账本才是官方记录。

为何常见:本地存储上手零成本、演示效果好,开发者容易忽略了真实用户换设备、清缓存、多端登录的场景。

面试题

Q1. 关于“会话状态”,最准确的理解是?

单选题 · easy

  • A.浏览器页面上的表单字段值集合
  • B.维持一次对话所需的全部信息集合← 正确答案
  • C.服务端数据库中存储的所有用户记录
  • D.大模型训练完成后的权重参数快照

答案:B。会话状态只关心“当前这次对话”的信息,包括历史消息、用户身份和任务变量,与页面全局表单、全量用户数据、模型权重无关。就像阿芳只记这一桌客人的接待信息,不用背下全店所有客人的十年账单。

Q2. 消息结构 m_i = (r_i, c_i, t_i) 中,c_i 表示的是?

单选题 · easy

  • A.消息的检索排序得分值
  • B.消息的转移目标状态值
  • C.消息的回复约束标签值
  • D.消息的内容文本正文值← 正确答案

答案:D。三元组里 r_i 是角色(谁说的),c_i 是内容(说了什么),t_i 是时间戳(什么时候说的)。内容就是消息正文本身,检索得分、状态目标、约束标签都不属于消息的基本存储结构。

Q3. 上下文窗口管理解决的核心问题是?

单选题 · easy

  • A.减少前端等待动画时长
  • B.模型输入长度有限且成本上涨← 正确答案
  • C.提高页面渲染响应速度
  • D.压缩图片资源的体积大小

答案:B。大模型对输入 Token 数有硬性上限,超出部分要么报错要么被静默截断,而且 Token 越多费用越高。窗口管理的目标是让输入“够用又不超预算”,与前端动画、渲染速度、图片资源无关。

Q4. 下列哪个不属于标准状态机的三个组成要素?

单选题 · mid

  • A.预定义的状态集合
  • B.可触发的事件集合
  • C.状态的转移函数
  • D.消息队列 MQ 缓存← 正确答案

答案:D。状态机三要素是状态集合 S、事件集合 E 和转移函数 δ。消息队列只是具体实现中可能用到的通信组件,不是状态机的定义性要素。判别方式是看它是否参与“状态×事件→状态”的映射关系。

Q5. 页面刷新之后要恢复对话,第一步应该做什么?

单选题 · mid

  • A.重新调用模型生成新的问候语
  • B.按用户标识与会话 ID 加载快照← 正确答案
  • C.清空旧的本地缓存记录
  • D.把历史消息全量发给模型

答案:B。恢复的第一步是“找到账本”——根据用户标识 u 和会话 ID sid 算出存储键,从数据库或 Redis 取出快照。生成问候语是恢复完成之后的动作,清空缓存会删掉可用的恢复数据,全量发给模型则可能超出上下文预算。

Q6. RAG 多轮对话中,K_retr 与 H_hist 的区别是什么?

单选题 · mid

  • A.前者来自知识库检索,后者是对话记录← 正确答案
  • B.前者是用户输入内容,后者是模型输出内容
  • C.前者来自向量数据库,后者也来自同一向量库
  • D.两者都是系统提示词的一部分组成

答案:A。K_retr 是检索增强模块从知识库/向量库召回的文档片段,回答“事实是什么”;H_hist 是窗口内保留的历史对话,回答“上下文是什么”。两者最终都会拼进提示词,但来源和用途完全不同。

Q7. 状态机收到一个非法转移事件时,最合理的处理方式是?

单选题 · hard

  • A.中断程序抛出运行时异常
  • B.维持当前状态并记录日志提示← 正确答案
  • C.强制跳转回初始化状态
  • D.自动重试转移直到成功

答案:B。非法转移说明事件与当前状态不匹配(比如还没上菜就要结账),最优策略是拒绝并保持原状态,同时记录日志用于排查。抛异常会让服务崩溃,强制跳初始会丢失中间状态,无限重试则浪费资源。

Q8. 哪些属于多轮对话状态管理的核心难点?

多选题 · mid

  • A.上下文窗口溢出需要合理截断← 正确答案
  • B.会话中断后需要完整恢复← 正确答案
  • C.多轮意图漂移需要识别处理← 正确答案
  • D.前端字体加载速度需要优化

答案:ABC。窗口溢出、会话恢复、意图漂移都是多轮对话的经典难题,分别对应“记不下”“突然断”“跑偏了”三种场景。前端字体加载是性能优化问题,与状态管理无关。

Q9. 哪些场景应该把会话状态放到服务端持久化?

多选题 · hard

  • A.用户跨设备切换后继续对话← 正确答案
  • B.客服需要审计完整历史记录← 正确答案
  • C.单机演示用的无状态原型
  • D.多客服协作查看同一个会话← 正确答案

答案:ABD。跨设备继续、审计追溯、多人协作都要求状态突破“单浏览器”边界,服务端持久化是唯一可靠载体。单机演示用前端内存就够了,硬上服务端反而增加成本和复杂度。

Q10. 关于上下文“摘要压缩”的正确做法包括?

多选题 · extreme

  • A.把早期对话浓缩成要点并存入附加状态← 正确答案
  • B.摘要里保留订单号、偏好等关键实体← 正确答案
  • C.把摘要放在最新窗口的尾部当普通消息
  • D.每次对话都从全量历史重新压缩生成

答案:AB。摘要应存放在附加上下文 c_t 或窗口头部,而不是尾巴;关键实体要单独保留以免被摘要“润色”丢掉。每次全量压缩成本过高且不必要,正确做法是增量合并:旧摘要 + 新消息 → 新摘要。