6.5 LLM 与动态规划的同构性——记忆化的现代重生
问题情境:KV-Cache 的效率之谜
推理慢的困境
2026 年,研究员 Alice 在使用 LLM 时遇到一个问题:
场景:用户问了多个相关问题,如:
- Q1:"什么是动态规划?"
- Q2:"动态规划的核心思想是什么?"
- Q3:"动态规划和分治的区别是什么?"
每次回答,LLM 都要重新计算整个 context(包括 Q1、Q2 的内容)。
问题:Q3 的推理时间是 Q1 + Q2 + Q3 的总时间,越来越慢。
Alice 想:"能不能缓存已计算的部分,避免重复计算?"
KV-Cache 的解决方案
Alice 查阅文献,发现 KV-Cache 技术:
核心思想:缓存已计算的 Key-Value 向量,下次推理时直接复用。
效果:Q3 的推理时间只计算新增部分,不再重复计算 Q1 和 Q2。
效率提升:3 倍加速(假设 Q1、Q2、Q3 长度相同)。
困惑:这不就是 DP 的记忆化吗?
Alice 想起动态规划的记忆化:
- Fibonacci:缓存 fib(k),避免重复计算
- KV-Cache:缓存 token 的 K-V 向量,避免重复计算
困惑:KV-Cache 和 DP 记忆化的条件是否相同?什么情况下缓存有效?
同构的发现
Alice 继续思考,发现两者的共同条件:
| DP 记忆化 | KV-Cache | 共同条件 |
|---|---|---|
| 子问题重叠 → 同一 fib(k) 被多次调用 | Prefix reuse → 同一前缀被多次查询 | 缓存复用的必要性 |
| 参数有限 → fib(k) 的 k ∈ [0, n] | Token 有限 → token 数固定 | 缓存空间可控 |
| DAG 依赖 → fib(k) 依赖 fib(k-1), fib(k-2) | Token DAG → token 依赖前缀 token | 依赖关系 DAG |
核心洞察:这不是类比,而是同构——同一计算思想的不同实例化。
直观思路:从 DP 到 KV-Cache 的映射
四对核心映射
| DP 概念 | LLM 对应 | 映射关系 |
|---|---|---|
| 记忆化 | KV-Cache | 缓存已计算结果,避免重复 |
| 子问题图 | Token DAG | 依赖关系 DAG |
| 最优子结构 | Markov 假设 | 状态最优不依赖路径历史 |
| 状态设计 | Prompt 设计 | 影响推理效率 |
映射详解
1. 记忆化 ↔ KV-Cache
DP 记忆化:
- 第一次计算 fib(k),存入 memo[k]
- 后续调用 fib(k),直接返回 memo[k]
KV-Cache:
- 第一次计算 token t 的 K-V 向量,存入 cache
- 后续推理时,直接复用 cache 中的 K-V 向量
共同条件:
- 子问题重叠 → prefix reuse
- 参数有限 → token 数有限
2. 子问题图 ↔ Token DAG
DP 子问题图:
- 节点:子问题 fib(k)
- 边:fib(k) → fib(k-1), fib(k) → fib(k-2)
- DAG(无环)
Token DAG:
- 节点:token t
- 边:token t 依赖前缀 token(attention)
- DAG(无环,因为 attention 只看之前的 token)
共同性质:DAG 依赖关系 → 可以按拓扑序计算。
3. 最优子结构 ↔ Markov 假设
DP 最优子结构:
- 子问题最优 → 整体最优
- 例如:最短路径的子路径最优
LLM Markov 假设:
- 状态最优不依赖路径历史
- 例如:ToT 的分支独立评估
共同前提:状态之间的独立性。
4. 状态设计 ↔ Prompt 设计
DP 状态设计:
- 状态维度影响复杂度
- 状态太少 → 无法正确刻画子问题
- 状态太多 → 空间爆炸
Prompt 设计:
- Prompt 长度影响推理效率
- Prompt 太短 → 信息不完备
- Prompt 太长 → 计算成本高
共同权衡:维度与效率的平衡。
规范定义:KV-Cache 的数学模型
KV-Cache 的本质
定义:KV-Cache 是 LLM 推理时缓存已计算的 Key-Value 向量的机制。
公式化:
设 token 序列为 t_1, t_2, ..., t_n。
- Key 向量:K_i = f_K(t_i)
- Value 向量:V_i = f_V(t_i)
- Attention:Attention(t_i) = softmax(K_j · K_i / √d) · V_j for j < i
KV-Cache:存储 (K_j, V_j) for j ∈ [1, i-1],避免重新计算。
Prefix Reuse 的条件
定义:Prefix reuse 是多个推理请求共享相同前缀 token。
示例:
- Request 1:"什么是动态规划?" → Prefix: "什么是动态规划?"
- Request 2:"什么是动态规划?核心思想是什么?" → Prefix: "什么是动态规划?"(相同)
KV-Cache 有效条件:
- Prefix 相同 → K-V 向量相同 → 可以复用
- Prefix 不同 → K-V 向量不同 → 不能复用
KV-Cache 的复杂度分析
无 KV-Cache:
- 每次推理:计算所有 token 的 K-V 向量
- 时间:O(n · d²),n 是 token 数,d 是向量维度
有 KV-Cache:
- 只计算新 token 的 K-V 向量
- 时间:O((n - m) · d²),m 是已缓存 token 数
效率提升:n → n - m,节省 m 的计算量。
算法实现:KV-Cache 策略
简化 KV-Cache 模型
class KVCache:
def __init__(self):
self.keys = []
self.values = []
def append(self, key, value):
"""添加新 token 的 K-V 向量"""
self.keys.append(key)
self.values.append(value)
def get_prefix_cache(self, length):
"""获取前缀 token 的 K-V 向量"""
return self.keys[:length], self.values[:length]
def reuse_prefix(self, prefix_tokens, new_tokens):
"""复用前缀,只计算新 token"""
prefix_len = len(prefix_tokens)
prefix_keys, prefix_values = self.get_prefix_cache(prefix_len)
# 只计算新 token 的 K-V 向量
for token in new_tokens:
key = compute_key(token)
value = compute_value(token)
self.append(key, value)
return prefix_keys + self.keys[prefix_len:],
prefix_values + self.values[prefix_len:]Prefix Reuse 检测
def detect_prefix_reuse(requests):
"""检测多个请求的共享前缀"""
prefixes = {}
for request in requests:
# 找最长共享前缀
max_prefix_len = 0
for cached_prefix in prefixes:
if request.startswith(cached_prefix):
max_prefix_len = len(cached_prefix)
break
# 新 token 部分
new_part = request[max_prefix_len:]
prefixes[request] = {
'reuse_len': max_prefix_len,
'new_tokens': new_part
}
return prefixes正确性分析:KV-Cache 何时有效?
KV-Cache 有效条件
条件 1:Prefix reuse 存在。
若所有请求的 prefix 都不同,KV-Cache 无效——每次都要重新计算。
类比 DP:若无子问题重叠,记忆化无效——每次子问题参数不同。
条件 2:缓存空间足够。
KV-Cache 需存储大量 K-V 向量,内存限制。
类比 DP:记忆化需要 memo 表,空间 O(子问题数)。
条件 3:Token 依赖 DAG。
Token 的 attention 只看之前的 token,形成 DAG。
类比 DP:子问题图是 DAG,保证计算顺序正确。
KV-Cache 失效案例
案例 1:完全不同的请求。
每次请求的 prefix 不同,无 reuse。
类比 DP:无子问题重叠(如 Quicksort)。
案例 2:缓存溢出。
Token 数太多,内存不够存储所有 K-V 向量。
类比 DP:状态空间爆炸(如 TSP)。
复杂度分析与优化
KV-Cache 空间复杂度
空间:O(n · d),n 是 token 数,d 是向量维度。
优化:
- 状态压缩(类似 DP 的状态压缩):只缓存关键 token
- Quantization(量化):降低向量精度,减少空间
KV-Cache 时间复杂度
无 KV-Cache:O(n · d²) 每次推理。
有 KV-Cache:O((n - m) · d²),m 是 reuse token 数。
效率提升:m 越大,效率越高。
反例与变式
反例 1:无 Prefix Reuse
场景:每个请求的 prefix 都不同。
KV-Cache 策略:缓存无效。
类比 DP:无子问题重叠 → 记忆化无效。
反例 2:Token 依赖非 DAG
场景:某 LLM 设计允许 token 看之后的 token(非因果 attention)。
问题:Token 依赖有环,无法按拓扑序计算。
类比 DP:子问题图有环 → 无法用 DP。
变式 1:动态 KV-Cache 管理
场景:缓存空间有限,需要动态丢弃部分 K-V 向量。
策略:
- LRU(最近最少使用):丢弃最久未用的缓存
- 关键 token 优先:保留对推理影响大的 token
类比 DP:滚动数组,只保留必要状态。
变式 2:Batch 推理优化
场景:多个请求同时推理,共享 prefix。
策略:将共享 prefix 的请求 batch 处理,一次计算共享部分。
类比 DP:批量计算共享子问题。
LLM 推理策略的 DP 视角
CoT(Chain-of-Thought)
类比:线性 DP(无分支)。
局限:一步错全错(无回溯)。
类比 DP:递推式无分支,依赖顺序固定。
ToT(Tree-of-Thought)
类比:回溯 + 记忆化。
局限:评估函数依赖人设计。
类比 DP:最优子结构需要人验证。
GoT(Graph-of-Thought)
类比:DAG 推理。
局限:思想聚合需要启发式。
类比 DP:子问题图 DAG,状态聚合。
常见错误诊断
错误 1:误以为 KV-Cache 对所有请求有效
澄清:需要 prefix reuse 条件。
错误 2:忽略 Token 依赖 DAG
澄清:若 token 依赖非 DAG(如双向 attention),KV-Cache 策略需调整。
错误 3:缓存管理不当
澄清:缓存空间有限,需要动态丢弃策略(类似滚动数组)。
练习
基本理解
概念解释:KV-Cache 和 DP 记忆化的共同条件是什么?
映射分析:解释"子问题图 ↔ Token DAG"的映射关系。
画图验证:画出 Token DAG 的结构,类比 Fibonacci 子问题图。
方法应用
Prefix Reuse 检测:实现 prefix reuse 检测算法。
KV-Cache 管理策略:设计动态 KV-Cache 管理策略(如 LRU)。
效率计算:计算有/无 KV-Cache 的推理时间对比。
错误诊断
诊断失效:给定一个无 prefix reuse 的场景,分析 KV-Cache 失效原因。
DAG 破坏:如果 token 依赖非 DAG,会发生什么问题?
缓存溢出:缓存空间不够时,如何管理?
方案比较
CoT vs ToT vs GoT:对比三种推理策略的 DP 对应。
KV-Cache vs 无缓存:对比两种策略的效率差异。
动态管理 vs 固定缓存:对比两种缓存管理策略。
开放设计
新缓存策略设计:设计一个基于 DP 思维的 KV-Cache 优化策略。
推理复杂度分析:分析 ToT 的推理复杂度,类比回溯。
Prompt 设计优化:基于状态设计思维,优化 Prompt 结构。
综合应用
真实场景分析:分析实际 LLM 推理场景的 prefix reuse 率。
推理优化方案:设计 LLM 推理优化方案,组合 KV-Cache 和 batch 推理。
综合挑战:设计一个 Agent,动态选择 KV-Cache 管理策略。
思考题
为什么 KV-Cache 和 DP 记忆化同构?
因为共同条件:
- 子问题重叠 → prefix reuse(缓存必要性)
- 参数有限 → token 有限(空间可控)
- DAG 依赖 → token DAG(计算顺序)
如何识别 KV-Cache 有效模式?
类比 DP 的子问题重叠识别:
- 检测 prefix reuse(多个请求共享前缀)
- 计算缓存复用率
- 设计缓存策略(类似记忆化)
KV-Cache 的局限?
- 需要 prefix reuse 条件
- 缓存空间有限
- Token 依赖必须是 DAG
总结:DP 记忆化 ↔ KV-Cache 同构,理解 DP → 理解 LLM 推理优化。但识别有效模式需要人的判断——这是机器做不了的。
参考文献:
- Yao S, Yu D, Zhao J, et al. Tree of Thoughts[C]//NeurIPS. 2023.
- Besta M, et al. Graph of Thoughts[C]//AAAI. 2024.
- Crystal-KV. arXiv 2026-01.
- Cormen T H, et al. Introduction to Algorithms[M]. 4th ed. MIT Press, 2022. Chapter 15.