一、多轮对话

1、概念

  • 多轮对话(Multi-turn Dialogue) 指的是系统与用户之间进行 连续的问答互动,每一轮都可能依赖之前的对话内容

  • 换句话说,它不仅处理当前用户输入,还要理解上下文,以生成更连贯、有针对性的回答

  • 例如:

    1. 用户问:"今天天气怎么样?"
    2. 助手答:"晴天,28℃。"
    3. 用户接着问:"那适合去公园吗?"
    4. 助手会根据之前的“晴天”回答给出建议

2、原理

image-20250424010107777

3、实现

  • 修改对话的时候,message 消息的格式就行

4、KV Cache

  • KV 缓存(Key-Value Cache)适用于 Transformer 结构中,常用于加速推理或多轮对话的场景,也包含了实际应用层的视角,如 LLM 推理中的 KV 缓存机制

4.1 概述

  • KV 缓存(Key-Value Cache)是一种将 Transformer 中间计算结果(尤其是注意力机制中的 Key 和 Value)缓存起来,从而在解码时避免重复计算的加速技术

  • 主要应用场景:

    • LLM 推理加速

    • 多轮对话保持上下文效率

    • 流式生成

4.2 原理

4.2.1 Attention 机制

  • 在自注意力机制中:

$$
Attention(Q, K, V) = softmax\left(\frac{QK^T}{\sqrt{d_k}}\right)V
$$

  • Q:当前时间步的 Query

  • KV:历史及当前的 Key 和 Value

  • 在生成式模型(Decoder-only)中,解码是逐 token 进行的,因此对于每一个新 token:

    • 只需要 新增一个Query

    • 但是需要和之前的所有Key、Value计算注意力

4.2.2 存在价值

  • 若每次生成一个 token 都重新计算所有之前的 Key 和 Value,会非常耗时,可以缓存历史的 K/V,在下一步生成时直接复用

4.3 KV缓存结构

通常按层维护:

# 假设模型有 N 层,每层都有自己的 KV 缓存
kv_cache = [
    {"key": [T1, T2, ..., Tn], "value": [...]},  # Layer 1
    {"key": [T1, T2, ..., Tn], "value": [...]},  # Layer 2
    ...
]
  • 更新方式:

    • 每生成一个新token,将其 $K/V$ 附加到对应层的缓存中

    • 缓存长度最多为上下文窗口(context length)

4.5 应用案例

  • 每轮对话传入已有的 KV 缓存
  • 模型仅处理新增问题部分的 Query
  • 最终合并 KV 缓存,用于下一轮

4.6 注意事项

  • 缓存过长:超过最大上下文窗口需截断
  • 缓存分离:不同 batch 的缓存要单独存储
  • 缓存迁移:KV 缓存不能跨模型版本、设备迁移
  • 多语言模型:KV 缓存不兼容多种 Tokenizer 混用

5、对话历史记录

5.1 解释

  • 例如:

    用户:我叫张三
    AI:你好张三
    
  • 下一轮:

    用户:我叫什么?
    
  • 系统需要:

    保存之前对话
    
  • 否则模型根本不知道“张三”是谁

5.2 存储

  • 内存中
  • redis 中
  • PostgreSQL 数据库中【langchain 推荐】

6、KV Cache 和对话历史记录

  • 历史记录最终会进入 Prompt
System:
你是AI助手

History:
用户:我叫张三
AI:你好张三

User:
我叫什么?
  • Prompt 进入模型后才产生 KV Cache
历史记录 → Prompt文本
Prompt → Token
Token → KV Cache
  • 区别
对比 KV Cache 历史记录
层级 模型内部 应用层
生命周期 一次推理期间 长期存在
存储内容 Token的K/V向量 原始对话文本
是否持久化 ❌ 通常不会 ✅ 会
作用 推理加速 上下文记忆
用户可见 ❌ 不可见 ✅ 可见

7、上下文连续对话

  • 上下文连续对话(Multi-turn Conversation)的实现,本质上依赖两部分能力协同工作:

7.1 应用层历史记录

  • 负责“记忆”用户与模型之前的对话内容

  • 通常会保存:

    • 用户问题

    • 模型回答

    • 系统提示词(System Prompt)

    • 会话元数据

  • 常见存储方式:

    • 内存(Memory)

    • Redis

    • MySQL / PostgreSQL

    • MongoDB

    • 向量数据库(长期记忆场景)

  • 其核心作用是:

让模型在下一轮对话时能够看到之前的聊天内容。

7.2 KV Cache

  • 负责“推理加速”

  • Transformer 在生成 Token 时,会缓存历史 Token 的:

    • Key

    • Value

  • 下一轮生成时无需重复计算之前的 Attention,从而显著降低推理开销

  • 其本质是:

用显存空间换取推理速度。
  • KV Cache 通常存储在:

    • GPU 显存

    • 推理服务缓存区

  • 它属于:

    • 模型层优化

    • 推理阶段缓存

7.3 上下文连续对话完整流程

用户输入
   ↓
读取历史记录(Memory)
   ↓
拼接 Prompt
   ↓
Tokenizer
   ↓
送入 LLM
   ↓
Transformer 推理
   ↓
KV Cache 缓存 Attention
   ↓
生成回答

7.4 历史记录不能无限增长

  • 在实际工程中,历史消息必须进行控制,原因有以下两个

7.4.1 Token 消耗问题

  • 大模型是按 Token 计费和计算的

  • 历史记录越长:

    • Prompt 越大

    • Token 消耗越高

    • 推理成本越高

    • 响应速度越慢

  • 例如:

历史记录 2k tokens
+
用户问题 500 tokens
+
模型输出 1k tokens
  • 一次请求可能就达到:高并发场景下成本会迅速增加
3500+ tokens

7.4.2 上下文窗口限制

  • LLM 并不能无限接收文本

  • 每个模型都有最大上下文长度,例如:

模型 上下文窗口
GPT-4o 128K
Qwen 部分模型 32K / 128K
Llama 8K ~ 128K
  • 如果超过窗口限制:

    • 早期对话会被截断

    • 或请求直接失败

7.5 常见优化方案

7.5.1 滑动窗口

  • 只保留最近 N 轮对话:
最近5轮
最近10轮
  • 优点:

    • 实现简单

    • 成本低

  • 缺点:

    • 长期记忆会丢失

7.5.2 对话摘要

  • 使用 LLM 对历史内容进行摘要压缩:
“用户是一名Java开发工程师,
最近在学习RAG系统开发”
  • 优点:

    • 保留长期语义

    • 降低 Token 消耗

  • 缺点:

    • 摘要可能丢失细节

7.5.3 向量检索记忆

  • 将历史对话向量化后存入:

    • ChromaDB

    • Milvus

    • FAISS

  • 对话时:

    • 根据当前问题检索相关历史,而不是全部拼接
  • 优点:

    • 支持长期记忆

    • 更适合 AI Agent


7.5.4 Memory 分层设计

  • 企业级 AI 系统通常采用:
短期记忆 + 长期记忆
  • 例如:
类型 存储
短期上下文 Recent Chat
长期记忆 Vector DB
用户画像 Profile DB
  • 这样既能保证:

    • 上下文连续性

    • 又能控制 Token 成本


7.6 总结

  • 上下文连续对话依赖“历史记录提供记忆”与“KV Cache提升推理效率”共同实现
  • 历史记录需要通过滑动窗口、摘要压缩、向量检索等方式进行优化,以解决 Token 成本和上下文窗口限制问题