很多团队在把大模型接入真实业务后,都会遇到一个相似的矛盾:想让模型回答更稳定,就得给它上思维链(Chain of Thought,CoT)提示,让它“多想一想”;但多想的代价是单次调用产生的 token 数量明显上涨。对于客服工单分类、代码告警归因、内容安全初筛这类每天重复上万次的任务,成本压力很快就会从“测试时的不在乎”变成“生产时的真金白银”。
本文将围绕一个优化思路展开:记忆增强压缩(Memory-Augmented Compression)。简单说,就是把那些稳定、可复用的推理过程从“每次生成阶段重新思考”中拿出来,提前提炼并压进提示词里。这样做能减少思维链带来的重复消耗,同时尽量保住模型输出质量。
阅读本文你能了解:
- 思维链成本到底从哪里来;
- 记忆增强压缩的核心逻辑是什么;
- 如何在提示词工程中落地静态压缩、动态记忆库注入;
- 一套可运行的最小示例;
- 以及落地时容易踩的坑和工程建议。
内容偏 AI 应用开发和提示词工程实践,适合有后端或脚本基础、正在做 LLM 应用落地的读者。
1. 思维链很强大,但成本不低
1.1 思维链的基本认识
思维链(CoT)是一种让大模型分步骤推理的提示方式。开发者在用户问题后补充类似“请一步一步思考”的指令,或者直接在提示词里写出“第一步做什么、第二步做什么”的骨架,模型便会生成一段中间推理过程,再给出最终答案。
之所以要在应用里加思维链,是因为很多任务表面上是“一句话问答”,实际上需要多步逻辑比较。如果不加限制,模型容易跳过关键判断,直接输出一个自信但可能错误的结果。
常见的 Prompt 写法大致是:
你是一个客服工单分类助手。 请一步一步思考用户问题中的关键信息,再判断它属于哪个分类,最后输出结果。从效果上看,CoT 能提升复杂任务的准确率;从成本上看,它也是最直接的 token 消耗放大器。
1.2 成本从哪些地方产生
大模型按 token 计费,CoT 的成本压力来自三个方向:
| 成本维度 | 产生原因 | 业务影响 |
|---|---|---|
| 输出 token 增加 | 模型需要把推理过程一个个字生成出来 | 单次调用费用上升 |
| 响应时延变长 | 自回归模型逐 token 生成,输出越长越慢 | 用户等待时间增加 |
| 系统吞吐下降 | 并发下长输出占用更多生成资源 | 每秒处理请求数下降 |
也就是说,多出来的“思考”并不是免费的。对一次咨询类调用,多几百 token 可能听起来不多;但如果是每天 10 万次调用,多出的成本会非常可观。
1.3 很多重复推理其实并不需要重新生成
进一步观察会发现一个问题:同一类任务里的思维链,有相当一部分是重复的。
举例来说,客服工单分类任务中,只要工单内容出现“验证码收不到”“密码错误”“无法登录”,无论用户换了多少种表达,模型每次都要重新分析“这个问题是否涉及登录态?”“是否属于账号问题?”。这种判断规则一旦沉淀下来,其实是稳定的。
如果每次都让模型从零开始把整条思路重新生成一遍,那么系统实际在为“重复思考”付费。
这就是记忆增强压缩要解决的问题:把可复用的推理链提前整理成压缩记忆,放进提示词;模型无需每次都从头推导,直接基于提示词中已有的判断模板输出结果。
2. 记忆增强压缩到底在做什么
2.1 推理也可以分层看
我们可以把模型在处理一类任务时的推理内容粗略分成两类:
- 可复用推理:跨样本稳定。比如规则优先级、分类边界、输出格式、常见特例。这类内容不依赖具体的用户输入,而是依赖业务本身。
- 实例级推理:针对当前输入的一次性判断。例如某条工单到底命中哪个关键词、两个条件冲突时选择哪个分类。
传统提示词工程中,这两类推理都发生在生成阶段。模型每收到一条新工单,都会把“业务规则”和“本条工单的判断”一起生成出来。
记忆增强压缩的思路是:把可复用推理离线提炼成一个更紧凑的表达,写入系统提示词或外部记忆库;生成阶段只保留少量必要的实例级判断。
2.2 用 Token 消耗公式理解优化空间
可以用一个简化公式来说明:
传统方案总消耗 ≈ 指令 Token + 上下文 Token + 可复用推理 Token + 实例推理 Token + 答案 Token 压缩后总消耗 ≈ 指令 Token + 压缩记忆 Token + 实例判断 Token + 答案 Token压缩方案并不是简单去掉所有推理,而是把“可复用推理 Token”从生成阶段提前到“提示词阶段”。
提示词阶段写入这些内容只需要计一次输入 Token,而且可以进行适当的压缩表达:把大段思维链提炼成优先级规则、判断分支、few-shot 示例。
目标不是让模型“不想”,而是让它不要重复想那些已经被验证过的思路。
2.3 它和 Few-Shot、蒸馏、RAG 的区别
不少读者会问:记忆增强压缩是不是就是多给几个示例?是不是等价于模型蒸馏?还是说它就是 RAG?
它们并不完全一样:
| 技术方向 | 核心思路 | 与记忆增强压缩的关系 |
|---|---|---|
| Few-Shot Prompt | 给模型若干输入输出示例 | 记忆增强压缩的一种载体,但更强调提炼“判断逻辑” |
| 模型蒸馏 | 训练一个小模型去模仿大模型 | 需要训练阶段,改动成本高 |
| RAG / 检索增强 | 从外部知识库召回内容注入上下文 | 可作为记忆增强压缩的动态记忆载体 |
| 记忆增强压缩 | 把可复用推理压成短记忆,减少重复生成 | 更多是提示词工程与应用架构层的组合优化 |
因此,不要把记忆增强压缩理解成一个单独的模型或一个固定的库。它是一套优化方法论。
3. 记忆增强压缩的三种落地形态
3.1 静态压缩:把推理骨架固化到 System Prompt
静态压缩是最容易理解的落地方式。
先人工分析这一类任务的历史优秀推理过程,把重复出现的决策点提炼成规则,然后写进 System Prompt 中。模型收到输入后,不需要展开整段思维链,只需要按 System Prompt 中的优先级判断并输出结果。
这种方法适合业务规则稳定、边界相对清晰的场景。优点是零额外依赖,改一个 Prompt 就能测试;缺点是提示词需要人工维护,面对超复杂任务时容易变长。
3.2 动态压缩:外部记忆库 + 检索注入
当任务类型太多、无法用一个 System Prompt 覆盖时,可以维护一个“记忆片段库”。
每个记忆片段可以包含:
片段 ID 适用问题类型 触发条件 / 召回关键词 压缩后的判断规则 可选的示例每次收到用户请求时,先从记忆库中召回与该请求最相关的一个或几个片段,动态拼接到提示词中,而不是把所有规则都塞进提示词。
这种方法本质上很像 RAG,但记忆库中存的不只是事实型知识,更多是“推理路径片段”和“判断策略”。适合任务类型多且差异较大的企业应用。
3.3 分层触发:先走轻量判断,再启用完整思维链
并不是所有请求都需要完整思维链。
工程上可以加入一层前置路由:先用较低成本的策略判断当前请求的复杂度。如果请求明显属于高频简单类型,模型直接按内置规则输出;只有在请求较复杂,或内置规则判定置信度不足时,才唤醒完整的思维链模式。
这种“分层触发”策略能在不降低复杂任务效果的前提下,大幅降低整体成本。
4. 实战:用记忆增强压缩优化客服工单分类
下面用一个具体的客服工单分类场景来演示如何操作。为便于理解,示例会保留完整的提示词和 Python 调用代码,但不会绑定特定厂商接口,使用的是常见的 OpenAI 兼容调用风格。
4.1 业务背景与优化前 Prompt
假设业务方需要把所有客服工单分为三类:
- 账号登录类
- 账务扣费类
- 产品功能咨询类
优化前的提示词让模型“一步一步思考”,输出分类结果。
# 文件路径:prompt/v1_original.py SYSTEM_PROMPT_ORIGINAL = """你是一个客服工单分类助手。 用户会提交一条客服工单内容,你需要判断这条工单属于哪个分类。 可选分类:账号登录类、账务扣费类、产品功能咨询类。 请先一步一步分析用户问题: 1. 用户是否在描述登录失败、验证码、密码等问题; 2. 用户是否在描述退款、扣费、账单、价格等问题; 3. 用户是否在描述某个具体功能不会用或找不到入口。 最后输出工单分类。"""这种写法质量往往不错,但模型每次都会生成一长段分析文字。
4.2 第一步:从历史数据中提炼可复用推理
接下来要做记忆增强压缩。可以先找历史中 50 到 100 条分类准确且解释清楚的样本,把模型的推理过程整理成反复出现的判断规则。
经过归纳后,规则可以压缩成如下清单:
规则 1:包含“验证码、无法登录、登录失败、密码错误、收不到短信”等关键词,优先归为账号登录类。 规则 2:包含“退款、扣费、重复扣款、发票、账单”等关键词,优先归为账务扣费类。 规则 3:包含“怎么用、找不到、如何使用、咨询”等关键词,优先归为产品功能咨询类。 规则 4:关键词存在冲突时,依次按 规则1 > 规则2 > 规则3 的优先级判断。 规则 5:都不命中时,输出“其他”,并返回不超过 15 个字的初步建议。你会发现,这些规则就是“可复用推理的压缩表达”。
4.3 第二步:编写压缩后的 System Prompt
压缩后的 System Prompt 不再要求模型“展开思考”,而是要求它基于规则直接输出 JSON。
# 文件路径:prompt/v2_compressed.py SYSTEM_PROMPT_COMPRESSED = """你是工单分类助手。请基于以下规则输出分类结果,不要展开额外推理。 规则1:包含“验证码、无法登录、登录失败、密码错误、收不到短信”等关键词,归为账号登录类。 规则2:包含“退款、扣费、重复扣款、发票、账单”等关键词,归为账务扣费类。 规则3:包含“怎么用、找不到、如何使用、咨询”等关键词,归为产品功能咨询类。 规则4:关键词冲突时,按 规则1 > 规则2 > 规则3 优先级处理。 规则5:全部不命中时,分类为“其他”,并给出不超过15个字的初步建议。 输出格式(必须是合法 JSON): {"category": "分类名", "matched_rule": "命中的规则编号", "brief_reason": "一句话原因"} """与 V1 对比,V2 对模型的约束更强,输出格式更固定,也减少了诱导模型长篇推理的空间。
4.4 第三步:封装调用函数并统计 Token
为了验证效果,我们需要在调用前后记录 token 数量。这里使用 tiktoken 作为本地的 token 统计工具,调用部分使用 OpenAI 兼容 SDK。
先安装依赖:
pip install tiktoken openai再编写调用脚本:
# 文件路径:scripts/compare_prompt.py import os import json import tiktoken from openai import OpenAI # 从环境变量读取密钥,不要在代码中硬编码 client = OpenAI( api_key=os.environ.get("LLM_API_KEY"), base_url=os.environ.get("LLM_BASE_URL"), ) ENCODER = tiktoken.get_encoding("cl100k_base") def count_tokens(text: str) -> int: return len(ENCODER.encode(text)) def call_model(system_prompt: str, user_text: str): resp = client.chat.completions.create( model=os.environ.get("LLM_MODEL", "gpt-4o-mini"), messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_text}, ], temperature=0, ) content = resp.choices[0].message.content usage = resp.usage return content, usage def main(): user_text = "我手机收不到验证码,无法登录APP,麻烦处理。" print("V1 系统提示词 token 数:", count_tokens(SYSTEM_PROMPT_ORIGINAL)) print("V2 系统提示词 token 数:", count_tokens(SYSTEM_PROMPT_COMPRESSED)) # 实际调用前请确认 LLM_API_KEY 与 LLM_BASE_URL 已配置 # content_v1, usage_v1 = call_model(SYSTEM_PROMPT_ORIGINAL, user_text) # content_v2, usage_v2 = call_model(SYSTEM_PROMPT_COMPRESSED, user_text) # # print("V1 输出:", content_v1) # print("V1 total_tokens:", usage_v1.total_tokens) # print("V2 输出:", content_v2) # print("V2 total_tokens:", usage_v2.total_tokens) if __name__ == "__main__": main()上面脚本中的本地 token 统计可直接运行,实际调用部分需要你根据自己的 API 配置打开注释。之所以没有把调用结果写死,是因为不同模型的输出长度、推理风格差异很大,必须基于真实观测数据来判断优化效果。
4.5 用动态记忆库承载多类型推理
如果业务分类不止三类,而是几十类,把全部规则塞进一个 System Prompt 会让输入越来越长。更合理的方式是维护一个“记忆片段库”。
下面是一个简化版模拟实现:
# 文件路径:memory_fragment_store.py MEMORY_FRAGMENTS = [ { "fragment_id": "rule_account_login", "scene": "账号登录类问题", "triggers": ["验证码", "无法登录", "登录失败", "密码错误", "收不到短信"], "rule": "涉及登录态、验证码、密码、短信的账号问题,优先归为账号登录类。", "sample": "用户说收不到验证码 -> 归类为账号登录类,不要扩展排查步骤。", }, { "fragment_id": "rule_billing", "scene": "账务扣费类问题", "triggers": ["退款", "扣费", "重复扣款", "发票", "账单"], "rule": "涉及扣费、退款、账单金额的问题,优先归为账务扣费类。", "sample": "用户说被重复扣费 -> 归类为账务扣费类。", }, ] def find_memory_fragments(user_text: str): """简化召回:真实生产环境可替换为向量检索或关键词加权召回。""" result = [] for item in MEMORY_FRAGMENTS: for keyword in item["triggers"]: if keyword in user_text: result.append(item) break return result生产中可以把triggers换成文本 Embedding,再使用向量数据库按相似度召回。但需要注意:无论用哪种召回方式,拼入提示词的记忆片段都应保持简洁,只保留必要规则。
动态提示词组装的核心代码如下:
# 文件路径:build_dynamic_prompt.py def build_dynamic_system_prompt(user_text: str) -> str: fragments = find_memory_fragments(user_text) if not fragments: return "你是工单分类助手。请直接判断工单分类并输出 JSON。" lines = ["你是工单分类助手。请基于以下记忆片段判断,不要展开长篇推理。"] for frag in fragments: lines.append(f"记忆片段 {frag['fragment_id']}:{frag['rule']}") lines.append('输出格式:{"category": "分类名", "brief_reason": "一句话原因"}') return "\n".join(lines)这样处理的好处是:不同请求只会携带与自身相关的记忆片段,而不是把整个业务知识库全部加载进来。
4.6 运行与验证
运行验证时,建议至少准备两组测试集:
- 相同难度的 50 条历史工单;
- 覆盖边界情况的 20 条对抗样本。
对比 V1 与 V2 时,重点看四个维度:
| 对比项 | V1 长推理方案 | V2 记忆增强压缩方案 |
|---|---|---|
| 平均输入 token | 由离线统计得到 | 由离线统计得到 |
| 平均输出 token | 通常更高 | 明显下降 |
| 平均响应时长 | 通常更长 | 更短 |
| 分类准确率 | 作为基线 | 应接近或不低于基线 |
如果 V2 准确率下降明显,说明压缩后的规则没有覆盖某些关键边界条件。此时不是要退回 V1,而是要把遗漏的边界条件补充进记忆片段。
5. 成本与效果评估方法
5.1 不要只看“单次省了多少”
评估记忆增强压缩的核心指标是:
单次调用成本 = 输入 token 成本 + 输出 token 成本 单日成本 = 单次调用成本 × 日均调用次数压缩输入提示词可以减少输入成本,但通常更明显的是输出 token 下降。
建议直接在代码中打印usage的三个字段:
prompt_tokenscompletion_tokenstotal_tokens
积累一定数据量后,按平均数和 P90 观察分布。因为部分复杂工单仍会走到长推理路径,只对比平均数会掩盖长尾问题。
5.2 估算成本下降空间
写一个简单的成本计算函数即可:
# 文件路径:scripts/estimate_cost.py def estimate_cost( input_tokens: int, output_tokens: int, input_price_per_million: float, output_price_per_million: float, ) -> float: """价格单位:元 / 百万 token。具体价格以你的模型供应商为准。""" input_cost = input_tokens / 1_000_000 * input_price_per_million output_cost = output_tokens / 1_000_000 * output_price_per_million return input_cost + output_cost使用时用自己实际观测到的 token 均值,并配合供应商的价格表填入即可。
5.3 什么时候不适合记忆增强压缩
不是所有任务都适合这个方案。遇到以下情况时要谨慎:
| 情况 | 原因 |
|---|---|
| 任务没有稳定规则,高度依赖开放性创造 | 压缩会丢失发散能力 |
| 提示词已经非常短 | 压缩空间有限 |
| 每轮用户问题上下文差异巨大,几乎没有相同推理 | 可复用的部分太少 |
| 强监管场景要求模型输出完整决策过程 | 压缩后难以审计,不建议过度压缩 |
记忆增强压缩的本质是“把稳定逻辑前置”,前提是任务确实存在稳定逻辑。
6. 常见问题与排查思路
6.1 压缩后模型不按规则执行
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 模型仍然输出长篇推理 | System Prompt 约束不够强 | 明确写明“不要展开额外推理”,并约束输出为 JSON |
| 模型忽略规则直接猜测 | 规则之间冲突、优先级不明确 | 检查规则是否重叠,补充优先级关系 |
| 少数边界工单分类错误 | 记忆片段覆盖不足 | 收集错误样本,提炼新规则或增加 few-shot 示例 |
6.2 把完整 CoT 去掉后准确率下降
如果去掉了所有 CoT,准确率下降,那说明当前任务仍需要一部分实例级推理。
处理方式不是回到 V1,而是采用“分层触发”:先用压缩提示词快速分类并记录置信度;如果关键词命中不明显、输出为空或置信度过低,再让它走一次完整思维链。
也可以只在规则无法覆盖判断时追加一句轻量推理指令:
如果上述规则无法判断,请简要说明你考虑了哪些候选分类,再输出结果。6.3 压缩后的 System Prompt 越来越长
优化过程中很容易出现“每遇到一个错误,就加一条规则”的情况,结果 System Prompt 越来越长,输入成本反而上升。
建议每个记忆片段都限制篇幅,最多两到三句话。如果某类规则超过三条,就单独建立片段并做检索注入,而不是继续堆在固定 System Prompt 中。
6.4 记忆片段之间冲突
多个规则可能同时命中同一条工单。处理方式是在记忆片段中显式设置优先级,并在 System Prompt 里写清楚“冲突时按哪个片段先执行”。
如果冲突经常发生,说明几个分类的边界定义本身不够清晰,应该回到业务定义层去调整。
6.5 安全与审计问题
生产环境中,不应让用户输入直接覆盖系统提示词中的规则。对模型输出要做格式校验和内容校验,尤其是自动执行后续动作时。
压缩后模型不再输出完整推理,这会给审计带来难度。建议保留一份“最终命中规则”字段,也就是模型必须返回matched_rule或fragment_id,用于事后追溯。
7. 最佳实践与工程建议
7.1 记忆片段的选择标准
什么样的推理值得被压缩成记忆片段?我的工程经验是看三个特征:
- 重复频率高:每天出现次数多,压缩收益大。
- 结论稳定:只要规则清晰,不同模型、不同时间跑出来的结果应该一致。
- 规则可表达:能用关键词、判断分支或简短描述提炼。如果规则本身无法描述,就很难稳定压缩。
不要把那些“只出现一次的特殊技巧”写进通用记忆片段,那会让提示词变脏。
7.2 把提示词当代码管理
记忆增强压缩落地后,System Prompt 会变成业务逻辑的一部分。建议像管理代码一样管理它:
- 每个提示词版本写入 Git,并记录对应业务规则变更;
- Prompt 变更必须跑回归测试集;
- 使用环境变量或配置中心管理不同环境的提示词;
- 线上要能看到当前使用的是哪个版本。
7.3 建立回归评测集
只凭几个样例来评估提示词是远远不够的。
建议准备一个不少于 100 条的评测集,包含:
- 历史真实工单;
- 关键词重叠的对抗样本;
- 完全无关的“其他”类样本。
每次修改记忆片段后,重新跑一遍评测集,记录准确率和平均 token 数量。这能帮你尽早发现“准确率暂时提升但 token 飙高”的副作用。
7.4 和 Agent / 长对话场景配合
如果应用是 Agent 或长对话场景,记忆增强压缩可以进一步扩展为“记忆层次”:
- 第一层:任务级记忆片段,存放判断规则;
- 第二层:会话级记忆,存放本次对话已经确认过的用户信息;
- 第三层:长期偏好记忆,存放与当前用户相关的历史偏好。
每一层都只注入与本轮请求最相关的内容,避免把所有历史记录都发给模型。
7.5 落地路线建议
很多团队一上来就想把所有规则都压缩进提示词,结果往往造成质量下降、返工。更稳妥的路线是:
- 先保留当前长 CoT 版本,采集一周完整日志;
- 对日志做错误归因,找出出现频率最高的稳定判断逻辑;
- 只针对 Top 3 高频场景做压缩改造;
- 用回归评测集对比压缩前后的准确率和成本;
- 验证通过后再逐步扩大范围。
8. 最后说几句实践心得
如果你正在做大模型应用的成本治理,记忆增强压缩是一个很值得投入的方向。它不需要重新训练模型,也不需要替换底层基础设施,只需要你愿意把“业务规则”真正梳理清楚,并设计好提示词的注入方式。
实际操作中,不要把思维链当成一个必须保留或必须删除的整体。更好的心态是把 CoT 当作一种可灵活分配的推理资源:稳定部分交给提示词记忆,真正的复杂判断才留给生成阶段。
这套方法也不是一步到位的。先从你的业务里挑一个高频分类任务,做一个压缩版本,跑一跑评测集,看看 token 节省和准确率变化。只要一次对比成功,你就知道该在哪些场景里继续复用了。