最近正在开发一些基于大语言模型API的应用, 针对过于长的上下文需要进行一些压缩处理, 因此想到了通过数学建模的方式进行分析. 在完成了问题定义和符号定义后, 简单推导了一下表达式, 然后我确信只需要按照表达式使用sympy实现并求解即可. 不过我懒得写这段代码了, 因此直接把问题发送给DeepSeek, 让DeepSeek写代码搞定. 结果DeepSeek这家伙根本不愿意好好写符号计算的代码, 直接自己脑内求出了表达式. 经过一番友好的交流后, 我让DeepSeek总结了对话内容, 生成了如下的数学建模风格的文章.

从最终的效果来看, DeepSeek已经能够很好的完成较为复杂的符号推导工作(反正比我强了, 我连求和都不想代入公式了), 甚至还能基于现有数学表达式, 探索一些更为复杂的问题(虽然有些问题一看就没啥用, 比如概率性命中缓存, 分为多次压缩求最小消耗之类的. 但是这里面的数学工具非常炫酷, 甚至还包含变分法). 不过正如那句经典的话, 如果大语言模型能给出答案, 那么问题是什么? 如何提出问题和对问题进行数学建模依然是一个需要用大脑仔细思考的事情. 而且数学建模可有趣了, 不是嘛?

1. 问题背景

在使用大语言模型(LLM)构建多轮对话应用时,每一轮调用都需要将整个对话历史作为输入传递给模型。随着对话轮次增加,输入 token 数线性增长,导致成本持续攀升。为控制成本,针对大部分主流 LLM 服务商存在两种优化机制:

  • 上下文缓存(Context Caching):如果连续请求中包含相同的前缀内容,命中缓存的部分可享受极低单价。
  • 对话历史压缩:在适当时候调用模型对历史进行总结压缩,用简短的摘要替代原始长文本,从而降低后续请求的 token 消耗。

但压缩本身也需要一次性的模型调用开销,因此我们需要回答一个核心决策问题:

已完成 n 轮对话,且预计未来还会进行 t 轮。此时是直接继续对话更经济,还是先压缩历史再重新开始更经济?平衡点如何受价格、长度和缓存折扣等因素影响?

本文采用数学建模方法,推导两种策略的成本表达式,通过符号计算得到精确的平衡条件,并绘出 n-t 二维决策分界图,最后总结操作建议。

2. 符号说明

符号 含义 单位
$u$ 用户平均输入 token 数 token/轮
$r$ 模型平均输出 token 数 token/轮
$a_i$ 输入 token 单价 元/token
$a_o$ 输出 token 单价 元/token
$a_h$ 缓存命中时的 token 单价(一般 $a_h \ll a_i$) 元/token
$k = a_i u + a_o r$ 一轮“全新”调用的基本成本(不计算历史缓存) 元/轮
$n$ 已经进行的对话轮数
$t$ 预计未来将继续进行的对话轮数
$d_1$ 压缩提示词的固定 token 开销 token
$d_2$ 压缩后文本的 token 长度 token

其中假设每轮对话的输入为 历史对话内容 + 当前用户输入,即第 m 轮输入 token 数为 $ (m-1)(u+r) + u $。缓存机制允许已处理过的历史部分仅按 $a_h$ 计费。

3. 模型建立

3.1 策略一:直接进行后续 t 轮对话

历史不经压缩,每一轮输入包含完整的历史前缀。由于缓存,历史部分的 token 按 $a_h$ 计费,当前轮的输入 u 按 $a_i$ 计费,输出 r 始终按 $a_o$ 计费。

  • 第 $n+1$ 轮:历史长度为 $n(u+r)$,成本为 $a_h \cdot n(u+r) + k$
  • 第 $n+2$ 轮:历史长度为 $(n+1)(u+r)$,成本为 $a_h \cdot (n+1)(u+r) + k$
  • 第 $n+t$ 轮:成本为 $a_h \cdot (n+t-1)(u+r) + k$

t 轮总成本求和:

$$
C_1 = \sum_{j=0}^{t-1} \big[ k + a_h (n+j)(u+r) \big]
$$

3.2 策略二:先压缩前 n 轮,再重新进行 t 轮对话

压缩步骤:将前 n 轮的完整对话(总 token 数 $n(u+r)$)连同压缩提示词(长度 $d_1$)输入模型,生成压缩摘要(长度 $d_2$)。此次调用无缓存,成本为:

$$
C_{\text{compress}} = a_i \big[ n(u+r) + d_1 \big] + a_o d_2
$$

新对话 t 轮:以压缩摘要 $d_2$ 替代原始历史。新的第 1 轮没有缓存(因为前缀为新摘要),第 2 轮起前缀命中缓存。逐轮成本为:

  • 第 1 轮:输入包含摘要 d2 + 用户输入 u,按 $a_i$ 计费;输出 r 按 $a_o$。成本为 $a_i(d_2+u) + a_o r = a_i d_2 + k$
  • 第 2 轮:历史为 d2 + 第 1 轮的 $u+r$,缓存命中 d2,成本为 $a_h d_2 + k + a_h (u+r)$
  • 第 3 轮:历史为 d2 + 2 轮对话,成本为 $a_h d_2 + k + a_h \cdot 2(u+r)$
  • 第 t 轮:成本为 $a_h d_2 + k + a_h (t-1)(u+r)$

新 t 轮总成本:

$$
C_{\text{new}} = (a_i d_2 + k) + \sum_{j=1}^{t-1} \big[ k + a_h d_2 + a_h j(u+r) \big]
$$

策略二总成本:

$$
C_2 = C_{\text{compress}} + C_{\text{new}}
$$

4. 符号求解与平衡点分析

我们使用 Sympy 进行符号推导,避免手工化简求和,保留一般性。

4.1 成本差 $\Delta = C_2 - C_1$

定义符号并构建求和表达式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import sympy as sp

u, r, a_i, a_o, a_h, n, t = sp.symbols('u r a_i a_o a_h n t', positive=True, real=True)
d1, d2 = sp.symbols('d1 d2', positive=True, real=True)
k = a_i*u + a_o*r

# 策略一:C1 = Σ_{j=0}^{t-1} [k + a_h*(n+j)*(u+r)]
j = sp.symbols('j', integer=True)
C1 = sp.Sum(k + a_h*(n + j)*(u + r), (j, 0, t-1)).doit()

# 压缩成本
C_comp = a_i*(n*(u + r) + d1) + a_o*d2

# 新对话成本:第一轮 + Σ_{j=1}^{t-1} [k + a_h*d2 + a_h*j*(u+r)]
C_new = (a_i*d2 + k) + sp.Sum(k + a_h*d2 + a_h*j*(u + r), (j, 1, t-1)).doit()

C2 = sp.simplify(C_comp + C_new)

Delta = sp.simplify(C2 - C1)
sp.pprint(Delta)

输出化简后的 $\Delta$:

$$
\Delta = n(u+r)(a_i - a_h t) + a_i d_1 + d_2 \big[ a_i + a_o + a_h(t-1) \big]
$$

这是一个关于 $n$ 和 $t$ 的双线性函数。

4.2 平衡条件 $\Delta = 0$

令 $\Delta = 0$,可解出平衡曲线:

  • 若将 $t$ 当作变量,解出 $t^*$:

$$
t^* = \frac{n(u+r)a_i + a_i d_1 + d_2(a_i + a_o - a_h)}{a_h\big[ n(u+r) - d_2 \big]} \quad (\text{当 } n(u+r) > d_2)
$$

  • 若将 $n$ 当作变量,解出 $n^*$:

$$
n^* = \frac{a_i d_1 + d_2\big[ a_i + a_o + a_h(t-1) \big]}{(u+r)(a_h t - a_i)}
$$

分母 $a_h t - a_i$ 的符号决定平衡点的存在性。通常 $a_h \ll a_i$,对于较小的 $t$,分母为负,$n^$ 为负,意味着对于所有正 $n$,$\Delta$ 均大于 0,即*永不压缩。只有当未来轮次 $t > a_i / a_h$ 时,$a_h t - a_i > 0$,才可能出现正临界历史长度。

5. 性质分析与决策逻辑

5.1 缓存的作用

  • 有缓存($a_h$ 很小):$\Delta$ 的斜率 $a_i - a_h t$ 对中等 $t$ 仍为正,意味着直接继续的优势区域较大。只有同时具备“较长的历史 n”和“较大的未来轮次 t”,压缩才占优。
  • 无缓存($a_h = a_i$):斜率变为 $a_i(1-t)$,当 $t \ge 2$ 时斜率即负,几乎任何正 n 下都会出现 $\Delta < 0$,压缩几乎总是更优。这凸显了缓存机制对“不压缩”策略的支撑作用。

5.2 对话长度的影响

历史长度 $n(u+r)$ 与输出长度 r 直接相关。r 越大,历史增长越快,$a_i - a_h t$ 的斜率绝对值不变,但 $n(u+r)$ 增大会使 $\Delta$ 的绝对值在相同变量下更大,压缩的优势区间会向更小的 t 偏移。若压缩后摘要长度 $d_2$ 也随历史成比例增长(压缩率 $\alpha = d_2 / (n(u+r))$),则平衡条件可改写为:

$$
t^* \approx \frac{a_i + \alpha(a_i + a_o - a_h)}{a_h(1-\alpha)} \quad (\text{当 } n \text{ 足够大})
$$

压缩率 $\alpha$ 越小,$t^*$ 越小,压缩越早合算。

5.3 模型价格的影响

  • 输出价格 $a_o$ 仅出现在常数项 $d_2 a_o$ 中,影响相对微弱。提高 $a_o$ 会略微增大 $t^*$。
  • 输入价格 $a_i$ 直接控制斜率常数项与截距。$a_i$ 越大,压缩的一次性成本越高,但同时不压缩时累积的缓存计费基数也变大(但乘以极小的 $a_h$)。总体而言,输入价格昂贵会稍许推动压缩(降低 $t^*$),但远不如缓存折扣比 $a_i / a_h$ 的影响显著。

5.4 决策规则总结

以实际常用价格为例($a_i=0.01,; a_h=0.002$,即缓存折扣 80%),可绘制 n-t 决策分界图,划分策略区域。

6. 数值实验与决策分界图

固定参数:$u=100,; r=200,; a_i=0.01,; a_o=0.03,; a_h=0.002,; d_1=50,; d_2=300$,生成 $n \in [1,50],; t \in [1,50]$ 的 $\Delta$ 矩阵,绘制二维分界图。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import numpy as np
import matplotlib.pyplot as plt

# Default parameters (same as before)
u, r = 100, 200
a_i, a_o, a_h = 0.01, 0.03, 0.002
d1, d2 = 50, 300

# Build meshgrid
n_vals = np.linspace(1, 50, 200)
t_vals = np.linspace(1, 50, 200)
N, T = np.meshgrid(n_vals, t_vals)

# Compute Delta
Delta = (u + r) * (a_i - a_h * T) * N + a_i * d1 + d2 * (a_i + a_o + a_h * (T - 1))

# Plot decision region
plt.figure(figsize=(9, 6))
plt.contourf(N, T, Delta, levels=[-1e10, 0, 1e10], colors=['#4A90D9', '#F5A623'], alpha=0.6)
contour = plt.contour(N, T, Delta, levels=[0], colors='black', linewidths=2)
plt.clabel(contour, fmt='Δ=0', fontsize=12)
plt.text(30, 5, 'Direct continuation better', ha='center', va='center', color='darkorange')
plt.text(10, 40, 'Compress then restart', ha='center', va='center', color='darkblue')
plt.xlabel('Completed rounds n')
plt.ylabel('Future rounds t')
plt.title('Decision boundary: Compress vs. Direct continuation')
plt.grid(True, alpha=0.3)
plt.xlim(1, 50); plt.ylim(1, 50)
plt.tight_layout()
plt.show()

输出图形(如图 1 所示)中,蓝色区域表示压缩更优($\Delta<0$),橙色区域表示直接继续更优($\Delta>0$)。黑色曲线为 $\Delta=0$ 的分界线。

Decision Boundary
图 1:压缩与直接继续的 n-t 决策分界图

从图中可以读出操作推荐:

n 范围(历史轮次) t 范围(未来轮次) 推荐策略
n ≤ 10 任意 t 直接继续
10 < n ≤ 30 t ≤ 15 直接继续
10 < n ≤ 30 t > 15 压缩后继续
n > 30 t ≤ 5 直接继续
n > 30 t > 5 压缩后继续

简言之,当历史较短或未来轮次很少时,缓存折扣可抵消历史累积成本,无需压缩;当历史已经很长且预计还有大量后续交互时,一次性压缩能显著节省总成本。

7. 结论

本文通过构建符号化的成本模型,系统分析了大语言模型多轮对话中“直接继续”与“压缩历史”两种策略的经济性。主要发现如下:

  1. 临界决策取决于已完成轮次 $n$ 和预计未来轮次 $t$ 的乘积效应,以及输入价格与缓存折扣的比值 $a_i / a_h$。
  2. 上下文缓存的存在极大地扩展了“不压缩”的优势区间;若无缓存机制,压缩几乎总是合算。
  3. 对话越长(输出 r 大)、历史积累越快,压缩的门槛越低。
  4. 输出价格对决策影响较小,决策主要由缓存折扣力度和历史长度主导。

文中的符号框架和 Python 代码可直接应用于任何 LLM API 的定价方案,只需替换相应单价和平均 token 长度,即可生成定制化的二维决策图,为智能应用的自动历史管理提供量化依据。


本着随便试一试的态度, 我选择了不给出任何假设, 只提出要求分析压缩和不压缩策略的优劣, 让DeepSeek直接进行数学建模分析. 结果令我大受震撼, 我把这个问题想复杂了, DeepSeek的抽象方式更为合理, 减少了很多参数, 计算和讨论都更简单. 真是印证了”数学就是给不同的事务起相同的名字”这句话了.

当然我必须要强行挽尊一波, 只有在按照我上面这样分析以后, 才能知道DeepSeek这样处理, 忽略掉一些不重要的因素是合理的.

数学建模:大语言模型上下文压缩的决策条件

1. 基本变量定义

设:

  • $L$:原始历史上下文的长度(token数)
  • $C$:压缩后的上下文长度($C < L$)
  • $N$:压缩后需要进行的后续 API 调用次数(每次调用均携带压缩后的上下文)
  • $p_{\text{in}}$:输入 token 的标准单价
  • $p_{\text{out}}$:输出 token 的标准单价,记价格比 $r = p_{\text{out}} / p_{\text{in}}$(通常 $r > 1$)
  • 每次调用除固定上下文外,还可能包含新增消息长度 $m$(假设两种方案中 $m$ 相同,后续分析可消去)
  • 每次调用的输出 token 长度假设相同,比较时可忽略

2. 无缓存情况

API 不提供缓存或缓存无效(每次输入均按标准单价计费)。

不压缩方案

总费用:
$$
F_{\text{no}} = N \cdot L \cdot p_{\text{in}}
$$

压缩方案

  • 压缩调用:输入 $L$,输出 $C$,费用为 $L p_{\text{in}} + C p_{\text{out}}$
  • 后续 $N$ 次调用:每次输入 $C$,费用为 $N \cdot C \cdot p_{\text{in}}$

总费用:
$$
F_{\text{comp}} = L p_{\text{in}} + C p_{\text{out}} + N C p_{\text{in}}
$$

决策条件

压缩优于不压缩当且仅当:
$$
L p_{\text{in}} + C p_{\text{out}} + N C p_{\text{in}} < N L p_{\text{in}}
$$
整理得:
$$
L p_{\text{in}} + C p_{\text{out}} < N (L - C) p_{\text{in}}
$$
$$
N > \frac{L + r C}{L - C} = 1 + \frac{C (1+r)}{L - C}
$$
定义阈值:
$$
N_{\text{min}}^{(0)} = 1 + \frac{C(1+r)}{L-C}
$$
当后续调用次数 $N > N_{\text{min}}^{(0)}$ 时,压缩值得。

3. 有缓存情况

API 支持提示缓存(Prompt Caching):同一段前缀文本在首次调用后会被缓存,后续相同输入仅需支付缓存单价 $p_{\text{cache}} = \alpha p_{\text{in}}$,其中 $0 < \alpha < 1$(例如 $\alpha = 0.1$)。首次调用仍按全价计费。

假设压缩后的上下文 $C$ 和原始上下文 $L$ 在多次调用中完全一致(即后续调用不改变历史),并且每次调用的新增消息 $m$ 各不相同,无法缓存(为简化设 $m=0$)。实际中如果 $m>0$,因 $m$ 部分每次不同,不享受缓存,但分析结论不变。

不压缩方案

  • 第1次调用:输入 $L$,全价 $L p_{\text{in}}$
  • 第2至 $N$ 次调用:缓存命中,每次 $L p_{\text{cache}} = \alpha L p_{\text{in}}$

总费用:
$$
F_{\text{no}}^{(c)} = L p_{\text{in}} + (N-1) \alpha L p_{\text{in}} = L p_{\text{in}} \bigl[1 + \alpha (N-1)\bigr]
$$

压缩方案

  • 压缩调用:输入 $L$(首次),输出 $C$,全价 $L p_{\text{in}} + C p_{\text{out}}$。注意:压缩调用本身不享受缓存(通常压缩输入与后续任务不同,且是首次)。
  • 后续第1次有用调用:输入 $C$(首次出现),全价 $C p_{\text{in}}$
  • 后续第2至 $N$ 次有用调用:输入 $C$ 缓存命中,每次 $\alpha C p_{\text{in}}$

后续调用总费用:
$$
C p_{\text{in}} + (N-1) \alpha C p_{\text{in}} = C p_{\text{in}} \bigl[1 + \alpha (N-1)\bigr]
$$
压缩方案总费用:
$$
F_{\text{comp}}^{(c)} = (L p_{\text{in}} + C p_{\text{out}}) + C p_{\text{in}} \bigl[1 + \alpha (N-1)\bigr]
$$

决策条件

压缩优于不压缩当且仅当:
$$
L p_{\text{in}} + C p_{\text{out}} + C p_{\text{in}} \bigl[1 + \alpha (N-1)\bigr] < L p_{\text{in}} \bigl[1 + \alpha (N-1)\bigr]
$$
化简:
$$
C p_{\text{out}} + C p_{\text{in}} < \alpha p_{\text{in}} (L - C)(N-1)
$$
$$
N - 1 > \frac{C(p_{\text{out}} + p_{\text{in}})}{\alpha p_{\text{in}} (L - C)} = \frac{C(1+r)}{\alpha (L - C)}
$$
得到阈值:
$$
N_{\text{min}}^{(c)} = 1 + \frac{C(1+r)}{\alpha (L - C)}
$$

4. 结果分析与讨论

4.1 影响决策的关键因素

因素 对阈值 $N_{\text{min}}$ 的影响 解释
原始长度 $L$ 随 $L$ 增大而减小 上下文越长,每次节省的 token 越多,压缩更易回本
压缩后长度 $C$ 随 $C$ 增大而增大 压缩效果差($C$ 接近 $L$)时节省少,且压缩成本高
价格比 $r$ 随 $r$ 增大而增大 输出 token 越贵,压缩调用的输出成本越高
缓存折扣 $\alpha$ 随 $\alpha$ 减小而增大 缓存越便宜,不压缩方案优势越大,压缩越不值得
后续调用次数 $N$ 需大于阈值 调用次数越多,压缩的长期节省越明显

特别地,当 $\alpha = 1$(无缓存)时,$N_{\text{min}}^{(c)} = 1 + \frac{C(1+r)}{L-C}$,与无缓存公式一致。当 $\alpha \to 0$(缓存极便宜),阈值 $N_{\text{min}}^{(c)} \to \infty$,意味着几乎永远不值得压缩——因为不压缩时后续调用成本可忽略。

4.2 数值示例

假设 $L = 10000$,$C = 2000$,$r = 3$(输出为输入价格的3倍),计算:

  • 无缓存:$N_{\text{min}}^{(0)} = 1 + \frac{2000 \times 4}{8000} = 1 + 1 = 2$。即只要后续调用 ≥2 次,压缩就划算。
  • 有缓存,$\alpha = 0.1$:$N_{\text{min}}^{(c)} = 1 + \frac{2000 \times 4}{0.1 \times 8000} = 1 + \frac{8000}{800} = 1 + 10 = 11$。需要至少 11 次后续调用才有压缩收益。

可见缓存大幅提高了压缩门槛。

4.3 扩展考虑

  • 压缩质量与长度权衡:实际中 $C$ 是可控参数(比如要求模型生成固定长度的摘要)。可在总成本最小化问题中进一步优化 $C$,即 $\min_{C} F_{\text{comp}}(C)$ 受限于 $C < L$ 和保留必要信息。通常存在最优 $C$,使得压缩节省与成本平衡。
  • 动态历史:若历史逐轮增长,每次调用上下文不同,缓存增益消失,此时回到无缓存情形;而压缩可以固定上下文长度,反而更有利。
  • 输出 token 的差异:压缩可能导致模型输出变短或需额外重试,但为简洁模型假设输出长度不变。

5. 结论

是否压缩历史上下文取决于后续调用次数是否超过由上下文长度、压缩效率、价格比和缓存折扣共同决定的阈值。无缓存时,只要 $N > 1 + \frac{C(1+r)}{L-C}$ 就应压缩;有缓存时,由于不压缩方案也能享受缓存折扣,压缩的盈亏平衡点显著提高($N > 1 + \frac{C(1+r)}{\alpha (L-C)}$)。开发者应根据实际 API 定价、缓存策略和预期调用频次,定量评估压缩的必要性。