grep이 LSP를 이긴 이유: 코딩 에이전트는 왜 정교한 도구를 무시할까
Grep beats LSP? Why coding agents ignore your fancier tools
코딩 에이전트가 더 정밀한 결과를 반환하는 LSP 기반 의미 탐색 대신 grep을 선택하는 이유를 소규모 연구로 분석했다. 단순 코드 위치 찾기에서는 모델들이 대부분 grep을 선택했지만, 참조 완전성 작업에서는 LSP를 절반 가까이 사용했다. 코드베이스의 어휘적 노이즈가 LSP의 가치를 결정했으며, 결과에 소스 코드를 포함시키자 후속 파일 읽기가 크게 줄었다. 이는 도구의 정확성보다 인터페이스와 출력 형태가 LLM 친화성에 중요함을 시사하며, 에이전트의 능력은 모델과 하네스의 결합으로 결정된다는 점을 강조한다.
모델은 도구를 고립적으로 사용하지 않는다. 하네스를 통해 사용하며, 하네스는 사용 가능한 액션, 이름, 입력, 모델에 반환되는 컨텍스트를 정의한다.
HN 토론
63- tonyarkles
클로드 코드를 쓰면서 흥미로운 공진화를 겪고 있다. 작업을 시키면 (종종 find와 grep, ripgrep을 잔뜩 쓰는) 과정을 지켜보고, 작업이 끝난 뒤에 더 쉬운 방법이 있었을 도구가 있는지 물어본다. 그렇게 fzf 같은 도구나 (예를 들어 이메일 인덱싱용 notmuch 같은) 다른 도구들을 알게 됐다. 그런 도구들을 내 워크플로우(CLI와 Emacs 양쪽)에 어떻게 통합할지 고민해서 적용했다.
또한 자주 처리하고 분석해야 하는 다소 느린 데이터 형식을 받아 전체 말뭉치를 인덱싱하고, 분석 시(내가 직접 하든 클로드 코드가 하든) 단일 패스로 Parquet으로 변환해 DuckDB로 질의할 수 있게 해주는 Python 도구를 함께 만들었다. 그 도구 덕분에 일회성 분석 작업의 처리 시간이 극적으로 줄었고, Typer를 쓴 Python CLI 도구라서 LLM 하네스가 다루기에도 인터페이스가 잘 드러난다.
- nomilk
주제와는 좀 다르지만, 내 LSP 설정이 몇 달마다 깨진다. 이제는 고치려고 애쓰지 않고 ~/dotfiles에서 LLM을 열어서 될 때까지 불평만 한다. 보통 몇 분이면 된다.
흥미로운 점은 이 작업에 얼마나 많은 노력이 드는지 관찰하는 것이다. (과거의 나에게 훨씬 공감이 간다. 서툰 인간이 이런 것들을 어떻게 알고 추론할 수 있었을까! 특히 몇 달 전에 만진 설정을 거의 다 잊어버린 상태라면 더더욱.)
대부분 10~20개의 아주 작은 프로그램들이 함께 협력해서 원하는 경험을 만들어낸다. "내 LSP가 안 돼" 같은 단순해 보이는 문제를 해결하는 데 필요한 시간과 토큰이 때로는 예상보다 훨씬 많이 든다.
- the_duke
코드의 희소 AST를 출력해 주는 도구를 직접 만들어 아주 좋은 성과를 봤다.
https://github.com/theduke/smartedit
스킬을 설치하면 GPT 5.6이 보통 자동으로 그걸 사용하는데, 예를 들어 파일 안의 타입과 함수를 본문 없이 출력하고 필요할 때만 펼쳐 보여줘서 코드 탐색 시간과 토큰 사용량을 크게 줄여 준다.
(참고: 편집 기능도 있는데, 모델들이 사후 학습에서 흔한 편집 도구에 크게 치우쳐 있어서 그쪽은 잘 작동하지 않는다)
- x-complexity
LSP를 설정해서 제대로 작동시키려면 두 가지 요건이 충족되어야 한다.
(a) LSP의 도구들이 유능하게 만들어져 있고 일관성이 있을 것, 그리고
(b) 그걸 사용하는 LLM이 일반적으로 LSP를 사용하도록 제대로 훈련되어 있을 것.
grep 같은 기본 도구를 쓰는 것도 같은 두 가지 가정이 필요하지만,
(a)는 grep의 핵심 기능이 굳어져 있기 때문에 충족되고(좋은 일이다),
(b)는 LLM이 "LSP 뒤에 감싼 grep의 20번째 변형이지만, 그냥 문제를 던질 만큼 다르게 생긴" 게 아니라 grep 자체를 제대로 사용하도록 훈련될 수 있기 때문에 더 잘 충족된다.
게다가 grep은 기본 Linux 환경에 거의 항상 있으므로, 필요할 때 그 존재를 가정하고 의지할 수 있다.
- brunoborges
나에게 잘 맞는 방법은 LSP를 되도록 자주 사용하라고 지시하는 SKILL을 두는 것이다.
LSP는 이미 로컬에 컴파일된 의존성을 사용할 때 가장 잘 작동하지만, 모든 소스가 있다면... 그래도 어느 쪽이 최선인지에 대한 확실한 답은 아직 없다.
하지만 다시 말해, 이미 컴파일된 의존성(Java 바이트코드 같은)의 경우 LSP 설정이 없으면 에이전트가 JAR 파일에서 바이너리를 추출하고, grep과 javap을 쓰고, 잠재적으로 .class 파일을 디컴파일하려고 시도할 가능성이 높다.