返回博客列表
性能优化2026-08-1515 分钟阅读

19K tokens 的「你好」:我们把系统提示词减掉了 80%,还顺手让一篇论文的措辞名副其实

提示词预算 · 锚点切分 · 按意图注入 · 整模块丢弃 · 灰度回退

WeClaw_87|19K tokens 的「你好」:我们把系统提示词减掉了 80%,还顺手让一篇论文的措辞名副其实

系列文章第 87 篇 - 提示词预算 · 锚点切分 · 按意图注入 · 整模块丢弃 · 灰度回退


📚 专栏信息

《从零到一构建跨平台 AI 助手:WeClaw 实战指南》专栏

专栏定位:面向开发者和技术决策者的实战专栏,用真实案例和完整代码带你理解如何构建生产级 AI 应用

本文记录一次「给系统提示词减肥」的完整战役。用户说一句「你好」,模型要先读完 19K tokens 的股票操作纪律、OCR 防泄漏规则和论文生命周期管理,然后才回一句「你好呀」。这不是修辞,是 WeClaw 改造前的真实加载行为。这篇讲我们怎么在不破坏任何既有行为、不触碰任何论文复现契约的前提下,把 10 个典型场景的系统提示词总量从 244,357 tokens 砍到 48,845(−80.0%),以及中途否决掉的三条弯路。


👨‍💻 作者与项目

作者简介:翁勇刚 WENG YONGGANG 新概念龙虾-WeClaw 开发团队负责人,一群专注于跨平台 AI 应用的实践者 理念:"再复杂的技术,也能用代码讲清楚"


📝 摘要

本文结构概览: 一句「你好」为什么要读 19K tokens(问题的量化)→ 三条被否决的瘦身路线以及否决理由(思辨)→ 两轮评审把一个方案从「看起来对」磨到「构造性对」(方案演进)→ 锚点切分 + 意图注入 + 模块预算三件套的技术实现 → 10 场景实测数据与门禁验收 → 一个意外收获:论文里 "lightweight" 的措辞从虚假宣传变成了事实陈述。

核心结论

  1. 系统提示词膨胀的根因不是「写多了」,而是装配方式错了——全量注入让每个请求都为所有领域付费;
  2. 安全的瘦身不是删文本,而是重构装配链:内容一行不丢(行多重集等价),加载量按需付费;
  3. 灰度开关 + 字节级回退不是保守,而是让高风险重构敢动手的前提。

一、问题:每个请求都在为全部 13 个领域付费

WeClaw 的系统提示词由一段核心常量 CORE_SYSTEM_PROMPT 构成,33,533 字符,实测约 19.3K tokens。里面装着 13 个领域的工具选择指南:浏览器、文档、金融、数据分析、创作、语音、古诗词、专业文档、学术、OCR 扫描、菜谱、通讯天气、定时任务——每个领域都是一段带「严禁」「必须」字样的硬规则。

装配逻辑简单粗暴:无论用户说什么,全量注入

于是出现了这样的账单:

场景用户实际说了什么模型要先读多少
闲聊「你好呀」27,983 tokens
问天气「今天北京天气怎么样」22,401 tokens
写首诗「写一首秋天的诗」27,983 tokens

一个只涉及天气的请求,为什么要携带「量化分析严禁手工绕行 stock_screen」「论文项目须用 paper_lifecycle.update_phase 记录进度」这些纪律?答案是:没有任何为什么,装配函数只会做加法。

更尴尬的是学术层面的连锁问题。我们有一篇在投论文(CFTA,异步工具编排模式)声称语音快聊路径使用 "a lightweight system prompt"——实测这条路径注入的是全量核心,19.9K tokens。"lightweight" 是纯粹的虚假宣传,是一颗等着被审稿人引爆的雷。

诊断结论:这不是「提示词写多了」的问题。每段指南在其领域内都是必要的硬规则,删不得。问题在于装配方式——全量注入让成本与请求无关,只与系统总规模挂钩。

二、思辨:三条被否决的路线

动手之前我们认真评估过四条路线,否决了三条。这部分「不做什么」的思辨,比最终方案本身更值钱。

路线 A:纯去重——否决,但保留为前置批次

最直觉的想法:33K 字符里有多少重复?实测扫了一遍,重复文本只有约 960 字符的收益。去重是干净的、零风险的,值得做(后来作为 P0 批次落地),但它解决不了问题:去重后日常请求仍要读约 13K+ tokens,稳定压在 15K 安全线上方。去重是卫生,不是手术。

路线 B:LLM 在线摘要——否决,理由有四

用一个小模型在每轮请求前把系统提示词「压缩」成摘要,听起来很优雅。评估后否决,四条理由一条比一条硬:

  1. 延迟与成本:每轮请求多一次 API 调用,恰好打击我们最想优化的首响应延迟;
  2. 不可控:摘要模型可能丢掉「严禁」「必须」这类硬规则——而恰恰是这些规则在防事故;
  3. 破坏 prefix 缓存:摘要结果每轮漂移,LLM 服务端的前缀缓存彻底失效,实际 token 成本不降反升;
  4. 不可审计:压缩后的提示词出了行为问题,你无法定位是哪条规则丢了。

路线 C:按 tier/置信度收窄——否决,风险外溢

意图分类器本来就输出置信度,「低置信度就少注入」看似顺理成章。但排查发现 tier 机制自身存在既有缺陷(收窄逻辑与工具 schema 暴露耦合),在它上面再叠一层提示词收窄,等于把两个有缺陷的判断串联。我们没有修 tier,而是绕开了它——这个决策后来被证明是对的:提示词装配与 tier 解耦后,tier 的任何后续修复都不会波及这里。

路线 D(采纳):结构化拆分 + 按意图装配

把全量常量原样保留,从它派生出一套结构化视图:核心残量 + 13 个领域指南 + 一行式索引,装配时按意图只取需要的部分。关键设计前提:原常量不删不改,任何异常一个配置开关回到原点。

三、方案演进:两轮评审把「看起来对」磨成「构造性对」

方案初稿(V1)自我感觉良好,然后被两轮评审打出了 4 个 Critical、10 个 Warning、7 个 Suggestion。挑三个改变了最终形态的发现:

发现一:切分不能靠复制粘贴。 V1 打算把 CORE 的 33K 文本手工切成 14 份新常量。评审指出这等于凭空制造 33K 字符的漂移面——CORE 改一个字,切分副本就静默失真。改成运行时锚点切分:切分代码只记录每个章节的起止锚点(章节标题字符串),导入时从活体 CORE 现场切出。CORE 是单一事实源,切分是它的视图。锚点失效(章节改名、被删)在导入时直接抛异常——红灯优于静默

发现二:等价性必须可证明,不能靠目测。 「切完应该没丢东西吧」这种话在评审里是不及格的。最终方案给出构造性证明:CORE 中未被任何指南区间覆盖的部分,按原顺序拼接就是核心残量——由定义可知 核心残量 + 全部指南 ≡ 原 CORE(行多重集)。验收脚本把这句话变成可执行断言,一行内容丢失即红。

发现三:三篇在投论文是冻结面。 全库 grep 后确认:多篇论文的实验脚本依赖意图分类器等符号的精确行为,而提示词改造极易顺手「优化」到它们。于是写入冻结契约:detect_intent_with_confidence 等符号只增不改,另配 10 条 query 的快照护栏——任何破坏意图行为的改动,门禁当场红灯。

这三条把方案从「一个瘦身技巧」变成了「一次有安全骨架的重构」。最终方案文档 463 行,其中约三分之一是风险表与否决记录。

四、技术栈:三件套实现

4.1 锚点切分(新模块 domain_guides.py)

切分核心逻辑不到 60 行,骨架是「先校验后切割」:

_GUIDE_SEGMENTS = [
    # (指南名, 起始锚点, 结束锚点)——锚点必须是 CORE 中唯一子串
    ("browser_guide",  "**浏览器工具选择指南】**", "【文档处理工具选择指南】"),
    ("finance_guide",  "6. **stock_query**",      "【数据分析工具选择指南】"),
    # …共 15 段(ocr_scan_guide 由三段合并),覆盖 13 个指南
]

def _build_split(core: str):
    intervals = []
    for name, start, end in _GUIDE_SEGMENTS:
        si, ei = core.find(start), core.find(end)
        if si < 0 or ei < 0:
            raise ValueError(f"锚点未找到: {name}")      # 红灯,绝不静默
        if core.find(start, si + 1) >= 0:
            raise ValueError(f"锚点不唯一: {name}")      # 唯一性校验
        intervals.append((si, ei, name))
    # 段间按序、不重叠校验 → 指南段 strip 合并
    # 核心残量 = 未覆盖区间按序拼接(构造性等价的关键)

切分结果(P0 去重后的实测规模):

产物规模用途
CORE_RULES 核心残量3,260 字符始终注入(身份/通用纪律)
13 个领域指南362 ~ 7,345 字符/个按意图注入,单请求 ≤3 个 ≤12K 字符
GUIDE_INDEX 一行式索引1,208 字符未命中意图时的兜底速查表

4.2 按意图注入:三条规则 + 一个反查表

装配函数接受一个 guide_override 参数,语义三分:

  • None:按 INTENT_GUIDE_MAPPING(15 个意图 → 指南列表)收集,命中意图按 (-score, 名称) 确定性排序取前 3;
  • "__index__":强制注入一行式索引(direct_tool 反查失败时的兜底);
  • 具体指南键:只注入该指南(斜杠直达工具时,TOOL_GUIDE_REVERSE 反查目标工具所属指南)。

两条互斥与兜底规则值得展开:

  • 互斥:用户明问「你都有哪些功能」时注入的是能力菜单,此时跳过索引兜底——两个「概览型」内容不得同场;
  • 兜底定义:「未命中」被定义为映射结果为空而不是「置信度低」。这个区分来自实测:10 条护栏 query 里有 4 条(含「写一首秋天的诗」)返回空意图——分类器存在覆盖盲区,这些请求一律由索引兜底,不做任何置信度判断。

4.3 模块列表 + 预算渲染器:丢弃的艺术

装配产物不再是字符串,而是带丢弃优先级的模块列表

(core_rules, 内容, -1)   # -1 = 永不丢弃
(companion,  内容, -1)   # 心理关怀锚点,不可丢
(skills,     内容, 45)
(files,      内容, 50)
(guide_*,    内容, 60/65/70)   # 相关性越低越先丢
(guide_index,内容, 75)
(capabilities,内容, 80)  # 最先被丢

渲染器在双预算下工作:字符硬上限 26,000(从 50,000 收紧)+ token 软预算 15,000(用真实估算器,废弃了沿用已久的 len//2 假设——实测中文密度 0.571 tok/字符,旧系数高估容量 14%)。超限时的纪律有两条反直觉但重要的规定:

  1. 整模块丢弃,禁止句中截断。旧代码的 prompt[:N] 会把一条「严禁」规则从中间切开,留下语义残骸;整模块丢弃保证活下来的每段都是完整的;
  2. 丢弃后回补索引。如果领域指南被丢光了,渲染器补回 1,208 字符的一行式索引——模型至少知道「有哪些领域、细节按需」,而不是对工具生态一无所知。

4.4 灰度开关:一行配置的回退契约

# config/default.toml
[prompts.domain_guides]
enabled = false   # 一键回退:原 CORE 全量路径,逐字节等价改造前

因为原常量从未被修改,回退路径与改造前的输出逐字节一致——这不是「行为差不多」,是可用断言验证的 ==。验收脚本真的 monkeypatch 了开关、真的断言了字节级等价。

五、五条链路,一套装配

WeClaw 共有五条会生成系统提示词的链路,改造前各有各的拼接代码(复制粘贴分叉是双路径行为漂移的温床)。P2 批次抽出共享装配函数后全部归一:

链路装配方式实测规模
普通对话(流式/非流式)意图装配 + 技能/经验/文件注入 + 预算渲染闲聊 3,465 tokens
语音快聊固定三模块(核心残量+陪伴+索引)~3,465 tokens
斜杠直达工具工具反查指南,未命中强制索引单指南 ≤7.3K 字符
斜杠直达技能复用指令意图正常装配同意图场景
CFTA 异步链路正常装配 + 不可丢弃的判定指令模块≤26K 硬上限内

统一之后,「同一输入经两条路径产出不同提示词」这类漂移在构造上不再可能——验收门禁里有逐字节一致性断言守着。

六、效果:数据说话

6.1 token 账单(真实估算器,10 场景 × 改造前后)

场景改造前改造后降幅
闲聊27,9833,465−87.6%
创作-诗词 / 语音 / 学术27,9833,465−87.6%
浏览器19,8803,582−82.0%
定时19,8803,465−82.6%
文档-格式转换22,4015,265−76.5%
日常-天气22,4015,984−73.3%
金融-股票分析19,8805,794−70.9%
能力菜单27,98310,895−61.1%
合计244,35748,845−80.0%

降幅最大的恰是最常见的请求:闲聊和空意图场景不再为 13 个领域付费,只带一张 1,208 字符的索引地图。

6.2 质量账单:内容一行没丢

  • 切分等价:核心残量 + 13 指南 ≡ 原 CORE,非空行多重集断言通过;
  • 场景正确性:天气请求含默认城市机制、不含股票纪律;股票分析含「严禁绕行」;学术场景含论文生命周期规则——7 场景逐项断言;
  • 冻结护栏:10 条 query 的意图快照与基线全一致,论文复现面零漂移;
  • 回归:定向回归 274 项,零新增失败(12 个失败经 git stash 干净 HEAD 对照,全部为既有问题)。

6.3 意外收获:论文措辞从虚假变成事实

CFTA 论文里 "lightweight system prompt" 的论断,改造前是 19.9K tokens 的虚假宣传,改造后是 ~3.9K tokens 的事实陈述。我们按论文一致性清单同步修订了三篇在投论文的 5 处漂移(含预算数字口径、意图类别数统一、一处成本论证的前提限定),并主动在 Limitations 补了一段敏感性披露:瘦身后 CFTA 的绝对延迟收益会从 ~11.5s 缩到 ~8-10s,但相对降幅稳定在 55-58%——收益来源是把工具执行移出首响应关键路径,而不是掩盖臃肿提示词。主动披露比被审稿人发现体面得多。

七、沉淀:四条可迁移的经验

  1. 膨胀问题的根因常在装配而非内容。先问「这段话在这个请求里为什么出现」,再决定删不删;
  2. 高风险重构的三件套:原物保留(回退面)+ 构造性等价(可证明不丢东西)+ 灰度开关(一键回到原点)。三件齐备,重构才敢动手;
  3. 丢弃要有优先级,截断是懒政prompt[:N] 切出来的语义残骸比不切更危险;
  4. 给论文时代的项目加冻结护栏。实验脚本依赖的符号就是公共 API,改动前先立快照断言,红灯比道歉便宜。

完整的验收脚本在仓库 scripts/ 下(verify_domain_guides_split / verify_prompt_assembly_p2 / probe_sp_tokens),全部只读、可重复执行。下一篇(第 88 篇)讲这场战役里容易被忽略的另一半:如何在「三篇论文依赖活体代码」的约束下设计安全骨架


📎 本文涉及的代码src/core/domain_guides.py(新模块)、src/core/prompts.pysrc/core/agent.pyconfig/default.toml 📊 版本:v9.13.0 | 迭代文档:docs/开发记录/v9.13.0_2026-08-10_系统提示词瘦身方案V3落地.md