用 Gisting 把长系统提示压缩成少量可学习 Token

2026-09-04 41 预计阅读时间: 1 分钟
来源: infoq.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:7 分钟

LLM 应用的系统提示正在变得越来越长:行为规则、品牌语气、安全边界、工具说明和输出格式常常占据数千个 token。Shopify 工程团队介绍的 gisting 技术,试图把这段固定但昂贵的上下文压缩成少量经过学习的“gist token”,从而减少推理时需要处理的输入,提高吞吐量并降低成本。

Gist token 不是普通的文本摘要

常规提示压缩通常生成一段更短的自然语言,例如把十页规则改写成十条要求。这样做容易接入现有 API,但信息仍然需要通过文字表达,压缩过程中还可能丢失细微约束。

Gisting 的思路不同:在训练阶段,让模型把长提示中的任务信息编码到一小组特殊 token 的内部表示中。后续执行任务时,模型读取这些表示,而不必反复处理完整提示。

可以把流程抽象为:

长系统提示 P + 训练样本 (X, Y)
             │
             ▼
      Gisting 训练过程
             │
             ▼
少量 gist token G = [g1, g2, ... gn]
             │
             ▼
推理输入:G + 用户请求 X

这里的 G 不是一串可以直接阅读的规则,也不是把摘要文字换了一个名字。它更接近模型学到的任务条件表示。因此,普通聊天 API 如果不支持自定义嵌入、软提示或相应模型结构,就不能仅靠在请求中写入 <gist_1> 来获得同样效果。

为什么它可能降低推理成本

假设系统提示有 S 个 token,每个请求还包含 U 个用户 token。传统方式处理 N 次请求时,输入规模大致为:

N × (S + U)

如果系统提示被压缩为 G 个 gist token,在线输入规模则近似变为:

N × (G + U),其中 G << S

真实收益还会受到模型架构、批处理、KV cache、输出长度、硬件利用率和训练开销影响。尤其需要把 gisting 与前缀缓存区分开:前缀缓存避免重复计算相同提示,而 gisting 直接减少模型需要携带的上下文长度。两者解决的问题相邻,但并不等价,也可能组合使用。

Gisting 更适合重复率高的固定前缀,例如稳定的客服政策、代码审查规范或工具调用说明。若每个请求的系统提示都不同,训练和管理 gist 的成本可能抵消节省。

先算清楚压缩是否值得

下面的 Python 脚本不会训练 gist token,而是用于评估候选场景。它只依赖标准库,可以直接运行。把 token 数、调用量和训练成本改成你的实际测量值即可。

from dataclasses import dataclass


@dataclass
class Workload:
    system_tokens: int
    gist_tokens: int
    user_tokens: int
    requests: int
    input_cost_per_million: float
    one_time_training_cost: float = 0.0


def estimate(w: Workload) -> None:
    baseline_tokens = w.requests * (w.system_tokens + w.user_tokens)
    gisted_tokens = w.requests * (w.gist_tokens + w.user_tokens)

    baseline_cost = baseline_tokens / 1_000_000 * w.input_cost_per_million
    serving_cost = gisted_tokens / 1_000_000 * w.input_cost_per_million
    total_gisted_cost = serving_cost + w.one_time_training_cost

    saved_tokens = baseline_tokens - gisted_tokens
    reduction = saved_tokens / baseline_tokens if baseline_tokens else 0
    net_saving = baseline_cost - total_gisted_cost

    saving_per_request = (
        (w.system_tokens - w.gist_tokens)
        / 1_000_000
        * w.input_cost_per_million
    )
    break_even = (
        w.one_time_training_cost / saving_per_request
        if saving_per_request > 0
        else float("inf")
    )

    print(f"Baseline input tokens : {baseline_tokens:,}")
    print(f"Gisted input tokens   : {gisted_tokens:,}")
    print(f"Token reduction       : {reduction:.1%}")
    print(f"Baseline cost         : ${baseline_cost:,.2f}")
    print(f"Gisted total cost     : ${total_gisted_cost:,.2f}")
    print(f"Net saving            : ${net_saving:,.2f}")
    print(f"Break-even requests   : {break_even:,.0f}")


if __name__ == "__main__":
    estimate(
        Workload(
            system_tokens=8_000,
            gist_tokens=128,
            user_tokens=600,
            requests=1_000_000,
            input_cost_per_million=1.00,
            one_time_training_cost=2_500.00,
        )
    )

运行方式:

python gist_cost.py

这只是 token 成本模型,不应当被当作延迟或账单承诺。生产评估至少还要记录首 token 延迟、每秒处理 token 数、批处理吞吐量、GPU 显存占用,以及压缩前后的任务质量。

落地时最容易遗漏的是版本和评测

一个 gist 应当与生成它的模型、原始提示和训练配置绑定。系统提示修改后,旧 gist 不一定仍然正确;基础模型升级后,原来的内部表示也不能默认兼容。可以这样维护一个版本清单:

# 假设自建推理服务支持加载训练得到的 gist artifact
name: support-policy
base_model: your-model-version
source_prompt_sha256: replace-with-real-sha256
gist_artifact: artifacts/support-policy-v3.safetensors
gist_tokens: 128
training_config: configs/support-policy-v3.yaml
evaluation_suite: evals/support-policy-v3.jsonl
status: candidate

上线门槛不能只有“回答看起来差不多”。评测集应覆盖正常请求、罕见规则、规则冲突、提示注入和工具调用失败等情况,并分别比较原始长提示与 gist 版本。对于合规、安全或金额计算规则,任何压缩造成的遗漏都可能比节省的推理成本更昂贵。

采用建议

可以先挑选一个调用量高、系统提示稳定、结果容易自动评分的任务进行试验。保留长提示作为基线和回退路径,在相同模型、硬件与流量分布下做对照测试。

上线前应确认四件事:质量下降在可接受范围内;训练成本能够在预期请求量内回收;gist 与模型及提示版本可以追踪;安全测试没有因为不可读的内部表示而被省略。Gisting 的价值不只是缩短提示,而是把重复的提示处理从每次在线请求转移到一次受控的训练与发布流程中。


相关推荐