
我先把话说在前头这篇文章的主角是一款智能检测工具专门评估你的代码库在LLM上下文窗口里的适配程度。过去一年里越来越多团队开始把代码库直接丢给大模型做架构评审、代码解释、自动化测试甚至全量重构但几乎所有人都会卡在同一个问题上——上下文窗口就那么大代码还没传完窗口已经吃满了后面的分析结果要么答非所问要么干脆给你编一个根本不存在的接口。“上下文窗口”这个词可以理解成一次聊天里模型能同时“看到”的全部内容总量。你往里面塞的代码越多留给模型思考的余量就越少。窗口爆掉之后模型就像个被灌了一晚上噪音的人什么都记不住只能凭概率硬猜。问题的根源往往不在模型能力而在代码库本身没有被设计成“适合被 LLM 读取”的样子。这篇文章要讲的这个检测工具就是在做这样一件事扫描你的仓库量化它在上下文窗口中的占用情况给出可执行的优化方向。无论你是正在做 AI 辅助研发的基建同学还是只是偶尔把项目喂给 LLM 写文档这篇文章都值得看完。1. 为什么代码库需要“上下文适配度”体检1.1 上下文窗口不是一道简单的算术题很多人第一次接触上下文窗口会觉得结论很直观模型支持 128K 个 token那我把 100K token 的代码丢进去不还有 28K 的余量吗实际操作过几次之后你就会发现事情远没有那么美好。上下文窗口里装的东西从来不止是代码本身。系统提示词要占一块多轮对话历史要占一块你或者工具框架注入的检索结果要占一块连调用工具时返回的报错信息也会占一块。等到这些杂七杂八的东西全部到位真正能留给代码的位置可能只剩窗口的六成甚至更少。我见过一个 32K 窗口的场景最后留给业务代码的只有不到 12K token相当于你本来想带一周的行李结果发现行李箱只有原来三分之一大。还有个更隐蔽的问题上下文窗口在物理上只受模型上限约束但在真实推理链路中很多部署方案和 API 网关会额外限制单次请求的 payload 大小或者限制多轮对话的累计长度。也就是说你看到“128K”这个宣传数字实际使用中可能要打七折八折。所以“适配度”这件事本质上不是在问“代码库有多大”而是在问“当前这套会话结构里代码能不能被完整、高效地装进去”。这需要专门量化而不是靠感觉估算。1.2 代码库与普通文本的最大区别结构即信息如果把代码库当成普通文本来做 token 统计会得出非常粗糙的结论。比如一个 10 万字的 markdown 文档它读起来是线性的内容密度基本均匀但一个 10 万行代码的仓库内部差异极其悬殊。有些文件是核心业务逻辑每一行都值得模型逐字理解有些文件是自动生成的 DTO字段重复率可能超过 70%还有些文件是配置文件,充满了换行、注释和格式噪音真正对模型理解有帮助的信息非常稀薄。代码库的“结构”本身就是信息。目录之间的依赖关系、模块边界的清晰程度、函数之间的内聚和耦合这些都会直接影响模型读取时的理解成本。一个边界模糊、互相 import 得乱七八糟的仓库即便 token 总数没有超限模型在分析时也会反复在文件之间跳转把本应连贯的上下文切得七零八落。反过来一个结构良好、依赖清晰的项目哪怕整体 token 多了一点模型的推理质量也会明显更高。所以面向代码库的上下文适配度检测不能只算 token 总量还应该分析目录结构、文件粒度、重复度、依赖密度这些代码特有的维度。这是这类工具跟普通“字数统计器”的根本区别也是它存在的前提。1.3 工具到底在解决谁的问题我梳理了一下这个检测工具真正能帮到的人大致有三类。第一类是正在搭建 AI 辅助研发平台的工程师。他们需要把企业内部的私有代码库接入到 LLM 工作流里比如做代码问答、自动补全、Review 辅助。接入前如果不做适配度评估上线后就会出现各种“上下文不足”“分析质量忽高忽低”的线上事故。这个工具等于在接入前给代码库做一次体检提前把风险文件筛出来。第二类是负责大型存量项目的技术负责人。手里攥着几十万甚至上百万行的老系统想借助 LLM 做技术债梳理、模块重构建议但又不敢直接把整个仓库喂进去。用这份检测报告可以快速知道哪些目录值得优先切片、哪些文件应该拆小、哪些历史遗留代码根本不适合进入上下文。第三类是普通开发者。哪怕只是偶尔把项目丢给 LLM 写文档、做 Code Review一份适配度报告也能告诉你这个项目的 Token 杀手到底藏在哪个文件里。很多时候你只需要把几个大文件拆一下、把注释去掉同样的窗口就能塞进更多有价值的代码。一句话概括这个工具解决的不是“代码能不能被 LLM 看到”的问题而是“代码是否值得被看到、以及怎么看才能看得好”的问题。2. 检测工具的整体设计与指标拆解2.1 一条完整的检测管线先把这个工具的工作流程讲清楚。它是一条只读的检测管线不会修改仓库里任何文件也不会执行测试用例所有操作都是静态分析。整体分五个阶段第一阶段是仓库扫描。工具会递归读取目录结构识别出所有源码文件、配置文件和文档文件同时过滤掉.git目录、二进制文件、构建产物这类无关内容。第二阶段是语言识别。根据文件后缀和文件头特征判断每个文件属于哪种语言。目前主流语言都覆盖了Java、Python、JavaScript/TypeScript、Go、Rust、C/C、C#外加常见的 JSON、YAML、Markdown、SQL 等辅助类型。第三阶段是 Token 估算。对每个文件执行分词统计这一步不是简单按字符数算而是模拟目标 LLM 的分词逻辑我后面会专门展开。第四阶段是结构分析。构建一份轻量级的仓库结构模型包括目录树、文件大小、函数/类级别的代码块边界以及文件之间的 import 依赖关系。基于这些信息计算冗余密度、依赖覆盖度、模块独立度等指标。第五阶段是评分与报告生成。把所有指标汇总产出一份包含适配度评分、风险文件清单、优化建议的报告。整个管线设计成只读模式是我刻意坚持的一点。很关键的原因是如果检测工具默认具备改写能力用户就会依赖它自动优化代码但代码改造涉及业务语义判断机器没法也不应该替人做决定。工具的价值在于把事实和风险摆到台面上具体怎么改还是开发者自己拍板。2.2 四个核心指标的设计逻辑这个工具的核心输出不是单一分数而是一组互相关联的指标。我挑了四个最关键的逐个说明它们的意义和计算思路。第一个是上下文占用率Context Occupancy衡量的是“如果把这个仓库完整塞进一个指定大小的上下文窗口会占用多少比例”。计算公式很简单文件 token 总和除以目标窗口 token 上限。但这个指标的价值在于它可以反过来推算“实际可用余量”。比如一个仓库整体占用 80K token你打算用 128K 窗口理论占用率是 62.5%再扣掉系统提示和对话历史的开销真实余量已经很小了。这个指标不需要非常精确它的目的是给出一个“危险程度”的直觉判断。第二个是冗余密度Redundancy Density。代码库里最常见的冗余是重复的 import、重复的字段定义、大量重复的日志格式、以及意义不大的模板注释。工具会按文件识别近似重复的代码块计算重复部分占文件总 token 的比例。这个指标越高说明这个文件“注水”越严重删掉冗余后能节省的上下文空间也越可观。第三个是依赖覆盖度Dependency Coverage衡量的是“要理解这个文件模型需要额外读取多少个被依赖文件”。如果一个核心模块 import 了 30 个其他文件而这些被依赖文件本身又层层嵌套那么即便这个文件本身只有 2K token模型想真正理解它可能还要再读额外的 20K token。依赖覆盖度就是用一种递归方式估算这种隐性读取成本。它高的时候说明这个模块的上下文代价远超文件字面大小。第四个是模块独立度Module Independence本质上是对依赖覆盖度的反向观察。如果一个目录下的文件之间耦合很少每个模块都能独立读取并理解那么上下文可以被灵活切片按需加载。反之如果目录内部文件互相 import 成一张密网那就很难独立切片只能把整个目录打包读取。模块独立度低是很多大项目在接入 LLM 时“拆不动”的根本原因。这四个指标搭配使用才能避免单看一个数字带来的误判。占用率高但冗余度也高说明有优化空间占用率不高但依赖覆盖度极高说明这个仓库“隐性上下文成本”惊人需要做模块解耦。2.3 为什么不需要调用 LLM 也能得出可靠结论这个设计我特别想解释一下因为很多人在听到“用 LLM 检测代码”的时候第一反应是为什么不直接让大模型自己来判断原因有三个方面。第一是成本问题。如果把整个仓库丢给 LLM 让它分析一次扫描的 token 消耗就是一个天文数字还要做几轮推理才能给出建议。而静态分析的 Token 估算成本极低本地几秒钟就能跑完省下来的预算可以花在实际的开发辅助上。第二是稳定性和可重复性。LLM 的输出有随机性同一个仓库跑两次结果可能不一样这会让“检测报告”失去可信度。静态规则是确定性的同样的输入永远得到同样的输出适合作为度量基准。我见过不少团队用 LLM 做代码度量最终都因为结果不可复现而放弃。度量工具需要的是稳定不是聪明。第三是可解释性。LLM 给出的判断很多时候说不清“为什么是这个结论”。而静态分析可以精确指出某文件有多少 token、某块重复代码位于第几行、某个模块依赖了多少外部文件。这些证据链条清晰开发者拿到报告后可以直接核对和信任。在专业工具链里可解释性往往是比智能程度更重要的属性。用生活类比来说它更像体脂秤而不是健身教练——体脂秤只负责给你准确的数据怎么练是教练的事。3. 核心检测逻辑从 Token 统计到结构打分3.1 Token 占用计算别拿字符数糊弄人Token 是 LLM 处理文本的最小单位它和字符数是完全不同的概念。英文文本里平均一个 token 大约对应 4 个字符但中文平均大概 1 到 1.5 个字符就是 1 个 token。代码混合了英文关键词、变量名、中英文注释和各种符号情况更加复杂如果直接用字符数除以 4 来估算 token 数误差可能达到 30% 以上会完全误导后续优化判断。这个工具的做法是集成目标模型的分词器或者使用与目标模型同系列的分词算法。对于开源模型可以直接复用其 tokenizer 文件对于闭源 API网上也能找到第三方实现的分词器近似版本。但在兼容离线环境、快速扫描大仓库时直接跑完整分词器可能太慢。我引入了一个两级策略对于超过 10KB 的大文件用完整分词器精确统计对于大量小文件先用启发式规则快速估算再抽样校验把误差控制在 5% 以内。这里有个细节不同模型的分词结果并不一致。同一段代码模型 A 可能切成 1000 token模型 B 切出来是 1100 token。所以报告里会标明“预估基于哪个分词器”的假设前提并且支持通过配置切换。如果没有明确指定模型工具默认使用一套通用的混合分词规则保证数字具有横向可比性。注意不要试图用一个固定的 token/字符比例来推算所有文件的成本。我踩过坑的结果是配置文件里大量缩进和括号的 token 占比远高于注释DTO 类里的字段名又往往比业务代码更容易切分。只有真正按分词逻辑走一遍才能拿到可信的占用数据。3.2 重复冗余识别与结构切分冗余识别做起来比想象中费劲。第一道关卡是“去除干扰后识别重复”。代码里的缩进、空格、空行都会影响文本相似度判断所以工具会先做归一化处理去掉缩进差异、统一引号风格、剥离注释后再计算相似度。这样能识别出语义上重复、只是格式略有差异的代码片段。典型的目标是重复的 DTO 类、重复的请求参数校验块、以及被复制粘贴到多个 Controller 里的业务工具方法。第二道关卡是“函数/类级别切分”。为了让报告真正落到可执行层面工具会用轻量级语法树来切分文件里的函数和类边界。对 Java、Python、TypeScript 这类常见语言这一步很成熟对没有正式语法树的语言会根据代码缩进和花括号做近似切分。切分的价值在于报告可以精确指出“这个文件里面最大的 3 个函数占了总体积的 70%”帮助开发者快速定位问题而不是笼统地建议“这个文件太大要拆”。第三道关卡是“重复跨文件识别”。很多冗余是跨文件的比如多个模块各自声明了相似的工具函数。工具会基于归一化后的代码特征建立索引寻找跨文件的近似重复片段。这部分数据可以为“合并工具类”“提炼公共模块”这类重构建议提供依据。3.3 报告输出让优化建议落到文件名上报告的输出格式我倾向于分成三个层次从总览到具体逐级加深。第一层是总览指标卡片给出适配度总分、上下文占用率、冗余密度、依赖覆盖度和模块独立度这五个综合数字以及一个直观的红黄绿状态标记。适配度总分采用百分制60 分以下说明这个仓库直接接入 LLM 风险很高60 到 80 分说明需要针对性优化80 分以上说明可以基本放心使用。第二层是风险文件清单按照“优化优先级”排序。优先级综合了文件 token 占用量、冗余密度和依赖覆盖度。每个文件旁边会标注具体数据比如“1.2K 重复 token”“依赖 14 个外部文件”这类明细。第三层是结构化优化建议会直接给出可以执行的动作。例如“将OrderService.java中的方法validateAddress拆出可减少约 800 token”“删除UserDTO.java中重复的 5 个字段定义可减少约 300 token”“建议将docs/architecture/目录移出代码仓库上下文单独维护知识库”。这些建议不是泛泛而谈而是每条都对应具体文件、具体位置、可估算的收益。为了让建议不误导人工具会同时标注置信度。比如检测出疑似重复代码块时会说明“相似度 0.92建议人工确认是否真正冗余”。这样既抓住绝大多数问题也保留了人对业务语义的最终判断权。4. 实操记录一个真实项目的体检与改造4.1 环境准备与接入方式这个工具是以命令行方式提供的我把使用过程完整记录一遍。首先确保本地装了 Python 3.9 以上版本因为核心解析器依赖较新的标准库。安装依赖后工具就绪。接入方式很直接针对一个本地 Git 仓库只需要指定仓库路径和目标窗口大小。下面是我实际用过的一条命令。llm-context-check --repo ./demo-project --window 128k --language java --output report.html参数含义我逐个解释一下--repo指向待检测的仓库根目录--window指定预估的目标上下文窗口规格可以是8k、32k、128k、200k几种常见档位--language会在仓库内语言识别失败时作为兜底规则--output指定报告输出路径支持 HTML 和 Markdown 两种格式。工具第一次运行时会先分析仓库规模并估算扫描时长。我建议遇到非常大的仓库超过 200MB时用--exclude参数先排除node_modules、vendor、target、dist这类依赖和构建目录否则扫描时间会主要浪费在无关文件上。这一点看起来不起眼但对使用体验影响极大。4.2 一次完整检测过程与中间输出我用一个真实的中型 Spring Boot 项目做了一次完整检测。这个项目有大约 180 个 Java 文件外加一批 XML 配置、YAML 文件和 Markdown 文档源码总字符数约 2.3MB。命令执行期间控制台会实时输出每个阶段的进度包括扫描文件数、识别出的语言分布、token 总量估算进度。最终生成的报告中我最关心的是“风险文件清单”那张表。为了让你直观了解报告长什么样我按记忆整理了几个关键条目。文件路径Token 数冗余占比依赖文件数建议src/main/java/com/example/service/OrderService.java683018%23拆分支付与物流逻辑src/main/java/com/example/dto/OrderDTO.java412043%5合并重复字段src/main/java/com/example/util/ExcelHelper.java392031%11清除复制粘贴的样式代码src/main/resources/application-prod.yaml18509%0建议单独管理配置这张表给我最直观的感受是真正的代价藏在那些“体积看起来没那么大”的文件里。OrderDTO.java的 token 数量排第三但冗余占比高达 43%意味着其中将近一半的 token 都是重复字段。而OrderService.java虽然 token 最多真正的风险其实在于它依赖了 23 个外部文件导致模型想要理解它必须连带读取很多额外代码。报告里“依赖覆盖度”这项指标把隐性成本量化了出来。实测下来工具判定整个项目完整读取所需的“实际上下文成本”比文件 token 总和高出约 63%这个差距主要来自文件间的依赖链。4.3 根据报告改造后的前后对比拿到报告之后我就按建议做了一轮针对性改造。首先把OrderService.java中支付和物流处理拆成两个独立的 Service让主文件依赖数量从 23 降到 9。其次清理了OrderDTO.java里 5 个重复字段统一收敛到公共基类里。然后删掉了ExcelHelper.java里一大段从旧项目复制过来的样式设置代码。最后把application-prod.yaml里几十行被注释掉的配置块清理掉只保留有效内容。改造完成之后再次运行检测结果对比很有意思。文件 token 总量从约 48K 降到 36K降幅 25%上下文占用率明显下降。更关键的是依赖覆盖度从 1.63 降到 1.18说明模型读取核心业务文件时需要连带读取的额外代码大幅减少。适配度总分从 58 分涨到 79 分状态从“高风险”变成“基本可用”。这个对比至少验证了一件事很多项目接入 LLM 卡壳问题不在于模型不行而在于代码库本身有太多“吃掉上下文空间”的规模。做一次十几分钟的检测与定向清理能产生的效果立竿见影。提示改造过程中有个原则值得坚持——纯粹为了适配上下文而大改业务代码是不可取的。检测报告的作用是帮你识别出“低信息价值、高上下文成本”的区域真正有业务价值的核心逻辑不要为了省 token 而过度删减。优化的优先级永远应该是先清理冗余再适度拆分最后才考虑裁剪实际功能。5. 常见问题与排查技巧实录5.1 Token 统计与实际调用不一致怎么办这是很多人报告的第一个坑。工具给出的 token 总量跟实际调用 API 时 prompt 里统计的量对不上有时差得还挺多。原因主要有两个。第一是分词器版本不一致工具默认估算用的分词规则跟目标 API 线上最新的 tokenizer 可能有细微差别。第二是上下文中额外的格式开销比如把代码以 JSON、Markdown 代码块或某种结构化格式传给模型时会附加一层格式 token这部分在静态检测阶段不会体现。我的解决办法是不要追求 token 总数完全一致而是关注相对量级和变化趋势。如果工具估算出某个文件占用了 6800 token实际 API 统计可能是 7200 多这个误差不影响定位问题文件。真正需要担心的不是单个文件的误差而是整体占用率是否已经逼近窗口上限。另外在接入特定模型之前可以先拿几个样本文件做一次真实调用微调工具里的“格式附加系数”把误差控制在 10% 以内。5.2 生成代码、第三方 SDK 与二进制文件怎么处理大型项目里必然存在一些不适合分析的文件node_modules里的依赖包、target目录下的编译产物、dist下的打包结果还有一些自动生成的协议文件、DTO 代码。如果不加区分地全部纳入检测报告会被这些噪音淹没真正的自研代码反而看不清。这个工具提供了文件分类策略。默认会把以下内容标记为“自动过滤”或“低优先级”位于.gitignore中的路径、常见构建产物目录、超过 5MB 的文件、非文本二进制文件。自动生成的代码如果无法自动识别可以通过--ignore参数手动指定规则。我还保留了一个经验法则检测报告里应该分成两栏一栏是“自研代码适配度”另一栏是“全部文件适配度”。如果只有全量统计而没有自研代码统计你很容易把第三方依赖带来的成本误判成自己的技术债导致优化方向完全跑偏。5.3 多语言混杂仓库的评分偏差不是所有仓库都像 Java 项目那样语言单一。现在很多系统是前后端一体仓库既有src/main/java的 Java 代码又有src/web的 TypeScript 代码还有config目录里的 Lua、Python 脚本甚至还有 SQL 初始化文件。不同语言的 token 密度差异很大直接混在一起统计会让评分产生偏差。Java 代码因为大量强类型声明、显式结构token 占用往往偏高TypeScript 相对紧凑而 SQL 和 YAML 这类声明式语言token 密度又各有不同。处理策略是报告按语言分组统计适配度总分再以“各语言的自研代码 token 占比”为权重做加权汇总。这样至少能分清“Java 部分风险高”和“整个仓库风险高”的区别避免把所有收益和问题搅在一起。如果你在检测时发现某个文件总是被错误识别语言比如.ts文件被当成 JavaScript可以通过配置后缀映射来修正。5.4 误报容忍度与自定义规则任何静态检测工具都会有误报这个工具也不例外。特别是重复代码识别两个函数可能只是长得像但实际语义完全不同。我的经验是不要为了消除误报而把相似度阈值调得过于苛刻否则会漏掉真正的冗余。对于检测到的疑似重复块工具默认标为“建议人工确认”同时支持通过配置文件把已确认的重复块加入白名单。自定义规则这块值得多说一句。不同团队的代码规范不同有些团队的“冗余”标准本身就不一样。工具允许在配置文件中自定义术语规则。比如你所在团队规定 Controller 层类名统一以Controller结尾那么报告中可以增加一条规则把某个不符合命名的类标记为风格风险。这样工具就不只是一个通用检测器还会慢慢沉淀成一个符合团队规范的上下文适配度门禁。最后再分享一个我个人的使用习惯这个工具不应该只在项目上线前跑一次而应该纳入日常质量门禁。我目前的做法是在 CI 流程里加一个检测步骤每次合并到主干前自动评估上下文适配度如果分数低于基线就触发提醒。这样做的好处是团队不会等到技术债积累到影响大模型使用的那一天才突然发现自己被上下文窗口卡得动弹不得。因为在真实业务里代码库的演化是持续性的适配度也应当是一个持续跟踪的数据而不是一次性的体检报告。