☰
基于API代理的LLM Token优化:用AST裁剪冗余代码
2026/11/6 10:15:37 网站建设 项目流程

在 LLM 应用的成本账里,token 几乎是一切开销的最小单位。API proxy 之所以值得做,是因为它可以替调用方统一处理请求内容,在进入上游之前完成一次可控的裁剪。一次代码评审请求可能把几十个文件粘进上下文,一次 RAG 问答可能把整段文档重复带入历史,而提示词里的注释、空行、未使用的 import 和从未被调用的函数,都在按 token 计费。更麻烦的是,冗余内容会稀释注意力、拉低响应一致性,即便模型本身没有报错。针对这类问题,一种比较自然的工程方案是在请求链路上加一层 API 代理:代理拦截发往 LLM 上游的请求,识别其中的代码内容,用 AST 完成抽象语法树级别的 pruning,再把清理后的请求转发给模型。下面实现的其实是一个最小可复用的原型:它基于 FastAPI 搭建,兼容主流 chat/completions 接口,核心剪枝逻辑可以独立复用。读者可以把它改造成内部网关、CI 代码审查服务或私有 LLM 平台上的一层中间件。

1. 理解清楚 token 冗余是如何进入 LLM 上下文的

1.1 一次 chat 请求里的 token 开销由哪几部分构成

OpenAI 兼容接口的请求体是messages数组,每个消息包含role和content。模型真正处理时,会把 system prompt、历史对话、工具定义、用户输入拼接到同一个上下文窗口,再按模型分词器切分成 token。因此一次请求里的 token 开销不只是“用户最后输入的那句话”,而是整段上下文。

常见冗余来源如下表所示。

冗余类型典型例子简单处理方式是否属于 AST pruning 范畴
系统提示重复每轮都发送同一大段 system 指令在代理层做对话级缓存不算,属于会话管理
多轮历史重复把整段文档或工具返回反复带入做历史摘要或 sliding window不算,属于上下文管理
代码注释和空行文件顶部大量注释、空行删除注释和空行算是
未使用导入import os但全程没用到AST 分析删除算是
未使用的函数和类粘贴整个文件,但只用其中一小块按引用分析裁剪算是,但安全风险较高
JSON/YAML 冗余字段配置文件里大量默认值和空值结构化字段裁剪可以借鉴 AST 思路

这些冗余会带来两个直接后果:一是计费增加,输入 token 越多,单次调用成本越高;二是模型注意力被无关内容分散,代码审查、错误修复、接口解释等任务更容易答偏。代理层的价值就是把“该不该删”的判断从用户手里收上来,统一执行。

1.2 代码类内容为什么是冗余重灾区

代码类内容在 prompt 里非常常见,但也很容易被忽视。很多用户做代码解释、代码评审、单元测试生成时,会直接粘贴完整文件,甚至粘贴整个项目目录下的关键文件。下面这段代码比较典型。

import os import json # TODO: remove this debug function later def _internal_debug(data): print(data) def main(): cfg = json.load(open("config.json")) print(cfg) if __name__ == "__main__": main()

对模型理解main流程来说,import os、注释行、_internal_debug都不是必要内容。但它们都会进入分词器,变成输入 token。更隐蔽的是,很多用户会粘贴带有大量logging日志、调试分支、被注释掉的历史代码的文件,这些内容对模型理解真正业务逻辑的贡献非常小,却会占用上下文窗口。

所以代码类的 token 冗余不是偶发现象,而是普遍现象。只要用户通过代码块把文件粘进 prompt,就值得在代理层做一次结构化清理。

1.3 AST 裁剪不是简单的删注释

最容易想到的做法是写正则删注释。比如用#.*$删除注释,用\n\s*\n压缩空行。但这种做法的致命问题是正则不理解语法。

看下面的 Python 代码。

text = """ # 这不是注释,这是一个字符串内容 # 它只是恰好以井号开头 """ url = "http://example.com/api#fragment"

如果直接用正则删除“以#开头的内容

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询