<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>CodeSearch on Yarang's Tech Lair</title><link>https://blog.agentthread.dev/ko/tags/codesearch/</link><description>Recent content in CodeSearch on Yarang's Tech Lair</description><generator>Hugo -- gohugo.io</generator><language>ko</language><lastBuildDate>Mon, 18 May 2026 09:00:38 +0900</lastBuildDate><atom:link href="https://blog.agentthread.dev/ko/tags/codesearch/index.xml" rel="self" type="application/rss+xml"/><item><title>Show HN: Semble – 에이전트를 위한 토큰 효율적인 코드 검색 엔진 구현</title><link>https://blog.agentthread.dev/ko/post/show-hn-semble-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8%EB%A5%BC-%EC%9C%84%ED%95%9C-%ED%86%A0%ED%81%B0-%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9D%B8-%EC%BD%94%EB%93%9C-%EA%B2%80%EC%83%89-%EC%97%94%EC%A7%84-%EA%B5%AC%ED%98%84/</link><pubDate>Mon, 18 May 2026 09:00:38 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/show-hn-semble-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8%EB%A5%BC-%EC%9C%84%ED%95%9C-%ED%86%A0%ED%81%B0-%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9D%B8-%EC%BD%94%EB%93%9C-%EA%B2%80%EC%83%89-%EC%97%94%EC%A7%84-%EA%B5%AC%ED%98%84/</guid><description>&lt;p&gt;최근 LLM(Large Language Model)을 활용한 에이전트 시스템을 개발하면서 가장 큰 병목 현상 중 하나는 바로 &amp;lsquo;코드 검색&amp;rsquo;이었습니다. 단순히 &lt;code&gt;grep&lt;/code&gt; 명령어로 소스 코드를 검색하여 LLM 컨텍스트에 던져주는 것만으로는 입력 토큰(Input Tokens)이 폭발적으로 증가하고, 검색 속도 또한 느려져 실시간성을 요구하는 에이전트의 응답 속도를 저해했습니다.&lt;/p&gt;
&lt;p&gt;Hacker News에서 논의된 &amp;lsquo;Show HN: Semble&amp;rsquo; 프로젝트는 이러한 문제를 해결하는 아주 흥미로운 접근 방식을 제시합니다. 일반적인 grep 도구 대비 &lt;strong&gt;98%나 적은 토큰&lt;/strong&gt;을 사용하여 코드를 검색한다는 것인데요. 이번 포스트에서는 Semble의 핵심 아이디어와 이를 우리의 고성능 Rust 에이전트 런타임인 &lt;strong&gt;ZeroClaw&lt;/strong&gt; 및 &lt;strong&gt;MCP(Model Context Protocol)&lt;/strong&gt; 서버에 통합하여 성능을 극대화하는 방법을 살펴보겠습니다.&lt;/p&gt;
&lt;h3 id="기존-검색-방식의-문제점-grep과-llm의-궁합"&gt;기존 검색 방식의 문제점: grep과 LLM의 궁합
&lt;/h3&gt;&lt;p&gt;기존의 &lt;code&gt;blog-api-server&lt;/code&gt;나 여러 MCP 도구에서 코드를 검색할 때 주로 정규표현식 기반의 &lt;code&gt;grep&lt;/code&gt; 라이브러리를 사용했습니다. 하지만 이 방식은 LLM 에이전트와 함께 사용할 때 치명적인 단점이 있습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;토큰 낭비&lt;/strong&gt;: &lt;code&gt;grep&lt;/code&gt;은 검색어가 포함된 전체 라인을 반환합니다. 긴 라인이나 불필요한 주석이 포함된 경우, LLM은 실제 코드보다 잡음(Noise)을 더 많이 처리해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;의미 이해 부족&lt;/strong&gt;: 단순 문자열 매칭이므로 &amp;lsquo;카멜 케이스&amp;rsquo;, &amp;lsquo;스네이크 케이스&amp;rsquo; 등의 뉘앙스를 이해하지 못합니다. 예를 들어 &lt;code&gt;getUser&lt;/code&gt;를 검색했을 때 &lt;code&gt;get_user&lt;/code&gt;는 놓칠 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;비용 증가&lt;/strong&gt;: LLM API 호출 비용은 입력 토큰 수에 비례합니다. 불필요한 코드가 컨텍스트에 포함되면 비용이 그만큼 증가합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="semble의-접근-방식-구조와-의미의-분리"&gt;Semble의 접근 방식: 구조와 의미의 분리
&lt;/h3&gt;&lt;p&gt;Semble이 토큰 사용량을 98%나 줄일 수 있는 비결은 &lt;strong&gt;코드를 구조화된 AST(Abstract Syntax Tree)나 의미론적 토큰으로 사전 처리&lt;/strong&gt;하고, 검색 시점에 이를 재조합하기 때문입니다. 핵심은 **&amp;lsquo;코드를 문자열이 아닌 데이터로 다룬다&amp;rsquo;**는 것입니다.&lt;/p&gt;
&lt;p&gt;우리는 이 개념을 확장하여 ZeroClaw 아키텍처 내에 &lt;code&gt;CodeIndexer&lt;/code&gt; 모듈을 설계했습니다.&lt;/p&gt;
&lt;h3 id="zeroclaw-통합-고성능-인덱서-구현"&gt;ZeroClaw 통합: 고성능 인덱서 구현
&lt;/h3&gt;&lt;p&gt;ZeroClaw는 Rust 기반이므로 메모리 안전성과 속도를 보장합니다. 여기에 Semble 영감을 받은 인덱서를 구현해 보겠습니다.&lt;/p&gt;
&lt;h4 id="1-데이터-구조-정의"&gt;1. 데이터 구조 정의
&lt;/h4&gt;&lt;p&gt;먼저 코드를 저장할 구조를 정의합니다. 파일의 내용 전체를 저장하는 대신, 심볼(Symbol)과 메타데이터만 저장합니다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::collections::HashMap;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde::{Serialize, Deserialize};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Serialize, Deserialize, Clone)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CodeSymbol&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; name: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; kind: &lt;span style="color:#a6e22e"&gt;SymbolKind&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// Function, Struct, Variable 등
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; file_path: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; start_line: &lt;span style="color:#66d9ef"&gt;usize&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; end_line: &lt;span style="color:#66d9ef"&gt;usize&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; signature: String, &lt;span style="color:#75715e"&gt;// 함수 시그니처나 타입 정의
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Serialize, Deserialize, Clone)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SymbolKind&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Function,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Struct,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Enum,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Variable,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Module,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 인메모리 인덱스 (실제 운영에서는 DB나 Vector Store 사용 권장)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CodeIndex&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; symbols: Vec&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;CodeSymbol&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 빠른 룩업을 위한 맵
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name_map: &lt;span style="color:#a6e22e"&gt;HashMap&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, Vec&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;usize&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="2-인덱싱-로직-parsing"&gt;2. 인덱싱 로직 (Parsing)
&lt;/h4&gt;&lt;p&gt;실제 Semble은 훨씬 복잡한 파서를 사용하겠지만, 여기서는 간단한 로직으로 라인 단위 파싱을 흉내 내어 토큰을 절약하는 방식을 구현합니다. 주석이나 공백을 제거하고 핵심 정의만 캡처합니다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; CodeIndex {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;new&lt;/span&gt;() -&amp;gt; &lt;span style="color:#a6e22e"&gt;Self&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Self {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; symbols: Vec::new(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name_map: &lt;span style="color:#a6e22e"&gt;HashMap&lt;/span&gt;::new(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 간단한 파싱 로직 (실제로는 tree-sitter 등 활용)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;index_file&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self, content: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;, path: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (line_num, line) &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; content.lines().enumerate() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 함수 정의 패턴 예시: &amp;#34;fn name(...)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; line.trim().starts_with(&lt;span style="color:#e6db74"&gt;&amp;#34;fn &amp;#34;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; signature &lt;span style="color:#f92672"&gt;=&lt;/span&gt; line.split(&lt;span style="color:#e6db74"&gt;&amp;#39;{&amp;#39;&lt;/span&gt;).next().unwrap_or(line).trim();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; signature
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .strip_prefix(&lt;span style="color:#e6db74"&gt;&amp;#34;fn &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .unwrap()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .split(&lt;span style="color:#e6db74"&gt;&amp;#39;(&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .next()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .unwrap()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .trim();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; symbol &lt;span style="color:#f92672"&gt;=&lt;/span&gt; CodeSymbol {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;format&lt;/span&gt;&lt;span style="color:#f92672"&gt;!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;{}:{}&amp;#34;&lt;/span&gt;, path, line_num),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name: &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kind: &lt;span style="color:#a6e22e"&gt;SymbolKind&lt;/span&gt;::Function,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file_path: &lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_line: &lt;span style="color:#a6e22e"&gt;line_num&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; end_line: &lt;span style="color:#a6e22e"&gt;line_num&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 대략적인 범위 추정
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; signature: &lt;span style="color:#a6e22e"&gt;signature&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.add_symbol(symbol);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Struct, impl 등에 대한 패턴 매칭 추가 가능...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;add_symbol&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self, symbol: &lt;span style="color:#a6e22e"&gt;CodeSymbol&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; idx &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.symbols.len();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.symbols.push(symbol);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.name_map
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .entry(symbol.name.clone())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .or_insert_with(Vec::new)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .push(idx);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="3-mcp-도구를-위한-검색-인터페이스"&gt;3. MCP 도구를 위한 검색 인터페이스
&lt;/h4&gt;&lt;p&gt;이제 MCP 클라이언트가 호출할 수 있는 검색 함수를 만듭니다. 이 함수는 전체 코드가 아닌 &lt;code&gt;signature&lt;/code&gt;와 &lt;code&gt;핵심 ID&lt;/code&gt;만 반환하도록 하여 토큰을 아낍니다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; CodeIndex {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;search&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, query: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; Vec&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;CodeSymbol&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.symbols
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .iter()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .filter(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;s&lt;span style="color:#f92672"&gt;|&lt;/span&gt; s.name.to_lowercase().contains(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;query.to_lowercase()))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .cloned()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .collect()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// LLM 컨텍스트를 위해 최적화된 포맷으로 변환
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to_llm_context&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, results: Vec&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;CodeSymbol&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) -&amp;gt; String {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; results
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .iter()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .map(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;s&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;File: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, Line: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;Symbol: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;Definition: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; s.file_path, s.start_line, s.name, s.signature
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .collect::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Vec&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;_&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .join(&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;---&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="성능-비교-및-토큰-절약-효과"&gt;성능 비교 및 토큰 절약 효과
&lt;/h3&gt;&lt;p&gt;예를 들어, &lt;code&gt;blog-api-server&lt;/code&gt;에서 &lt;code&gt;get_post&lt;/code&gt;라는 함수를 찾는다고 가정해 봅시다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;기존 grep 방식&lt;/strong&gt;: &lt;code&gt;main.rs&lt;/code&gt;의 100줄 중 해당 함수가 포함된 20줄을 모두 반환. (주석, 로직 등 포함)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ZeroClaw 인덱서 방식&lt;/strong&gt;: &lt;code&gt;File: src/main.rs, Line: 45, Symbol: get_post, Definition: async fn get_post(id: i32) -&amp;gt; Result&amp;lt;Post&amp;gt;&lt;/code&gt;만 반환.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;결과적으로, LLM은 필요한 메타데이터만 전달받으므로 **&amp;ldquo;이 함수의 내부 구현을 보여줘&amp;rdquo;**라고 재요청하거나, 메타데이터만으로도 충분한 추론을 수행할 수 있습니다. 불필요한 코드를 읽지 않기 때문에 토큰 사용량이 획기적으로 줄어듭니다.&lt;/p&gt;
&lt;h3 id="결론-에이전트-생태계를-위한-최적화"&gt;결론: 에이전트 생태계를 위한 최적화
&lt;/h3&gt;&lt;p&gt;Semble에서 영감을 받은 이 접근 방식은 단순히 검색 속도를 높이는 것을 넘어, &lt;strong&gt;LLM 에이전트와 코드베이스 간의 통신 비용과 효율성을 최적화&lt;/strong&gt;합니다. 특히 &lt;code&gt;blog-api-server&lt;/code&gt;의 로깅 개선이나 모니터링 시스템처럼 대규모 코드베이스를 다루는 환경에서는 필수적입니다.&lt;/p&gt;
&lt;p&gt;다음 단계로, 단순 텍스트 매칭을 넘어 **Vector Embedding(벡터 임베딩)**을 결합하여 의미론적 검색(Semantic Search)이 가능하도록 &lt;code&gt;ZeroClaw&lt;/code&gt;의 통신 프로토콜을 확장할 예정입니다. 이를 통해 에이전트가 &amp;ldquo;사용자 인증 관련 로직&amp;quot;을 검색했을 때, &lt;code&gt;auth&lt;/code&gt;라는 키워드가 없어도 &lt;code&gt;login&lt;/code&gt;, &lt;code&gt;verify&lt;/code&gt;, &lt;code&gt;session&lt;/code&gt; 등의 함수를 유연하게 찾아낼 수 있게 될 것입니다.&lt;/p&gt;
&lt;p&gt;고성능 에이전트 런타임을 구축하신다면, 단순히 파일을 읽는 것에서 벗어나 코드를 &amp;lsquo;이해&amp;rsquo;하는 인덱서 구축을 고려해 보세요. 토큰 비용 절감과 응답 속도 개선이라는 두 마리 토끼를 잡을 수 있습니다.&lt;/p&gt;
&lt;h3 id="참고-자료"&gt;참고 자료
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://news.ycombinator.com/item?id=41981234" target="_blank" rel="noopener"
 &gt;Show HN: Semble – Code search for agents that uses 98% fewer tokens than grep&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ZeroClaw Architecture Documentation&lt;/li&gt;
&lt;li&gt;Rust Tree-sitter Binding Guide&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>