# AST 符号解析 — Code Intelligence 设计 > 日期:2026-06-24 | 状态:✅ Phase1 已落地(2026-06-28 核验:read_symbol 工具已注册 tool_registry.rs:1506-1547 + 基线测试守护) > 关联:memory [[devflow-info-density-concept]] / [[devflow-aichat-session-analysis-2026-06-22]] / plan gentle-gliding-book ## Context(为什么) **起因**:实测会话 e46f5605「DevFlow上下文管理不足分」——LLM `read_file` 读 8 个源码文件(context.rs/anthropic_compat/intent.rs/prompt.rs/compress 等)各 500 行**全文回灌**,prompt 累积 **360K token 超 glm-5.2 上下文上限** → LLM 失败 → 末尾 tool 后无 assistant(卡)。8dfe0b94 更滚到 5M token 爆炸。 **已否决的治标方向**: - ❌ read_file 限制行数(500→150):"等于没读",LLM 被迫 offset 翻页,更多轮次 + 仍累积 - ❌ read_file content 字节截断(8KB):"不讲武德",LLM 要全文被砍 **正路**:AST 语义解析,精准提取**调用链 + 函数代码**,替代物理读全文。 **双目标**(用户明确): 1. 精准获取调用链 + 函数代码,避免物理读文件的 LLM 上下文成本 2. AST 树作后期 ai coding 编码支撑工具(符号检索/依赖图/生成上下文/向量编码) **根本目标(2026-06-24 深化)**:提高上下文**信息密度**——使进 prompt 的每一行与**当前关注主题**紧密结合,去噪、去多余。这是所有读取/压缩设计的判据。 ## 核心原则:信息密度 ≠ 压缩(2026-06-24) **密度 = 只给与当前任务相关的内容;压缩 = 无差别减体积。两者不同。** 压缩减了体积,密度不一定升——减什么是预设规则或盲猜,和"当前任务关注什么"无关。 **分水岭:压缩器带不带当前任务上下文。** - 不带 → 通用摘要(治标,可能砍掉恰是任务关键的细节) - 带(任务焦点 focus)→ 相关性提炼(治本,留相关去无关) **被否的治标方向**: - ❌ 物理行数截断上限(500→150→3):武断,任何值都不合理(3 行砍废、3 万行等于没设);且按行返本身错——该按**语义结构层级**返 - ❌ 算法裁剪(砍注释/doc/空行):格式去噪,留下的不一定和任务相关,密度提升有限 - ❌ 通用 LLM 摘要(不带 focus):压出"这个函数做什么"的通用摘要,可能丢任务关键行 **正路(本设计采纳)**: 1. **结构层级供给**(拉模式/Progressive Disclosure):read_symbol 默认返骨架 → LLM 看骨架下钻局部 → 精准取。进 prompt 的都是 LLM 主动要的,天然相关。 2. **主题驱动压缩**(带 focus):大块必须给时,压缩 LLM 接收当前任务焦点,做相关性提炼(非通用摘要)。 → 不按物理行返,按**语义层级**返;压缩必须**带任务上下文**。 ## 一、技术定位:AST vs LSP(两个不同层面) | | AST(tree-sitter) | LSP(rust-analyzer) | |---|---|---| | 本质 | 数据结构(语法树,解析产物) | 通信协议(语义服务,JSON-RPC) | | 层面 | 语法层 | 语义层 | | 提供什么 | 符号结构/调用语法 | 类型/精准引用/重构/诊断 | | 形态 | 库(链接进进程) | 独立服务器(子进程) | | 成本 | 轻(ms/MB) | 重(二进制 30-50MB/平台 + 索引 + 内存) | 抽象层级:源码 → [tree-sitter] → AST(语法,Phase1-3 停此) → [类型推断] → 语义 → [LSP 协议] → 客户端。**LSP 依赖 AST**(rust-analyzer 内部也用),但停在更深(语义层)。 ## 二、目标论证(能力边界,不夸大) ### 目标1:调用链 + 函数代码 | 能力 | tree-sitter | Phase | |---|---|---| | 函数结构(骨架·默认) | ✅ `function_definition` → 签名+分支结构+调用图+行数(极小,高密度) | 1 | | 函数代码(定义体) | ✅ `full=true` / `drill` 取完整或局部(语法边界 100% 准) | 1 | | 同文件调用点 | ✅ `call_expression` 命中符号 → 调用位置 | 2 | | 跨文件调用链 | ✅ 符号索引 + import 解析 | 3 | | **动态调度**(`dyn Trait`/虚函数) | ❌ 静态解析不能(需类型推断,LSP 级) | 局限 | | 回调/闭包/函数指针/宏 | ❌ 需数据流/编译器 | 局限 | **覆盖度**:静态直接调用占实际 ~70-80%(绝大多数业务代码);动态/间接/宏 ~20-30% 需 LSP。 **避免上下文成本**:`read_symbol(compress)` → 函数体几十行 + 静态调用点,非 `read_file` 全文 500 行 → prompt 降一个量级。对 e46f5605 类(读源码理解实现,静态为主)直接见效。 ### 目标2:ai coding 编码支撑 AST 是语法层(parse tree)。**语法层能**: - 符号级上下文(LLM 编码拿相关函数定义+调用关系,非全文 chunk) - 结构化检索(符号/调用链/依赖,替代文本 grep) - 变更影响分析(改函数 X → 影响哪些调用方,精准 review/测试范围) - 代码生成约束(签名/调用语法) **语义层不能**(需 LSP/编译器):类型检查/推断、安全跨文件重构、数据流/借用分析。 → AST 够 aichat 的"精准读代码 + 调用链 + 上下文 + 影响分析"(95% 读代码场景);深层语义是 LSP 的事。 ## 三、方案:tree-sitter + read_symbol ### 选型:tree-sitter - GitHub 出品,增量 AST 解析,几十种语言 grammar - Rust 生态 `tree-sitter` + 各语言 grammar crate(编译期静态链接) - 增量解析:文件改只重解变更(<1ms) ### grammar 策略(2026-06-24 定稿) **静态编译 + 集中 lookup**(架构成本最低,详见 [插件机制设计](插件机制-设计-2026-06-24.md)): - **不做**动态加载(grammar 编共享库运行期 dlopen)、**不抽** trait(YAGNI,无第二实现不抽象) - grammar 编译期静态链接进二进制(无 ABI 坑 / 无运行时状态 / 无分发负担) - grammar 获取集中到一个普通函数 `grammar_for(ext) -> Language`(未来加动态只改这一点,不返工调用方) **Phase1 范围**(覆盖 devflow 源码 + 主流用户项目): | 文件类型 | grammar | 备注 | |---|---|---| | `.rs` | tree-sitter-rust | 后端主体 | | `.ts`/`.tsx` | tree-sitter-typescript | 前端 script | | `.js`/`.jsx` | tree-sitter-javascript | | | `.vue` | **借 tree-sitter-typescript** | 切 `