将代码置于显微镜下:面向LLM的小波上下文
摘要
WaveScope 是一个 MCP 服务器,它应用小波变换对代码库进行处理,为 LLM 提供多分辨率结构上下文,以改进代码理解和编辑,解决上下文退化与结构性感知问题。
暂无内容
查看缓存全文
缓存时间: 2026/06/02 17:33
# (iterate think thoughts): 把代码放在显微镜下:基于小波的 LLM 上下文
来源:https://yogthos.net/posts/2026-06-02-wavescope.html
每个尝试过 AI 编码工具的开发者都熟悉这样的问题:看着模型在代码库中摸索,寻找需要编辑的相关部分。由于不可能将整个代码库加载到大项目的上下文中,它会通过 grep 搜索几个文件来获取一些上下文,然后猜测接下来该做什么。但代码具有层次结构,包含层级和边界。函数位于类内部。类存在于文件中。文件组成模块。一个 400 行的文件可能包含六个不同的概念区域,每个区域都有其独特的用途。
当人类开发者阅读代码时,我们会利用结构来理解它。我们检查文件和类的组织方式,并基于此尝试找到相关的逻辑。如果代理也能像你一样,可以放大和缩小代码,从而看到全局,然后直接跳转到所需的精确函数,而无需打开整个文件,那岂不是很好?
这就是 **WaveScope** 所做的。它是一个 MCP 服务器,使用小波变换为 LLM 提供代码库的多分辨率视图。想象一下类似渐进式图像加载的东西,但用于源文件。尽管较新的模型理论上可以处理大上下文,但在实践中,它们会开始失去焦点。代理拥有的上下文越多,就越难弄清楚它实际需要做什么,以及优先处理什么,从而导致上下文腐烂。
目前,处理这个问题主要有两种方法。基于 grep 的搜索可以找到精确匹配,但忽略了结构,因为在单行上进行模式匹配无法告诉你类边界在哪里,或者错误处理区域从哪里开始。基于嵌入的 RAG 是另一种方法,它理解语义含义,但失去了位置和结构。这两种方法都不能让模型真正感知代码的架构。
### 代码有其节奏
打开任何语言的源文件,比如 Clojure、TypeScript、Rust 或 Go,你会看到整个代码中重复出现的常见结构。导入位于顶部。类和函数定义以规律的间隔出现。缩进在每种语言中也有其独特的模式。注释块和空行是中间的停顿。如果有某种方法可以提取这些模式,并创建类似于 AST 的结构,而无需实际了解语言的语法,那会怎样?
幸运的是,小波正是为处理这种信号而设计的,它可以同时将信号分解为多个尺度。变换可以同时提供所有精细细节和大尺度模式。这一系列算法非常通用,已在许多不同领域中使用。地震学家用它们来发现地震,医生用它们来锐化 MRI 扫描,音频工程师用它们来分离低音线和人声。事实证明,代码结构只是另一种可以用类似方式分解的信号。
那么,这实际上是如何工作的呢?一旦每行都有一个得分,文件就可以被视为一个一维信号,表示一系列数字,这些数字随着结构的密度而上升和下降。Ricker 小波是一个小模板,形状像一个凸起,两侧各有一个凹陷。你将它逐个位置滑过信号,并在每个位置测量信号与该形状的匹配程度。强匹配意味着一个高起区域位于两个较安静区域之间,这暗示了一个结构边界。输出是每行的系数,根据其看起来像边界的程度进行评分。
对不同分辨率进行编码的技巧在于模板的宽度。你可以将相同形状拉伸到多个宽度,每个宽度代表一个不同的尺度。窄小波仅在凸起区域只有一两行宽时匹配,因此它作用于小的、尖锐的特征。宽小波忽略行级噪声,并对相对于周围环境较高的较大区域做出响应,作用于大型结构。因此,下一个技巧是同时运行多个宽度,以查看在多个宽度范围内都亮起的边界,而不仅仅是一个宽度。跨不同尺度一致的特征往往是我们关心的真正结构边缘。
由于代码结构在不同大小上嵌套,每个大小都会出现在适合它的宽度上。我们可以通过在一个具体例子中运行 WaveScope 在其自身的 `src/context.ts` 上来看到这是如何工作的。单行,例如一个单独的 `import` 语句,或者 `export class FileContext {` 声明,在其较安静的邻居中脱颖而出,使其成为一个尖锐的单行尖峰,精细的窄小波会锁定它。它的系数在尺度 1 或 2 处达到峰值,并在更宽的尺度处消失。另一个极端是 `inferLabel` 方法内部的长关键词密集级联,它有一个长的连续运行,包含 `if (tokens.includes("class"))`、`interface`、`enum` 和 `struct` 分支。整个区域读作一个宽的平坦高原,其系数随着小波变宽而稳步上升,大约在尺度 16 处为 0.5,尺度 32 处为 1.0,尺度 64 处为 1.3,尺度 128 处约为 2.3,在那里达到峰值,成为整个文件中最强的结构响应。最大的结构产生最强的粗尺度信号,这正是在你缩小时首先希望浮现的点。
为这一切提供输入的行得分来自同一个过程。在我们的例子中,`export class FileContext {` 得分为 1.6,因为 `class` 关键字权重为 1.0,`export` 为 0.6;单行的 `get lineCount()` 访问器得分约为 0.58;其下的 `readonly` 字段声明每个得分约为 0.08;而该类周围的注释和空行得分平坦的 0.0。类声明在其自身主体之上高耸,主体在其周围的空白之上高耸,小波在每个宽度上读取这些相对高度。
上面的直觉是管道的前半部分,你将每一行评分为一维信号,然后在八个尺度上滑动 Ricker 小波,这些尺度分别为 1、2、4、8、16、32、64 和 128 行,从而在每个行和宽度上为我们提供系数。接下来,我们需要几个额外的步骤,将原始的系数数组转换成模型可以使用的形式。
首先是进行多尺度峰值检测,扫描数组中的局部最大值并按幅度排序。最强的边界代表诸如类开始或导入与代码之间的过渡等特征。由于一个真正的边界会在几个相邻尺度上出现,如我们上面所见,这些重复可以安全地合并为一个峰值,以避免用同一个点的多个副本淹没排序。
第二步是波段组装,将峰值分成三个宽泛的缩放波段。精细波段(尺度 1-2)显示查询中心附近一个紧密窗口中的原始源代码行。中等波段(尺度 4-16)跟踪函数和类签名及其周围的一些上下文。最后,粗尺度波段(尺度 32-128)将整个半径压缩成一个部分级摘要。
所有这些处理都由 MCP 服务器处理,模型只需查看带有波段和峰值位置的结构化 JSON,而无需担心任何小波数学。
### 模型实际得到的东西
假设一个代理调用 `query_wavelet_context`,该调用以一个 500 行 TypeScript 文件中的第 150 行为中心,该文件包含一些身份验证逻辑。在这种情况下,精细波段将包含正在检查的实际代码行。中等波段将提供第 0-400 行的摘要,由诸如顶部的导入和底部的测试助手等峰值引导。
模型通过关注精细波段来了解 `updateUser` 做什么,但它也从粗尺度波段了解身份验证上下文。它能够通过识别小波峰值中的类和函数边界来跳转到相关代码,而无需看到该文件的所有 500 行文本。
还有一个名为 `get_important_positions` 的实用程序,它操作整个项目。它遍历每个源文件,平滑小波峰值,并为代码中最重要的位置提供一个排序列表。
除了定位结构边界之外,服务器还可以使用一对熵分析工具来测量这些结构的复杂程度或不规则程度,这些工具由 Haar 离散小波变换和我在上一篇帖子(https://yogthos.net/posts/2026-05-24-libwce.html)中讨论的比特成本估计驱动。可以使用 `get_entropy_bands` 在每个尺度上量化 Ricker 系数,该函数计算它们的位平面计数,其中较高的成本表示在该分辨率下结构不规则性更大。还可以使用 `get_complexity_heatmap` 通过多个 Haar 级别分解原始的每行结构信号,将熵成本投影回每行不规则性得分。模型可以将这些得分用作一种纹理通道,以了解代码中棘手部分的位置。任何样板区域最终得分都会较低,因此可以安全地总结或跳过,而高熵区域可能包含密集的逻辑或不寻常的模式,需要格外注意。这些工具为模型提供了一种数据驱动的方式,可以在高层次上对代码进行分类,并且非常适合重构任务,模型可以轻松找到逻辑纠结的部分并将其分解。
小波的关键优势在于它们关注代码的整体结构,而这只能通过正则表达式等工具推断。值得一提的是,使用 AST 解析可以获得许多相同类型的分析,甚至更精确。然而,AST 工具需要为每种语言配备一个解析器,而小波完全不受所应用文本的语义影响。它们只是标记统计规律性,这正是它们成为如此广泛适用的工具的首要原因。
WaveScope 的方法在 grep 和全面 AST 分析之间取得了良好的平衡,因为变换适用于任何一维信号。语言感知来自一个简单的关键词权重层,而不是一个完整的解析器,每种语言只需要一个 10 行的配置来描述其核心语义。而且整个运行成本很低,能够在几毫秒内处理整个文件,生成层次化、多尺度的输出。这些尺度恰好是代码结构的自然表示,为 LLM 提供了一张导航地图。
由于小波可以同时定位所有级别的边缘位置,它可以轻松地定位甚至复杂的解析器可能难以检测的结构变化。例如,一长串 `if`/`else` 块在结构上看起来与具有许多短方法的类不同,而文档区域则显示为峰值之间的谷底。小波不需要知道这些东西实际是什么就能感知到它们在结构上是不同的。而这往往正是模型找出该做什么所需要的。
### 数据说话
为了说明这个概念,我针对 WaveScope 自己的 14 个文件代码库(包含不到五千行 TypeScript)运行了三个实际开发任务,以比较令牌成本与传统方法。这里的“传统”方法是指 LLM 编码代理实际所做的:grep 查找标志性元素,读取有针对性的代码块,并浏览文件头部以获取结构样式的样本。
一个常见任务是理解一个大文件的结构。因此,我让代理分析 854 行的 `index.ts`,以查看导入在哪里结束,找到工具注册聚集的位置,并识别启动代码。这些是典型任务,传统方法会 grep 查找导出标志和部分注释,然后读取导入块,找到一个注册示例,并识别启动尾部。这大约花费 2,000 个令牌,产生一个不完整的画面,这只是一个启发式方法。WaveScope 的粗尺度波段加上前 15 个重要位置,仅用 750 个令牌就给出了相同的结构概览,并带有部分级边界,而 grep 无法呈现这些边界,因为它只匹配行,而没有它们周围的结构上下文。
现在,让我们看看另一种类型的任务,我之前提到过,即我们希望找到需要重构的纠结代码。一种简单的方法是运行 `wc -l` 来找到最大的文件,然后浏览大块内容,寻找深层嵌套和高圈复杂度。这样的任务大约需要 5,200 个令牌来读取两个文件中的 600 行,而且你仍然会错过任何没有扫描的文件中的纠结代码。另一方面,WaveScope 的 `get_complexity_heatmap` 在你指向的每个文件中标记精确的每行不规则性得分。在三个最大的文件(`index.ts`、`wce.ts` 和 `context.ts`)上运行它仅需 436 个令牌。这减少了高达 92%,但还能精确定位热点:`handleDiffWaveletContext` 中的第 287 行得分为 0.92,`FileContext` 中的第 59 行得分为 0.92,等等。该分析在整个代码库中找到每个感兴趣的部分,生成一个需要仔细查看的位置排序列表。
另一个例子是识别哪些文件在架构上是核心的,哪些是外围的。传统方法对每个文件运行 `head -25` 来读取导入,最终所有 14 个文件大约花费 2,900 个令牌。结果,你了解了每个文件导入了什么,但并不知道哪些文件定义了项目的架构,模型将不得不在其最佳猜测的基础上花费更多令牌深入挖掘。WaveScope 的项目范围 `get_important_positions` 仅用 1,700 个令牌就返回了每个文件的结构密度排序,并带有有意义的排名。现在很明显,`signal.ts` 以每行最高关键词密度位居榜首。重量级算法文件是 `wce.ts`、`context.ts` 和 `index.ts`,它们的平均密度较低,因为它们的结构特征分布在数百行的实现中。其他文件,如 `haar.ts` 和 `file-cache.ts` 实用程序,最终排名较低。现在很清楚,要理解项目的概念骨架,需要首先阅读哪些文件。
在所有三个任务中,WaveScope 使用了显著更少的令牌,同时产生了有意义的答案,这些答案是结构性的而非文本性的,这正是我们所感兴趣的。结构为模型提供了对代码库内关系的理解,这是通过基于正则表达式的启发式方法根本不可能做到的。除此之外,一个 128K 令牌的窗口使用传统方法处理这三个任务会消耗其 8% 的容量,而 WaveScope 只需要 2%。而且,这个差距随着代码库大小按比例扩大,使得该工具在分析大型项目时特别有效。
还值得注意的是,通过信号提取、Ricker CWT(8 个尺度)、峰值检测和波段组装处理所有 14 个文件,平均每个文件只需 3 毫秒。而熵热图在此基础上每文件增加约 1 毫秒。在模型的推理时间背景下,这基本上是免费的。
希望上面的例子已经清楚地展示了使用结构峰值分析的价值,但我们还可以进一步利用已经生成的信息,通过熵编码器传递它,以查看这些区域实际上有多复杂。针对 `index.ts` 运行 `get_entropy_bands`,给出了每个小波尺度的比特成本估算分解,这是结构不规则性的间接度量。在这里,可以看到最精细的细节在尺度上花费 613 比特,而最粗糙的细节花费 322 比特,这表明精细结构区域比粗尺度结构更复杂……
相似文章
我构建了一个开源编码代理,让上下文可见且可编辑 — 你可以精确策划大语言模型所看到的内容
作者构建了 Nice Coding Agent,这是一个开源编码工作台,具有可见且可编辑的上下文堆栈,允许用户精确策划大语言模型所看到的内容。它具备本地优先检索、沙盒执行和混合代码搜索功能,旨在让开发者对上下文组装拥有控制和可见性。
我们使用 LLM 分析代码库中的每一个文件。所有人都认为这是出于成本考虑的一个愚蠢想法,但事实并非如此。
一项基准研究表明,使用 LLM 分析整个代码库具有成本效益。DeepSeek V4 Flash 因其低成本以及与 Claude Opus 等高端选项相当的准确率,被确定为最佳默认模型。
WaveFilter: 通过小波引导的KV缓存过滤增强扩散LLMs的长上下文能力
WaveFilter提出了一种无需训练的小波引导KV缓存过滤框架,用于扩散大语言模型,通过精确识别关键令牌并构建稀疏缓存来增强长上下文能力,从而提升复杂长上下文任务的性能。
使用上下文分析器优化LLM调用并减少Token使用
ContextSpy 是一款本地代理工具,用于分析 LLM 应用如何使用其上下文窗口,按类别细分 Token 使用情况,帮助开发者优化并降低成本。
zilliztech/claude-context
Zilliz 开源 Claude Context,一款为 Claude Code 等 AI 编程助手增加语义代码搜索的 MCP 插件,通过向量搜索低成本地把整个代码库变成深度上下文。