别让 agent 用 grep 猜符号:给 Claude Code 装上语言服务器
让 agent 做一次跨包重构,最贵的部分往往不是写代码,而是确认符号在哪里。[unverified] Claude Code 的内置搜索是文本层的:内容搜索走正则,文件搜索走文件名模式,于是”这个函数还有谁在调用”就退化成一串 grep 加好几次文件读取。[3] 语言服务器把这一层换成编译器级的符号查询,编辑之后直接给诊断,找定义和引用走 LSP 工具。[1]
换掉的是两件很具体的事#
装上 code intelligence 插件之后,Claude 拿到的是编辑器里那套能力。每次它编辑或写入该服务器处理的文件,都会收到服务器报出的错误和警告,不必先跑一次编译就能看见自己引入的类型错误、缺失导入或语法错误;符号查询则通过一个只读的 LSP 工具完成,不再靠文本匹配。[1] 官方文档把 LSP 工具的行为明确标成 read-only。[1]
成本结构对 agent 也友好。能力对照表把 code intelligence 的加载时机写成”文件编辑后和按需”,成本标为低,并注明它能减少别处的文件读取。[2] 也就是说它不像 MCP server 那样长期占着上下文,而是按需换取更少的读文件次数。[2]
两个边界先记住。云会话里 Claude Code 不会启动插件的语言服务器,那边既没有诊断也没有符号导航。[1] 另外 LSP 只覆盖服务器注册过的扩展名,没有服务器的文件类型会直接返回错误。[7]
快速上手:三步接入 TypeScript#
第一步装二进制。官方给的命令是 npm install -g typescript-language-server typescript,装完确认它在启动 claude 的那个 shell 的 PATH 上。[1]
npm install -g typescript-language-server typescript
which typescript-language-server
第二步在会话里装插件。插件本身不含语言服务器,它只负责告诉 Claude Code 用哪个命令启动、接管哪些扩展名。[1]
/plugin install typescript-lsp@claude-plugins-official
第三步验证服务器真的起来了。让 Claude 故意在一个文件里引入类型错误再修掉,看编辑下方有没有出现诊断行;没有就打开 /plugin 的 Errors 标签,看到 Executable not found in $PATH 就把缺的二进制补上。[1] 想让仓库里所有人都默认带上,把插件写进项目设置的 enabledPlugins,比让每个人各装一遍稳。[4]
官方市场里现成的插件覆盖 C/C++、C#、Go、Java、Kotlin、Lua、PHP、Python、Ruby、Rust、Swift 和 TypeScript/JavaScript,Python 用 pyright-lsp,Rust 用 rust-analyzer-lsp,除 Shopify 维护的 liquid-lsp 外都由 Anthropic 维护。[1]
装好不等于会用#
这里才是多数人卡住的地方。有人装完 LSP 之后翻了自己的会话库做统计:四天里 LSP 被调用 12 次,同期 Grep 539 次、Glob 531 次,占比 1.1%。[7] 原因不复杂,他原先在 CLAUDE.md 里只写了一句”优先用 LSP”,而系统提示本身就在引导模型用 Grep 搜内容、Glob 搜文件名,那句叮嘱压不过它。[7]
他后来改成写清分工:找符号的定义或引用用 LSP,找文件和搜字面文本用 Grep/Glob;先用搜索定位文件,再用 LSP 在文件内导航,不要整份读进来。[7] 这个思路和官方那篇大仓库配置一致,官方把 code intelligence 放进”减少 Claude 要读的内容”一节,和 Read 拒绝规则并列。[4]
还有一条容易被漏掉的指令:信任语言服务器的结果,不要为了确认再打开一遍文件。[6] CircleCI 的基准测试专门点了这一条,因为不信任的模型会在 findReferences 之后把每个文件重读一遍,反而比 grep 更贵。
他们往 CLAUDE.md 里加了这句话后再跑三个导航任务,Opus 的工具输出 token 从 18,673 降到 12,916,降了 31%,成本降 3%,耗时多 2%;换到 Sonnet,LSP 在耗时、成本、token 三项都更好,分别是 -34%、-14%、-33%,而且是唯一没有漏掉引用的配置。[6] 他们的结论很直接:模型越弱,语言服务器越像一条可靠性地板。[6] 判断自己在哪个位置也别凭感觉,把会话记录里各个工具的调用次数拉出来,看 LSP、Grep、Glob 三者的比例,再决定是继续调 CLAUDE.md 的措辞,还是承认这个仓库暂时用不上。[7]
账单和缺口#
语言服务器不是免费的。它要把项目的符号图放进内存,大工作区上的 rust-analyzer 常见占用好几 GB;冷启动要先索引,大型 monorepo 的首次查询可能很慢甚至返回空;每种语言都要有自己的二进制,而服务器按项目根识别,工作区在仓库根下一层时可能根本不激活;长时间会话在切分支或重新生成代码之后还会变旧,需要重启。[6] monorepo 里 import 被判成未解析的假诊断,官方排错文档也单独列了一条。[1]
没有官方插件的语言可以自己补。插件根目录放一个 .lsp.json,或者把 lspServers 直接写进 plugin.json,列清楚启动命令和扩展名映射就行,command 必须在 PATH 上;启动慢和崩溃这两种情况分别由 startupTimeout、restartOnCrash、maxRestarts 兜住。[5]
顺带一个容易被当成 bug 的细节:如果二进制已经在 PATH 上但插件没装,Claude Code 会在你编辑对应文件之后弹一次 LSP 插件推荐对话框,一次会话最多弹一次,30 秒不选算忽略,累计忽略五次就不再问了;想重新打开,得去 ~/.claude.json 里删掉 lspRecommendationDisabled 和 lspRecommendationIgnoredCount 两个键。[1]
它也不是 CI 的替代品。语言服务器做的是让明显的错误在最便宜的时候暴露,完整的类型检查和测试仍然要留在 CI 里。[6] 至于找一处 TODO 注释或者某个配置字符串,字面文本搜索仍然是 grep 的活。[6]
Sources#
[1] https://code.claude.com/docs/en/plugins/code-intelligence — Code intelligence plugins (Claude Code docs) [2] https://code.claude.com/docs/en/features-overview — Extend Claude Code (Claude Code docs) [3] https://code.claude.com/docs/en/how-claude-code-works — How Claude Code works (Claude Code docs) [4] https://code.claude.com/docs/en/large-codebases — Set up Claude Code in a monorepo or large codebase [5] https://code.claude.com/docs/en/plugins-reference — Plugins reference: LSP servers (Claude Code docs) [6] https://circleci.com/blog/claude-code-lsp — Why you should use Language Server Protocol (LSP) with Claude Code [7] https://scottspence.com/posts/enable-lsp-in-claude-code — Enable LSP in Claude Code