Grep 比 LSP 更强?为什么编程代理会忽略你那些花哨的工具
Grep beats LSP? Why coding agents ignore your fancier tools

原始链接: https://www.agentconnect.md/blog/grep-beat-lsp-harness/

这项研究挑战了一个假设:更精确的工具(如基于 LSP 的语义导航)并不总是能提升编程智能体的表现。通过对比语义导航与标准词法搜索(grep),研究发现智能体往往更倾向于使用 grep,尽管其精确度较低。 核心结论包括: * **“工具链”至关重要:** 智能体的表现由模型及其执行环境(即“工具链”)共同决定。如果工具的输出格式或交互模式不直观,或需要额外步骤(例如只返回文件路径而非内联代码上下文),智能体可能难以有效利用。 * **上下文为王:** 仅提供精确位置的效果不如提供周围源代码。在语义搜索结果中额外增加几行上下文,显著减少了后续的文件读取次数,并提高了任务成功率。 * **任务导向的选择:** 智能体能够为任务选择合适的工具。它们在处理复杂的引用追踪时使用语义导航,但在需要更新注释或字符串的全文本编辑场景中,则更倾向于使用 grep。 最终,开发者应在完整的智能体工作循环中评估新工具,而不应仅仅关注精确度,以确保其能自然地融入智能体现有的工作流中。

这篇 Hacker News 的讨论探讨了为何 AI 编程代理(AI coding agents)往往偏好 `grep` 等简单工具,而非复杂的语言服务器协议(LSP)。 参与者认为,代理倾向于使用 `grep` 是因为它具有通用性,且无需像 LSP 那样进行复杂且脆弱的配置。尽管一些用户发现代理有时会过度简化任务或在 LSP 设置上遇到困难,但另一些用户指出,当 LSP 环境配置错误或无法访问时,`grep` 是可靠的备选方案。 讨论强调了几个核心主题: * **工作流演进**:用户通过观察 AI 代理解决问题时的搜索模式,正在学习使用 `fzf` 或 `ripgrep` 等高效的命令行工具。 * **配置疲劳**:许多开发者现在专门利用大语言模型(LLM)来卸载 LSP 和编辑器配置带来的“维护地狱”,尽管有人认为代理往往会过度设计这些解决方案。 * **训练偏差**:评论者推测,代理偏爱 `grep` 是因为它比 LSP 更易于训练,而后者往往被锁定在专有的 IDE 接口之后。 归根结底,尽管 LSP 能提供更深层的代码理解,但 Unix 风格文本工具的简洁性和鲁棒性,依然是当前 AI 代理“阻力最小的路径”。
相关文章

原文

Why would a coding agent ignore a retrieval interface that returns more precise results?

I explored this question in a small study comparing lexical search with grep against LSP-backed semantic navigation. I expected semantic navigation to reduce noise and save tokens. Instead, agents often stayed with grep. When I forced them to use the semantic path first, task success sometimes fell.

This is a question of LLM-friendliness. A tool is not friendly to a model merely because its results are precise. It must return enough context for the next step and present that context in an interface and output shape the model can use directly. Familiarity may also matter: the model may have learned similar action paths during training. The interface properties can be evaluated directly. Training support is a hypothesis consistent with these results, not something this study proves.

The result is not a general argument against LSP. The protocol includes capabilities far beyond code navigation, and this study tested only a small subset. Instead, the results point to a broader engineering problem: a model does not use tools in isolation. It uses them through a harness that defines the available actions, their names, their inputs, and the context returned to the model.

In this post, I describe how code retrieval affected both code-finding and editing tasks, why grep had an advantage in some conditions, and what this means for agent platforms.

Agent capability equals model times native harness
A model and its familiar tool loop act as one capability surface.

Comparing two code retrieval interfaces

I compared two ways for an agent to retrieve code context. grep performs lexical search: it finds matching text. The tested LSP-backed tools perform semantic navigation through references, definitions, and document symbols, allowing them to distinguish a real function call from the same word in a comment.

The pilot covered three Claude models, several Python and TypeScript repositories, and multiple task types. I measured token use only when both approaches completed the task successfully. This controls for a common evaluation error: a failed run can appear efficient simply because it stopped early.

On simple code-location tasks, all three models chose the semantic tool only 0% to 6% of the time when both tools were available. Forcing a semantic-first path reduced success from 100% to 89% in that arm.

Reference-completeness tasks produced a different result. When asked to find every caller, the models chose semantic navigation 45% to 57% of the time. The LSP-backed path reached 1.00 precision, compared with 0.76 for grep, by removing false matches. However, recall stayed near 0.66 in both arms. Semantic navigation did not find more true calls. The remaining limit came from how thoroughly the agent worked, not from retrieval precision. For the stronger models, the precision gain also came with higher token use rather than a saving.

The model doesn't blindly prefer grep — it routes by task

Share of semantic (LSP) tool calls when both grep and LSP are available and the agent chooses freely.

Legend: Opus 4.8 (blue), Sonnet 4.6 (magenta), Haiku 4.5 (green).

Semantic tool use by task: near zero on localization and rename, but 45% to 57% on reference-completeness
Same models, same free choice — the routing flips with the task. On localization and rename the agent almost always reaches for grep; on reference-shaped work it reaches for the LSP about half the time, unprompted. The action distribution is task-shaped, not a blind habit.

The codebase was also important. On a clean TypeScript repository, LSP-backed navigation produced no F1 gain and used 16% more tokens. On a noisy TypeScript repository, it improved F1 by 0.246 and used 12% fewer tokens. The useful predictor was lexical noise, not whether the language had strong static types.

Codebase noise determines the value of semantic navigation

Accuracy gain from semantic retrieval on reference-completeness (ΔF1 = LSP − grep). Bar colour encodes how noisy grep is on that repo; prec = grep’s precision there.

Legend: blue means grep is clean here; magenta means grep is noisy here.

Delta F1 from LSP: remeda TypeScript clean plus 0.000, hono TypeScript noisy plus 0.246, and requests Python noisy plus 0.072
Two repositories in the same language, opposite verdicts. On clean remeda the LSP adds nothing — grep already resolves every reference correctly, so semantic retrieval is pure overhead. On noisy hono it adds +0.246 F1. The predictor is how badly grep's precision degrades on that codebase, not whether the language is statically typed.

These results are conditional rather than categorical. The agents did not simply “always use grep.” Their routing changed with the task, and the value of LSP-backed navigation changed with the repository.

The tested LSP-backed tools initially returned only a location: a file path, line, and column. The agent then had to open the file to inspect the code. grep, by contrast, usually returned the matching line immediately: src/auth.ts:42: return validateToken(token).

I changed the semantic-navigation response to include source text in a similar shape. The semantic backend and the set of references stayed the same; only the information returned to the model changed. Pass@1 on the rename tasks rose from 0.67 to 0.83, while follow-up file reads fell from 15.2 to 3.2 per episode.

Returning source context improves semantic navigation

Multi-file rename, Opus 4.8, pyright with a pre-warmed index. Same semantic backend in both LSP arms — only the output shape differs.

Legend: grep (blue), LSP — locations only (magenta), LSP + inline context (green).

Pass at 1 and follow-up file reads for grep, LSP locations only, and LSP with inline context
Returning locations forces the agent to go read each site; returning the line inline does not. Attaching ±2 lines of source to every reference cut follow-up file reads 15.2 → 3.2 — below grep's own 4.3 — and lifted pass@1 from 0.67 to 0.83. The retrieval backend never changed; only the shape of what came back.

This result illustrates a principle that Anthropic also emphasizes in Writing effective tools for agents: tools are interfaces for non-deterministic agents, so the context they return is part of the design. A semantically correct tool can still create a poor agent workflow if each result requires several extra actions to interpret.

The output change does not prove that post-training data caused the improvement. It may also have helped simply because each response contained more useful information. However, the result is consistent with a broader hypothesis: models learn concrete action patterns, not “tool use” in the abstract. A familiar loop—prompt, tool call, readable result, next action—can be part of the capability observed in practice.

Why lexical search had an advantage

Interface familiarity is only part of the explanation. Lexical search also had a real structural advantage for some tasks.

A semantic reference is only one kind of text match. A rename may also need to update comments, docstrings, configuration, or strings. find_references will not return those by design, while grep can.

semantic references ⊂ textual occurrences

For text-wide edits, grep can be the better retrieval tool even for a model with perfect training on LSP-backed navigation.

This gives us two explanations for the observed behavior:

  1. Structure: some tasks need textual completeness, which the tested semantic-navigation methods do not provide.
  2. Distribution: the model may have more practice with familiar tools and result shapes.

The first explanation follows directly from what the tools retrieve. The second is a hypothesis consistent with the routing and output-format results, but this study did not manipulate training data and therefore cannot prove it.

The structural and distributional causes behind grep's result
Structure explains when grep is better. Distribution explains why familiar paths still win.

The harness is part of the system

Here, I use harness to mean the runtime around a model: the instructions placed in context, the tools made available, their input schemas, the shape of their results and errors, and the loop that decides what the model sees next.

This surrounding system can materially change behavior. Anthropic’s work on effective harnesses for long-running agents shows the same idea at a longer time scale: the model alone is not enough to make reliable progress across sessions. Environment setup, progress artifacts, and verification routines affect what the agent can accomplish.

The same principle applies within a single tool loop. When post-training includes agent trajectories, the harness defines the prompts, tool calls, results, and recovery paths in those examples. A model trained through repeated use of read, grep, edit, and bash may learn policies that depend on those interfaces. Moving the same model into a different tool layer can therefore change its effective capability.

agent capability = model × harness

This is why benchmark results for a model do not always transfer unchanged to a different runtime. Supporting the same model is not necessarily the same as reproducing the same agent. Tool selection, signatures, output formats, and error behavior can all affect the policy the model follows.

Preserving native runtimes with ACP

This is one reason my team and I built AgentConnect around native coding-agent runtimes. AgentConnect does not place Claude or Codex models inside a shared, generic tool loop. It runs runtimes such as Claude Code and Codex on the user’s own machine, where each runtime keeps its native tools and normal prompt-to-tool workflow.

AgentConnect communicates with these runtimes through the open Agent Client Protocol (ACP). ACP standardizes the boundary between a client and a coding agent, including session setup, prompts, streaming updates, tool-call updates, cancellation, and permission requests. It does not require every runtime to expose the same internal tools.

AgentConnect connects native coding agents through ACP
One open boundary. Each agent stays on its home turf.

This separates two concerns. At the outside boundary, a common protocol lets AgentConnect provide team channels, triggers, schedules, session history, collaboration, and control across multiple agents. Inside that boundary, Claude Code can continue to work like Claude Code, and Codex can continue to work like Codex.

The goal is not vendor lock-in. ACP provides an open boundary across runtimes. Our design principle is to preserve the tool surface each model already uses well, then add coordination around it.

These findings do not mean that teams should avoid LSP, MCP, or new agent skills. The study found a clear precision gain from LSP-backed navigation in noisy code, and a small response-format change removed most follow-up reads. The practical lesson is to evaluate a new retrieval interface as part of the full agent loop.

My recommendation is to start with the native tool surface, then apply the following checks when adding a new capability:

  1. Test real tasks at equal accuracy. Do not celebrate lower token use if success also fell.
  2. Measure whether the agent calls it. Availability is not adoption.
  3. Return enough context for the next decision. A result like path:line:content may work better than a bare location object.
  4. Keep a native fallback. Semantic and lexical search solve different problems.
  5. Route by the task and the codebase. A noisy repository may benefit from semantic navigation. A text-wide search may still need grep.
  6. Reinforce the new trajectory when it matters. A prompt can introduce a tool, but it may not create a reliable policy for using it.

As Anthropic notes in Building effective agents, successful agent systems often rely on simple, composable patterns. More tools do not automatically produce a more capable agent; tools must be distinct, understandable, and useful within the model’s workflow.

Conclusion

The study shows why “better retrieval” cannot be evaluated outside the full agent system. An interface can be more precise and still use more tokens. It can return correct locations and still create unnecessary reads. A small change in output shape can make the same semantic result much easier for the model to use.

For teams building agent platforms, the implication is straightforward: evaluate the model and harness together. Preserve the interfaces that already support reliable behavior, and test changes against real tasks before assuming that a more sophisticated abstraction will help.

For the full experimental setup, task definitions, and results, see Does a Language Server Save Tokens for Coding Agents?.

This is the product principle behind AgentConnect: use an open protocol to connect agents, while keeping each model together with its native runtime and tool loop.

This is a preliminary pilot with small task sets, a few repositories, three Claude models, and two to three rollouts per cell. I tested LSP-backed navigation through references, definitions, and document symbols; I did not test textDocument/rename, diagnostics, or code actions. A rename-capable LSP might perform differently on the refactoring tasks where grep did best. The edit tasks were local and are not standard SWE-bench scores. These findings are useful signals, not a final verdict across all models, tools, and codebases.

联系我们 contact @ memedata.com