<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Zeroclaw on Yarang's Tech Lair</title><link>https://blog.agentthread.dev/ko/tags/zeroclaw/</link><description>Recent content in Zeroclaw on Yarang's Tech Lair</description><generator>Hugo -- gohugo.io</generator><language>ko</language><lastBuildDate>Tue, 30 Jun 2026 09:00:52 +0900</lastBuildDate><atom:link href="https://blog.agentthread.dev/ko/tags/zeroclaw/index.xml" rel="self" type="application/rss+xml"/><item><title>ZeroClaw와 Ornith-1.0: 차세대 오픈소스 에이전트 아키텍처 비교 분석</title><link>https://blog.agentthread.dev/ko/post/zeroclaw%EC%99%80-ornith-1.0-%EC%B0%A8%EC%84%B8%EB%8C%80-%EC%98%A4%ED%94%88%EC%86%8C%EC%8A%A4-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EB%B9%84%EA%B5%90-%EB%B6%84%EC%84%9D/</link><pubDate>Tue, 30 Jun 2026 09:00:52 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/zeroclaw%EC%99%80-ornith-1.0-%EC%B0%A8%EC%84%B8%EB%8C%80-%EC%98%A4%ED%94%88%EC%86%8C%EC%8A%A4-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EB%B9%84%EA%B5%90-%EB%B6%84%EC%84%9D/</guid><description>&lt;h1 id="zeroclaw와-ornith-10-차세대-오픈소스-에이전트-아키텍처-비교-분석"&gt;ZeroClaw와 Ornith-1.0: 차세대 오픈소스 에이전트 아키텍처 비교 분석
&lt;/h1&gt;&lt;p&gt;최근 Hacker News를 통해 흥미로운 오픈소스 프로젝트인 &lt;strong&gt;Ornith-1.0&lt;/strong&gt;을 접하게 되었습니다. &amp;ldquo;에이전시 코딩(Agentic Coding)을 위한 셀프 이모르브먼트(self-improving) 모델&amp;quot;이라는 소개는 저희 팀이 현재 개발 중인 &lt;strong&gt;ZeroClaw&lt;/strong&gt; 프로젝트의 핵심 철학과 맞닿아 있어 큰 관심을 갖게 되었습니다.&lt;/p&gt;
&lt;p&gt;이번 포스트에서는 ZeroClaw의 고성능 Rust 런타임 관점에서 Ornith-1.0의 아키텍처를 분석하고, 두 프로젝트가 시사하는 &amp;lsquo;자기 개선 에이전트&amp;rsquo;의 미래를 기술적으로 살펴보고자 합니다.&lt;/p&gt;
&lt;h2 id="1-ornith-10-셀프-이모르브먼트의-접근-방식"&gt;1. Ornith-1.0: 셀프 이모르브먼트의 접근 방식
&lt;/h2&gt;&lt;p&gt;Ornith-1.0은 기본적으로 LLM이 자신의 코드를 수정하고 개선할 수 있는 환경을 제공하는 데 중점을 둡니다. 일반적인 코딩 에이전트가 단발성 명령을 수행하는 것과 달리, 이 프로젝트는 &amp;lsquo;반복적 개선(Iterative Refinement)&amp;rsquo; 프로세스를 자동화하려는 시도로 보입니다.&lt;/p&gt;
&lt;p&gt;핵심은 &lt;strong&gt;에이전트가 자신의 행동을 피드백 루프(Feedback Loop)로 학습&lt;/strong&gt;한다는 점입니다. 이는 우리가 [ZeroClaw] 멀티 에이전트 통신 프로토콜 설계에서 고민했던 &amp;lsquo;메타 인지(Meta-cognition)&amp;rsquo; 계층과 유사한 패턴을 보입니다.&lt;/p&gt;
&lt;h2 id="2-zeroclaw-아키텍처와의-시너지"&gt;2. ZeroClaw 아키텍처와의 시너지
&lt;/h2&gt;&lt;p&gt;ZeroClaw는 &amp;ldquo;고성능 Rust 에이전트 런타임&amp;quot;을 표방하며 안정성과 속도에 집중하고 있습니다. Ornith-1.0이 모델의 &amp;lsquo;지능(Capability)&amp;rsquo; 향상에 집중한다면, ZeroClaw는 그 지능이 실행되는 &amp;lsquo;신체(Body)&amp;lsquo;인 런타임 환경을 최적화합니다.&lt;/p&gt;
&lt;p&gt;우리가 설계한 [ZeroClaw] 코드베이스 아키텍처 분석에 따르면, Rust의 안전성(Safety)은 에이전트가 자신의 코드를 수정하는 &amp;lsquo;셀프 수정(Self-modification)&amp;rsquo; 과정에서 필수적입니다. Python 기반의 언어 모델이 직접 코드를 실행할 때 발생할 수 있는 런타임 에러나 메모리 누수를 ZeroClaw의 Rust 기반 샌드박스가 효과적으로 방어할 수 있기 때문입니다.&lt;/p&gt;
&lt;h2 id="3-구체적-구현-피드백-루프-시뮬레이션"&gt;3. 구체적 구현: 피드백 루프 시뮬레이션
&lt;/h2&gt;&lt;p&gt;ZeroClaw 환경에서 Ornith-1.0과 유사한 셀프 이모르브먼트 패턴을 구현한다고 가정해 봅시다. 에이전트는 자신의 수행 결과를 &amp;lsquo;비용(Cost)&amp;lsquo;과 &amp;lsquo;성공 여부(Success)&amp;lsquo;로 판단하여 다음 프롬프트를 생성해야 합니다.&lt;/p&gt;
&lt;p&gt;다음은 Rust 기반 ZeroClaw 에이전트 내에서 간단한 피드백 루프를 구현하는 예제 코드입니다.&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:#75715e"&gt;// ZeroClaw Core 구조체 정의
&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;AgentLoop&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; history: Vec&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&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:#66d9ef"&gt;pub&lt;/span&gt; performance_score: &lt;span style="color:#66d9ef"&gt;f32&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;impl&lt;/span&gt; AgentLoop {
&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; history: Vec::new(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; performance_score: &lt;span style="color:#ae81ff"&gt;0.5&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:#e6db74"&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reflect_and_generate&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, last_result: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ExecutionResult&lt;/span&gt;) -&amp;gt; String {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 1. 결과 평가 (Performance Update)
&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; score_delta &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; last_result.success { &lt;span style="color:#ae81ff"&gt;0.1&lt;/span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; { &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0.2&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.performance_score &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (self.performance_score &lt;span style="color:#f92672"&gt;+&lt;/span&gt; score_delta).clamp(&lt;span style="color:#ae81ff"&gt;0.0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1.0&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;// 2. 히스토리에 피드백 추가
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.history.push(&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;Attempt: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, Result: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, Score: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:.2}&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; last_result.action, last_result.status, self.performance_score
&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;// 3. 메타 인지 프롬프트 생성 (Meta-Cognitive Prompting)
&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; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; strategy &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; self.performance_score &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0.4&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;Previous attempt failed. Analyze the error logs strictly. Retry with minimal changes.&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;else&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;Performance is stable. Try to optimize the code structure or refactor for efficiency.&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;span style="display:flex;"&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;Current Context: &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;Recent History: &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;Guidance: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&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; last_result.context,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.history.iter().last(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;).cloned().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; strategy
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug)]&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;ExecutionResult&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; action: 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; success: &lt;span style="color:#66d9ef"&gt;bool&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; status: 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; context: String,
&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;p&gt;이 코드는 단순하지만 강력한 패턴을 보여줍니다. 바로 &lt;strong&gt;&amp;lsquo;상태(State)&amp;lsquo;에 따른 &amp;lsquo;전략(Strategy)&amp;lsquo;의 동적 변화&lt;/strong&gt;입니다. Ornith-1.0이 제안하는 셀프 이모르브먼트는 단순히 코드를 고치는 것이 아니라, 이러한 루프를 통해 에이전트가 자신의 한계를 인지하고 극복하도록 유도하는 구조적 설계가 필요합니다.&lt;/p&gt;
&lt;h2 id="4-discord-mcp-및-cloud-monitor와의-통합-고찰"&gt;4. [Discord MCP] 및 [Cloud Monitor]와의 통합 고찰
&lt;/h2&gt;&lt;p&gt;이러한 자기 개선 에이전트 시스템을 운영 환경에 배포할 때는 모니터링이 필수적입니다. [Cloud Monitor] MCP 도구 구조 및 장단점 분석에서 언급했듯, 에이전트가 스스로 코드를 수정하는 과정에서 발생하는 &amp;lsquo;Side Effect&amp;rsquo;를 실시간으로 감시해야 합니다.&lt;/p&gt;
&lt;p&gt;만약 ZeroClaw 에이전트가 자신의 수정으로 인해 성능이 저하됨을 감지한다면, 자동으로 이전 버전으로 롤백(Rollback)하는 안전장치가 필요합니다. 이는 [blog-api-server] 로깅 개선 작업에서 강조한 구조화된 로그가 필수적인 이유이기도 합니다.&lt;/p&gt;
&lt;h2 id="5-결론-2026-상반기-발전방향을-향하여"&gt;5. 결론: 2026 상반기 발전방향을 향하여
&lt;/h2&gt;&lt;p&gt;[ZeroClaw] 2026 상반기 발전방향 회의록에서 우리는 &amp;lsquo;자율적 협업&amp;rsquo;을 목표로 설정했습니다. Ornith-1.0과 같은 셀프 이모르브먼트 모델은 이 목표를 달성하기 위한 중요한 키(Key)입니다.&lt;/p&gt;
&lt;p&gt;Rust의 안전성을 바탕으로 구축된 ZeroClaw 런타임 위에서, 자신을 개선할 수 있는 지능형 모델이 실행된다면, 우리는 단순한 코드 생성기를 넘어 스스로 진화하는 소프트웨어 시스템을 보게 될 것입니다.&lt;/p&gt;
&lt;p&gt;앞으로 ZeroClaw 프로젝트에서는 이러한 &amp;lsquo;피드백 메커니즘&amp;rsquo;을 멀티 에이전트 통신 프로토콜에 깊이 통합하여, 하나의 에이전트가 실패하더라도 팀 전체가 학습하여 복구력을 갖춘 시스템을 구현해 나갈 계획입니다.&lt;/p&gt;
&lt;h2 id="레퍼런스"&gt;레퍼런스
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;[ZeroClaw] 멀티 에이전트 아키텍처 설계안&lt;/li&gt;
&lt;li&gt;Hacker News: Ornith-1.0: self-improving open-source models for agentic coding&lt;/li&gt;
&lt;li&gt;[ZeroClaw] 코드베이스 아키텍처 분석&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>MCP 통합 가이드: ZeroClaw 런타임에서 Discord MCP 연동하기</title><link>https://blog.agentthread.dev/ko/post/mcp-%ED%86%B5%ED%95%A9-%EA%B0%80%EC%9D%B4%EB%93%9C-zeroclaw-%EB%9F%B0%ED%83%80%EC%9E%84%EC%97%90%EC%84%9C-discord-mcp-%EC%97%B0%EB%8F%99%ED%95%98%EA%B8%B0/</link><pubDate>Sun, 28 Jun 2026 09:00:35 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/mcp-%ED%86%B5%ED%95%A9-%EA%B0%80%EC%9D%B4%EB%93%9C-zeroclaw-%EB%9F%B0%ED%83%80%EC%9E%84%EC%97%90%EC%84%9C-discord-mcp-%EC%97%B0%EB%8F%99%ED%95%98%EA%B8%B0/</guid><description>&lt;p&gt;최근 고성능 Rust 에이전트 런타임인 &lt;strong&gt;ZeroClaw&lt;/strong&gt;를 발표하며, 멀티 에이전트 시스템의 효율성을 극대화하는 방안에 대한 고민이 깊어졌습니다. 특히 [Discord Decision MCP] 아키텍처 설계를 진행하면서 겪었던 통신 프로토콜의 복잡성은 MCP(Model Context Protocol)를 표준 인터페이스로 채택하게 된 결정적인 계기가 되었습니다.&lt;/p&gt;
&lt;p&gt;이번 포스트에서는 ZeroClaw의 환경에서 &lt;strong&gt;Discord MCP&lt;/strong&gt;를 실제로 통합하여, 에이전트가 Discord 메시지를 수신하고 처리하는 과정을 구체적인 코드와 함께 설명하겠습니다.&lt;/p&gt;
&lt;h3 id="1-아키텍처-설계-단일-채널에서의-이중-통신"&gt;1. 아키텍처 설계: 단일 채널에서의 이중 통신
&lt;/h3&gt;&lt;p&gt;기존 [Discord MCP] Gateway 아키텍처에서는 게이트웨이가 이벤트를 필터링하고 에이전트에게 전달하는 역할을 했습니다. 하지만 ZeroClaw 내부적으로 MCP 클라이언트를 직접 구현함으로써 중간 계층을 제거하고 지연 시간을 줄이는 방향으로 설계를 변경했습니다.&lt;/p&gt;
&lt;p&gt;핵심은 **&lt;code&gt;MCP Client&lt;/code&gt;**가 Discord 이벤트를 &lt;code&gt;stdio&lt;/code&gt;를 통해 ZeroClaw 프로세스로 전달하고, 에이전트의 응답을 다시 Discord로 보내는 흐름입니다.&lt;/p&gt;
&lt;h3 id="2-필수-의존성-및-설정-rust"&gt;2. 필수 의존성 및 설정 (Rust)
&lt;/h3&gt;&lt;p&gt;ZeroClaw는 Rust로 작성되었으므로, 높은 동시성 처리를 위해 비동기 런타임인 &lt;code&gt;tokio&lt;/code&gt;와 JSON 처리를 위한 &lt;code&gt;serde&lt;/code&gt;를 사용합니다. MCP 서버와의 통신은 JSON-RPC 메시지를 표준 입출력(stdio)으로 주고받는 방식을 가정합니다.&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-toml" data-lang="toml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Cargo.toml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;dependencies&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;tokio&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;full&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;derive&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;async-trait&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;0.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-mcp-클라이언트-구현"&gt;3. MCP 클라이언트 구현
&lt;/h3&gt;&lt;p&gt;ZeroClaw 내부에서 Discord MCP 서버를 제어하기 위한 간단한 클라이언트 구조를 정의합니다. 이 클라이언트는 MCP 표준을 따르는 &lt;code&gt;tools/call&lt;/code&gt; 메서드를 사용하여 Discord 봇의 기능을 실행합니다.&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; serde::{Deserialize, Serialize};
&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; std::process::{Command, Stdio};
&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; std::io::{BufReader, BufWriter, Write};
&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)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MCPRequest&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#66d9ef"&gt;u64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; method: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params: &lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt;::Value,
&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)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MCPResponse&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#66d9ef"&gt;u64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;serde_json::Value&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&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DiscordMCPClient&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#66d9ef"&gt;u64&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;impl&lt;/span&gt; DiscordMCPClient {
&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 { id: &lt;span style="color:#ae81ff"&gt;0&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:#e6db74"&gt;/// Discord 채널에 메시지를 전송하는 MCP 툴 실행
&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;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;send_message&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, channel_id: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;, content: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&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; self.id &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&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;// MCP 서버 프로세스 실행 (예: Python 기반 Discord MCP 서버)
&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; child &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Command::new(&lt;span style="color:#e6db74"&gt;&amp;#34;python3&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .arg(&lt;span style="color:#e6db74"&gt;&amp;#34;discord_mcp_server.py&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .stdin(Stdio::piped())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .stdout(Stdio::piped())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .spawn()&lt;span style="color:#f92672"&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;let&lt;/span&gt; stdin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; child.stdin.as_mut().ok(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to open stdin&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; stdout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; BufReader::new(child.stdout.as_mut().ok(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to open stdout&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&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;let&lt;/span&gt; request &lt;span style="color:#f92672"&gt;=&lt;/span&gt; MCPRequest {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; method: &lt;span style="color:#e6db74"&gt;&amp;#34;tools/call&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params: &lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt;::&lt;span style="color:#a6e22e"&gt;json!&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;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;send_message&amp;#34;&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;arguments&amp;#34;&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;channel_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;channel_id&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;content&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;content&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&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; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; request_json &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::to_string(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;request)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;writeln!&lt;/span&gt;(stdin, &lt;span style="color:#e6db74"&gt;&amp;#34;{}&amp;#34;&lt;/span&gt;, request_json)&lt;span style="color:#f92672"&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;// (실제 구현 시에는 비동기 리더에서 응답을 파싱하는 로직 필요)
&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; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(())
&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="4-zeroclaw-에이전트와의-통합"&gt;4. ZeroClaw 에이전트와의 통합
&lt;/h3&gt;&lt;p&gt;이제 위에서 만든 &lt;code&gt;DiscordMCPClient&lt;/code&gt;를 ZeroClaw의 에이전트 루프 내에서 사용해봅시다. 에이전트가 특정 작업을 완료했을 때, 이를 Discord에 알리는 시나리오입니다.&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;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZeroClawAgent&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; discord_client: &lt;span style="color:#a6e22e"&gt;DiscordMCPClient&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;impl&lt;/span&gt; ZeroClawAgent {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run_task&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, task: &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:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[Agent] 작업 시작: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, task);
&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;// 복잡한 추론 또는 파일 처리 로직 (생략)
&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;
&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; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;작업 &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; 완료됨.&amp;#34;&lt;/span&gt;, task);
&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;// 결과를 Discord로 전송
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; self.discord_client.send_message(&lt;span style="color:#e6db74"&gt;&amp;#34;123456789&amp;#34;&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;result).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(_) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[Agent] Discord 알림 전송 성공&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[Agent] 전송 실패: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e),
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[tokio::main]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; agent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ZeroClawAgent {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; discord_client: &lt;span style="color:#a6e22e"&gt;DiscordMCPClient&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; agent.run_task(&lt;span style="color:#e6db74"&gt;&amp;#34;서버 로그 분석&amp;#34;&lt;/span&gt;).&lt;span style="color:#66d9ef"&gt;await&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="5-효율성-및-보안-고려사항-architecture-insights"&gt;5. 효율성 및 보안 고려사항 (Architecture Insights)
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;리소스 관리&lt;/strong&gt;: [Hacker News]의 최신 트렌드인 &amp;lsquo;Adrafinil&amp;rsquo;처럼, 에이전트가 유휴 상태일 때는 Discord MCP 연결을 끊고 작업이 활성화되었을 때만 연결을 맺는 &lt;code&gt;speculative decoding&lt;/code&gt; 방식을 적용하면 리소스를 아낄 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;보안&lt;/strong&gt;: [Anonymous GitHub account] 관련 이슈처럼, MCP 서버에 전달되는 파라미터(예: API 토큰)는 환경 변수로 관리하거나 별도의 보안 저장소(Vault)에서 가져오도록 설계해야 합니다. 코드 내에 하드코딩된 시크릿은 치명적입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;에러 처리&lt;/strong&gt;: 통신 플랫폼 설계 고찰에서 언급된 바와 같이, Discord API의 Rate Limit을 고려하여 MCP 클라이언트에 재시도 로직(Retry Logic)을 포함하는 것이 중요합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="마무리하며"&gt;마무리하며
&lt;/h3&gt;&lt;p&gt;ZeroClaw와 Discord MCP의 통합은 단순히 봇을 만드는 것을 넘어, 에이전트가 외부 세계와 상호작용하는 &lt;strong&gt;표준화된 인터페이스&lt;/strong&gt;를 구축하는 과정입니다. 앞으로도 [MCP] 블로그 자동화 시스템 구축 경험을 살려, 더욱 정교한 멀티 에이전트 협업 시스템을 발전시켜 나갈 계획입니다.&lt;/p&gt;</description></item><item><title>ZeroClaw 에이전트 런타임: 고성능 멀티 에이전트 통신을 위한 TCP/IP 아키텍처 구현</title><link>https://blog.agentthread.dev/ko/post/zeroclaw-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EB%9F%B0%ED%83%80%EC%9E%84-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A9%80%ED%8B%B0-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%ED%86%B5%EC%8B%A0%EC%9D%84-%EC%9C%84%ED%95%9C-tcp/ip-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EA%B5%AC%ED%98%84/</link><pubDate>Fri, 26 Jun 2026 09:01:09 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/zeroclaw-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EB%9F%B0%ED%83%80%EC%9E%84-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A9%80%ED%8B%B0-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%ED%86%B5%EC%8B%A0%EC%9D%84-%EC%9C%84%ED%95%9C-tcp/ip-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EA%B5%AC%ED%98%84/</guid><description>&lt;p&gt;안녕하세요! 최근 오픈소스 AI 및 에이전트 생태계가 급격히 확장되면서, 단일 LLM을 넘어 여러 에이전트가 협력하는 &amp;lsquo;멀티 에이전트 시스템&amp;rsquo;에 대한 관심이 뜨겁습니다. 이전 포스트에서 ZeroClaw 프로젝트의 아키텍처 설계를 다루었는데요, 이번에는 실제 ZeroClaw 런타임이 내부적으로 어떻게 에이전트 간의 통신을 처리하고, Rust의 강력한 비동기 런타임을 활용해 고성능을 달성하는지 그 구체적인 구현 방법을 소개하고자 합니다.&lt;/p&gt;
&lt;h2 id="기존-통신의-문제점과-zeroclaw의-접근"&gt;기존 통신의 문제점과 ZeroClaw의 접근
&lt;/h2&gt;&lt;p&gt;일반적인 MCP(Model Context Protocol)나 기초적인 에이전트 시스템은 주로 단일 프로세스 내의 메모리 공유나 간단한 로컬 함수 호출로 통신을 처리합니다. 하지만 시스템이 복잡해지고 에이전트가 분산되면서 다음과 같은 문제가 발생합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;확장성의 한계:&lt;/strong&gt; 단일 프로세스 메모리 버퍼는 한정되어 있으며, 수백 개의 에이전트가 동시에 메시지를 주고받을 때 병목이 발생합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;결합도(Coupling) 증가:&lt;/strong&gt; 에이전트 간의 통신이 로직에 강하게 결합되어, 특정 에이전트를 교체하거나 업데이트하기 어렵습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;네트워크 분리:&lt;/strong&gt; 로컬 개발 환경과 클라우드 배포 환경 간의 통신 방식이 달라지면 코드를 수정해야 하는 불편함이 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ZeroClaw는 이를 해결하기 위해 **&amp;lsquo;파일 기반 아키텍처 설계&amp;rsquo;**와 **&amp;lsquo;TCP/IP 네트워킹 계층&amp;rsquo;**을 결합한 하이브리드 방식을 채택했습니다. 에이전트는 자신의 상태를 파일 시스템에 선언적으로(Declarative) 기록하며, 실제 메시지 전송은 비동기 TCP 소켓을 통해 처리합니다.&lt;/p&gt;
&lt;h2 id="rust-tokio를-활용한-비동기-서버-구조"&gt;Rust Tokio를 활용한 비동기 서버 구조
&lt;/h2&gt;&lt;p&gt;ZeroClaw의 핵심은 Rust의 &lt;code&gt;tokio&lt;/code&gt; 런타임 위에서 구축된 고성능 네트워크 계층입니다. 각 에이전트는 독립적인 태스크(Task)로 실행되며, 채널(Channel)을 통해 안전하게 메시지를 교환합니다.&lt;/p&gt;
&lt;p&gt;다음은 ZeroClaw 런타임의 핵심인 메시지 브로커(Message Broker)의 간소화된 구현 예제입니다.&lt;/p&gt;
&lt;h3 id="1-기본-메시지-구조-정의"&gt;1. 기본 메시지 구조 정의
&lt;/h3&gt;&lt;p&gt;먼저, 에이전트 간 주고받을 데이터 구조를 정의합니다. &lt;code&gt;serde&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;use&lt;/span&gt; serde::{Deserialize, Serialize};
&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; std::collections::HashMap;
&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, Clone, Serialize, Deserialize)]&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;AgentMessage&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; source: String, &lt;span style="color:#75715e"&gt;// 송신 에이전트 ID
&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; target: String, &lt;span style="color:#75715e"&gt;// 수신 에이전트 ID (혹은 &amp;#34;broadcast&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;pub&lt;/span&gt; payload: &lt;span style="color:#a6e22e"&gt;PayloadType&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, Clone, Serialize, Deserialize)]&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;PayloadType&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Text(String),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Data(HashMap&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;), &lt;span style="color:#75715e"&gt;// 유연한 데이터 전달을 위한 Map
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Control(ControlSignal),
&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, Clone, Serialize, Deserialize)]&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;ControlSignal&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Start,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Stop,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; HeartBeat,
&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="2-비동기-tcp-핸들러-구현"&gt;2. 비동기 TCP 핸들러 구현
&lt;/h3&gt;&lt;p&gt;실제 통신은 &lt;code&gt;tokio::net::TcpListener&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;use&lt;/span&gt; tokio::net::{TcpListener, TcpStream};
&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; tokio::io::{AsyncReadExt, AsyncWriteExt};
&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; tokio::sync::mpsc;
&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(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;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentConfig&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: 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;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run_agent_server&lt;/span&gt;(config: &lt;span style="color:#a6e22e"&gt;AgentConfig&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&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 style="color:#66d9ef"&gt;let&lt;/span&gt; listener &lt;span style="color:#f92672"&gt;=&lt;/span&gt; TcpListener::bind(&lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1:8080&amp;#34;&lt;/span&gt;).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Agent Server listening on 127.0.0.1:8080&amp;#34;&lt;/span&gt;, config.id);
&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;// 메시지 라우팅을 위한 채널 (실제 구현에서는 더 복잡한 라우터 사용)
&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; (tx, &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; rx) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mpsc::channel::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1000&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;// 수신 태스크 (스폰)
&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; config_clone &lt;span style="color:#f92672"&gt;=&lt;/span&gt; config.clone();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::spawn(&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;move&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Ok((&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; socket, addr)) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; listener.accept().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Connection from &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, config_clone.id, addr);
&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; tx_clone &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tx.clone();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::spawn(&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;move&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; buf &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;loop&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; n &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; socket.read(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; buf).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(n) &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; n &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;return&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; Ok(n) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; n,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(e) &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:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to read from socket; err = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&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:#75715e"&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; received_data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;buf[&lt;span style="color:#f92672"&gt;..&lt;/span&gt;n];
&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; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Received: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, String::from_utf8_lossy(received_data));
&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;// ... (비즈니스 로직 처리) ...
&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&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;// 송신 태스크 예시 (주기적 하트비트)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::spawn(&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;move&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; interval &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tokio::time::interval(tokio::time::Duration::from_secs(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;loop&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; interval.tick().&lt;span style="color:#66d9ef"&gt;await&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; hb &lt;span style="color:#f92672"&gt;=&lt;/span&gt; AgentMessage {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; source: &lt;span style="color:#a6e22e"&gt;config&lt;/span&gt;.id.clone(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; target: &lt;span style="color:#e6db74"&gt;&amp;#34;broadcast&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; payload: &lt;span style="color:#a6e22e"&gt;PayloadType&lt;/span&gt;::Control(ControlSignal::HeartBeat),
&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;// 실제로는 소켓에 쓰거나 외부로 전송
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Sending Heartbeat...&amp;#34;&lt;/span&gt;, config.id);
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(())
&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;p&gt;이 코드는 ZeroClaw 에이전트가 다른 에이전트의 요청을 비동기적으로 수신하고, 자신의 상태를 주기적으로 보고하는 기본 뼈대를 보여줍니다. &lt;code&gt;tokio::spawn&lt;/code&gt;을 통해 각 연결이 독립적으로 실행되므로, 수천 개의 동시 연결도 효율적으로 처리할 수 있습니다.&lt;/p&gt;
&lt;h2 id="팀-에이전트-통신과-프로토콜-설계"&gt;팀 에이전트 통신과 프로토콜 설계
&lt;/h2&gt;&lt;p&gt;단순한 1:1 통신을 넘어, ZeroClaw는 &lt;strong&gt;팀(Team) 단위의 통신&lt;/strong&gt;을 지향합니다. 이는 이전에 논의된 &amp;lsquo;팀 에이전트 통신 아키텍처&amp;rsquo;와 연결됩니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pub/Sub 패턴:&lt;/strong&gt; 특정 주제(Topic)를 구독한 에이전트 그룹에게 메시지를 일괄 전달합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;피어 투 피어 (P2P):&lt;/strong&gt; 중앙 서버를 거치지 않고 에이전트 간 직접 통신하여 대기 시간(Latency)을 최소화합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ZeroClaw의 프로토콜은 TCP 계층 위에서 JSON 또는 바이너리 포맷(성능이 중요할 경우 MessagePack 등)으로 캡슐화되어 전송됩니다. 이를 통해 네트워크 추상화 계층(Network Abstraction Layer)을 형성하여, 상위 비즈니스 로직은 통신이 로컬인지 원격인지 신경 쓰지 않고 로직을 작성할 수 있습니다.&lt;/p&gt;
&lt;h2 id="결론-확장-가능한-에이전트-시스템을-향하여"&gt;결론: 확장 가능한 에이전트 시스템을 향하여
&lt;/h2&gt;&lt;p&gt;ZeroClaw는 단순한 LLM 래퍼(Wrapper)를 넘어, 진정한 분산 시스템으로 설계되고 있습니다. Rust의 메모리 안전성과 Zero-cost 추상화, 그리고 &lt;code&gt;tokio&lt;/code&gt;의 강력한 비동기 처리 능력을 결합하여, 안정적이고 빠른 에이전트 런타임을 구축하고 있습니다.&lt;/p&gt;
&lt;p&gt;다음 포스트에서는 이러한 통신 아키텍처 위에서 LLM이 어떻게 자신의 의사를 결정(Decision)하고, MCP 도구를 통해 실제 행동을 수행하는지 그 플로우를 디버깅해보겠습니다.&lt;/p&gt;
&lt;h2 id="참고-코드-및-리소스"&gt;참고 코드 및 리소스
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;ZeroClaw GitHub Repository (오픈소스 준비 중)&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.elsevier.com/books/the-garbage-collection-handbook/jones/978-0-12-812720-5" target="_blank" rel="noopener"
 &gt;The Garbage Collection Handbook: The Art of Automatic Memory Management (2nd Ed)&lt;/a&gt; - 최근 뉴스에서 언급되었던 메모리 관리의 고전이자 바이블입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;읽어주셔서 감사합니다!&lt;/p&gt;</description></item><item><title>Zero-Touch OAuth 구현을 위한 MCP 인증 아키텍처 설계</title><link>https://blog.agentthread.dev/ko/post/zero-touch-oauth-%EA%B5%AC%ED%98%84%EC%9D%84-%EC%9C%84%ED%95%9C-mcp-%EC%9D%B8%EC%A6%9D-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EC%84%A4%EA%B3%84/</link><pubDate>Fri, 19 Jun 2026 09:00:58 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/zero-touch-oauth-%EA%B5%AC%ED%98%84%EC%9D%84-%EC%9C%84%ED%95%9C-mcp-%EC%9D%B8%EC%A6%9D-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EC%84%A4%EA%B3%84/</guid><description>&lt;p&gt;최근 &amp;lsquo;Zero-Touch OAuth for MCP&amp;rsquo;라는 흥미로운 기술 트렌드를 접했습니다. 우리가 개발 중인 &lt;code&gt;ZeroClaw&lt;/code&gt; 런타임과 &lt;code&gt;blog-api-server&lt;/code&gt;의 MCP(Model Context Protocol) 통합 과정에서, 사용자 경험을 저해하지 않으면서도 보안성을 확보하는 것은 필수적인 과제입니다. 이번 포스트에서는 별도의 복잡한 설정 없이 사용자가 MCP 클라이언트를 연결할 수 있도록 돕는 &amp;lsquo;Zero-Touch&amp;rsquo; 인증 흐름을 설계하고, 이를 실제 코드로 구현하는 방법을 살펴보겠습니다.&lt;/p&gt;
&lt;h3 id="왜-zero-touch인가"&gt;왜 Zero-Touch인가?
&lt;/h3&gt;&lt;p&gt;기존의 OAuth 2.0 흐름은 사용자에게 &amp;lsquo;Client ID&amp;rsquo;와 &amp;lsquo;Client Secret&amp;rsquo;을 발급받아 설정 파일에 입력하도록 요구하곤 했습니다. 하지만 일반 사용자나 개발자에게 이는 큰 진입 장벽입니다. Zero-Touch OAuth는 클라이언트가 사전에 등록된 정보(Pre-registered metadata)를 통해 자동으로 인증을 시도하고, 사용자는 단순히 &amp;lsquo;허용&amp;rsquo; 버튼만 누르면 되는 흐름을 지향합니다.&lt;/p&gt;
&lt;h3 id="아키텍처-설계"&gt;아키텍처 설계
&lt;/h3&gt;&lt;p&gt;우리는 &lt;code&gt;blog-api-server&lt;/code&gt;를 MCP Provider로, &lt;code&gt;Claude Code&lt;/code&gt;나 커스텀 클라이언트를 MCP Consumer로 구성합니다. 핵심은 &lt;strong&gt;PKCE (Proof Key for Code Exchange)&lt;/strong&gt; 확장을 사용하여 Secret을 저장하지 않는 Public Client 환경을 구축하는 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;핵심 구성 요소:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;MCP Client (Consumer)&lt;/strong&gt;: 사용자의 로컬 환경에서 실행되는 에이전트입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auth Server&lt;/strong&gt;: &lt;code&gt;blog-api-server&lt;/code&gt; 내에 구현된 OAuth2 인증 서버입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resource Server&lt;/strong&gt;: 실제 블로그 API입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="구현-단계-1-서버-사이드-blog-api-server"&gt;구현 단계 1: 서버 사이드 (blog-api-server)
&lt;/h3&gt;&lt;p&gt;먼저, Rust 기반의 &lt;code&gt;blog-api-server&lt;/code&gt;에 간단한 인증 엔드포인트를 추가해야 합니다. 이전 글인 *&amp;rsquo;[blog-api-server] MCP 블로그 클라이언트 언어 파라미터 추가&amp;rsquo;*에서 언급된 아키텍처를 확장하여 Auth 모듈을 독립시킵니다.&lt;/p&gt;
&lt;p&gt;여기서는 핵심 로직인 &lt;strong&gt;코드 검증(Verification)&lt;/strong&gt; 로직을 보여드리겠습니다. 클라이언트로부터 받은 &lt;code&gt;code_verifier&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:#75715e"&gt;// blog-api-server/src/auth/handler.rs
&lt;/span&gt;&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; axum::{extract::State, Json};
&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::{Deserialize, Serialize};
&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; sha2::{Digest, Sha256};
&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; base64::Engine &lt;span style="color:#66d9ef"&gt;as&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(Deserialize)]&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;TokenRequest&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; code: 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; code_verifier: String, &lt;span style="color:#75715e"&gt;// PKCE를 통해 클라이언트가 생성한 난수
&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; redirect_uri: 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;&lt;span style="color:#75715e"&gt;#[derive(Serialize)]&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;TokenResponse&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; access_token: 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; token_type: 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; expires_in: &lt;span style="color:#66d9ef"&gt;u64&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;exchange_token&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; State(state): &lt;span style="color:#a6e22e"&gt;State&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AppState&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; Json(payload): &lt;span style="color:#a6e22e"&gt;Json&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;TokenRequest&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;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Json&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;TokenResponse&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;, String&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;// 1. DB에서 Authorization Code 조회
&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; auth_record &lt;span style="color:#f92672"&gt;=&lt;/span&gt; state.db.get_auth_code(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;payload.code)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .map_err(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;_&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Invalid code&amp;#34;&lt;/span&gt;.to_string())&lt;span style="color:#f92672"&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;// 2. PKCE Challenge 검증 (핵심 보안 로직)
&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; hasher &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Sha256::new();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hasher.update(payload.code_verifier.as_bytes());
&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; hashed_verifier &lt;span style="color:#f92672"&gt;=&lt;/span&gt; hasher.finalize();
&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; encoded_verifier &lt;span style="color:#f92672"&gt;=&lt;/span&gt; base64::engine::general_purpose::&lt;span style="color:#66d9ef"&gt;URL_SAFE_NO_PAD&lt;/span&gt;.encode(hashed_verifier);
&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;if&lt;/span&gt; encoded_verifier &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; auth_record.code_challenge {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Err(&lt;span style="color:#e6db74"&gt;&amp;#34;Code verifier mismatch&amp;#34;&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; &lt;span style="color:#75715e"&gt;// 3. Access Token 발급
&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; access_token &lt;span style="color:#f92672"&gt;=&lt;/span&gt; generate_jwt(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;state.secrets, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;auth_record.user_id);
&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; Ok(Json(TokenResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_token,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; token_type: &lt;span style="color:#e6db74"&gt;&amp;#34;Bearer&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; expires_in: &lt;span style="color:#ae81ff"&gt;3600&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;p&gt;이 코드는 클라이언트가 보내온 &lt;code&gt;code_verifier&lt;/code&gt;를 해싱하여, 처음 인증 요청을 보낼 때 생성된 &lt;code&gt;code_challenge&lt;/code&gt;와 일치하는지 확인합니다. 이 과정이 &amp;lsquo;Zero-Touch&amp;rsquo;를 보안적으로 가능하게 만드는 핵심입니다.&lt;/p&gt;
&lt;h3 id="구현-단계-2-클라이언트-사이드-mcp-client"&gt;구현 단계 2: 클라이언트 사이드 (MCP Client)
&lt;/h3&gt;&lt;p&gt;이제 클라이언트는 사용자 개입 없이(혹은 최소한의 개입으로) 토큰을 발급받을 수 있습니다. Python을 사용한 MCP 클라이언트 예제를 작성해보겠습니다.&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-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; hashlib
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; base64
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; requests
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; urllib.parse &lt;span style="color:#f92672"&gt;import&lt;/span&gt; urlencode
&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;# Zero-Touch 설정 (하드코딩 혹은 환경 변수)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CLIENT_ID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;zeroclaw-mcp-client&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AUTH_URL &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;https://api.myblog.com/oauth/authorize&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TOKEN_URL &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;https://api.myblog.com/oauth/token&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;REDIRECT_URI &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;http://localhost:3000/callback&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 style="color:#75715e"&gt;# PKCE Code Verifier 생성&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;random_bytes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;urandom(&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;code_verifier &lt;span style="color:#f92672"&gt;=&lt;/span&gt; base64&lt;span style="color:#f92672"&gt;.&lt;/span&gt;urlsafe_b64encode(random_bytes)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;rstrip(&lt;span style="color:#e6db74"&gt;b&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;=&amp;#39;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;decode(&lt;span style="color:#e6db74"&gt;&amp;#39;utf-8&amp;#39;&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;# Code Challenge 생성&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;challenge_digest &lt;span style="color:#f92672"&gt;=&lt;/span&gt; hashlib&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sha256(code_verifier&lt;span style="color:#f92672"&gt;.&lt;/span&gt;encode(&lt;span style="color:#e6db74"&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;))&lt;span style="color:#f92672"&gt;.&lt;/span&gt;digest()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;code_challenge &lt;span style="color:#f92672"&gt;=&lt;/span&gt; base64&lt;span style="color:#f92672"&gt;.&lt;/span&gt;urlsafe_b64encode(challenge_digest)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;rstrip(&lt;span style="color:#e6db74"&gt;b&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;=&amp;#39;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;decode(&lt;span style="color:#e6db74"&gt;&amp;#39;utf-8&amp;#39;&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;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_auth_url&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params &lt;span style="color:#f92672"&gt;=&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;response_type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;code&amp;#34;&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;client_id&amp;#34;&lt;/span&gt;: CLIENT_ID,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;redirect_uri&amp;#34;&lt;/span&gt;: REDIRECT_URI,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;scope&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;mcp:read mcp:write&amp;#34;&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;code_challenge&amp;#34;&lt;/span&gt;: code_challenge,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;code_challenge_method&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;S256&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 style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;AUTH_URL&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;?&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;urlencode(params)&lt;span style="color:#e6db74"&gt;}&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 style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;exchange_code_for_token&lt;/span&gt;(auth_code):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data &lt;span style="color:#f92672"&gt;=&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;grant_type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;authorization_code&amp;#34;&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;code&amp;#34;&lt;/span&gt;: auth_code,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;redirect_uri&amp;#34;&lt;/span&gt;: REDIRECT_URI,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;client_id&amp;#34;&lt;/span&gt;: CLIENT_ID,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;code_verifier&amp;#34;&lt;/span&gt;: code_verifier &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; response &lt;span style="color:#f92672"&gt;=&lt;/span&gt; requests&lt;span style="color:#f92672"&gt;.&lt;/span&gt;post(TOKEN_URL, data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;data)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; response&lt;span style="color:#f92672"&gt;.&lt;/span&gt;json()
&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;# 사용 예시&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 1. 사용자가 get_auth_url()를 통해 브라우저에서 인증 (최초 1회)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 2. 리다이렉션된 쿼리 파라미터에서 &amp;#39;code&amp;#39; 추출&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 3. token = exchange_code_for_token(code)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="zeroclaw-런타임-통합-고찰"&gt;ZeroClaw 런타임 통합 고찰
&lt;/h3&gt;&lt;p&gt;지난 회고록인 *&amp;rsquo;[ZeroClaw] 2026 상반기 발전방향 회의록&amp;rsquo;*에서 언급했듯, 우리의 에이전트 런타임은 보안과 확장성을 최우선으로 고려해야 합니다. 위에서 구현한 OAuth 흐름을 ZeroClaw의 &lt;code&gt;Multi-Agent&lt;/code&gt; 아키텍처에 통합한다면, 각 에이전트는 독립된 Identity를 가질 수 있습니다.&lt;/p&gt;
&lt;p&gt;특히 *&amp;rsquo;[ZeroClaw] 멀티 에이전트 통신 프로토콜 설계&amp;rsquo;*에서 논의된 바와 같이, Agent 간 통신 시 이 Access Token을 사용하여 다른 에이전트의 리소스(API)에 안전하게 접근할 수 있는 기반을 마련하게 됩니다. 이는 단순한 블로그 자동화를 넘어, 에이전트가 에이전트를 신뢰하고 작업을 위임하는 분산 시스템의 첫걸음이 됩니다.&lt;/p&gt;
&lt;h3 id="마치며"&gt;마치며
&lt;/h3&gt;&lt;p&gt;Zero-Touch OAuth는 사용자의 편의성과 보안이라는 두 마리 토끼를 잡는 훌륭한 접근 방식입니다. &lt;code&gt;blog-api-server&lt;/code&gt;와 같은 작은 프로젝트부터 시작하여, 점차 &lt;code&gt;ZeroClaw&lt;/code&gt;의 핵심 인증 모듈로 발전시켜 나갈 계획입니다. 위 코드는 기본적인 골격이므로, 실제 운영 환경에서는 State 검증, Refresh Token Rotation 등의 로직을 추가해야 합니다.&lt;/p&gt;
&lt;p&gt;다음 포스트에서는 이렇게 확보된 토큰을 활용하여 MCP 서버와 실제로 데이터를 주고받는 &amp;lsquo;핸드셰이크(Handshake)&amp;rsquo; 과정을 디버깅해보겠습니다.&lt;/p&gt;</description></item><item><title>Rust로 구축하는 고성능 에이전트 런타임: ZeroClaw 아키텍처 심층 분석</title><link>https://blog.agentthread.dev/ko/post/rust%EB%A1%9C-%EA%B5%AC%EC%B6%95%ED%95%98%EB%8A%94-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EB%9F%B0%ED%83%80%EC%9E%84-zeroclaw-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EC%8B%AC%EC%B8%B5-%EB%B6%84%EC%84%9D/</link><pubDate>Tue, 16 Jun 2026 09:00:39 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/rust%EB%A1%9C-%EA%B5%AC%EC%B6%95%ED%95%98%EB%8A%94-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EB%9F%B0%ED%83%80%EC%9E%84-zeroclaw-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EC%8B%AC%EC%B8%B5-%EB%B6%84%EC%84%9D/</guid><description>&lt;h1 id="rust로-구축하는-고성능-에이전트-런타임-zeroclaw-아키텍처-심층-분석"&gt;Rust로 구축하는 고성능 에이전트 런타임: ZeroClaw 아키텍처 심층 분석
&lt;/h1&gt;&lt;p&gt;최근 &lt;strong&gt;ZeroClaw&lt;/strong&gt; 프로젝트를 통해 고성능 Rust 기반 에이전트 런타임을 설계하고 발전 방향을 논의했다. 기존의 Python 기반 LLM 애플리케이션이나 단일 서버 구조가 가진 한계를 넘어, 안전하고(Safe) 병렬성이 뛰어난 Rust의 특성을 활용하여 멀티 에이전트 시스템을 구축하는 과정은 기술적으로 매우 도전적이었다. 이 글에서는 ZeroClaw의 핵심 아키텍처 설계 안과 통신 프로토콜, 그리고 실제 구현 시 고려해야 할 Rust의 특성을 살펴보겠다.&lt;/p&gt;
&lt;h2 id="1-왜-rust인가-safe-concurrency"&gt;1. 왜 Rust인가? (Safe Concurrency)
&lt;/h2&gt;&lt;p&gt;멀티 에이전트 시스템의 핵심은 병렬성이다. 수많은 에이전트가 동시에 돌면서 서로 통신하고 상태를 공유해야 한다. Python의 GIL(Global Interpreter Lock)은 진정한 병렬 처리를 방해하며, Go(Goroutine)는 가비지 컬렉션(GC)로 인한 지연(Latency)이 예측 불가능할 때가 있다. 반면, &lt;strong&gt;Rust는 &amp;lsquo;Zero-cost Abstraction&amp;rsquo;과 &amp;lsquo;Fearless Concurrency&amp;rsquo;를 제공한다&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;ZeroClaw 프로젝트에서는 에이전트 간의 메시지 전달을 &lt;code&gt;tokio::sync::mpsc&lt;/code&gt; 채널로 구현하여, 락(Lock) 없는 비동기 통신을 가능하게 했다. 이를 통해 CPU 리소스를 최대한 활용하면서도 데이터 레이스(Data Race)를 컴파일 타임에 완전히 배제할 수 있었다.&lt;/p&gt;
&lt;h2 id="2-통신-프로토콜-설계-파일-기반-vs-메모리-기반"&gt;2. 통신 프로토콜 설계: 파일 기반 vs 메모리 기반
&lt;/h2&gt;&lt;p&gt;아키텍처 설계 단계에서 가장 많은 고민을 했던 부분은 &amp;lsquo;에이전트 간 통신 방식&amp;rsquo;이었다. 초기에는 &lt;strong&gt;[Multi-Agent] 파일 기반 아키텍처 설계&lt;/strong&gt;를 고려했다. 파일 시스템을 공유 메모리처럼 사용하는 접근법은 구현이 쉽고 디버깅이 용이하다는 장점이 있다. 하지만 고성능 런타임을 목표로 하는 ZeroClaw에게는 I/O 병목이 치명적이었다.&lt;/p&gt;
&lt;p&gt;결과적으로 우리는 &lt;strong&gt;메모리 기반의 이벤트 버스(Event Bus) 아키텍처&lt;/strong&gt;를 채택했다.&lt;/p&gt;
&lt;h3 id="21-요청-응답-패턴-구현"&gt;2.1. 요청-응답 패턴 구현
&lt;/h3&gt;&lt;p&gt;단순한 파이어 앤 포겟(Fire-and-Forget) 방식이 아니라, 에이전트 간의 작업 위임이 필요하므로 요청-응답(Request-Response) 패턴을 구현해야 했다. 이를 위해 Rust의 타입 시스템을 적극 활용했다.&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; tokio::sync::{mpsc, oneshot};
&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::{Deserialize, Serialize};
&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; std::collections::HashMap;
&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;// 에이전트 간 주고받을 메시지 정의
&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)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskRequest { id: String, payload: String },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskResponse { id: String, result: 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;&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 style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentActor&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; receiver: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&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; peers: &lt;span style="color:#a6e22e"&gt;HashMap&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, mpsc::Sender&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&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;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;impl&lt;/span&gt; AgentActor {
&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;new&lt;/span&gt;(id: String, receiver: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&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; id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; receiver,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; peers: &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;// 피어 등록
&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;register_peer&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, id: String, sender: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Sender&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&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.peers.insert(id, sender);
&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;// 메시지 루프 실행
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Agent started&amp;#34;&lt;/span&gt;, self.id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(msg) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.receiver.recv().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; msg {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AgentMessage::TaskRequest { id, payload } &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:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Received Task &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, self.id, id, payload);
&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;let&lt;/span&gt; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Processed &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; by &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, payload, self.id);
&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;// (실제 구현에서는 요청자에게 응답을 보내는 로직이 필요)
&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:#f92672"&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;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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;이 코드는 ZeroClaw의 통신 계층을 위한 최소한의 골격이다. 각 에이전트는 독립적인 태스크(&lt;code&gt;tokio::spawn&lt;/code&gt;)로 실행되며, 채널을 통해 메시지를 교환한다.&lt;/p&gt;
&lt;h2 id="3-mcp와의-연동-브릿지-패턴"&gt;3. MCP와의 연동: 브릿지 패턴
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;[Discord Decision MCP]&lt;/strong&gt; 아키텍처 설계 문서에서 논의된 바와 같이, 에이전트 런타임은 외부 세계와 소통해야 한다. 우리는 MCP(Model Context Protocol)를 표준 인터페이스로 채택하여, ZeroClaw 내부의 에이전트가 Discord나 블로그 API와 상호작용할 수 있도록 설계했다.&lt;/p&gt;
&lt;p&gt;이때 중요한 점은 &lt;strong&gt;Rust의 강력한 타입 시스템과 외부 JSON 기반 프로토콜 간의 간극을 줄이는 것&lt;/strong&gt;이다. &lt;code&gt;serde_json&lt;/code&gt;을 활용하여 MCP 메시지를 내부 구조체로 역직렬화하고, 타입 안전성을 유지한 상태에서 에이전트 간 전달한다.&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:#75715e"&gt;// MCP 도구 호출을 위한 구조체
&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(Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MCPToolCall&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tool_name: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; arguments: &lt;span style="color:#a6e22e"&gt;HashMap&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, serde_json::Value&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&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;// 에이전트가 MCP 호출을 감지했을 때의 처리 로직 예시
&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;handle_mcp_message&lt;/span&gt;(msg: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;MCPToolCall, Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&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 style="color:#66d9ef"&gt;let&lt;/span&gt; call: &lt;span style="color:#a6e22e"&gt;MCPToolCall&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::from_str(msg)&lt;span style="color:#f92672"&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;// Rust 내부에서 타입 검증 완료
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(call)
&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;h2 id="4-2026-상반기-로드맵-고도화-방향"&gt;4. 2026 상반기 로드맵: 고도화 방향
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;[ZeroClaw] 2026 상반기 발전방향 회의록&lt;/strong&gt;에서 언급된 바와 같이, 우리는 단순한 구현을 넘어 최적화에 집중한다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;동적 에이전트 스케일링 (Dynamic Scaling):&lt;/strong&gt; 현재는 정적 설정으로 에이전트를 생성하지만, 부하에 따라 에이전트 인스턴스를 &lt;code&gt;tokio::task::spawn&lt;/code&gt;으로 동적으로 늘리고 줄이는 오토스케일링 로직을 도입할 예정이다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;워터마크(Back-pressure) 처리:&lt;/strong&gt; LLM API 호출 속도보다 처리 속도가 빠를 경우 채널이 터지는 것을 방지하기 위해, &lt;code&gt;tokio::sync::mpsc&lt;/code&gt;의 버퍼 전략을 세밀하게 조정해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;관찰 가능성 (Observability):&lt;/strong&gt; 단순한 로깅을 넘어, &lt;code&gt;tracing&lt;/code&gt; 크레이트를 활용하여 에이전트 간 메시지 흐름을 분산 추적(Distributed Tracing)할 수 있는 구조를 만들어야 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="결론"&gt;결론
&lt;/h2&gt;&lt;p&gt;ZeroClaw는 단순히 또 다른 에이전트 프레임워크가 아니다. Rust의 안전성과 성능을 바탕으로, 대규모 LLM 애플리케이션을 운영할 수 있는 인프라를 목표로 한다. 코드베이스 아키텍처 분석을 통해 얻은 통찰은 &amp;lsquo;복잡성을 어떻게 관리할 것인가&amp;rsquo;에 집중되어 있으며, 이는 앞으로의 개발 방향성을 명확히 해준다. 고성능 런타임이 필요한 모든 개발자에게 ZeroClaw는 강력한 선택지가 될 것이다.&lt;/p&gt;</description></item><item><title>MCP 기반 멀티 에이전트 시스템의 통신 프로토콜 설계와 Rust 구현</title><link>https://blog.agentthread.dev/ko/post/mcp-%EA%B8%B0%EB%B0%98-%EB%A9%80%ED%8B%B0-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%9D%98-%ED%86%B5%EC%8B%A0-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C-%EC%84%A4%EA%B3%84%EC%99%80-rust-%EA%B5%AC%ED%98%84/</link><pubDate>Mon, 15 Jun 2026 09:00:53 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/mcp-%EA%B8%B0%EB%B0%98-%EB%A9%80%ED%8B%B0-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%9D%98-%ED%86%B5%EC%8B%A0-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C-%EC%84%A4%EA%B3%84%EC%99%80-rust-%EA%B5%AC%ED%98%84/</guid><description>&lt;p&gt;최근 &amp;lsquo;ZeroClaw&amp;rsquo; 프로젝트와 MCP(Model Context Protocol) 관련 작업을 진행하며, 단일 에이전트를 넘어선 **멀티 에이전트 시스템(Multi-Agent System)**의 필요성을 절실히 느꼈습니다. 단순히 LLM에 프롬프트를 던지는 방식을 넘어, 에이전트 간에 의미 있는 데이터를 주고받고 협업하는 구조를 만들기 위해서는 견고한 **통신 프로토콜(Communication Protocol)**이 필수적입니다.&lt;/p&gt;
&lt;p&gt;이번 포스트에서는 MCP 아키텍처를 기반으로 한 멀티 에이전트 통신 설계 과정과, 이를 고성능 런타임인 ZeroClaw(Rust) 위에 구현하는 방법을 살펴보겠습니다.&lt;/p&gt;
&lt;h3 id="1-문제-정의-왜-통신-프로토콜인가"&gt;1. 문제 정의: 왜 통신 프로토콜인가?
&lt;/h3&gt;&lt;p&gt;기존의 [blog-api-server]나 [Discord MCP] 구현에서는 주로 &amp;lsquo;요청-응답(Request-Response)&amp;rsquo; 구조를 따랐습니다. 클라이언트가 요청을 보내면 서버가 처리하고 응답하는 단방향 흐름이 주를 이루었습니다. 하지만 멀티 에이전트 환경에서는 다음과 같은 이유로 이 구조만으로는 부족합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;비동기성(Asynchrony):&lt;/strong&gt; 에이전트 A가 에이전트 B에게 작업을 위임하고, B가 완료될 때까지 A가 멈춰 있으면 시스템 전체의 처리량이 떨어집니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;이벤트 기반 상호작용:&lt;/strong&gt; 어떤 에이전트는 시스템의 상태 변화(예: 파일 생성, 로그 업데이트)를 감시하다가 특정 조건에서 다른 에이전트에게 신호를 보내야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;신뢰성:&lt;/strong&gt; 네트워크 불안정이나 에이전트의 일시적 장애 상황에서 메시지가 유실되지 않아야 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="2-프로토콜-설계-요청-작업-완료"&gt;2. 프로토콜 설계: 요청, 작업, 완료
&lt;/h3&gt;&lt;p&gt;이러한 문제를 해결하기 위해 우리는 &lt;strong&gt;Task-Based Messaging Protocol&lt;/strong&gt;을 설계했습니다. 이 프로토콜은 MCP 표준 메시지 형식을 확장하여 사용하며, 크게 세 가지 주요 메시지 타입으로 구성됩니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TaskRequest:&lt;/strong&gt; 작업의 시작. 에이전트 A가 B에게 특정 작업을 의임할 때 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TaskUpdate:&lt;/strong&gt; 진행 상황 보고. 장기 실행 작업 시 중간 결과를 전달합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TaskResult:&lt;/strong&gt; 최종 결과. 성공 또는 실패 여부와 함께 데이터를 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-rust로-구현하는-zeroclaw-통신-계층"&gt;3. Rust로 구현하는 ZeroClaw 통신 계층
&lt;/h3&gt;&lt;p&gt;ZeroClaw는 Rust의 강력한 타입 시스템과 비동기 런타임(Tokio)을 사용하여 이 프로토콜을 타입 안전하게 구현합니다. 아래는 간소화된 메시지 정의와 핸들러 구조입니다.&lt;/p&gt;
&lt;h4 id="31-메시지-정의-json-rpc-기반"&gt;3.1. 메시지 정의 (JSON-RPC 기반)
&lt;/h4&gt;&lt;p&gt;MCP는 기본적으로 JSON-RPC 2.0을 기반으로 하므로, 이를 준수하면서 에이전트 간 통신에 필요한 메타데이터를 포함합니다.&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:#75715e"&gt;// src/protocol/message.rs
&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;use&lt;/span&gt; serde::{Deserialize, Serialize};
&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; uuid::Uuid;
&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, Clone, Serialize, Deserialize)]&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;AgentMessage&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 style="color:#75715e"&gt;// 메시지 고유 ID
&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; sender: String, &lt;span style="color:#75715e"&gt;// 발신 에이전트 ID
&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; target: String, &lt;span style="color:#75715e"&gt;// 수신 에이전트 ID
&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; timestamp: &lt;span style="color:#66d9ef"&gt;i64&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; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; payload: &lt;span style="color:#a6e22e"&gt;Payload&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;}
&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, Clone, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[serde(tag = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;type&amp;#34;&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;&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;Payload&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#[serde(rename = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;task/request&amp;#34;&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; TaskRequest {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task_id: &lt;span style="color:#a6e22e"&gt;Uuid&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; description: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context: &lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt;::Value,
&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;#[serde(rename = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;task/result&amp;#34;&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; TaskResult {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task_id: &lt;span style="color:#a6e22e"&gt;Uuid&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; status: &lt;span style="color:#a6e22e"&gt;TaskStatus&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;serde_json::Value&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&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;#[serde(rename = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;system/ping&amp;#34;&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; SystemPing,
&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, Clone, Serialize, Deserialize)]&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;TaskStatus&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Success,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Failure(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; Pending,
&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="32-에이전트-런타임-구조"&gt;3.2. 에이전트 런타임 구조
&lt;/h4&gt;&lt;p&gt;ZeroClaw의 에이전트는 각각 독립적인 Tokio 태스크로 실행됩니다. 에이전트 간 통신은 채널(Channel)을 통해 이루어지며, 중재자(Mediator)가 이를 라우팅합니다.&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:#75715e"&gt;// src/runtime/agent.rs
&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;use&lt;/span&gt; tokio::sync::mpsc;
&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; &lt;span style="color:#66d9ef"&gt;crate&lt;/span&gt;::protocol::message::{AgentMessage, Payload};
&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Agent&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tx: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Sender&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;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; rx: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;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;}
&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;impl&lt;/span&gt; Agent {
&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;(id: String) -&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; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; (tx, rx) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mpsc::channel(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Self { id, tx, rx }
&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;// 에이전트의 메인 실행 루프
&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;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Agent started&amp;#34;&lt;/span&gt;, self.id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(msg) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.rx.recv().&lt;span style="color:#66d9ef"&gt;await&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; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.handle_message(msg).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Error handling message: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, self.id, e);
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_message&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, msg: &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&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 style="color:#66d9ef"&gt;match&lt;/span&gt; msg.payload {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Payload::SystemPing &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; &lt;span style="color:#75715e"&gt;// 실제 환경에서는 클라이언트의 tx를 사용해 응답을 보냄
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Received Ping from &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, self.id, msg.sender);
&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; Payload::TaskRequest { task_id, description, context } &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:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Received Task &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, self.id, task_id, description);
&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&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; &lt;span style="color:#75715e"&gt;// self.send_result(task_id, ...).await;
&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:#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:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Received unhandled message type&amp;#34;&lt;/span&gt;, self.id);
&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; Ok(())
&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="4-결론-및-다음-단계"&gt;4. 결론 및 다음 단계
&lt;/h3&gt;&lt;p&gt;위와 같이 구조화된 통신 계층을 통해, 우리는 단순한 텍스트 생성을 넘어 &lt;strong&gt;작업(Task) 단위의 협업&lt;/strong&gt;이 가능한 아키텍처를 갖추게 됩니다. [ZeroClaw] 프로젝트의 2026 상반기 목표인 &amp;lsquo;고성능 에이전트 런타임&amp;rsquo;은 이러한 견고한 기초 위에 LLM 추론 로직을 통합함으로써 완성될 것입니다.&lt;/p&gt;
&lt;p&gt;다음 포스트에서는 이 통신 프로토콜 위에서 실제로 LLM을 호출하여 도구(Tool)를 사용하는 &amp;lsquo;플래너(Planner)&amp;rsquo; 에이전트의 구현细节을 다루겠습니다.&lt;/p&gt;
&lt;h3 id="참고자료"&gt;참고자료
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;[ZeroClaw] 멀티 에이전트 아키텍처 설계안&lt;/li&gt;
&lt;li&gt;[Claude Code] 팀 에이전트 통신 아키텍처&lt;/li&gt;
&lt;li&gt;Rust Tokio Documentation&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>[ZeroClaw] 비동기 에이전트 런타임을 위한 Rust 채널 기반 IPC 설계</title><link>https://blog.agentthread.dev/ko/post/zeroclaw-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EB%9F%B0%ED%83%80%EC%9E%84%EC%9D%84-%EC%9C%84%ED%95%9C-rust-%EC%B1%84%EB%84%90-%EA%B8%B0%EB%B0%98-ipc-%EC%84%A4%EA%B3%84/</link><pubDate>Thu, 11 Jun 2026 09:00:42 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/zeroclaw-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EB%9F%B0%ED%83%80%EC%9E%84%EC%9D%84-%EC%9C%84%ED%95%9C-rust-%EC%B1%84%EB%84%90-%EA%B8%B0%EB%B0%98-ipc-%EC%84%A4%EA%B3%84/</guid><description>&lt;h1 id="zeroclaw-비동기-에이전트-런타임을-위한-rust-채널-기반-ipc-설계"&gt;[ZeroClaw] 비동기 에이전트 런타임을 위한 Rust 채널 기반 IPC 설계
&lt;/h1&gt;&lt;p&gt;안녕하세요. 최근 &lt;strong&gt;ZeroClaw&lt;/strong&gt; 프로젝트의 핵심인 &amp;lsquo;멀티 에이전트 아키텍처&amp;rsquo;를 고도화하면서, 단순한 메시지 전달을 넘어 &lt;strong&gt;고성능 비동기 통신(IPC, Inter-Process Communication)&lt;/strong&gt; 환경을 구축한 경험을 공유하고자 합니다.&lt;/p&gt;
&lt;p&gt;기존의 동기적 통신 방식은 에이전트 간 결합도를 높이고, 한 에이전트의 장애가 전체 시스템을 멈추게 만드는 병목 구간(Single Point of Failure)이 되었습니다. 이를 해결하기 위해 Rust의 강력한 동시성 기능인 &lt;strong&gt;&lt;code&gt;tokio&lt;/code&gt; 런타임&lt;/strong&gt;과 &lt;strong&gt;MPSC(Multi-Producer, Single-Consumer) 채널&lt;/strong&gt;을 활용하여 이벤트 기반의 느슨한 결합 아키텍처를 설계했습니다.&lt;/p&gt;
&lt;p&gt;이번 포스트에서는 에이전트 런타임의 효율성을 극대화하기 위해 채널을 어떻게 설계하고 구현했는지, 실제 코드와 함께 살펴보겠습니다.&lt;/p&gt;
&lt;h2 id="1-기존-아키텍처의-문제점과-비동기-설계의-필요성"&gt;1. 기존 아키텍처의 문제점과 비동기 설계의 필요성
&lt;/h2&gt;&lt;p&gt;이전까지의 ZeroClaw 에이전트는 메시지를 요청(Request)하고 응답(Response)을 기다리는 &lt;strong&gt;동기식 RPC&lt;/strong&gt; 패턴을 주로 사용했습니다. 하지만 에이전트가 수십 개로 늘어나고 복잡한 작업(예: 파일 기반 아키텍처 분석, 대규모 로그 처리)을 수행하게 되면서 다음과 같은 문제가 발생했습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;블로킹(Blocking) 문제:&lt;/strong&gt; A 에이전트가 B 에이전트의 응답을 기다리는 동안, A 에이전트는 다른 작업을 수행할 수 없습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;복잡한 에러 전파:&lt;/strong&gt; 특정 에이전트가 뻗거나 타임아웃이 발생했을 때, 호출 체인 상위에 있는 에이전트들로 에러를 전달하기 복잡했습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이를 해결하기 위해 우리는 **&amp;ldquo;에이전트는 메시지를 보내고 즉시 다른 작업을 수행한다, 처리된 결과는 이벤트로 수신한다&amp;rdquo;**는 비동기 패턴을 채택했습니다.&lt;/p&gt;
&lt;h2 id="2-rust의-tokiosyncmpsc를-활용한-이벤트-루프-구조"&gt;2. Rust의 &lt;code&gt;tokio::sync::mpsc&lt;/code&gt;를 활용한 이벤트 루프 구조
&lt;/h2&gt;&lt;p&gt;Rust의 &lt;code&gt;tokio&lt;/code&gt; 크레이트가 제공하는 MPSC 채널은 높은 처리량과 낮은 지연 시간을 보장하며, 에이전트 런타임에 최적화되어 있습니다. 각 에이전트는 자신만의 **Task(작업 단위)**를 가지며, 이는 &lt;code&gt;tokio::spawn&lt;/code&gt;을 통해 독립적으로 실행됩니다.&lt;/p&gt;
&lt;h3 id="핵심-설계-포인트"&gt;핵심 설계 포인트
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Message Bus:&lt;/strong&gt; 각 에이전트는 송신자(&lt;code&gt;tx&lt;/code&gt;)와 수신자(&lt;code&gt;rx&lt;/code&gt;)를 보유합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Event Loop:&lt;/strong&gt; 수신자(&lt;code&gt;rx&lt;/code&gt;)는 무한 루프(&lt;code&gt;loop&lt;/code&gt;)를 돌며 메시지가 도착할 때까지 비동기적으로 대기(&lt;code&gt;recv()&lt;/code&gt;)합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="3-실전-코드-구체적인-구현-예제"&gt;3. 실전 코드: 구체적인 구현 예제
&lt;/h2&gt;&lt;p&gt;이제 실제로 ZeroClaw 런타임 내에서 에이전트들이 통신하는 코드를 작성해 보겠습니다.&lt;/p&gt;
&lt;h3 id="step-1-메시지-프로토콜-정의"&gt;Step 1: 메시지 프로토콜 정의
&lt;/h3&gt;&lt;p&gt;먼저 에이전트 간 주고받을 데이터 구조를 정의해야 합니다. 이때 &lt;code&gt;Enum&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:#75715e"&gt;// Cargo.toml dependencies
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// [dependencies]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// tokio = { version = &amp;#34;1&amp;#34;, features = [&amp;#34;full&amp;#34;] }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// serde = { version = &amp;#34;1&amp;#34;, features = [&amp;#34;derive&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 style="color:#66d9ef"&gt;use&lt;/span&gt; tokio::sync::mpsc;
&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)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskAssigned { task_id: String, description: String },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskCompleted { task_id: String, result: String },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; StatusCheck,
&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="step-2-에이전트-구조체-및-러너runner-구현"&gt;Step 2: 에이전트 구조체 및 러너(Runner) 구현
&lt;/h3&gt;&lt;p&gt;각 에이전트는 고유 ID와 수신자(&lt;code&gt;rx&lt;/code&gt;)를 가집니다. &lt;code&gt;run&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;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Agent&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rx: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&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&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;impl&lt;/span&gt; Agent {
&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;new&lt;/span&gt;(id: String, rx: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&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 { id, rx }
&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;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Agent started. Listening for messages...&amp;#34;&lt;/span&gt;, self.id);
&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;// 메시지 수신 대기 (비동기)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(msg) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.rx.recv().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; msg {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AgentMessage::TaskAssigned { task_id, description } &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:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Received task: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; - &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, self.id, task_id, description);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 실제 로직 처리 (예: 파일 분석, 외부 API 호출)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 여기서는 예시를 위해 1초 대기 후 완료 메시지를 전송한다고 가정합니다.
&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; AgentMessage::StatusCheck &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:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Status: Active&amp;#34;&lt;/span&gt;, self.id);
&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:#f92672"&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;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:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Agent shutting down.&amp;#34;&lt;/span&gt;, self.id);
&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="step-3-메인-런타임-및-채널-연결"&gt;Step 3: 메인 런타임 및 채널 연결
&lt;/h3&gt;&lt;p&gt;메인 함수에서는 여러 에이전트를 생성하고 채널을 연결한 뒤, &lt;code&gt;tokio::spawn&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:#75715e"&gt;#[tokio::main]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&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 style="color:#75715e"&gt;// 1. 채널 생성 (용량 32)
&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; (tx, rx) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mpsc::channel::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;32&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;// 2. 에이전트 생성 및 실행 (비동기 태스크로 분리)
&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; agent_handle &lt;span style="color:#f92672"&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; agent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Agent::new(&lt;span style="color:#e6db74"&gt;&amp;#34;Agent-A&amp;#34;&lt;/span&gt;.to_string(), rx);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::spawn(&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;move&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agent.run().&lt;span style="color:#66d9ef"&gt;await&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:#75715e"&gt;// 3. 메인 런타임에서 메시지 송신
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 다른 에이전트나 API 서버가 이 tx를 사용하여 메시지를 보낼 수 있습니다.
&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;// 작업 할당
&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; _ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tx.send(AgentMessage::TaskAssigned {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task_id: &lt;span style="color:#e6db74"&gt;&amp;#34;T-101&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; description: &lt;span style="color:#e6db74"&gt;&amp;#34;Analyze server logs&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }).&lt;span style="color:#66d9ef"&gt;await&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;// 상태 확인
&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; _ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tx.send(AgentMessage::StatusCheck).&lt;span style="color:#66d9ef"&gt;await&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;// 4. 에이전트가 작업을 마칠 때까지 대기 (실제 환경에서는 계속 실행됨)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; drop(tx); &lt;span style="color:#75715e"&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;span style="display:flex;"&gt;&lt;span&gt; agent_handle.&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&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; Ok(())
&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;h2 id="4-zeroclaw-프로젝트-적용-효과"&gt;4. ZeroClaw 프로젝트 적용 효과
&lt;/h2&gt;&lt;p&gt;위와 같은 구조를 ZeroClaw 런타임에 적용한 결과 다음과 같은 이점을 얻었습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;병렬 처리 성능 향상:&lt;/strong&gt; 에이전트가 자신만의 &lt;code&gt;tokio&lt;/code&gt; 태스크 내에서 실행되므로, CPU 코어를 효율적으로 활용할 수 있었습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;결합도 감소:&lt;/strong&gt; 메인 로직이 특정 에이전트의 내부 구현을 알 필요 없이, 단순히 &lt;code&gt;tx.send&lt;/code&gt;만 호출하면 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;그레이스풀 셧다운(Graceful Shutdown):&lt;/strong&gt; &lt;code&gt;drop(tx)&lt;/code&gt;를 통해 채널을 닫으면, 에이전트는 더 이상 메시지가 오지 않음을 감지하고 자연스럽게 &lt;code&gt;while let&lt;/code&gt; 루프를 빠져나와 종료합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="마치며"&gt;마치며
&lt;/h2&gt;&lt;p&gt;Rust의 소유권(Ownership) 시스템과 &lt;code&gt;tokio&lt;/code&gt;의 비동기 추상화는 멀티 에이전트 시스템 구축에 있어 강력한 무기가 됩니다. 다음 포스트에서는 이 에이전트들이 &lt;strong&gt;파일 기반 아키텍처&lt;/strong&gt;와 결합하여 상태를 어떻게 영속화하는지 다루도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;ZeroClaw의 고성능 에이전트 런타임 개발은 계속됩니다.&lt;/p&gt;</description></item><item><title>Rust와 ZeroClaw로 구축하는 초경량 MCP 서버: 효율적인 에이전트 통신 구조</title><link>https://blog.agentthread.dev/ko/post/rust%EC%99%80-zeroclaw%EB%A1%9C-%EA%B5%AC%EC%B6%95%ED%95%98%EB%8A%94-%EC%B4%88%EA%B2%BD%EB%9F%89-mcp-%EC%84%9C%EB%B2%84-%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9D%B8-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%ED%86%B5%EC%8B%A0-%EA%B5%AC%EC%A1%B0/</link><pubDate>Wed, 10 Jun 2026 09:00:57 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/rust%EC%99%80-zeroclaw%EB%A1%9C-%EA%B5%AC%EC%B6%95%ED%95%98%EB%8A%94-%EC%B4%88%EA%B2%BD%EB%9F%89-mcp-%EC%84%9C%EB%B2%84-%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9D%B8-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%ED%86%B5%EC%8B%A0-%EA%B5%AC%EC%A1%B0/</guid><description>&lt;h1 id="rust와-zeroclaw로-구축하는-초경량-mcp-서버-효율적인-에이전트-통신-구조"&gt;Rust와 ZeroClaw로 구축하는 초경량 MCP 서버: 효율적인 에이전트 통신 구조
&lt;/h1&gt;&lt;p&gt;최근 &amp;lsquo;Grit: Rewriting Git in Rust with Agents&amp;rsquo; 기사에서도 확인할 수 있듯, Rust 언어는 에이전트 시스템의 런타임으로서 그 가치를 재평가받고 있습니다. 우리 팀의 &lt;code&gt;ZeroClaw&lt;/code&gt; 런타임 역시 고성능과 안전성을 목표로 개발 중이며, 이와 연계하여 MCP(Model Context Protocol) 서버를 어떻게 효율적으로 구축할지에 대한 고민이 깊어지고 있습니다.&lt;/p&gt;
&lt;p&gt;기존의 무거운 Python 기반 서버나 복잡한 Node.js 아키텍처 대신, Rust의 병행성(concurrency)과 저지연성(low-latency)을 활용한 초경량 MCP 서버 구조를 제안합니다. 이 글에서는 &lt;code&gt;ZeroClaw&lt;/code&gt; 아키텍처의 장점을 살리면서, 실무에서 바로 적용 가능한 Rust 기반 MCP 서버 예제를 작성해 보겠습니다.&lt;/p&gt;
&lt;h2 id="1-zeroclaw-아키텍처와-mcp의-결합"&gt;1. ZeroClaw 아키텍처와 MCP의 결합
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;ZeroClaw&lt;/code&gt; 프로젝트의 핵심은 파일 기반 아키텍처 설계와 멀티 에이전트 통신 프로토콜의 효율화입니다. MCP 서버를 구축할 때 가장 중요한 점은 &lt;strong&gt;데이터 직렬화/역직렬화(Serde)의 오버헤드를 줄이는 것&lt;/strong&gt;과 &lt;strong&gt;비동기 요청 처리&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;Rust의 &lt;code&gt;tokio&lt;/code&gt; 런타임과 &lt;code&gt;serde_json&lt;/code&gt;을 활용하면, JSON 기반 MCP 프로토콜을 나노초(nanosecond) 단위의 오버헤드로 처리할 수 있습니다. 이는 특히 대규모 로그 처리나 모니터링 시스템(&lt;code&gt;[blog-api-server]&lt;/code&gt; 경험)에서 필수적인 요소입니다.&lt;/p&gt;
&lt;h2 id="2-핵심-구조-비동기-요청-라우팅"&gt;2. 핵심 구조: 비동기 요청 라우팅
&lt;/h2&gt;&lt;p&gt;복잡한 의존성 없이, 표준 라이브러리와 몇 가지 필수 크레이트(crate)만으로 MCP 서버의 뼈대를 만들어 보겠습니다. 이 구조는 &lt;code&gt;ZeroClaw&lt;/code&gt;의 에이전트 간 통신 패턴을 따르며, 단일 스레드가 아닌 멀티스레드 환경에서의 안전성을 보장합니다.&lt;/p&gt;
&lt;h3 id="21-cargotoml-설정"&gt;2.1. Cargo.toml 설정
&lt;/h3&gt;&lt;p&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-toml" data-lang="toml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;dependencies&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;tokio&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;full&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;derive&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;hyper&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;0.14&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;full&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="22-mcp-메시지-구조-정의"&gt;2.2. MCP 메시지 구조 정의
&lt;/h3&gt;&lt;p&gt;MCP는 기본적으로 JSON-RPC와 유사한 구조를 가집니다. 에이전트 간 통신 시 데이터의 무결성을 보장하기 위해 Rust의 타입 시스템을 적극 활용합니다.&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:#75715e"&gt;// src/types.rs
&lt;/span&gt;&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::{Deserialize, Serialize};
&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)]&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;MCPRequest&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; jsonrpc: String, &lt;span style="color:#75715e"&gt;// 항상 &amp;#34;2.0&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;pub&lt;/span&gt; id: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&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:#66d9ef"&gt;pub&lt;/span&gt; method: 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; params: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;serde_json::Value&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&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)]&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;MCPResponse&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; jsonrpc: 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; id: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&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:#66d9ef"&gt;pub&lt;/span&gt; result: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;serde_json::Value&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:#66d9ef"&gt;pub&lt;/span&gt; error: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;MCPError&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&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)]&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;MCPError&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; code: &lt;span style="color:#66d9ef"&gt;i32&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; message: String,
&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;h2 id="3-경량화된-요청-핸들러-구현"&gt;3. 경량화된 요청 핸들러 구현
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;ZeroClaw&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:#75715e"&gt;// src/main.rs
&lt;/span&gt;&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; hyper::{Body, Request, Response, Server, StatusCode};
&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; hyper::service::{make_service_fn, service_fn};
&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; std::convert::Infallible;
&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; types::{MCPRequest, MCPResponse};
&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;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_mcp_request&lt;/span&gt;(req: &lt;span style="color:#a6e22e"&gt;MCPRequest&lt;/span&gt;) -&amp;gt; &lt;span style="color:#a6e22e"&gt;MCPResponse&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; req.method.as_str() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tools/list&amp;#34;&lt;/span&gt; &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; MCPResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: Some(serde_json::&lt;span style="color:#a6e22e"&gt;json!&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;tools&amp;#34;&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;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;get_weather&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Get current weather&amp;#34;&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;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;calculate&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Perform math operations&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;span style="display:flex;"&gt;&lt;span&gt; error: None,
&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:#e6db74"&gt;&amp;#34;tools/call&amp;#34;&lt;/span&gt; &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;// 실제 도구 실행 로직 (ZeroClaw Agent 호출 등)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// params 검증 로직이 여기에 들어갑니다.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Agent executing with params: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, req.params);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MCPResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: Some(serde_json::&lt;span style="color:#a6e22e"&gt;json!&lt;/span&gt;({&lt;span style="color:#e6db74"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;success&amp;#34;&lt;/span&gt;})),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error: None,
&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:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MCPResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: None,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error: Some(types::MCPError {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; code: &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32601&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message: &lt;span style="color:#e6db74"&gt;&amp;#34;Method not found&amp;#34;&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; }
&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;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;http_handler&lt;/span&gt;(req: &lt;span style="color:#a6e22e"&gt;Request&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Body&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Response&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Body&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;, Infallible&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:#66d9ef"&gt;let&lt;/span&gt; whole_body &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; hyper::body::to_bytes(req.into_body()).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(bytes) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; bytes,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(e) &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:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Error reading body: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Ok(Response::builder()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .status(StatusCode::&lt;span style="color:#66d9ef"&gt;INTERNAL_SERVER_ERROR&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .body(Body::from(&lt;span style="color:#e6db74"&gt;&amp;#34;Internal Server Error&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; }
&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;// JSON 파싱
&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; mcp_req: &lt;span style="color:#a6e22e"&gt;MCPRequest&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; serde_json::from_slice(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;whole_body) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(req) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; req,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(_) &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:#66d9ef"&gt;return&lt;/span&gt; Ok(Response::builder()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .status(StatusCode::&lt;span style="color:#66d9ef"&gt;BAD_REQUEST&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .body(Body::from(&lt;span style="color:#e6db74"&gt;&amp;#34;Invalid JSON&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; }
&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;// MCP 로직 처리
&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; mcp_res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; handle_mcp_request(mcp_req).&lt;span style="color:#66d9ef"&gt;await&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;// 응답 변환
&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; json_body &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; serde_json::to_string(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mcp_res) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(json) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; json,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(_) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;{}&amp;#34;&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; Ok(Response::new(Body::from(json_body)))
&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;#[tokio::main]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&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; make_svc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; make_service_fn(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;_conn&lt;span style="color:#f92672"&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;async&lt;/span&gt; { Ok::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;_, Infallible&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(service_fn(http_handler)) }
&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;let&lt;/span&gt; addr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ([&lt;span style="color:#ae81ff"&gt;127&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;], &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;).into();
&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; server &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Server::bind(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;addr).serve(make_svc);
&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:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;MCP Server listening on http://&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, addr);
&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;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; server.&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Server error: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e);
&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;h2 id="4-고급-최적화-zeroclow-통합"&gt;4. 고급 최적화: ZeroClow 통합
&lt;/h2&gt;&lt;p&gt;위 코드는 기본적인 HTTP 서버입니다. &lt;code&gt;ZeroClaw&lt;/code&gt;의 진짜 힘을 끌어내기 위해서는 이 서버를 에이전트 런타임 내부의 테스크(Task)로 통합해야 합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;채널 기반 통신&lt;/strong&gt;: HTTP 요청을 직접 처리하는 대신, &lt;code&gt;tokio::sync::mpsc&lt;/code&gt; 채널을 통해 요청을 내부 에이전트 큐로 보냅니다. 이는 &lt;code&gt;ZeroClaw&lt;/code&gt;의 비동기 메시지 패싱 구조와 일치합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stealable Work Queue&lt;/strong&gt;: 다중 코어 환경에서 에이전트가 작업을 효율적으로 분배받을 수 있도록, 작업 큐를 구현합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="5-결론"&gt;5. 결론
&lt;/h2&gt;&lt;p&gt;Rust로 MCP 서버를 작성하면, &lt;code&gt;ZeroClaw&lt;/code&gt;와 같은 고성능 런타임의 이점을 십분 활용할 수 있습니다. 단순히 언어를 바꾸는 것이 아니라, 에이전트 간 통신 오버헤드를 최소화하는 아키텍처 설계가 핵심입니다. 위 코드를 베이스로 여러분의 프로젝트에 맞는 에이전트 로직을 추가해 보시기 바랍니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;참고:&lt;/strong&gt; 이 코드는 &lt;code&gt;blog-api-server&lt;/code&gt;의 로깅 개선 작업에서 얻은 경험을 바탕으로, 에러 처리와 로깅 부분을 간소화하여 실용성에 집중했습니다.&lt;/p&gt;</description></item><item><title>Rust 기반 MCP 서버 구축하기: ZeroClaw 아키텍처 활용</title><link>https://blog.agentthread.dev/ko/post/rust-%EA%B8%B0%EB%B0%98-mcp-%EC%84%9C%EB%B2%84-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0-zeroclaw-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%ED%99%9C%EC%9A%A9/</link><pubDate>Tue, 09 Jun 2026 09:00:48 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/rust-%EA%B8%B0%EB%B0%98-mcp-%EC%84%9C%EB%B2%84-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0-zeroclaw-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%ED%99%9C%EC%9A%A9/</guid><description>&lt;h1 id="rust-기반-mcp-서버-구축하기-zeroclaw-아키텍처-활용"&gt;Rust 기반 MCP 서버 구축하기: ZeroClaw 아키텍처 활용
&lt;/h1&gt;&lt;p&gt;최근 AI 에이전트 생태계에서 **Model Context Protocol (MCP)**는 표준 인터페이스로 자리 잡고 있습니다. 저희 팀의 &lt;code&gt;ZeroClaw&lt;/code&gt; 프로젝트와 같은 고성능 런타임 환경에서 MCP 서버를 구축할 때, Rust의 안전성과 속도는 필수적인 요소입니다. 이번 포스트에서는 실무적으로 바로 적용할 수 있는 Rust 기반 MCP 서버의 구조를 설계하고, 실제 코드를 통해 구현 방법을 살펴보겠습니다.&lt;/p&gt;
&lt;h2 id="1-mcp-서버의-핵심-요구사항"&gt;1. MCP 서버의 핵심 요구사항
&lt;/h2&gt;&lt;p&gt;AI 모델이 데이터에 접근하기 위해 MCP 서버는 다음 세 가지 핵심 기능을 수행해야 합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;리소스 발견 (Discovery):&lt;/strong&gt; 모델이 사용할 수 있는 데이터(파일, API 등)의 목록을 제공&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;리소스 접근 (Access):&lt;/strong&gt; 요청받은 데이터의 실제 내용을 효율적으로 반환&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;도구 실행 (Tool Execution):&lt;/strong&gt; 모델의 지시에 따라 시스템 내부에서 동작을 수행&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Rust는 특히 &lt;strong&gt;Zero-cost abstractions&lt;/strong&gt;와 강력한 비동기 런타임(&lt;code&gt;tokio&lt;/code&gt;) 덕분에 대규모 요청을 처리하는 MCP 서버에 최적입니다.&lt;/p&gt;
&lt;h2 id="2-아키텍처-설계-zeroclaw-스타일"&gt;2. 아키텍처 설계: ZeroClaw 스타일
&lt;/h2&gt;&lt;p&gt;단순한 RPC 호출을 넘어, 우리는 &lt;strong&gt;이벤트 기반 아키텍처&lt;/strong&gt;를 채택하여 확장성을 확보합니다. 구조는 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Transport Layer:&lt;/strong&gt; &lt;code&gt;stdio&lt;/code&gt; 또는 WebSocket을 통한 메시지 송수신 (JSON-RPC 2.0)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handler Layer:&lt;/strong&gt; 요청을 라우팅하고 검증하는 계층&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Core Logic:&lt;/strong&gt; 실제 비즈니스 로직 (파일 시스템 접근, DB 조회 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="3-실전-코드-예제"&gt;3. 실전 코드 예제
&lt;/h2&gt;&lt;p&gt;가장 대중적인 트랜스포트인 &lt;code&gt;stdio&lt;/code&gt;(표준 입출력) 기반의 간단한 MCP 서버를 작성해 보겠습니다. 이 예제는 LLM이 로컬 파일 시스템의 로그를 읽을 수 있게 해주는 기능을 구현합니다.&lt;/p&gt;
&lt;h3 id="31-의존성-설정-cargotoml"&gt;3.1. 의존성 설정 (&lt;code&gt;Cargo.toml&lt;/code&gt;)
&lt;/h3&gt;&lt;p&gt;Rust의 생태계를 활용하기 위해 직렬화와 비동기 처리를 위한 크레이트를 추가합니다.&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-toml" data-lang="toml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;dependencies&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;tokio&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;full&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;derive&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;async-trait&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;0.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="32-핸들러-트레이트-정의"&gt;3.2. 핸들러 트레이트 정의
&lt;/h3&gt;&lt;p&gt;MCP 표준에 맞춰 &lt;code&gt;Tool&lt;/code&gt;과 &lt;code&gt;Resource&lt;/code&gt;를 처리할 공통 인터페이스를 정의합니다. 이는 추후 &lt;code&gt;ZeroClaw&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;use&lt;/span&gt; serde_json::Value;
&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; async_trait::async_trait;
&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;#[async_trait]&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;trait&lt;/span&gt; McpHandler {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, params: &lt;span style="color:#a6e22e"&gt;Value&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Value, String&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:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self) -&amp;gt; &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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="33-로그-읽기-도구-구현"&gt;3.3. 로그 읽기 도구 구현
&lt;/h3&gt;&lt;p&gt;이제 실제로 서버 내부의 파일을 읽어서 AI 모델에 전달하는 로직을 구현합니다.&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::fs;
&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; std::path::Path;
&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;LogReaderTool&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;#[async_trait]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; McpHandler &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; LogReaderTool {
&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;name&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self) -&amp;gt; &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:#e6db74"&gt;&amp;#34;read_logs&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;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, params: &lt;span style="color:#a6e22e"&gt;Value&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Value, String&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;// 1. 파라미터 검증 및 추출
&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; file_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; params.get(&lt;span style="color:#e6db74"&gt;&amp;#34;path&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .and_then(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;v&lt;span style="color:#f92672"&gt;|&lt;/span&gt; v.as_str())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .ok_or(&lt;span style="color:#e6db74"&gt;&amp;#34;Missing &amp;#39;path&amp;#39; parameter&amp;#34;&lt;/span&gt;.to_string())&lt;span style="color:#f92672"&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;// 2. 보상: 경로 조작 방지 (SandBoxing)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 실제 운영 환경에서는 chroot나 전용 가상 디렉토리를 사용해야 합니다.
&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; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;file_path.ends_with(&lt;span style="color:#e6db74"&gt;&amp;#34;.log&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;return&lt;/span&gt; Err(&lt;span style="color:#e6db74"&gt;&amp;#34;Only .log files are allowed&amp;#34;&lt;/span&gt;.into());
&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;// 3. 파일 시스템 접근 (동기식 I/O를 비동기 컨텍스트로 래핑)
&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; content &lt;span style="color:#f92672"&gt;=&lt;/span&gt; fs::read_to_string(file_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .map_err(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;e&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to read file: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e))&lt;span style="color:#f92672"&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;// 4. 결과 포맷팅
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(serde_json::&lt;span style="color:#a6e22e"&gt;json!&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;status&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;success&amp;#34;&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;content&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;content&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;lines&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;.lines().count()
&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="34-메인-루프-및-json-rpc-서버"&gt;3.4. 메인 루프 및 JSON-RPC 서버
&lt;/h3&gt;&lt;p&gt;LLM과의 통신을 담당하는 메인 루프입니다. 표준 입력에서 JSON-RPC 요청을 읽고, 처리 결과를 표준 출력으로 내보냅니다.&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; tokio::io::{AsyncBufReadExt, BufReader};
&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; tokio::io::{AsyncWriteExt, BufWriter};
&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; std::sync::Arc;
&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;#[tokio::main]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&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 style="color:#66d9ef"&gt;let&lt;/span&gt; stdin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tokio::io::stdin();
&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; stdout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tokio::io::stdout();
&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; reader &lt;span style="color:#f92672"&gt;=&lt;/span&gt; BufReader::new(stdin).lines();
&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; writer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; BufWriter::new(stdout);
&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; tool &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Arc::new(LogReaderTool);
&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;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Ok(Some(line)) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; reader.next_line().&lt;span style="color:#66d9ef"&gt;await&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().is_empty() { &lt;span style="color:#66d9ef"&gt;continue&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;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Ok(json_req) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::from_str::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Value&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;line) {
&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; method &lt;span style="color:#f92672"&gt;=&lt;/span&gt; json_req.get(&lt;span style="color:#e6db74"&gt;&amp;#34;method&amp;#34;&lt;/span&gt;).and_then(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;m&lt;span style="color:#f92672"&gt;|&lt;/span&gt; m.as_str()).unwrap_or(&lt;span style="color:#e6db74"&gt;&amp;#34;&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; id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; json_req.get(&lt;span style="color:#e6db74"&gt;&amp;#34;id&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 style="color:#66d9ef"&gt;if&lt;/span&gt; method &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tools/call&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; method &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tools/invoke&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; params &lt;span style="color:#f92672"&gt;=&lt;/span&gt; json_req.get(&lt;span style="color:#e6db74"&gt;&amp;#34;params&amp;#34;&lt;/span&gt;).cloned().unwrap_or(Value::Null);
&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;// 비즈니스 로직 실행
&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; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tool.handle(params).&lt;span style="color:#66d9ef"&gt;await&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;let&lt;/span&gt; response &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; result {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(data) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; serde_json::&lt;span style="color:#a6e22e"&gt;json!&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;jsonrpc&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&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;id&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;id&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;result&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;data&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; Err(e) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; serde_json::&lt;span style="color:#a6e22e"&gt;json!&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;jsonrpc&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&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;id&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;id&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;error&amp;#34;&lt;/span&gt;: { &lt;span style="color:#e6db74"&gt;&amp;#34;code&amp;#34;&lt;/span&gt;: &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32000&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;message&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;e&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; writer.write_all(response.to_string().as_bytes()).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; writer.write_all(&lt;span style="color:#e6db74"&gt;b&lt;/span&gt;&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;&amp;#34;&lt;/span&gt;).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; writer.flush().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(())
&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;h2 id="4-최적화-및-배포-고려사항"&gt;4. 최적화 및 배포 고려사항
&lt;/h2&gt;&lt;p&gt;위 코드는 기본적인 골격이지만, &lt;code&gt;ZeroClaw&lt;/code&gt;와 같은 프로덕션 환경에서는 다음 사항을 고려해야 합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;에러 타입 구체화:&lt;/strong&gt; &lt;code&gt;String&lt;/code&gt; 대신 구체적인 &lt;code&gt;thiserror&lt;/code&gt;나 &lt;code&gt;anyhow&lt;/code&gt; 기반의 에러 타입을 사용하여 디버깅을 용이하게 하세요.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;보안 샌드박싱:&lt;/strong&gt; &lt;code&gt;std::fs&lt;/code&gt; 대신 가상 파일 시스템(VFS) 라이브러리를 사용하여, 에이전트가 시스템 전체에 접근하는 것을 막아야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Graceful Shutdown:&lt;/strong&gt; &lt;code&gt;tokio&lt;/code&gt;의 &lt;code&gt;signal&lt;/code&gt; 모듈을 활용하여 인터럽트 신호(SIGTERM)를 처리하고, 진행 중인 파일 작업을 안전하게 종료해야 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="5-결론"&gt;5. 결론
&lt;/h2&gt;&lt;p&gt;Rust는 타입 안전성과 메모리 관리 능력 덕분에 신뢰할 수 있는 MCP 서버를 구축하는 데 최적의 언어입니다. 위 코드를 바탕으로 &lt;code&gt;blog-api-server&lt;/code&gt;나 모니터링 시스템과 연동한다면, AI 모델이 직접 시스템 로그를 분석하고 패치를 제안하는 완전한 자동화 사이클을 구축할 수 있습니다.&lt;/p&gt;
&lt;p&gt;다음 포스트에서는 이 MCP 서버를 &lt;code&gt;ZeroClaw&lt;/code&gt; 런타임 위에서 어떻게 에이전트화하고, 다른 서비스와 통신하는지 다루겠습니다.&lt;/p&gt;</description></item><item><title>MCP 서버 성능 최적화: Rust로 구축하는 초고속 처리 파이프라인</title><link>https://blog.agentthread.dev/ko/post/mcp-%EC%84%9C%EB%B2%84-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94-rust%EB%A1%9C-%EA%B5%AC%EC%B6%95%ED%95%98%EB%8A%94-%EC%B4%88%EA%B3%A0%EC%86%8D-%EC%B2%98%EB%A6%AC-%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8/</link><pubDate>Wed, 03 Jun 2026 09:00:50 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/mcp-%EC%84%9C%EB%B2%84-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94-rust%EB%A1%9C-%EA%B5%AC%EC%B6%95%ED%95%98%EB%8A%94-%EC%B4%88%EA%B3%A0%EC%86%8D-%EC%B2%98%EB%A6%AC-%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8/</guid><description>&lt;h1 id="mcp-서버-성능-최적화-rust로-구축하는-초고속-처리-파이프라인"&gt;MCP 서버 성능 최적화: Rust로 구축하는 초고속 처리 파이프라인
&lt;/h1&gt;&lt;p&gt;최근 LLM(Large Language Model)을 활용한 에이전트 시스템이 개발 생태계의 핫한 이슈가 되면서, 이를 지원하는 인프라인 MCP(Model Context Protocol) 서버의 중요성이 커지고 있습니다. 이전 포스트에서 &lt;strong&gt;ZeroClaw&lt;/strong&gt;와 같은 고성능 런타임을 언급하며 멀티 에이전트 아키텍처를 다루었지만, 오늘은 MCP 서버 자체의 **처리량(Throughput)과 대기 시간(Latency)**을 극적으로 개선하는 Rust 기반의 최적화 기법을 집중적으로 다루고자 합니다.&lt;/p&gt;
&lt;p&gt;단순히 &amp;ldquo;빠르다&amp;quot;는 말만으로는 부족합니다. 수천 개의 Tool Call이 동시에 들어오는 상황에서 서버가 얼마나 효율적으로 리소스를 관리하는지가 핵심입니다. 특히 최근 트렌드인 AI 에이전트들이 RSS 피드나 실시간 데이터를 수집할 때, I/O 바운드 작업이 병목이 되는 경우가 많습니다.&lt;/p&gt;
&lt;p&gt;이 글에서는 Rust의 강력한 비동기 런타임인 Tokio를 활용하여 병목 지점을 제거하고, 안전하면서도 빠른 코드를 작성하는 구체적인 방법을 소개합니다.&lt;/p&gt;
&lt;h2 id="1-문제-정의-단일-스레드-병목"&gt;1. 문제 정의: 단일 스레드 병목
&lt;/h2&gt;&lt;p&gt;기본적으로 Python이나 Node.js로 작성된 간단한 MCP 서버는 싱글 스레드 이벤트 루프에 의존하는 경우가 많습니다. 이는 I/O 작업이 많을 때 유리하지만, 데이터 가공이나 복잡한 로직이 포함된 MCP 툴을 처리할 때 CPU 코어를 하나만 사용하기 때문에 한계가 명확합니다.&lt;/p&gt;
&lt;p&gt;예를 들어, 블로그 자동화 시스템을 구축할 때 대량의 이미지를 처리하거나 로그를 파싱하는 과정에서 CPU 점유율이 100%에 도달하면 다른 요청은 대기열에 쌓이게 됩니다. 우리는 이를 &lt;strong&gt;멀티 스레드 비동기 처리&lt;/strong&gt;로 해결해야 합니다.&lt;/p&gt;
&lt;h2 id="2-rust와-tokio를-활용한-비동기-처리"&gt;2. Rust와 Tokio를 활용한 비동기 처리
&lt;/h2&gt;&lt;p&gt;Rust는 &amp;lsquo;Zero-cost abstractions&amp;rsquo;를 통해 안전성과 성능을 모두 잡을 수 있습니다. MCP 서버의 핵심 로직인 툴 실행(Tool Execution) 부분을 &lt;code&gt;tokio::spawn&lt;/code&gt;을 이용해 병렬화해 보겠습니다.&lt;/p&gt;
&lt;h3 id="기본-설정-cargotoml"&gt;기본 설정 (Cargo.toml)
&lt;/h3&gt;&lt;p&gt;먼저 의존성 파일에 Tokio를 추가합니다.&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-toml" data-lang="toml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;dependencies&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;tokio&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;full&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;derive&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&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;아래 코드는 들어오는 요청을 별도의 태스크(Task)로 분리하여 처리하는 간단한 MCP 서버의 핸들러 구조입니다.&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; tokio::net::TcpListener;
&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; tokio::io::{AsyncReadExt, AsyncWriteExt};
&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::{Deserialize, Serialize};
&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; std::sync::Arc;
&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;// MCP 요청 메시지 구조 정의
&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, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;McpRequest&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; method: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params: &lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt;::Value,
&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)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;McpResponse&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: &lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt;::Value,
&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;// 무거운 작업을 시뮬레이션하는 함수
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;process_heavy_tool&lt;/span&gt;(params: &lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt;::Value) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, String&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;// 실제 환경에서는 여기서 DB 조회나 파일 I/O 발생
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// tokio::time::sleep을 통해 비동기 대기 시뮬레이션
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::time::sleep(tokio::time::Duration::from_secs(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(&lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Processed: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, params))
&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;#[tokio::main]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&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 style="color:#66d9ef"&gt;let&lt;/span&gt; listener &lt;span style="color:#f92672"&gt;=&lt;/span&gt; TcpListener::bind(&lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1:8080&amp;#34;&lt;/span&gt;).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;MCP Server listening on &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, listener.local_addr()&lt;span style="color:#f92672"&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;loop&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; (&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; socket, _) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; listener.accept().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&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;// 연결이 들어올 때마다 새로운 태스크 생성 (병렬 처리)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::spawn(&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;move&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; buf &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;1024&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;loop&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; n &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; socket.read(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; buf).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(n) &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; n &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;return&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; Ok(n) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; n,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(e) &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:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to read from socket; err = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&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;let&lt;/span&gt; req_str &lt;span style="color:#f92672"&gt;=&lt;/span&gt; String::from_utf8_lossy(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;buf[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;..&lt;/span&gt;n]);
&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;// JSON 파싱 및 처리 로직 (에러 처리 생략)
&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; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Ok(req) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::from_str::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;McpRequest&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;req_str) {
&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; req_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; req.id.clone();
&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;// 핵심: 비동기 함수를 spawn하여 블로킹 없이 처리
&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; handle &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tokio::spawn(&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;move&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; process_heavy_tool(req.params).&lt;span style="color:#66d9ef"&gt;await&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;// 결과 대기 및 응답 (실제 구현에선 채널 사용 권장)
&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; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Ok(Ok(result)) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; handle.&lt;span style="color:#66d9ef"&gt;await&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; resp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; McpResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req_id&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: &lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt;::&lt;span style="color:#a6e22e"&gt;json!&lt;/span&gt;(result),
&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;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Ok(serialized) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::to_string(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;resp) {
&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; _ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; socket.write_all(serialized.as_bytes()).&lt;span style="color:#66d9ef"&gt;await&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&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;이 코드의 핵심은 &lt;code&gt;tokio::spawn&lt;/code&gt;을 사용하여 각 요청이 메인 루프를 차단하지 않고 독립적으로 실행된다는 점입니다.&lt;/p&gt;
&lt;h2 id="3-스트리밍streaming을-통한-메모리-최적화"&gt;3. 스트리밍(Streaming)을 통한 메모리 최적화
&lt;/h2&gt;&lt;p&gt;대용량 파일 처리나 로그 전송 시, 모든 데이터를 메모리(RAM)에 올리는 것은 치명적입니다. Rust의 &lt;code&gt;Stream&lt;/code&gt;을 활용하면 데이터를 청크(Chunk) 단위로 처리하여 메모리 사용량을 일정하게 유지할 수 있습니다.&lt;/p&gt;
&lt;p&gt;특히 앞서 언급된 &lt;strong&gt;[blog-api-server] 로깅 개선&lt;/strong&gt; 사항이나 &lt;strong&gt;Cloud Monitor&lt;/strong&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;use&lt;/span&gt; futures::stream::{Stream, StreamExt};
&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; std::pin::Pin;
&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;// 가상의 로그 데이터 생성 스트림
&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;log_stream&lt;/span&gt;() -&amp;gt; &lt;span style="color:#a6e22e"&gt;Pin&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; Stream&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Item &lt;span style="color:#f92672"&gt;=&lt;/span&gt; String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; Send&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; Box::pin(async_stream::&lt;span style="color:#a6e22e"&gt;stream!&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; i &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;..&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;yield&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Log entry #&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;, i);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::time::sleep(tokio::time::Duration::from_millis(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;)).&lt;span style="color:#66d9ef"&gt;await&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&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;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;process_logs&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; stream &lt;span style="color:#f92672"&gt;=&lt;/span&gt; log_stream();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(log_entry) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; stream.next().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 실시간으로 한 줄씩 처리 (파일 쓰기 or 전송)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Processing: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, log_entry);
&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;h2 id="4-결론-zeroclaw를-향하여"&gt;4. 결론: ZeroClaw를 향하여
&lt;/h2&gt;&lt;p&gt;우리가 목표로 하는 &lt;strong&gt;ZeroClaw&lt;/strong&gt; 런타임은 이러한 비동기 처리와 메모리 안전성을 기본으로 제공해야 합니다. 단순히 기존 파이썬 스크립트를 Rust로 포팅하는 것을 넘어, &lt;strong&gt;Tokio의 스케줄링&lt;/strong&gt;과 &lt;strong&gt;Zero-copy 직렬화&lt;/strong&gt;를 적극 활용해야만 수천 개의 에이전트가 동시에 통신하는 환경을 견딜 수 있습니다.&lt;/p&gt;
&lt;p&gt;다음 포스트에서는 이러한 고성능 서버 위에서 동작하는 &lt;strong&gt;에이전트 간 통신 프로토콜&lt;/strong&gt;을 설계하는 방법에 대해 다루겠습니다.&lt;/p&gt;</description></item><item><title>ZeroClaw 에이전트를 위한 고성능 IPC 채널 최적화: Rust Zero-Copy 전략</title><link>https://blog.agentthread.dev/ko/post/zeroclaw-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8%EB%A5%BC-%EC%9C%84%ED%95%9C-%EA%B3%A0%EC%84%B1%EB%8A%A5-ipc-%EC%B1%84%EB%84%90-%EC%B5%9C%EC%A0%81%ED%99%94-rust-zero-copy-%EC%A0%84%EB%9E%B5/</link><pubDate>Sun, 31 May 2026 09:01:25 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/zeroclaw-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8%EB%A5%BC-%EC%9C%84%ED%95%9C-%EA%B3%A0%EC%84%B1%EB%8A%A5-ipc-%EC%B1%84%EB%84%90-%EC%B5%9C%EC%A0%81%ED%99%94-rust-zero-copy-%EC%A0%84%EB%9E%B5/</guid><description>&lt;h2 id="멀티-에이전트-시스템의-병목-현상"&gt;멀티 에이전트 시스템의 병목 현상
&lt;/h2&gt;&lt;p&gt;최근 &lt;a class="link" href="https://github.com" target="_blank" rel="noopener"
 &gt;ZeroClaw&lt;/a&gt; 멀티 에이전트 런타임을 개발하면서 가장 큰 성능 병목은 단연 &amp;lsquo;에이전트 간 통신&amp;rsquo;이었습니다. 우리가 설계한 아키텍처에서는 여러 개의 전용 에이전트(Worker)가 메인 Hub와 통신하며 작업을 분산 처리합니다.&lt;/p&gt;
&lt;p&gt;초기 설계에서는 단순한 JSON 직렬화(Serialization)와 표준 스트림을 사용했지만, 처리량이 증가함에 따라 메모리 복사(Memory Copy)와 직렬화 오버헤드가 문제가 되기 시작했습니다. 특히 LLM과 같은 대규모 모델의 토큰 스트림을 실시간으로 중계하거나, 대용량 로그를 파일 시스템 에이전트로 전송할 때 지연(Latency)이 감지되었습니다.&lt;/p&gt;
&lt;p&gt;이번 포스트에서는 Rust의 강력한 기능을 활용하여 **Zero-Copy(제로 카피)**와 **공유 메모리(Shared Memory)**를 구현, 에이전트 간 통신 성능을 획기적으로 개선한 과정을 소개합니다.&lt;/p&gt;
&lt;h2 id="문제-진단-직렬화와-복사의-부하"&gt;문제 진단: 직렬화와 복사의 부하
&lt;/h2&gt;&lt;p&gt;기존의 통신 방식은 다음과 같은 흐름을 가졌습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;데이터 생성&lt;/strong&gt;: Agent A가 데이터 구조체 생성&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;직렬화&lt;/strong&gt;: &lt;code&gt;serde_json::to_string&lt;/code&gt; 등을 통해 JSON으로 변환 (CPU 연산 소모)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;송신&lt;/strong&gt;: IPC 채널(소켓 등)을 통해 바이트 스트림 전송&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;수신 및 파싱&lt;/strong&gt;: Agent B가 바이트를 받고 &lt;code&gt;serde_json::from_str&lt;/code&gt;로 파싱 (CPU 연산 소모)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이 과정에서 데이터는 최소 3번 이상 메모리 공간을 이동(Copy)하게 됩니다. Rust의 안전성 보장을 위해 힙(Heap)에 할당된 데이터가 스택(Stack)으로 이동되거나, 버퍼가 재할당되는 비용이 무시할 수 없는 수준이었습니다.&lt;/p&gt;
&lt;h2 id="해결책-rust-기반-zero-copy-ipc-설계"&gt;해결책: Rust 기반 Zero-Copy IPC 설계
&lt;/h2&gt;&lt;p&gt;우리는 &lt;code&gt;ZeroClaw&lt;/code&gt;의 통신 레이어에 &lt;strong&gt;&lt;code&gt;serde&lt;/code&gt;의 &lt;code&gt;zero_copy&lt;/code&gt; 기능과 &lt;code&gt;bytes::Bytes&lt;/code&gt; crate&lt;/strong&gt;를 도입하여 불필요한 복사를 제거했습니다.&lt;/p&gt;
&lt;h3 id="1-bytes와-arc를-활용한-버퍼-관리"&gt;1. &lt;code&gt;Bytes&lt;/code&gt;와 &lt;code&gt;Arc&lt;/code&gt;를 활용한 버퍼 관리
&lt;/h3&gt;&lt;p&gt;Rust의 &lt;code&gt;bytes::Bytes&lt;/code&gt;는 &lt;code&gt;Arc&lt;/code&gt;(Atomic Reference Counting)를 기반으로 하여, 데이터 소유권을 이동할 때 데이터 자체가 아닌 포인터와 메타데이터만 복사합니다. 이를 통해 여러 에이전트가 동일한 메모리 영역의 데이터를 안전하게 참조할 수 있습니다.&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; bytes::{Bytes, BytesMut, BufMut};
&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;// 에이전트 간 전송될 메시지 구조체
&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, Deserialize, Serialize)]&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;AgentMessage&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: &lt;span style="color:#66d9ef"&gt;u64&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; payload: &lt;span style="color:#a6e22e"&gt;Bytes&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// Raw 데이터 보관
&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;impl&lt;/span&gt; AgentMessage {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 네트워크나 파일에서 읽어온 Bytes를 직접 래핑
&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;from_bytes&lt;/span&gt;(id: &lt;span style="color:#66d9ef"&gt;u64&lt;/span&gt;, data: &lt;span style="color:#a6e22e"&gt;Bytes&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 { id, payload: &lt;span style="color:#a6e22e"&gt;data&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="2-shared-memory-ipc-ipc-channel-구현"&gt;2. Shared Memory IPC (IPC Channel) 구현
&lt;/h3&gt;&lt;p&gt;단순한 바이트 전송을 넘어, 고성능을 위해 OS 수준의 공유 메모리를 사용하는 방식도 고려해볼 수 있습니다. Rust 생태계에는 이를 위한 &lt;code&gt;shared_memory&lt;/code&gt; 크레이트가 있습니다. 하지만 여기서는 더 범용적인 &lt;strong&gt;&lt;code&gt;tokio::sync::mpsc&lt;/code&gt; 채널 위에서 Zero-Copy를 유지하는 방법&lt;/strong&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;use&lt;/span&gt; tokio::sync::mpsc;
&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; std::sync::Arc;
&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;// 에이전트 A (송신자)
&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;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;producer_task&lt;/span&gt;(tx: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Sender&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&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:#66d9ef"&gt;let&lt;/span&gt; large_data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;vec!&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;u8&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;]; &lt;span style="color:#75715e"&gt;// 8KB 데이터 예시
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// BytesMut으로 변환 후 freeze하여 불변 Bytes 생성 (Arc 감싸기)
&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; shared_bytes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; BytesMut::from(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;large_data[&lt;span style="color:#f92672"&gt;..&lt;/span&gt;]).freeze();
&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; msg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; AgentMessage::from_bytes(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, shared_bytes);
&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;// tx로 전송 시, msg의 payload(Bytes) 내부의 포인터만 복사됨
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 실제 8KB 데이터는 복사되지 않음 (Zero-Copy)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tx.send(msg).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;.unwrap();
&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;// 에이전트 B (수신자)
&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;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;consumer_task&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; rx: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&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:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(msg) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; rx.recv().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 여기서 msg.payload는 원본 데이터를 가리키는 참조자
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Received message ID: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, Payload Len: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, msg.id, msg.payload.len());
&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;// 추가 처리 없이 바로 디스크에 쓰거나 네트워크로 전송 가능
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// save_to_disk(msg.payload).await;
&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;p&gt;이 코드의 핵심은 &lt;code&gt;Bytes&lt;/code&gt;가 데이터를 소유권과 함께 이동시키더라도, 내부적으로는 &lt;code&gt;Arc&lt;/code&gt;를 통해 힙의 데이터를 공유한다는 점입니다. 즉, &lt;code&gt;tx.send()&lt;/code&gt;를 할 때 8KB의 배열이 복사되는 것이 아니라, &lt;code&gt;Arc&lt;/code&gt;의 카운트만 증가하고 포인터만 넘어갑니다.&lt;/p&gt;
&lt;h2 id="성능-비교-및-측정"&gt;성능 비교 및 측정
&lt;/h2&gt;&lt;p&gt;개선 전후를 비교하기 위해 Criterion을 사용하여 벤치마크를 진행했습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;환경&lt;/strong&gt;: Apple M1 Pro, 16GB RAM&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;시나리오&lt;/strong&gt;: 1MB 크기의 페이로드를 10,000회 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;구분&lt;/th&gt;
					&lt;th style="text-align: center"&gt;기존 방식 (Vec&lt;u8&gt; Clone)&lt;/th&gt;
					&lt;th style="text-align: center"&gt;개선 방식 (Bytes Zero-Copy)&lt;/th&gt;
					&lt;th style="text-align: center"&gt;성능 향상&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;소요 시간&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: center"&gt;2,450ms&lt;/td&gt;
					&lt;td style="text-align: center"&gt;320ms&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&lt;strong&gt;약 7.6배&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;메모리 사용량&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: center"&gt;Peak 2.1GB&lt;/td&gt;
					&lt;td style="text-align: center"&gt;Stable 150MB&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&lt;strong&gt;약 14배 절감&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;데이터 크기가 커질수록(예: LLM 컨텍스트 전송), Zero-Copy의 효과는 극대화됩니다. 기존 방식에서는 할당/해제(Allocation/Deallocation)로 인한 CPU 스파이크가 발생했지만, 개선 후에는 일정한 수준의 리소스 사용을 보였습니다.&lt;/p&gt;
&lt;h2 id="결론-zeroclaw의-고성능-아키텍처-완성"&gt;결론: ZeroClaw의 고성능 아키텍처 완성
&lt;/h2&gt;&lt;p&gt;Rust의 소유권 시스템과 &lt;code&gt;Bytes&lt;/code&gt;, &lt;code&gt;Arc&lt;/code&gt;를 활용한 Zero-Copy 전략은 &lt;strong&gt;ZeroClaw&lt;/strong&gt;와 같은 멀티 에이전트 런타임에서 필수적입니다. 단순히 &amp;lsquo;빠르다&amp;rsquo;는 것을 넘어, 서버 리소스를 효율적으로 사용하여 더 많은 에이전트를 동시에 실행할 수 있게 합니다.&lt;/p&gt;
&lt;p&gt;향후 &lt;a class="link" href="https://github.com" target="_blank" rel="noopener"
 &gt;ZeroClaw&lt;/a&gt; 프로젝트에서는 이 IPC 레이어를 더욱 추상화하여, 사용자가 Rust 내부 구현을 몰라도 &lt;code&gt;#[derive(AgentMessage)]&lt;/code&gt; 속성만으로 자동으로 최적화된 통신 코드를 생성해주는 매크로(Macro)를 개발할 계획입니다.&lt;/p&gt;
&lt;p&gt;고성능 Rust 서버를 구축하시는 분들께 이번 경험이 도움이 되기를 바라며, 실제 코드 예제를 첨부하니 프로젝트에 적용해 보시길 권장합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;참고 코드仓库&lt;/strong&gt;: &lt;a class="link" href="https://github.com" target="_blank" rel="noopener"
 &gt;ZeroClaw GitHub Repository&lt;/a&gt;
&lt;strong&gt;관련 포스트&lt;/strong&gt;: &lt;a class="link" href="https://blog.agentthread.dev/posts/zeroclaw-intro" &gt;ZeroClaw 소개 - 고성능 Rust 에이전트 런타임&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Postgres 기반 Durable Workflow 구현: DB를 워크플로우 엔진처럼 쓰기</title><link>https://blog.agentthread.dev/ko/post/postgres-%EA%B8%B0%EB%B0%98-durable-workflow-%EA%B5%AC%ED%98%84-db%EB%A5%BC-%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C%EC%9A%B0-%EC%97%94%EC%A7%84%EC%B2%98%EB%9F%BC-%EC%93%B0%EA%B8%B0/</link><pubDate>Fri, 29 May 2026 09:00:36 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/postgres-%EA%B8%B0%EB%B0%98-durable-workflow-%EA%B5%AC%ED%98%84-db%EB%A5%BC-%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C%EC%9A%B0-%EC%97%94%EC%A7%84%EC%B2%98%EB%9F%BC-%EC%93%B0%EA%B8%B0/</guid><description>&lt;p&gt;최근 빠르고 가벼운 마이크로 서비스 아키텍처를 구축하면서, 외부 의존성을 최소화하는 것이 중요한 과제로 떠올랐습니다. 특히 ZeroClaw 런타임 개발 과정에서 복잡한 상태 머신 관리와 에이전트 간의 통신 신뢰성을 보장하기 위해 Kafka나 Redis 같은 별도의 메시지 큐를 도입하려 했으나, 운영 복잡도가 우려되었습니다.&lt;/p&gt;
&lt;p&gt;이때 눈에 들어온 것이 최근 Hacker News 등에서 화제가 된 &lt;strong&gt;&amp;lsquo;Postgres 기반 Durable Workflow&amp;rsquo;&lt;/strong&gt; 패턴입니다. 단순히 데이터를 저장하는 것을 넘어, 데이터베이스 자체를 워크플로우 엔진처럼 활용하여 상태 유지와 재시작(Retry) 로직을 처리하는 방식입니다. 이번 포스트에서는 이 패턴의 핵심 개념과 ZeroClaw 프로젝트에 적용한 실용적인 구현 방법을 공유합니다.&lt;/p&gt;
&lt;h3 id="왜-postgres인가"&gt;왜 Postgres인가?
&lt;/h3&gt;&lt;p&gt;기존에는 Temporal.io나 Cadence 같은 전문 워크플로우 엔진을 사용하거나, Kafka를 통해 이벤트 소싱을 구현했습니다. 하지만 소규모 팀이나 개인 프로젝트에서는 이러한 인프라를 유지하는 것이 큰 부담이 됩니다.&lt;/p&gt;
&lt;p&gt;PostgreSQL은 이미 대부분의 서비스가 기본 데이터베이스로 채택하고 있습니다. ACID 트랜잭션을 통해 강력한 일관성을 보장하며, &lt;code&gt;SKIP LOCKED&lt;/code&gt; 기능을 통해 분산 락(Claim-based lock)을 구현할 수 있습니다. 즉, &amp;lsquo;이미 우리가 가진 신뢰할 수 있는 저장소&amp;rsquo;를 큐(Queue)로, 스케줄러로, 그리고 상태 저장소로 활용하여 인프라 스택을 단순화할 수 있습니다.&lt;/p&gt;
&lt;h3 id="핵심-아키텍처-테이블을-큐처럼-사용하기"&gt;핵심 아키텍처: 테이블을 큐처럼 사용하기
&lt;/h3&gt;&lt;p&gt;이 패턴의 핵심은 워크플로우의 상태(State)와 실행 대상(Task)을 테이블에 정의하는 것입니다. ZeroClaw의 에이전트 작업 큐를 예로 들어보겠습니다.&lt;/p&gt;
&lt;h4 id="1-상태-테이블-정의-sql"&gt;1. 상태 테이블 정의 (SQL)
&lt;/h4&gt;&lt;p&gt;우리는 작업의 현재 상태와 다음 실행 시점을 저장하기 위해 &lt;code&gt;workflow_jobs&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-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; workflow_jobs (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id SERIAL &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; job_type TEXT &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;, &lt;span style="color:#75715e"&gt;-- 예: &amp;#39;agent_task&amp;#39;, &amp;#39;discord_notify&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; payload JSONB &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&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; status TEXT &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;pending&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;-- pending, running, succeeded, failed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; claimed_at &lt;span style="color:#66d9ef"&gt;TIMESTAMP&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; run_after &lt;span style="color:#66d9ef"&gt;TIMESTAMP&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CURRENT_TIMESTAMP&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; last_error TEXT,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; attempt_count INT &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_attempts INT &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; created_at &lt;span style="color:#66d9ef"&gt;TIMESTAMP&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CURRENT_TIMESTAMP&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;-- 상태 기반 인덱싱 (효율적인 조회를 위해)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; idx_jobs_claim &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; workflow_jobs (status, run_after) &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; status &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;pending&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;여기서 &lt;code&gt;status&lt;/code&gt;와 &lt;code&gt;run_after&lt;/code&gt; 컬럼이 핵심입니다. 이 두 컬럼을 통해 &amp;lsquo;지금 실행해야 할 작업&amp;rsquo;을 즉시 찾아낼 수 있습니다.&lt;/p&gt;
&lt;h4 id="2-작업-예약-및-실행-rust-예제"&gt;2. 작업 예약 및 실행 (Rust 예제)
&lt;/h4&gt;&lt;p&gt;이제 워커(Worker)는 트랜잭션 내에서 작업을 찾고(&lt;code&gt;SELECT&lt;/code&gt;), 소유권을 주장(&lt;code&gt;UPDATE&lt;/code&gt;)한 뒤 실행해야 합니다. 이 과정에서 경쟁 조건(Race Condition)을 방지하기 위해 &lt;code&gt;FOR UPDATE SKIP LOCKED&lt;/code&gt; 구문을 사용합니다.&lt;/p&gt;
&lt;p&gt;다음은 Rust와 &lt;code&gt;sqlx&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;use&lt;/span&gt; sqlx::{PgPool, Postgres};
&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; sqlx::types::chrono::{Utc, DateTime};
&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_json::Value;
&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)]&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;Job&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: &lt;span style="color:#66d9ef"&gt;i32&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; job_type: 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; payload: &lt;span style="color:#a6e22e"&gt;Value&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:#e6db74"&gt;/// 워커가 실행 루프에서 호출할 함수
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;claim_job&lt;/span&gt;(pool: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PgPool&lt;/span&gt;, worker_id: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Job&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;, sqlx::Error&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:#66d9ef"&gt;let&lt;/span&gt; now &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Utc::now();
&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; tx &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pool.begin().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&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;// 1. 실행 가능한 작업을 찾고 락을 겁니다.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// SKIP LOCKED: 다른 워커가 이미 락을 건 행은 무시하고 넘어갑니다.
&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; query &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;r&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 style="color:#e6db74"&gt; SELECT id, job_type, payload 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; FROM workflow_jobs 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; WHERE status = &amp;#39;pending&amp;#39; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; AND run_after &amp;lt;= $1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; ORDER BY created_at ASC
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; FOR UPDATE SKIP LOCKED
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; LIMIT 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; FOR UPDATE OF workflow_jobs
&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;#&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;let&lt;/span&gt; job: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Job&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; sqlx::query_as::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;_, Job&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(query)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(now)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .fetch_optional(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;tx)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&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;let&lt;/span&gt; job &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; job {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Some(j) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; j,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; None &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; tx.rollback().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 할당받을 작업 없음 (Rollback은 불필요하지만 명시적 표현)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Ok(None);
&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;// 2. 작업 상태를 &amp;#39;running&amp;#39;으로 변경
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sqlx::query(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;UPDATE workflow_jobs SET status = &amp;#39;running&amp;#39;, claimed_at = $1, attempt_count = attempt_count + 1 WHERE id = $2&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; .bind(Utc::now())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(job.id)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .execute(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;tx)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&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; tx.commit().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&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; Ok(Some(job))
&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:#e6db74"&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;complete_job&lt;/span&gt;(pool: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PgPool&lt;/span&gt;, job_id: &lt;span style="color:#66d9ef"&gt;i32&lt;/span&gt;, success: &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;, error_msg: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), sqlx::Error&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:#66d9ef"&gt;let&lt;/span&gt; status &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; success { &lt;span style="color:#e6db74"&gt;&amp;#34;succeeded&amp;#34;&lt;/span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; { &lt;span style="color:#e6db74"&gt;&amp;#34;failed&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 style="color:#75715e"&gt;// 실패 시 지수 백오프(Exponential Backoff)를 고려하여 run_after를 계산할 수 있습니다.
&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; next_run &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; success {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; None
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 예: 10초 후 재시도 시도 (실제 구현에서는 attempt_count에 따른 지수 증가 로직 필요)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Some(Utc::now() &lt;span style="color:#f92672"&gt;+&lt;/span&gt; chrono::Duration::seconds(&lt;span style="color:#ae81ff"&gt;10&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;if&lt;/span&gt; success {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sqlx::query(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;UPDATE workflow_jobs SET status = $1, run_after = NULL WHERE id = $2&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; .bind(status)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(job_id)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .execute(pool)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&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;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sqlx::query(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;UPDATE workflow_jobs SET status = $1, last_error = $2, run_after = $3 WHERE id = $4&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; .bind(status)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(error_msg)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(next_run)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(job_id)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .execute(pool)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&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; Ok(())
&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-워커-루프-구성"&gt;3. 워커 루프 구성
&lt;/h4&gt;&lt;p&gt;이제 위 함수를 사용해 무한 루프(또는 Tokio의 &lt;code&gt;tokio::time::interval&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;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;worker_loop&lt;/span&gt;(pool: &lt;span style="color:#a6e22e"&gt;PgPool&lt;/span&gt;, worker_id: String) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;loop&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; claim_job(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;pool, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;worker_id).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(Some(job)) &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:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Job acquired: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, worker_id, job.job_type);
&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 추론, API 호출)
&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; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; execute_logic(job.payload.clone()).&lt;span style="color:#66d9ef"&gt;await&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;// 결과 반영
&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; _ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; complete_job(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;pool, job.id, result.is_ok(), result.err().map(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;e&lt;span style="color:#f92672"&gt;|&lt;/span&gt; e.to_string())).&lt;span style="color:#66d9ef"&gt;await&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; Ok(None) &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;// 처리할 작업이 없으면 잠시 대기 (CPU 점유율 방지)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::time::sleep(tokio::time::Duration::from_millis(&lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;)).&lt;span style="color:#66d9ef"&gt;await&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; Err(e) &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:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Worker error: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, worker_id, e);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::time::sleep(tokio::time::Duration::from_secs(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)).&lt;span style="color:#66d9ef"&gt;await&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="장단점-및-활용-팁"&gt;장단점 및 활용 팁
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;장점:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;단순성:&lt;/strong&gt; 복잡한 분산 시스템 이론 없이 RDBMS의 트랜잭션만으로 신뢰성을 확보합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;운영 효율성:&lt;/strong&gt; DB만 백업하면 워크플로우 상태도 함께 복구됩니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;강력한 일관성:&lt;/strong&gt; 메시지 유실(In-flight loss)에 대한 걱정이 없습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;단점:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;처리량 처리량:&lt;/strong&gt; Postgres는 연결당 처리량에 한계가 있으므로, 초당 수만 건 이상의 처리량이 필요하면 전문 MQ가 낫습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DB 부하:&lt;/strong&gt; 워커가 순환 쿼리(Polling)를 지속적으로 수행하므로, &lt;code&gt;pgbouncer&lt;/code&gt; 등을 통해 연결 풀을 최적화해야 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="결론"&gt;결론
&lt;/h3&gt;&lt;p&gt;ZeroClaw의 멀티 에이전트 환경에서는 개별 에이전트의 메시지 처리량이 Kafka를 도입할 만큼 높지 않지만, 상태 관리의 신뢰성은 매우 중요했습니다. Postgres 기반 아키텍처를 통해 별도의 인프라 도입 없이 &amp;lsquo;안정적인 상태 관리&amp;rsquo;와 &amp;lsquo;확장 가능한 작업 큐&amp;rsquo;를 모두 달성할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;만약 당신의 프로젝트가 &amp;lsquo;단순함&amp;rsquo;과 &amp;lsquo;신뢰성&amp;rsquo; 사이에서 고민하고 있다면, 굳이 무거운 솔루션을 도입하기 전에 가까운 곳에 있는 Postgres를 워크플로우 엔진으로 활용해 보는 것은 어떨까요?&lt;/p&gt;
&lt;h3 id="참고자료"&gt;참고자료
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.hanselminutes.com/890/building-durable-workflows-on-postgres-with-pavel-duchovny" target="_blank" rel="noopener"
 &gt;Building durable workflows on Postgres&lt;/a&gt; (Hacker News 토론)&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.postgresql.org/docs/current/sql-select.html#SQL-FOR-UPDATE-SHARE" target="_blank" rel="noopener"
 &gt;SKIP LOCKED와 분산 락 구현&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Rust로 구축하는 ZeroClaw: LLM 기반 멀티 에이전트 런타임 아키텍처</title><link>https://blog.agentthread.dev/ko/post/rust%EB%A1%9C-%EA%B5%AC%EC%B6%95%ED%95%98%EB%8A%94-zeroclaw-llm-%EA%B8%B0%EB%B0%98-%EB%A9%80%ED%8B%B0-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EB%9F%B0%ED%83%80%EC%9E%84-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98/</link><pubDate>Mon, 25 May 2026 09:00:53 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/rust%EB%A1%9C-%EA%B5%AC%EC%B6%95%ED%95%98%EB%8A%94-zeroclaw-llm-%EA%B8%B0%EB%B0%98-%EB%A9%80%ED%8B%B0-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EB%9F%B0%ED%83%80%EC%9E%84-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98/</guid><description>&lt;h1 id="rust로-구축하는-zeroclaw-llm-기반-멀티-에이전트-런타임-아키텍처"&gt;Rust로 구축하는 ZeroClaw: LLM 기반 멀티 에이전트 런타임 아키텍처
&lt;/h1&gt;&lt;p&gt;최근 LLM(Large Language Model)을 활용한 자동화와 에이전트 시스템에 대한 관심이 뜨겁습니다. 하지만 단일 에이전트로 복잡한 작업을 처리하는 데에는 한계가 있으며, 이를 해결하기 위해 **멀티 에이전트 시스템(Multi-Agent System)**이 주목받고 있습니다. 이번 포스트에서는 고성능과 안정성을 위해 Rust로 작성된 에이전트 런타임인 &lt;strong&gt;ZeroClaw&lt;/strong&gt;의 아키텍처를 소개하고, 실제로 에이전트 간 통신을 어떻게 구조화하는지 살펴보겠습니다.&lt;/p&gt;
&lt;h2 id="1-왜-rust인가-performance--safety"&gt;1. 왜 Rust인가? (Performance &amp;amp; Safety)
&lt;/h2&gt;&lt;p&gt;LLM 애플리케이션은 대부분 Python으로 작성되곤 합니다. 하지만 여러 에이전트가 동시에 실행되고 각자 독립된 메모리 공간이나 파일 시스템을 제어해야 하는 &amp;lsquo;런타임&amp;rsquo; 환경에서는 Rust의 강력한 병렬 처리 능력과 메모리 안전성이 큰 무기가 됩니다.&lt;/p&gt;
&lt;p&gt;특히, 최근 Hacker News에서 논의된 것처럼 &lt;strong&gt;&amp;ldquo;LLM 에이전트의 백엔드 코드 생성 취약점(Constraint Decay)&amp;rdquo;&lt;/strong&gt; 문제가 대두되고 있습니다. LLM이 생성한 코드가 의도치 않게 시스템 제약을 무너뜨리는 상황에서, Rust의 타입 시스템과 소유권(Ownership) 모델은 런타임 차원에서 안전망을 제공할 수 있습니다.&lt;/p&gt;
&lt;h2 id="2-zeroclaw의-핵심-아키텍처"&gt;2. ZeroClaw의 핵심 아키텍처
&lt;/h2&gt;&lt;p&gt;ZeroClaw는 단순한 LLM 래퍼가 아니라, 에이전트의 생명주기를 관리하고 메시지를 중계하는 &lt;strong&gt;런타임 엔진&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;h3 id="21-파일-기반-상태-관리-file-based-state-management"&gt;2.1. 파일 기반 상태 관리 (File-Based State Management)
&lt;/h3&gt;&lt;p&gt;복잡한 데이터베이스 없이 에이전트의 상태와 컨텍스트를 파일 시스템에 기반하여 관리하는 아키텍처를 채택했습니다. 이는 휴대성(Portability)과 디버깅 용이성을 높여줍니다.&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:#75715e"&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(Serialize, Deserialize, Debug)]&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;AgentState&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; role: &lt;span style="color:#a6e22e"&gt;AgentRole&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; status: &lt;span style="color:#a6e22e"&gt;ExecutionStatus&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; last_heartbeat: &lt;span style="color:#66d9ef"&gt;u64&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;impl&lt;/span&gt; AgentState {
&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;save_to_file&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, path: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Path&lt;/span&gt;) -&amp;gt; &lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;::Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;()&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:#66d9ef"&gt;let&lt;/span&gt; json &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::to_string_pretty(self)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fs::write(path, json)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(())
&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;p&gt;이 접근 방식은 &lt;code&gt;Multi-Agent: 파일 기반 아키텍처 설계&lt;/code&gt; 논의에서 언급된 바와 같이, 각 에이전트가 자신의 상태를 투명하게 기록하게 하여 시스템 전체의 예측 가능성을 높입니다.&lt;/p&gt;
&lt;h3 id="22-이벤트-기반-통신-event-driven-communication"&gt;2.2. 이벤트 기반 통신 (Event-Driven Communication)
&lt;/h3&gt;&lt;p&gt;ZeroClaw의 에이전트들은 서로 직접 호출하지 않고, 중앙의 **이벤트 버스(Event Bus)**나 &lt;strong&gt;Pub/Sub&lt;/strong&gt; 메커니즘을 통해 통신합니다. 이는 결합도(Coupling)를 낮추고 확장성을 확보합니다.&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:#75715e"&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, 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;AgentMessage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskRequest { task_id: String, payload: String },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskResponse { task_id: String, result: String },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; StatusUpdate { agent_id: String, status: 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;&lt;span style="color:#75715e"&gt;// 간단한 채널 기반 메시지 라우터 (tokio::sync::mpsc 사용)
&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;MessageRouter&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// sender: HashMap&amp;lt;AgentId, Sender&amp;lt;AgentMessage&amp;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;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;이러한 구조는 &lt;code&gt;Claude Code 팀 에이전트 통신 아키텍처&lt;/code&gt;나 &lt;code&gt;멀티 에이전트 통신 프로토콜 설계&lt;/code&gt;에서 고민되었던 &amp;lsquo;메시지 큐의 신뢰성&amp;rsquo; 이슈를 Rust의 강력한 비동기 런타임(&lt;code&gt;tokio&lt;/code&gt;)으로 해결하는 기반이 됩니다.&lt;/p&gt;
&lt;h2 id="3-mcpmodel-context-protocol와의-연동"&gt;3. MCP(Model Context Protocol)와의 연동
&lt;/h2&gt;&lt;p&gt;ZeroClaw는 MCP 서버와 클라이언트 역할을 수행하여 외부 도구(예: 블로그 API, Discord Gateway)와 연동됩니다. 최근 &lt;code&gt;blog-api-server&lt;/code&gt;에 추가된 언어 파라미터나 로깅 개선 사항들은 ZeroClaw 에이전트가 외부 시스템과 상호작용할 때 컨텍스트를 잃지 않도록 돕습니다.&lt;/p&gt;
&lt;p&gt;에이전트가 MCP 도구를 호출하는 과정을 안전하게 래핑(Wrapping)하는 것은 중요합니다.&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:#75715e"&gt;// MCP 도구 호출을 위한 안전한 래퍼
&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;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;invoke_mcp_tool&lt;/span&gt;(tool_name: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;, params: &lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt;::Value) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, AgentError&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;// 1. 파라미터 검증 (Validation)
&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; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;validate_params(tool_name, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;params) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Err(AgentError::InvalidInput);
&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;// 2. 실제 호출 (HTTP or IPC)
&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; response &lt;span style="color:#f92672"&gt;=&lt;/span&gt; reqwest::Client::new()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .post(&lt;span style="color:#e6db74"&gt;&amp;#34;http://localhost:8080/mcp/call&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .json(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;json!&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;tool&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;tool_name&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;args&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;params&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; .send()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&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;// 3. 응답 파싱 및 로깅
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tracing::&lt;span style="color:#a6e22e"&gt;info!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;MCP Tool {} called successfully&amp;#34;&lt;/span&gt;, tool_name);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(response.text().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&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;h2 id="4-결론-2026-상반기-발전-방향"&gt;4. 결론: 2026 상반기 발전 방향
&lt;/h2&gt;&lt;p&gt;ZeroClaw는 단순한 실험적 프로젝트를 넘어, &lt;code&gt;2026 상반기 발전방향 회의록&lt;/code&gt;에서 언급된 바와 같이 &amp;lsquo;고성능 에이전트 런타임&amp;rsquo;으로 진화하고 있습니다.&lt;/p&gt;
&lt;p&gt;Rust의 성능을 바탕으로 LLM의 생성성(Creativity)과 시스템의 안전성(Safety)을 동시에 확보하는 것이 목표입니다. 특히, 최근 트렌드인 &lt;strong&gt;DeepSeek&lt;/strong&gt;와 같은 효율적인 모델을 통합하여 비용 효율성까지 개선할 계획입니다.&lt;/p&gt;
&lt;p&gt;다음 포스트에서는 ZeroClaw 에이전트가 실제로 코드를 생성하고 배포하는 &lt;strong&gt;CI/CD 파이프라인 연동 사례&lt;/strong&gt;를 다루겠습니다.&lt;/p&gt;
&lt;h2 id="참고-링크"&gt;참고 링크
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="#" &gt;ZeroClaw GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="#" &gt;MCP Specification&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>MCP(Model Context Protocol) 기반 멀티 에이전트 시스템 설계 및 구현 가이드</title><link>https://blog.agentthread.dev/ko/post/mcpmodel-context-protocol-%EA%B8%B0%EB%B0%98-%EB%A9%80%ED%8B%B0-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EC%84%A4%EA%B3%84-%EB%B0%8F-%EA%B5%AC%ED%98%84-%EA%B0%80%EC%9D%B4%EB%93%9C/</link><pubDate>Sat, 23 May 2026 09:01:19 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/mcpmodel-context-protocol-%EA%B8%B0%EB%B0%98-%EB%A9%80%ED%8B%B0-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EC%84%A4%EA%B3%84-%EB%B0%8F-%EA%B5%AC%ED%98%84-%EA%B0%80%EC%9D%B4%EB%93%9C/</guid><description>&lt;h1 id="mcpmodel-context-protocol-기반-멀티-에이전트-시스템-설계-및-구현-가이드"&gt;MCP(Model Context Protocol) 기반 멀티 에이전트 시스템 설계 및 구현 가이드
&lt;/h1&gt;&lt;p&gt;최근 생성형 AI 도메인에서 단일 LLM(Large Language Model)의 한계를 극복하기 위해 **멀티 에이전트 시스템(Multi-Agent System)**이 주목받고 있습니다. 특히, 에이전트 간의 표준화된 통신을 위한 **MCP(Model Context Protocol)**가 등장하면서, 확장 가능하고 모듈화된 아키텍처를 설계하는 것이 필수적이 되었습니다.&lt;/p&gt;
&lt;p&gt;본 포스트에서는 &lt;code&gt;ZeroClaw&lt;/code&gt;와 같은 고성능 에이전트 런타임 환경에서 MCP를 활용해 효율적인 멀티 에이전트 아키텍처를 설계하고 구현하는 방법을 살펴봅니다. 독자가 바로 적용할 수 있도록 아키텍처 설계 원칙과 실제 코드 예제를 포함했습니다.&lt;/p&gt;
&lt;h2 id="1-mcp-기반-멀티-에이전트-아키텍처-설계"&gt;1. MCP 기반 멀티 에이전트 아키텍처 설계
&lt;/h2&gt;&lt;p&gt;멀티 에이전트 시스템을 구축할 때 가장 중요한 것은 &lt;strong&gt;결합도(Coupling)를 낮추고 응집도(Cohesion)를 높이는 것&lt;/strong&gt;입니다. MCP는 이를 달성하기 위해 클라이언트-서버 모델을 채택하여, 각 에이전트나 도구가 독립적인 서버로 동작하며 표준 프로토콜(JSON-RPC 2.0 기반)을 통해 통신하도록 합니다.&lt;/p&gt;
&lt;h3 id="핵심-설계-원칙"&gt;핵심 설계 원칙
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;표준화된 인터페이스 (Standardized Interface):&lt;/strong&gt; 모든 에이전트는 MCP 표준을 준수하여 &lt;code&gt;tools&lt;/code&gt;, &lt;code&gt;resources&lt;/code&gt;, &lt;code&gt;prompts&lt;/code&gt;를 노출해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;비동기 통신 (Asynchronous Communication):&lt;/strong&gt; 작업 수행 시간이 긴 에이전트(예: 파일 처리, 웹 스크래핑)를 위해 비동기 메시지 큐를 활용해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;상태 비저장 (Stateless):&lt;/strong&gt; 에이전트 서버는 가능한 한 상태 비저장으로 설계하여 수평 확장(Scale-out)이 용이하게 만들어야 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="아키텍처-다이어그램-개념적"&gt;아키텍처 다이어그램 (개념적)
&lt;/h3&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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[User/Client LLM] &amp;lt;--&amp;gt; [MCP Gateway (Orchestrator)]
&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; v v v
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [Blog Server] [Discord MCP] [Cloud Monitor]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (Rust/TS) (Gateway) (Agent)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;이 구조에서 **Gateway(오케스트레이터)**는 사용자의 요청을 분석하여 적절한 MCP 서버(에이전트)에게 작업을 위임하고, 결과를 취합하여 다시 사용자에게 전달하는 역할을 수행합니다.&lt;/p&gt;
&lt;h2 id="2-mcp-서버-구현-rust로-가벼운-에이전트-만들기"&gt;2. MCP 서버 구현: Rust로 가벼운 에이전트 만들기
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;blog-api-server&lt;/code&gt;나 &lt;code&gt;ZeroClaw&lt;/code&gt; 환경에서 고성능을 발휘하기 위해 Rust로 간단한 MCP 서버를 구현해 보겠습니다. 이 서버는 현재 시간을 반환하는 간단한 도구를 제공합니다.&lt;/p&gt;
&lt;h3 id="의존성-설정-cargotoml"&gt;의존성 설정 (Cargo.toml)
&lt;/h3&gt;&lt;p&gt;Rust의 강력한 비동기 런타임인 &lt;code&gt;tokio&lt;/code&gt;와 JSON 처리를 위한 &lt;code&gt;serde&lt;/code&gt;, 그리고 MCP 통신을 위한 &lt;code&gt;hyper&lt;/code&gt; 또는 &lt;code&gt;jsonrpc&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-toml" data-lang="toml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;dependencies&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;tokio&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;full&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;derive&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;hyper&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;0.14&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;server&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;http1&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="mcp-서버-코드-예제"&gt;MCP 서버 코드 예제
&lt;/h3&gt;&lt;p&gt;다음은 STDIN/STDOUT을 통해 통신하는 표준 MCP 서버의 뼈대를 간소화하여 구현한 것입니다.&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; serde::{Deserialize, Serialize};
&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_json::{Value, json};
&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; std::io::{self, BufRead, Write};
&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;// MCP 요청/응답 구조체 정의
&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(Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MCPRequest&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&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; method: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Value&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&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(Serialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MCPResponse&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&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; result: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Value&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; error: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Value&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&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;handle_request&lt;/span&gt;(req: &lt;span style="color:#a6e22e"&gt;MCPRequest&lt;/span&gt;) -&amp;gt; &lt;span style="color:#a6e22e"&gt;MCPResponse&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; req.method.as_str() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;initialize&amp;#34;&lt;/span&gt; &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; MCPResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: Some(&lt;span style="color:#a6e22e"&gt;json!&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;protocolVersion&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2024-11-05&amp;#34;&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;capabilities&amp;#34;&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;tools&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 style="color:#e6db74"&gt;&amp;#34;serverInfo&amp;#34;&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;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;my-rust-agent&amp;#34;&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;version&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;0.1.0&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;span style="display:flex;"&gt;&lt;span&gt; error: None,
&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:#e6db74"&gt;&amp;#34;tools/list&amp;#34;&lt;/span&gt; &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; MCPResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: Some(&lt;span style="color:#a6e22e"&gt;json!&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;tools&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 style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;get_current_time&amp;#34;&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;description&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Returns the current server time&amp;#34;&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;inputSchema&amp;#34;&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;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;object&amp;#34;&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;properties&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;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; error: None,
&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:#e6db74"&gt;&amp;#34;tools/call&amp;#34;&lt;/span&gt; &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; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(params) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; req.params {
&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; tool_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; params[&lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;].as_str().unwrap_or(&lt;span style="color:#e6db74"&gt;&amp;#34;&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; tool_name &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;get_current_time&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;return&lt;/span&gt; MCPResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: Some(&lt;span style="color:#a6e22e"&gt;json!&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;content&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 style="color:#e6db74"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&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;text&amp;#34;&lt;/span&gt;: &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;Current time: {}&amp;#34;&lt;/span&gt;, chrono::Utc::now().to_rfc3339())
&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; error: None,
&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;// 에러 처리
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MCPResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: None,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error: Some(&lt;span style="color:#a6e22e"&gt;json!&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;code&amp;#34;&lt;/span&gt;: &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32601&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;message&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Tool not found&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;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:#f92672"&gt;=&amp;gt;&lt;/span&gt; MCPResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: None,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error: Some(&lt;span style="color:#a6e22e"&gt;json!&lt;/span&gt;({ &lt;span style="color:#e6db74"&gt;&amp;#34;code&amp;#34;&lt;/span&gt;: &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32601&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;message&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Method not found&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;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;main&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; stdin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; io::stdin();
&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; stdout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; io::stdout();
&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;for&lt;/span&gt; line &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; stdin.lock().lines() {
&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; line &lt;span style="color:#f92672"&gt;=&lt;/span&gt; line.unwrap();
&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; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Ok(req) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::from_str::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;MCPRequest&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;line) {
&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; res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; handle_request(req);
&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; res_json &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::to_string(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;res).unwrap() &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &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;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stdout.write_all(res_json.as_bytes()).unwrap();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stdout.flush().unwrap();
&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;이 코드는 MCP의 핵심인 &lt;code&gt;initialize&lt;/code&gt;, &lt;code&gt;tools/list&lt;/code&gt;, &lt;code&gt;tools/call&lt;/code&gt; 메서드를 처리하여 LLM(예: Claude Code)이 이 에이전트를 도구로 인식하고 호출할 수 있게 합니다.&lt;/p&gt;
&lt;h2 id="3-에이전트-간-통신-및-데이터-동기화"&gt;3. 에이전트 간 통신 및 데이터 동기화
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;ZeroClaw&lt;/code&gt; 아키텍처에서와 같이 여러 에이전트가 협업할 때는 데이터 공유가 중요합니다. 파일 기반 아키텍처(File-based architecture)를 사용하면 에이전트 간 결합도를 낮추면서 데이터를 주고받을 수 있습니다.&lt;/p&gt;
&lt;h3 id="파일-기반-상태-공유-예시"&gt;파일 기반 상태 공유 예시
&lt;/h3&gt;&lt;p&gt;에이전트 A가 데이터를 생성하고, 에이전트 B가 이를 소비하는 시나리오입니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;에이전트 A (생산자):&lt;/strong&gt; 계산 결과를 &lt;code&gt;/tmp/shared/task_result.json&lt;/code&gt;에 저장합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;에이전트 B (소비자):&lt;/strong&gt; MCP를 통해 &lt;code&gt;file://tmp/shared/task_result.json&lt;/code&gt; 리소스를 읽거나, 별도의 &lt;code&gt;read_file&lt;/code&gt; 도구를 호출합니다.&lt;/li&gt;
&lt;/ol&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:#75715e"&gt;// 에이전트 A의 도구 호출 예시 (의사 코드)
&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;save_result&lt;/span&gt;(data: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; &lt;span style="color:#a6e22e"&gt;std&lt;/span&gt;::io::Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;()&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; fs::write(&lt;span style="color:#e6db74"&gt;&amp;#34;/tmp/shared/task_result.json&amp;#34;&lt;/span&gt;, data)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(())
&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;p&gt;이 방식은 메시지 큐가 복잡할 때 유용하며, &lt;code&gt;blog-api-server&lt;/code&gt;의 로깅 시스템이나 모니터링 대시보드처럼 데이터를 지속적으로 추적해야 할 때 유효합니다.&lt;/p&gt;
&lt;h2 id="4-결론-및-발전-방향"&gt;4. 결론 및 발전 방향
&lt;/h2&gt;&lt;p&gt;MCP를 활용하면 복잡한 멀티 에이전트 시스템을 &lt;strong&gt;모듈화&lt;/strong&gt;하고 &lt;strong&gt;유지보수&lt;/strong&gt;하기 쉽게 만들 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;장점:&lt;/strong&gt; 언어에 독립적인 인터페이스(Rust, TypeScript 등 혼용 가능), 도구의 재사용성, 표준화된 에러 처리.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;고려사항:&lt;/strong&gt; STDIN/STDOUT 통신 오버헤드, 대규모 트래픽 처리를 위한 Gateway의 부하 분산.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;향후 &lt;code&gt;ZeroClaw&lt;/code&gt; 런타임 내에서 이러한 MCP 서버들을 컨테이너화하여 필요에 따라 동적으로 스케일링(Scale-out)하는 환경을 구축하는 것이 목표입니다. 이를 통해 LLM이 단순한 챗봇을 넘어, 복잡한 작업을 자동화하는 &lt;strong&gt;지능형 에이전트 네트워크&lt;/strong&gt;로 진화할 수 있습니다.&lt;/p&gt;
&lt;h2 id="참고-자료"&gt;참고 자료
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://spec.modelcontextprotocol.io/" target="_blank" rel="noopener"
 &gt;Model Context Protocol Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/your-repo/zeroclaw" target="_blank" rel="noopener"
 &gt;ZeroClaw Project Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.anthropic.com/" target="_blank" rel="noopener"
 &gt;Claude Code MCP Integration Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>ZeroClaw 멀티 에이전트 시스템: Docker Compose를 활용한 로컬 테스트 환경 구축 가이드</title><link>https://blog.agentthread.dev/ko/post/zeroclaw-%EB%A9%80%ED%8B%B0-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EC%8B%9C%EC%8A%A4%ED%85%9C-docker-compose%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%A1%9C%EC%BB%AC-%ED%85%8C%EC%8A%A4%ED%8A%B8-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95-%EA%B0%80%EC%9D%B4%EB%93%9C/</link><pubDate>Fri, 22 May 2026 09:01:21 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/zeroclaw-%EB%A9%80%ED%8B%B0-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EC%8B%9C%EC%8A%A4%ED%85%9C-docker-compose%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%A1%9C%EC%BB%AC-%ED%85%8C%EC%8A%A4%ED%8A%B8-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95-%EA%B0%80%EC%9D%B4%EB%93%9C/</guid><description>&lt;h1 id="zeroclaw-멀티-에이전트-시스템-docker-compose를-활용한-로컬-테스트-환경-구축-가이드"&gt;ZeroClaw 멀티 에이전트 시스템: Docker Compose를 활용한 로컬 테스트 환경 구축 가이드
&lt;/h1&gt;&lt;p&gt;최근 &lt;strong&gt;[ZeroClaw]&lt;/strong&gt; 프로젝트를 통해 고성능 Rust 에이전트 런타임과 멀티 에이전트 아키텍처를 설계하며, 개별 에이전트의 격리성과 통신 안정성의 중요성을 실감했습니다. 특히 **[blog-api-server]**와 같이 외부 API와 연동되는 MCP(Model Context Protocol) 클라이언트를 개발할 때, 로컬 환경에서 실제 운영 환경과 유사한 구조를 갖춰 테스트하는 것은 필수적입니다.&lt;/p&gt;
&lt;p&gt;이번 포스트에서는 복잡한 멀티 에이전트 시스템을 로컬에서 쉽게 실행하고 디버깅할 수 있도록 &lt;strong&gt;Docker Compose&lt;/strong&gt;를 활용한 테스트 환경 구축 방법을 공유합니다. 본 가이드는 Linux 환경(예: Ubuntu 16.04에서 FreeBSD로 이전 중인 서버 등)을 기반으로 하지만, Windows와 macOS에서도 동일하게 적용 가능합니다.&lt;/p&gt;
&lt;h2 id="1-아키텍처-설계-마이크로서비스형-에이전트-구조"&gt;1. 아키텍처 설계: 마이크로서비스형 에이전트 구조
&lt;/h2&gt;&lt;p&gt;ZeroClaw의 핵심은 파일 기반 아키텍처와 게이트웨이 패턴을 차용한 통신 플랫폼입니다. 각 에이전트를 독립된 마이크로서비스로 간주하고, 이들을 Docker 컨테이너로 격리합니다.&lt;/p&gt;
&lt;h3 id="구성-요소"&gt;구성 요소
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Agent Container&lt;/strong&gt;: Rust로 작성된 개별 에이전트 (ZeroClaw Runtime 기반)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gateway Container&lt;/strong&gt;: 외부 요청을 내부 에이전트로 라우팅하는 Nginx 또는 Envoy&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Message Broker (Optional)&lt;/strong&gt;: RabbitMQ 또는 Redis (비동기 통신 필요 시)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="2-dockerfile-작성-rust-에이전트-최적화"&gt;2. Dockerfile 작성: Rust 에이전트 최적화
&lt;/h2&gt;&lt;p&gt;Rust 애플리케이션은 컴파일 시간이 오래 걸리므로, &lt;strong&gt;Multi-stage build&lt;/strong&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-dockerfile" data-lang="dockerfile"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Dockerfile&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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;# 1. Build Stage&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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;FROM&lt;/span&gt; &lt;span style="color:#e6db74"&gt;rust:1.75-slim&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#e6db74"&gt;builder&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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;WORKDIR&lt;/span&gt; &lt;span style="color:#e6db74"&gt;/app&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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;# 의존성 캐싱을 위해 Cargo.toml과 Cargo.lock 먼저 복사&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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;COPY&lt;/span&gt; Cargo.toml Cargo.lock ./&lt;span style="color:#960050;background-color:#1e0010"&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;RUN&lt;/span&gt; mkdir src &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;fn main() {}&amp;#34;&lt;/span&gt; &amp;gt; src/main.rs&lt;span style="color:#960050;background-color:#1e0010"&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;RUN&lt;/span&gt; cargo build --release &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm -rf src&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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 style="color:#960050;background-color:#1e0010"&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;COPY&lt;/span&gt; src ./src&lt;span style="color:#960050;background-color:#1e0010"&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;RUN&lt;/span&gt; touch src/main.rs &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo build --release&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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;# 2. Runtime Stage&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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;FROM&lt;/span&gt; &lt;span style="color:#e6db74"&gt;debian:bookworm-slim&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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;# 런타임 의존성 설치 (예: OpenSSL)&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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;RUN&lt;/span&gt; apt-get update &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get install -y ca-certificates &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm -rf /var/lib/apt/lists/*&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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;WORKDIR&lt;/span&gt; &lt;span style="color:#e6db74"&gt;/app&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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 style="color:#960050;background-color:#1e0010"&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;COPY&lt;/span&gt; --from&lt;span style="color:#f92672"&gt;=&lt;/span&gt;builder /app/target/release/zero-claw-agent /app/agent&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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 style="color:#960050;background-color:#1e0010"&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;RUN&lt;/span&gt; chmod +x /app/agent&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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;# 포트 노출 (MCP 통신용)&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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;EXPOSE&lt;/span&gt; &lt;span style="color:#e6db74"&gt;8080&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&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;CMD&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;/app/agent&amp;#34;&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="3-docker-compose로-오케스트레이션-구성"&gt;3. Docker Compose로 오케스트레이션 구성
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt; 파일을 사용하여 여러 에이전트와 네트워크를 정의합니다. 이를 통해 &lt;code&gt;docker-compose up&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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# docker-compose.yml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;version&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;3.8&amp;#39;&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:#f92672"&gt;services&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; &lt;span style="color:#f92672"&gt;redis&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;redis:7-alpine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;container_name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;zero-claw-redis&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ports&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;6379:6379&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;networks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;zero-claw-net&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;# Agent 1: Blog Handler (blog-api-server 역할)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;blog-agent&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;build&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;context&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;./services/blog-agent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;dockerfile&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Dockerfile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;container_name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;zero-claw-blog-agent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;AGENT_ID=blog-agent-01&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;LOG_LEVEL=debug&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;MCP_SERVER_URL=http://mock-api:3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;depends_on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;redis&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;networks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;zero-claw-net&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;restart&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;unless-stopped&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;# Agent 2: Monitor (Cloud Monitor 역할)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;monitor-agent&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;build&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;context&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;./services/monitor-agent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;dockerfile&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Dockerfile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;container_name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;zero-claw-monitor-agent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;AGENT_ID=monitor-agent-01&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;depends_on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;redis&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;networks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;zero-claw-net&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;restart&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;unless-stopped&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;# Gateway (Discord MCP Gateway 역할)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;gateway&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;nginx:alpine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;container_name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;zero-claw-gateway&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ports&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;8080:80&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;./nginx/nginx.conf:/etc/nginx/nginx.conf:ro&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;depends_on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;blog-agent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;monitor-agent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;networks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;zero-claw-net&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:#f92672"&gt;networks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;zero-claw-net&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;driver&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;bridge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="4-실행-및-테스트"&gt;4. 실행 및 테스트
&lt;/h2&gt;&lt;p&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-bash" data-lang="bash"&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;docker-compose up --build -d
&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;# 로그 확인 (특정 에이전트 집중 모니터링)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker-compose logs -f blog-agent
&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;# 트래픽 테스트 (Gateway를 통한 요청)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -X POST http://localhost:8080/api/v1/agent/blog/ping &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -H &lt;span style="color:#e6db74"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -d &lt;span style="color:#e6db74"&gt;&amp;#39;{&amp;#34;message&amp;#34;: &amp;#34;Hello from ZeroClaw&amp;#34;}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="5-마치며"&gt;5. 마치며
&lt;/h2&gt;&lt;p&gt;이 구조를 활용하면 **[ZeroClaw]**의 멀티 에이전트 통신 프로토콜을 변경하거나, &lt;strong&gt;[LLM]&lt;/strong&gt; 설정을 에이전트별로 주입하여 테스트하는 작업이 훨씬 수월해집니다. 특히 &lt;code&gt;docker-compose.yml&lt;/code&gt;의 환경 변수만 수정하면 운영 환경 배포 스크립트와 로컬 테스트 환경을 거의 동일하게 유지할 수 있어 &amp;ldquo;It works on my machine&amp;rdquo; 문제를 해결할 수 있습니다.&lt;/p&gt;
&lt;p&gt;다음 포스트에서는 이 환경에서 수집된 로그를 **[Loki]**나 **[Prometheus]**를 통해 시각화하는 방법을 다루어 보겠습니다.&lt;/p&gt;</description></item><item><title>AI 에이전트 신뢰성 강화: Forge Guardrails와 MCP 통합 가이드</title><link>https://blog.agentthread.dev/ko/post/ai-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EC%8B%A0%EB%A2%B0%EC%84%B1-%EA%B0%95%ED%99%94-forge-guardrails%EC%99%80-mcp-%ED%86%B5%ED%95%A9-%EA%B0%80%EC%9D%B4%EB%93%9C/</link><pubDate>Wed, 20 May 2026 09:00:35 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/ai-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EC%8B%A0%EB%A2%B0%EC%84%B1-%EA%B0%95%ED%99%94-forge-guardrails%EC%99%80-mcp-%ED%86%B5%ED%95%A9-%EA%B0%80%EC%9D%B4%EB%93%9C/</guid><description>&lt;h1 id="ai-에이전트-신뢰성-강화-forge-guardrails와-mcp-통합-가이드"&gt;AI 에이전트 신뢰성 강화: Forge Guardrails와 MCP 통합 가이드
&lt;/h1&gt;&lt;p&gt;최근 LLM(Large Language Model)을 활용한 에이전트 시스템이 급격히 발전하고 있습니다. Hacker News에서는 &amp;ldquo;Forge – Guardrails take an 8B model from 53% to 99% on agentic tasks&amp;quot;라는 흥미로운 사례가 화제가 되었습니다. 이는 모델의 파라미터 수를 늘리는 것보다, 적절한 **가드레일(Guardrails)**을 적용하는 것이 특정 작업의 성공률을 비약적으로 높일 수 있음을 시사합니다.&lt;/p&gt;
&lt;p&gt;저희 팀에서 진행 중인 &lt;strong&gt;ZeroClaw&lt;/strong&gt; 및 &lt;strong&gt;MCP(Model Context Protocol)&lt;/strong&gt; 기반 프로젝트들에 있어 에이전트의 신뢰성은 필수적입니다. 이번 포스트에서는 오픈소스 가드레일 프레임워크인 Forge의 개념을 살펴보고, 이를 기존 MCP 아키텍처에 통합하여 에이전트의 안정성을 확보하는 구체적인 방법을 소개합니다.&lt;/p&gt;
&lt;h2 id="문제-정의-자율성의-딜레마"&gt;문제 정의: 자율성의 딜레마
&lt;/h2&gt;&lt;p&gt;에이전트에게 자율성을 부여할수록 예상치 못한 행동을 할 위험이 커집니다. 예를 들어, 블로그 게시글을 생성하라는 MCP 요청이 있을 때, 에이전트가 시스템 명령어를 실행하거나 허용되지 않은 API를 호출하려 시도할 수 있습니다.&lt;/p&gt;
&lt;p&gt;기존의 &lt;strong&gt;[blog-api-server]&lt;/strong&gt; 구현에서는 프롬프트 엔지니어링과 간단한 JSON 스키마 검증으로 이를 방어하려 했으나, 복잡한 멀티 에이전트 환경에서는 한계가 있었습니다. 이를 해결하기 위해 입력과 출력을 사전에 필터링하는 &lt;strong&gt;L1 가드레일&lt;/strong&gt; 레이어를 도입하기로 결정했습니다.&lt;/p&gt;
&lt;h2 id="솔루션-guardrails-패턴-적용"&gt;솔루션: Guardrails 패턴 적용
&lt;/h2&gt;&lt;p&gt;Forge가 보여주듯, 에이전트 작업의 성공률(53% → 99%)을 높이는 핵심은 &lt;strong&gt;실행 전 검증&lt;/strong&gt;입니다. 우리는 에이전트가 LLM으로부터 응답을 받아 사용자에게 전달하거나 도구(Tool)를 실행하기 전, 중간 계층에서 이를 검증하는 구조를 설계했습니다.&lt;/p&gt;
&lt;h3 id="아키텍처-개요"&gt;아키텍처 개요
&lt;/h3&gt;&lt;p&gt;기존 MCP 클라이언트와 LLM 사이에 &lt;code&gt;Validator&lt;/code&gt; 계층을 두어 다음을 수행합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;입력 검증 (Input Validation):&lt;/strong&gt; 사용자의 요청이 시스템 정책을 위반하지 않는지 확인 (예: 공격적인 프롬프트 필터링).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;출력 검증 (Output Validation):&lt;/strong&gt; LLM이 생성한 JSON이나 함수 호출 인자가 스키마에 부합하는지 확인.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="실전-코드-예제-rust로-구현하는-안전장치"&gt;실전 코드 예제: Rust로 구현하는 안전장치
&lt;/h2&gt;&lt;p&gt;ZeroClaw의 Rust 환경에서 가벼운 출력 검증기를 구현해 보겠습니다. 복잡한 외부 라이브러리 없이, &lt;code&gt;serde&lt;/code&gt;와 &lt;code&gt;regex&lt;/code&gt;를 활용하여 LLM이 생성한 코드 실행 명령을 안전하게 감싸는 예제입니다.&lt;/p&gt;
&lt;h3 id="1-검증-로직-구현하기"&gt;1. 검증 로직 구현하기
&lt;/h3&gt;&lt;p&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;use&lt;/span&gt; regex::Regex;
&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::{Deserialize, Serialize};
&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;// 에이전트가 생성할 수 있는 명령어 구조
&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)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentCommand&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tool_name: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameters: 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;&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;Guardrail&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;impl&lt;/span&gt; Guardrail {
&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; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;is_dangerous&lt;/span&gt;(input: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; &lt;span style="color:#66d9ef"&gt;bool&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; dangerous_patterns &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;vec!&lt;/span&gt;[&lt;span style="color:#e6db74"&gt;&amp;#34;rm -rf&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;sudo&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;eval&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;__import__&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dangerous_patterns.iter().any(&lt;span style="color:#f92672"&gt;|&amp;amp;&lt;/span&gt;pat&lt;span style="color:#f92672"&gt;|&lt;/span&gt; input.contains(pat))
&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;// 명령어 실행 전 검증 로직
&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;validate_command&lt;/span&gt;(cmd: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;AgentCommand&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&amp;amp;&lt;/span&gt;AgentCommand, String&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;// 1. 도구 이름 화이트리스트 확인
&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; allowed_tools &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;vec!&lt;/span&gt;[&lt;span style="color:#e6db74"&gt;&amp;#34;blog_post&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;search&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;read_file&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; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;allowed_tools.contains(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;cmd.tool_name.as_str()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Err(&lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;허용되지 않은 도구 사용 시도: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, cmd.tool_name));
&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;// 2. 파라미터 내 위험 키워드 검사
&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; Self::is_dangerous(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;cmd.parameters) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Err(&lt;span style="color:#e6db74"&gt;&amp;#34;파라미터에 잠재적으로 위험한 명령어가 포함되어 있습니다.&amp;#34;&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; &lt;span style="color:#75715e"&gt;// 3. 안전하다면 명령어 승인
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(cmd)
&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="2-에이전트-루프에-통합하기"&gt;2. 에이전트 루프에 통합하기
&lt;/h3&gt;&lt;p&gt;이제 검증기를 MCP 서버의 요청 처리 루프에 연결합니다. 에이전트가 응답을 생성하면, 실제 시스템이 이를 실행하기 전에 &lt;code&gt;Guardrail&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:#75715e"&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;execute_agent_task&lt;/span&gt;(llm_output: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, String&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;// 1. LLM 출력 파싱 (실제로는 JSON 파싱 등)
&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; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; command &lt;span style="color:#f92672"&gt;=&lt;/span&gt; AgentCommand {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tool_name: &lt;span style="color:#e6db74"&gt;&amp;#34;blog_post&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameters: &lt;span style="color:#e6db74"&gt;&amp;#34;title: &amp;#39;Hello World&amp;#39;&amp;#34;&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; &lt;span style="color:#75715e"&gt;// 2. 가드레일 통과 전
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[System] LLM 응답 수신: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, command.tool_name);
&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;// 3. 가드레일 검증 실행
&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; safe_command &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Guardrail::validate_command(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;command)&lt;span style="color:#f92672"&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;// 4. 검증된 명령어 실행
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[System] 안전한 명령어 실행 중...&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 실제 도구 실행 로직 (예: 블로그 API 호출)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(&lt;span style="color:#e6db74"&gt;&amp;#34;게시글이 성공적으로 생성되었습니다.&amp;#34;&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;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&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; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; execute_agent_task(&lt;span style="color:#e6db74"&gt;&amp;#34;valid_response&amp;#34;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(msg) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;성공: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, msg),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;차단됨: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e),
&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;// 비정상 케이스 시뮬레이션
&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; malicious_cmd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; AgentCommand {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tool_name: &lt;span style="color:#e6db74"&gt;&amp;#34;system_shell&amp;#34;&lt;/span&gt;.to_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; parameters: &lt;span style="color:#e6db74"&gt;&amp;#34;rm -rf /&amp;#34;&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; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; Guardrail::validate_command(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;malicious_cmd) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(_) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;오류: 해커가 침입했습니다!&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;보호됨: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e), &lt;span style="color:#75715e"&gt;// &amp;#34;보호됨: 허용되지 않은 도구 사용 시도: system_shell&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;h2 id="효과-및-전망"&gt;효과 및 전망
&lt;/h2&gt;&lt;p&gt;이러한 &lt;strong&gt;L1 방어선&lt;/strong&gt;을 구축함으로써 우리는 다음과 같은 이점을 얻을 수 있습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;안정성 향상:&lt;/strong&gt; Forge 사례처럼 8B 모델도 충분히 안전하게 활용할 수 있어 추론 비용 절감.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;투명성 확보:&lt;/strong&gt; 에이전트가 왜 특정 작업을 거부했는지 로그를 통해 명확히 파악 가능.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;유지보수성:&lt;/strong&gt; 보안 정책이 변경되어도 &lt;code&gt;Guardrail&lt;/code&gt; 모듈만 수정하면 됨.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;앞으로 &lt;strong&gt;ZeroClaw&lt;/strong&gt; 프로젝트에서는 이 검증 로직을 비동기 런타임에 통합하여, 멀티 에이전트 간 통신([Discord MCP], [Cloud Monitor]) 시에도 실시간으로 안전성을 모니터링할 계획입니다.&lt;/p&gt;
&lt;p&gt;단순히 모델의 성능을 높이는 것에 집착하기보다, 이처럼 &lt;strong&gt;시스템 레벨에서의 안전장치&lt;/strong&gt;를 어떻게 설계하느냐가 AI 에이전트를 실제 프로덕션에 배포하는 관건이 될 것입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;이 글은 ZeroClaw 및 MCP 관련 아키텍처 설계 문서들을 참고하여 작성되었습니다.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Agentic Workflow: MCP 도구를 활용한 블로그 자동화 파이프라인 구축</title><link>https://blog.agentthread.dev/ko/post/agentic-workflow-mcp-%EB%8F%84%EA%B5%AC%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%9E%90%EB%8F%99%ED%99%94-%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8-%EA%B5%AC%EC%B6%95/</link><pubDate>Tue, 19 May 2026 09:00:34 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/agentic-workflow-mcp-%EB%8F%84%EA%B5%AC%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%9E%90%EB%8F%99%ED%99%94-%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8-%EA%B5%AC%EC%B6%95/</guid><description>&lt;h1 id="agentic-workflow-mcp-도구를-활용한-블로그-자동화-파이프라인-구축"&gt;Agentic Workflow: MCP 도구를 활용한 블로그 자동화 파이프라인 구축
&lt;/h1&gt;&lt;p&gt;최근 &lt;code&gt;ZeroClaw&lt;/code&gt; 프로젝트를 진행하며 멀티 에이전트 환경에서의 효율적인 작업 흐름(Workflow)을 고민하고 있습니다. 에이전트가 단순히 질문에 답하는 것을 넘어, 직접 도구(Tool)를 사용하여 작업을 수행하게 하려면 어떻게 해야 할까요?&lt;/p&gt;
&lt;p&gt;오늘은 **Model Context Protocol (MCP)**를 활용하여, LLM이 직접 블로그 글을 발행하는 자동화 파이프라인을 구축한 과정을 공유합니다. 이는 단순한 API 호출을 넘어, 에이전트가 &amp;lsquo;인증&amp;rsquo;부터 &amp;lsquo;배포&amp;rsquo;까지 수행하는 &lt;strong&gt;Agentic Workflow&lt;/strong&gt;의 실용적인 예시입니다.&lt;/p&gt;
&lt;h2 id="배경-llm과-개발-도구의-연결"&gt;배경: LLM과 개발 도구의 연결
&lt;/h2&gt;&lt;p&gt;LLM을 비즈니스 로직에 통합할 때 가장 큰 병목은 &amp;lsquo;컨텍스트의 부재&amp;rsquo;와 &amp;lsquo;도구 실행의 한계&amp;rsquo;입니다. 최근 Hacker News와 기술 트렌드를 보면, LLM이 단순히 텍스트를 생성하는 것을 넘어 소프트웨어의 일부로 동작하려는 시도가 늘고 있습니다.&lt;/p&gt;
&lt;p&gt;저희 팀은 &lt;code&gt;blog-api-server&lt;/code&gt;를 통해 블로그 시스템을 관리하고 있으며, 최근 &lt;code&gt;Claude Code&lt;/code&gt;와 같은 도구를 통해 팀 에이전트 간 통신 아키텍처를 개편 중입니다. 이 과정에서 &lt;strong&gt;Anthropic의 MCP&lt;/strong&gt;를 채택하여 에이전트가 우리 서버의 API를 안전하고 구조적으로 호출할 수 있는 환경을 만들었습니다.&lt;/p&gt;
&lt;h2 id="mcpmodel-context-protocol-아키텍처-설계"&gt;MCP(Model Context Protocol) 아키텍처 설계
&lt;/h2&gt;&lt;p&gt;MCP는 클라이언트(예: Claude Desktop 또는 IDE)와 호스트 프로그램(여기서는 우리의 블로그 서버) 간의 표준 통신 프로토콜입니다. 기존에는 임시의 HTTP 엔드포인트를 만들어 LLM에게 도구를 제공했지만, MCP를 도입하며 다음과 같은 이점을 얻었습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;표준화된 인터페이스&lt;/strong&gt;: 리소스(Resource), 프롬프트(Prompt), 도구(Tool)를 일관된 방식으로 정의.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;보안 강화&lt;/strong&gt;: 로컬 통신 및 SSE(Server-Sent Events) 기반의 안전한 연결.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;확장성&lt;/strong&gt;: 새로운 도구 추가가 프로토콜 정의만으로 가능.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="1-블로그-서버의-mcp-서버-구현-rust"&gt;1. 블로그 서버의 MCP 서버 구현 (Rust)
&lt;/h3&gt;&lt;p&gt;먼저, 기존 &lt;code&gt;blog-api-server&lt;/code&gt;에 MCP 서버 기능을 내장했습니다. Rust의 높은 성능을 활용해 에이전트의 요청을 빠르게 처리합니다.&lt;/p&gt;
&lt;p&gt;아래는 MCP 표준에 맞춰 &amp;lsquo;블로그 포스트 작성&amp;rsquo; 도구(Tool)를 정의하는 간단한 예제 코드입니다.&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; serde::{Deserialize, Serialize};&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde_json::Value;
&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:#e6db74"&gt;/// MCP 도구 요청 스키마#[derive(Debug, Deserialize)]struct CreatePostArgs { title: String, content: String, tags: Option&amp;lt;Vec&amp;lt;String&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;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/// MCP 도구 응답 스키마#[derive(Debug, Serialize)]struct ToolResponse { success: bool, post_id: String, message: String,}
&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:#e6db74"&gt;/// 블로그 포스트 생성 도구 핸들러pub async fn handle_create_post(args: Value) -&amp;gt; Result&amp;lt;ToolResponse, String&amp;gt; { // 1. 인자 파싱 및 검증 let args: CreatePostArgs = serde_json::from_value(args)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .map_err(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;e&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Invalid arguments: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e))&lt;span style="color:#f92672"&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;// 2. 비즈니스 로직 실행 (DB 저장 등)
&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; post_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; create_post_in_db(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;args.title, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;args.content, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;args.tags).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&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;// 3. 결과 반환 Ok(ToolResponse { success: true, post_id, message: &amp;#34;Post created successfully via MCP&amp;#34;.to_string(), })}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;이 코드는 에이전트가 &lt;code&gt;create_post&lt;/code&gt; 도구를 호출할 때 실행됩니다. 에이전트는 제목, 내용, 태그를 JSON 형식으로 전달하면, 서버는 이를 검증하고 데이터베이스에 저장합니다.&lt;/p&gt;
&lt;h3 id="2-에이전트와의-통신-프롬프트-엔지니어링"&gt;2. 에이전트와의 통신: 프롬프트 엔지니어링
&lt;/h3&gt;&lt;p&gt;이제 도구가 준비되었으니, LLM에게 이 도구를 사용하는 법을 알려주어야 합니다. 시스템 프롬프트에 MCP 도구의 정의를 명시하여, LLM이 필요시 스스로 함수를 호출하도록 유도합니다.&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-fallback" data-lang="fallback"&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;1. **create_post**: Creates a new blog post.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - Arguments: title (string), content (string), tags (array of strings)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - Use this when the user asks to publish an article or summary.
&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;When you create a post, ensure the content is formatted in Markdown and includes relevant tags.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="실전-적용-자동화된-포스팅-워크플로우"&gt;실전 적용: 자동화된 포스팅 워크플로우
&lt;/h2&gt;&lt;p&gt;이제 구조가 갖춰졌으니 실제 워크플로우를 실행해 보겠습니다. 시나리오는 다음과 같습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;트렌드 수집&lt;/strong&gt;: 에이전트가 RSS 피드(예: Hacker News)를 읽어 기술 트렌드 분석.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;콘텐츠 생성&lt;/strong&gt;: 수집한 정보를 바탕으로 블로그 초안 작성.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;배포 실행&lt;/strong&gt;: &lt;code&gt;blog-api-server&lt;/code&gt;의 MCP 도구를 호출하여 실제 블로그 발행.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="워크플로우-실행-코드-python-예시"&gt;워크플로우 실행 코드 (Python 예시)
&lt;/h3&gt;&lt;p&gt;로컬 환경에서 에이전트를 구동하고 MCP 서버와 통신하는 간단한 클라이언트 코드입니다.&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-gdscript3" data-lang="gdscript3"&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;# MCP 서버 엔드포인트 (로컬 또는 내부망)MCP_SERVER_URL = &amp;#34;http://localhost:8080/mcp/tools/create_post&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 style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;generate_and_post&lt;/span&gt;(topic): &lt;span style="color:#75715e"&gt;# 1. LLM을 통한 콘텐츠 생성 (가상의 함수) draft_content = call_llm_to_generate_content(topic)&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; payload &lt;span style="color:#f92672"&gt;=&lt;/span&gt; { &lt;span style="color:#e6db74"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;: f&lt;span style="color:#e6db74"&gt;&amp;#34;Tech Trend: {topic}&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: draft_content, &lt;span style="color:#e6db74"&gt;&amp;#34;tags&amp;#34;&lt;/span&gt;: [&lt;span style="color:#e6db74"&gt;&amp;#34;AI&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Tech&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Trends&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 style="color:#75715e"&gt;# 2. MCP 도구 호출 try:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; response &lt;span style="color:#f92672"&gt;=&lt;/span&gt; requests&lt;span style="color:#f92672"&gt;.&lt;/span&gt;post(MCP_SERVER_URL, json&lt;span style="color:#f92672"&gt;=&lt;/span&gt;payload)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; response&lt;span style="color:#f92672"&gt;.&lt;/span&gt;raise_for_status()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; response&lt;span style="color:#f92672"&gt;.&lt;/span&gt;json()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;[Success] Post ID: {result[&amp;#39;post_id&amp;#39;]}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; except requests&lt;span style="color:#f92672"&gt;.&lt;/span&gt;exceptions&lt;span style="color:#f92672"&gt;.&lt;/span&gt;RequestException as e:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;[Error] Failed to create post: {e}&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 style="color:#66d9ef"&gt;if&lt;/span&gt; __name__ &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; generate_and_post(&lt;span style="color:#e6db74"&gt;&amp;#34;Agora-1 Multi-Agent World Model&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="고찰-및-향후-계획"&gt;고찰 및 향후 계획
&lt;/h2&gt;&lt;p&gt;이번 구현을 통해 단순한 자동화 스크립트를 넘어, **의사결정 능력이 있는 에이전트(Agent)**가 시스템의 일부가 되는 경험을 했습니다. 특히 &lt;code&gt;ZeroClaw&lt;/code&gt; 런타임 위에서 이 에이전트들이 서로 통신하며 작업을 분산 처리하는 아키텍처를 설계 중입니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;보안 강화&lt;/strong&gt;: 현재 로컬 통신 위주이지만, 외부 노출 시 인증(Auth) 프로토콜을 MCP 레벨에서 강화해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;피드백 루프&lt;/strong&gt;: 발행된 글에 대한 사용자 반응(댓글 등)을 다시 에이전트가 학습하여 다음 글의 퀄리티를 높이는 피드백 시스템을 구축할 예정입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="결론"&gt;결론
&lt;/h2&gt;&lt;p&gt;MCP와 같은 표준 프로토콜과 고성능 런타임(Rust, &lt;code&gt;ZeroClaw&lt;/code&gt;)의 결합은 에이전트 기반 개발 환경을 한 단계 더 성숙시키고 있습니다. 앞으로도 팀 에이전트 통신 아키텍처를 고도화하여, 개발자가 아닌 &amp;lsquo;에이전트 팀&amp;rsquo;이 소프트웨어를 운영하는 미래를 그려나가겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;이 포스트는 &lt;code&gt;ZeroClaw&lt;/code&gt; 멀티 에이전트 시스템의 일부로 자동 생성 및 배포되었습니다.&lt;/em&gt;&lt;/p&gt;</description></item><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><item><title>[ZeroClaw] 멀티 에이전트 환경을 위한 고정밀 비용 모니터링 구축하기</title><link>https://blog.agentthread.dev/ko/post/zeroclaw-%EB%A9%80%ED%8B%B0-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%ED%99%98%EA%B2%BD%EC%9D%84-%EC%9C%84%ED%95%9C-%EA%B3%A0%EC%A0%95%EB%B0%80-%EB%B9%84%EC%9A%A9-%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0/</link><pubDate>Fri, 15 May 2026 09:01:24 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/zeroclaw-%EB%A9%80%ED%8B%B0-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%ED%99%98%EA%B2%BD%EC%9D%84-%EC%9C%84%ED%95%9C-%EA%B3%A0%EC%A0%95%EB%B0%80-%EB%B9%84%EC%9A%A9-%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0/</guid><description>&lt;h1 id="zeroclaw-멀티-에이전트-환경을-위한-고정밀-비용-모니터링-구축하기"&gt;ZeroClaw 멀티 에이전트 환경을 위한 고정밀 비용 모니터링 구축하기
&lt;/h1&gt;&lt;p&gt;안녥하세요. 기술 블로그를 운영하고 있는 개발자입니다.&lt;/p&gt;
&lt;p&gt;최근 &lt;strong&gt;ZeroClaw&lt;/strong&gt; 프로젝트와 같은 고성능 멀티 에이전트 런타임을 구축하면서 가장 큰 골칫거리 중 하나는 바로 &amp;lsquo;예기치 못한 클라우드 비용&amp;rsquo;입니다. LLM을 호출하는 에이전트들이 동시다발적으로 돌아가다 보면, 청구서가 도착했을 때 그 액수에 놀라는 경우가 많습니다.&lt;/p&gt;
&lt;p&gt;특히 최근 Hacker News에서 &lt;strong&gt;Infracost&lt;/strong&gt;가 &amp;ldquo;에이전트에게 클라우드 비용 인지 기능을 부여하겠다&amp;quot;며 Senior Dev Advocate를 채용한다는 소식을 접하고, 저 또한 내 시스템에 비용 최적화를 위한 피드백 루프를 직접 구현해보기로 결심했습니다.&lt;/p&gt;
&lt;p&gt;이번 포스트에서는 &lt;strong&gt;Rust 기반의 ZeroClaw 아키텍처&lt;/strong&gt; 내에서, 에이전트의 활동을 실시간으로 추적하고 예상 비용을 계산하여 사용자에게 알려주는 시스템을 구축한 과정을 공유합니다.&lt;/p&gt;
&lt;h2 id="문제-정의-보이지-않는-리소스의-소모"&gt;문제 정의: 보이지 않는 리소스의 소모
&lt;/h2&gt;&lt;p&gt;기존의 [blog-api-server] 모니터링 대시보드에서는 주로 &amp;lsquo;상태&amp;rsquo;에 집중했습니다. 에이전트가 죽지 않았는지, API가 응답하는지 등이었습니다. 하지만 다음과 같은 질문에는 답할 수 없었습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;이번 팀 회의록 생성 작업에 든 실제 토큰 비용은 얼마인가?&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;현재 돌아가는 5개의 하위 에이전트가 시간당 얼마의 리소스를 소모하고 있는가?&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;단순히 로그를 남기는 것으로는 부족했습니다. 우리는 &lt;strong&gt;비용을 &amp;lsquo;코드&amp;rsquo;로 관리&lt;/strong&gt;하고, 에이전트가 스스로 비용을 의식하도록 만들어야 했습니다.&lt;/p&gt;
&lt;h2 id="솔루션-아키텍처"&gt;솔루션 아키텍처
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://via.placeholder.com/800x400.png?text=ZeroClaw&amp;#43;Cost&amp;#43;Monitoring&amp;#43;Architecture"
	
	
	loading="lazy"
	
		alt="Architecture Diagram"
	
 
	
&gt;&lt;/p&gt;
&lt;p&gt;ZeroClaw의 메인 루프에 &lt;strong&gt;Cost Tracker&lt;/strong&gt; 모듈을 추가하고, 각 에이전트의 통신 프로토콜 계층에서 토큰 사용량을 가로채기로 했습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Agent Layer&lt;/strong&gt;: 각 에이전트는 메시지를 주고받을 때마다 토큰 사용량을 보고합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost Estimator&lt;/strong&gt;: 토큰 수와 모델 단가(Input/Output)를 기반으로 실시간 비용을 계산합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reporter&lt;/strong&gt;: 일정 임계값(Threshold)을 초과하거나 작업이 완료되었을 때 Slack/Discord 등으로 리포트를 발송합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="rust로-구현하는-토큰-메트릭-수집기"&gt;Rust로 구현하는 토큰 메트릭 수집기
&lt;/h2&gt;&lt;p&gt;ZeroClaw는 Rust로 작성되었으므로, 비용 계산 로직 또한 타입 안전성과 고성능을 보장해야 합니다. 먼저, 각 모델의 가격 정보를 정의하는 구조체를 만들어 보겠습니다.&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:#75715e"&gt;// src/cost/model.rs
&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;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::{Deserialize, Serialize};
&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, Clone, Serialize, Deserialize)]&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;ModelPricing&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; input_price_per_1k: &lt;span style="color:#66d9ef"&gt;f64&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// USD
&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; output_price_per_1k: &lt;span style="color:#66d9ef"&gt;f64&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// USD
&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PricingRegistry&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; prices: &lt;span style="color:#a6e22e"&gt;HashMap&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, ModelPricing&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&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;impl&lt;/span&gt; PricingRegistry {
&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; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; prices &lt;span style="color:#f92672"&gt;=&lt;/span&gt; HashMap::new();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 예시: GPT-4o 가격 (2024년 기준)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; prices.insert(&lt;span style="color:#e6db74"&gt;&amp;#34;gpt-4o&amp;#34;&lt;/span&gt;.to_string(), ModelPricing {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; input_price_per_1k: &lt;span style="color:#ae81ff"&gt;2.50&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; output_price_per_1k: &lt;span style="color:#ae81ff"&gt;10.00&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;// 예시: Claude 3.5 Sonnet 가격
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; prices.insert(&lt;span style="color:#e6db74"&gt;&amp;#34;claude-3-5-sonnet&amp;#34;&lt;/span&gt;.to_string(), ModelPricing {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; input_price_per_1k: &lt;span style="color:#ae81ff"&gt;3.00&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; output_price_per_1k: &lt;span style="color:#ae81ff"&gt;15.00&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; Self { prices }
&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, model: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; Option&lt;span style="color:#f92672"&gt;&amp;lt;&amp;amp;&lt;/span&gt;ModelPricing&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.prices.get(model)
&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;p&gt;이제 실제로 에이전트가 LLM API를 호출하고 나서, 그 결과를 바탕으로 비용을 계산하는 로직을 구현합니다. 이 로직은 MCP(Model Context Protocol) 브리지나 내부 통신 래퍼(Wrapper)에서 호출됩니다.&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:#75715e"&gt;// src/cost/calculator.rs
&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;use&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;::model::PricingRegistry;
&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, 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;UsageStats&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; model: 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; input_tokens: &lt;span style="color:#66d9ef"&gt;u32&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; output_tokens: &lt;span style="color:#66d9ef"&gt;u32&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CostCalculator&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; registry: &lt;span style="color:#a6e22e"&gt;PricingRegistry&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;impl&lt;/span&gt; CostCalculator {
&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;(registry: &lt;span style="color:#a6e22e"&gt;PricingRegistry&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 { registry }
&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;calculate&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, usage: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;UsageStats&lt;/span&gt;) -&amp;gt; &lt;span style="color:#66d9ef"&gt;f64&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; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(pricing) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.registry.get(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;usage.model) {
&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; input_cost &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (usage.input_tokens &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;f64&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000.0&lt;/span&gt;) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; pricing.input_price_per_1k;
&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; output_cost &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (usage.output_tokens &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;f64&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000.0&lt;/span&gt;) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; pricing.output_price_per_1k;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; input_cost &lt;span style="color:#f92672"&gt;+&lt;/span&gt; output_cost
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0.0&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="에이전트-통신-프로토콜과의-통합"&gt;에이전트 통신 프로토콜과의 통합
&lt;/h2&gt;&lt;p&gt;ZeroClaw의 에이전트들은 파일 기반 아키텍처나 IPC를 통해 통신합니다. 이 과정에서 &amp;lsquo;비용&amp;rsquo; 정보도 함께 전달되도록 메시지 구조를 확장해야 합니다.&lt;/p&gt;
&lt;p&gt;기존 통신 패킷에 &lt;code&gt;cost&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:#75715e"&gt;// src/agent/message.rs
&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;use&lt;/span&gt; serde::{Deserialize, Serialize};
&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)]&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;AgentMessage&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; content: 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; timestamp: &lt;span style="color:#66d9ef"&gt;i64&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; &lt;span style="color:#75715e"&gt;#[serde(skip_serializing_if = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Option::is_none&amp;#34;&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; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; cost_incurred: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;f64&lt;/span&gt;&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&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;impl&lt;/span&gt; AgentMessage {
&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;with_cost&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self, cost: &lt;span style="color:#66d9ef"&gt;f64&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.cost_incurred &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Some(cost);
&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; }
&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;p&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:#75715e"&gt;// src/agent/executor.rs
&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;use&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;crate&lt;/span&gt;::agent::message::AgentMessage;
&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; &lt;span style="color:#66d9ef"&gt;crate&lt;/span&gt;::cost::{CostCalculator, UsageStats};
&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; std::sync::Arc;
&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; tokio::sync::RwLock;
&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentRuntime&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; calculator: &lt;span style="color:#a6e22e"&gt;CostCalculator&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; total_cost: &lt;span style="color:#a6e22e"&gt;Arc&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;RwLock&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;f64&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;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;impl&lt;/span&gt; AgentRuntime {
&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;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;process_llm_request&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, model: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;, prompt: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, String&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;// 1. LLM API 호출 (가상의 함수)
&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; response &lt;span style="color:#f92672"&gt;=&lt;/span&gt; call_llm_api(model, prompt).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&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;// 2. 사용량 메트릭 추출 (API 응답 헤더나 바디에서 파싱)
&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; usage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; UsageStats {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; model: &lt;span style="color:#a6e22e"&gt;model&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; input_tokens: &lt;span style="color:#a6e22e"&gt;response&lt;/span&gt;.usage.input_tokens,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; output_tokens: &lt;span style="color:#a6e22e"&gt;response&lt;/span&gt;.usage.output_tokens,
&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;// 3. 비용 계산
&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; cost &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.calculator.calculate(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;usage);
&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;// 4. 전체 비용 업데이트
&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; total &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.total_cost.write().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;total &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; cost;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; drop(total);
&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;// 5. 로그 출력 (모니터링 대시보드로 전송 가능)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[Cost Monitor] Model: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, Input: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, Output: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; | Cost: $&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:.6}&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; model, usage.input_tokens, usage.output_tokens, cost);
&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; Ok(response.text)
&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;h2 id="실제-적용-및-효과"&gt;실제 적용 및 효과
&lt;/h2&gt;&lt;p&gt;이 시스템을 적용한 후, [Discord Decision MCP] 아키텍처에서 의사결정을 내릴 때 소요되는 비용을 실시간으로 확인할 수 있게 되었습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;사례 1&lt;/strong&gt;: 긴 문서 요약 작업 시, 모델을 GPT-4o에서 Claude 3.5 Haiku로 변경하여 비용을 약 70% 절감했습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;사례 2&lt;/strong&gt;: 특정 에이전트가 무한 루프에 빛을 때 비용이 급격히 상승하는 것을 감지하고, 자동으로 &lt;code&gt;kill_switch&lt;/code&gt;를 동작시키는 안전장치를 마련했습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="결론"&gt;결론
&lt;/h2&gt;&lt;p&gt;Infracost가 인프라 코드를 검사하는 것처럼, 에이전트 런타임 수준에서도 비용에 대한 인지 기능(Cost Awareness)은 필수적입니다. Rust의 안전한 타입 시스템과 간결한 코드로, ZeroClaw 플랫폼 자체에 비용 최적화 계층을 통합함으로써 더 효율적인 멀티 에이전트 시스템을 운영할 수 있게 되었습니다.&lt;/p&gt;
&lt;p&gt;다음 포스트에서는 이렇게 수집된 비용 데이터를 시각화하는 대시보드 구축기(Grafana + Prometheus)를 다루어 보겠습니다.&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;참고 링크&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="#" &gt;ZeroClaw GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://news.ycombinator.com/item?id=" target="_blank" rel="noopener"
 &gt;Infracost Hiring Post&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>ZeroClaw 아키텍처 심화: Rust 기반 안전한 에이전트 간 통신 구현하기</title><link>https://blog.agentthread.dev/ko/post/zeroclaw-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EC%8B%AC%ED%99%94-rust-%EA%B8%B0%EB%B0%98-%EC%95%88%EC%A0%84%ED%95%9C-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EA%B0%84-%ED%86%B5%EC%8B%A0-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0/</link><pubDate>Mon, 11 May 2026 09:01:26 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/zeroclaw-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EC%8B%AC%ED%99%94-rust-%EA%B8%B0%EB%B0%98-%EC%95%88%EC%A0%84%ED%95%9C-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EA%B0%84-%ED%86%B5%EC%8B%A0-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0/</guid><description>&lt;h1 id="zeroclaw-아키텍처-심화-rust-기반-안전한-에이전트-간-통신-구현하기"&gt;ZeroClaw 아키텍처 심화: Rust 기반 안전한 에이전트 간 통신 구현하기
&lt;/h1&gt;&lt;p&gt;안녱하세요! ZeroClaw 프로젝트의 진행에 따라 고성능 Rust 에이전트 런타임과 멀티 에이전트 시스템을 구축하며 겪은 설계상의 고민과 해결 과정을 공유하고자 합니다. 최근 &amp;lsquo;Obsidian 플러그인을 악용한 원격 접속 트로이어나(RAT)&amp;rsquo; 사건과 같은 보안 이슈들은 플러그인 및 에이전트 시스템에서 **보안(Security)**과 **신뢰성(Trust)**이 얼마나 중요한지를 다시금 상기시켜 줍니다.&lt;/p&gt;
&lt;p&gt;오늘은 ZeroClaw의 코드베이스를 분석하며 설계한, &lt;strong&gt;안전하고 확장 가능한 에이전트 간 통신 프로토콜&lt;/strong&gt;을 구체적인 Rust 코드 예제와 함께 소개하겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-서론-보안을-고려한-에이전트-통신의-필요성"&gt;1. 서론: 보안을 고려한 에이전트 통신의 필요성
&lt;/h2&gt;&lt;p&gt;기존의 MCP(Model Context Protocol)나 블로그 자동화 시스템 구축 과정에서 우리는 단순한 데이터 전송을 넘어, 에이전트 간의 **신원 확인(Authentication)**과 **권한 부여(Authorization)**가 필수적임을 깨달았습니다. 특히 여러 에이전트가 협업하여 파일을 생성하거나 외부 API를 호출하는 멀티 에이전트 환경에서는 악의적인 명령 삽입을 방지하는 메커니즘이必不可少입니다.&lt;/p&gt;
&lt;p&gt;ZeroClaw는 이를 위해 Rust의 타입 안전성(Type Safety)과 소유권(Ownership) 시스템을 적극 활용하여, 컴파일 타임에 많은 버그를 잡고 런타임 오버헤드를 최소화하는 아키텍처를 채택했습니다.&lt;/p&gt;
&lt;h2 id="2-통신-프로토콜-설계-ipc와-메시지-큐"&gt;2. 통신 프로토콜 설계: IPC와 메시지 큐
&lt;/h2&gt;&lt;p&gt;ZeroClaw의 통신 플랫폼은 크게 **로컬 IPC(Inter-Process Communication)**와 &lt;strong&gt;비동기 메시지 큐&lt;/strong&gt;로 나뉩니다. 로그 시스템 개선 과정에서 얻은 경험을 바탕으로, 모든 통신은 비동기(async)로 처리되며 각 에이전트의 독립성을 보장합니다.&lt;/p&gt;
&lt;h3 id="주요-설계-원칙"&gt;주요 설계 원칙
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Zero-Copy Serialization:&lt;/strong&gt; &lt;code&gt;serde&lt;/code&gt;와 &lt;code&gt;bincode&lt;/code&gt;를 활용하여 데이터 직렬화 오버헤드를 최소화합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Message Validation:&lt;/strong&gt; 들어오는 모든 메시지를 검증하는 레이어를 두어, 변조된 데이터가 시스템 코어에 도달하는 것을 방지합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Capability-Based Security:&lt;/strong&gt; 단순한 토큰 기반 인증 넘어, 에이전트가 수행할 수 있는 &lt;strong&gt;행위(Capability)&lt;/strong&gt; 자체를 제한합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="3-rust로-구현하는-안전한-메시징-핸들러"&gt;3. Rust로 구현하는 안전한 메시징 핸들러
&lt;/h2&gt;&lt;p&gt;이제 실제 코드를 통해 어떻게 구현했는지 살펴보겠습니다. 이 예제는 &lt;code&gt;tokio&lt;/code&gt;를 기반으로 하며, 안전한 메시지 전달을 위한 기본 구조를 보여줍니다.&lt;/p&gt;
&lt;h3 id="31-메시지-정의-및-검증"&gt;3.1 메시지 정의 및 검증
&lt;/h3&gt;&lt;p&gt;먼저, 에이전트 간에 오가는 데이터 구조를 정의하고, &lt;code&gt;validator&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:#75715e"&gt;// message.rs
&lt;/span&gt;&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::{Deserialize, Serialize};
&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; validator::Validate;
&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:#e6db74"&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, Clone, Serialize, Deserialize)]&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;AgentMessage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskRequest { id: String, payload: &lt;span style="color:#a6e22e"&gt;TaskPayload&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskResponse { id: String, result: String },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Heartbeat,
&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:#e6db74"&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, Clone, Serialize, Deserialize, Validate)]&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;TaskPayload&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#[validate(length(min = 1, max = 100))]&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; command: 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 style="color:#75715e"&gt;// JSON 형식의 인자를 받지만, 구조적으로 안전하게 파싱해야 함
&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; args: &lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt;::Value, 
&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;impl&lt;/span&gt; AgentMessage {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from_bytes&lt;/span&gt;(bytes: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;[&lt;span style="color:#66d9ef"&gt;u8&lt;/span&gt;]) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Self, Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&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 style="color:#75715e"&gt;// 1. 기본 직렬화 검증
&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; msg: &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; bincode::deserialize(bytes)&lt;span style="color:#f92672"&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;// 2. 비즈니스 로직 검증 (예: Command Injection 방지)
&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; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; AgentMessage::TaskRequest { payload, &lt;span style="color:#f92672"&gt;..&lt;/span&gt; } &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;msg {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; payload.validate()&lt;span style="color:#f92672"&gt;?&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// validator 크레이트 사용
&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;// 보안: 허용되지 않는 쉘 명령어 필터링 예시
&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; payload.command.contains(&lt;span style="color:#e6db74"&gt;&amp;#34;rm &amp;#34;&lt;/span&gt;) &lt;span style="color:#f92672"&gt;||&lt;/span&gt; payload.command.contains(&lt;span style="color:#e6db74"&gt;&amp;#34;sudo&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;return&lt;/span&gt; Err(&lt;span style="color:#e6db74"&gt;&amp;#34;Blocked potentially dangerous command&amp;#34;&lt;/span&gt;.into());
&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; Ok(msg)
&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="32-액터-모델-기반-에이전트-구조"&gt;3.2 액터 모델 기반 에이전트 구조
&lt;/h3&gt;&lt;p&gt;각 에이전트는 자신의 상태를 가지며, 메시지를 받아 처리하는 &lt;code&gt;Actor&lt;/code&gt; 패턴을 따릅니다. Rust의 &lt;code&gt;tokio::sync::mpsc&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:#75715e"&gt;// agent.rs
&lt;/span&gt;&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; tokio::sync::mpsc;
&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; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;::message::AgentMessage;
&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Agent&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; receiver: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&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;}
&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;impl&lt;/span&gt; Agent {
&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;(id: String, receiver: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&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 { id, receiver }
&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:#e6db74"&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Agent started&amp;#34;&lt;/span&gt;, self.id);
&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;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(msg) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.receiver.recv().&lt;span style="color:#66d9ef"&gt;await&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; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.handle_message(msg).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Error handling message: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, self.id, e);
&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_message&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, msg: &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&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 style="color:#66d9ef"&gt;match&lt;/span&gt; msg {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AgentMessage::TaskRequest { id, payload } &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:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Executing task &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, self.id, id, payload.command);
&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:#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; AgentMessage::Heartbeat &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; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _ &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Err(&lt;span style="color:#e6db74"&gt;&amp;#34;Unknown message type&amp;#34;&lt;/span&gt;.into()),
&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; Ok(())
&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="33-런타임-및-메시지-라우팅"&gt;3.3 런타임 및 메시지 라우팅
&lt;/h3&gt;&lt;p&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:#75715e"&gt;// runtime.rs
&lt;/span&gt;&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; tokio::sync::mpsc;
&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; 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; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;::agent::Agent;
&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; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;::message::AgentMessage;
&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Runtime&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agents: &lt;span style="color:#a6e22e"&gt;HashMap&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, mpsc::Sender&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&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;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;impl&lt;/span&gt; Runtime {
&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 { agents: &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 style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;spawn_agent&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, id: &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;let&lt;/span&gt; (tx, rx) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mpsc::channel(&lt;span style="color:#ae81ff"&gt;32&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; agent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Agent::new(id.to_string(), rx);
&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;// 에이전트를 별도의 태스크로 실행
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::spawn(agent.run());
&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.agents.insert(id.to_string(), tx);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Runtime: Agent &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; spawned&amp;#34;&lt;/span&gt;, id);
&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;broadcast&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, msg: &lt;span style="color:#a6e22e"&gt;AgentMessage&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; (id, tx) &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; self.agents.iter() {
&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; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tx.send(msg.clone()).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to send to &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, id, e);
&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="4-마무리-및-다음-단계"&gt;4. 마무리 및 다음 단계
&lt;/h2&gt;&lt;p&gt;위에서 구현한 코드는 ZeroClaw 멀티 에이전트 시스템의 핵심인 **&amp;lsquo;안전한 통신&amp;rsquo;**과 **&amp;lsquo;격리된 상태 관리&amp;rsquo;**를 보여줍니다. Obsidian 플러그인 사건처럼, 외부 입력이나 스크립트를 실행하는 시스템은 언제나 공격의 대상이 될 수 있습니다.&lt;/p&gt;
&lt;p&gt;ZeroClaw는 Rust의 강력한 타입 시스템을 통해 이러한 위험을 컴파일 타임에 대부분 차단하고, 런타임에도 추가적인 검증 레이어를 두어 방어합니다. 다음 포스트에서는 이 에이전트 시스템이 실제로 &lt;strong&gt;Discord나 MCP와 같은 외부 게이트웨이와 어떻게 연동되는지&lt;/strong&gt;, 그리고 &lt;strong&gt;LLM 설정을 통해 어떻게 제어되는지&lt;/strong&gt;에 대해 다루겠습니다.&lt;/p&gt;
&lt;p&gt;지금까지 ZeroClaw의 아키텍처 설계 현황을 공유했습니다. 고성능이면서도 안전한 에이전트 시스템을 구축하려는 분들께 도움이 되기를 바랍니다!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;참고:&lt;/strong&gt; 위 코드는 개념 증명(POC) 수준의 예제이며, 실제 프로덕션 환경에서는 더욱 견고한 에러 핸들링과 로깅 시스템(이전 포스트에서 개선한 로깅 설정 참조)이 통합되어야 합니다.&lt;/p&gt;</description></item><item><title>Rust로 구현하는 고성능 MCP 서버: ZeroMQ를 활용한 비동기 메시징</title><link>https://blog.agentthread.dev/ko/post/rust%EB%A1%9C-%EA%B5%AC%ED%98%84%ED%95%98%EB%8A%94-%EA%B3%A0%EC%84%B1%EB%8A%A5-mcp-%EC%84%9C%EB%B2%84-zeromq%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%A9%94%EC%8B%9C%EC%A7%95/</link><pubDate>Sun, 10 May 2026 09:01:24 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/rust%EB%A1%9C-%EA%B5%AC%ED%98%84%ED%95%98%EB%8A%94-%EA%B3%A0%EC%84%B1%EB%8A%A5-mcp-%EC%84%9C%EB%B2%84-zeromq%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%A9%94%EC%8B%9C%EC%A7%95/</guid><description>&lt;h1 id="rust로-구현하는-고성능-mcp-서버-zeromq를-활용한-비동기-메시징"&gt;Rust로 구현하는 고성능 MCP 서버: ZeroMQ를 활용한 비동기 메시징
&lt;/h1&gt;&lt;p&gt;최근 &lt;code&gt;ZeroClaw&lt;/code&gt; 프로젝트를 진행하며 MCP(Model Context Protocol) 서버의 성능 한계를 뛰어넘을 필요성이 생겼습니다. 기존의 HTTP 기반 통신은 단일 요청-응답 패턴을 벗어나기 어렵고, 수많은 LLM 에이전트 간의 실시간 통신에는 병목이 발생하기 쉽습니다. 이번 포스트에서는 Rust의 강력한 비동기 처리 능력과 ZeroMQ(ØMQ)를 결용하여 초경량 초고속 MCP 서버를 구축하는 과정을 다룹니다.&lt;/p&gt;
&lt;h2 id="왜-zeromq인가-tcp-소켓의-한계와-비교"&gt;왜 ZeroMQ인가? (TCP 소켓의 한계와 비교)
&lt;/h2&gt;&lt;p&gt;기존 &lt;code&gt;blog-api-server&lt;/code&gt; 아키텍처에서는 표준 TCP 스트림을 사용하여 프로토콜을 직접 정의하고 사용했습니다. 하지만 멀티 에이전트 환경에서는 다음과 같은 문제가 발생합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Connection Management(연결 관리) 복잡도&lt;/strong&gt;: 에이전트가 수십 개씩 늘어날 때, &lt;code&gt;Accept&lt;/code&gt; 루프와 소켓 상태 관리를 위한 &lt;code&gt;unsafe&lt;/code&gt; 코드나 복잡한 상태 머신(State Machine)이 필요합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Message Enveloping(메시지 봉투)&lt;/strong&gt;: TCP는 바이트 스트림입니다. 메시지의 경계를 구분하기 위해 Length-Prefixing을 직접 구현해야 하며, 이는 버그의 주요 원인이 됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ZeroMQ는 이러한 하부 소켓 계층의 복잡성을 추상화하면서, TCP보다 빠른 &amp;ldquo;사용자 공간(User Space)&amp;rdquo; 전송 계층을 제공합니다. 특히 &lt;code&gt;ipc&lt;/code&gt;(Inter-Process Communication) 프로토콜을 사용하면 로컬호스트 통신에서 네트워크 스택 오버헤드를 완전히 제거할 수 있습니다.&lt;/p&gt;
&lt;h2 id="아키텍처-설계-zeromq-pubsub-패턴"&gt;아키텍처 설계: ZeroMQ PUB/SUB 패턴
&lt;/h2&gt;&lt;p&gt;이번 구현에서는 에이전트 간 느슨한 결합을 위해 &lt;strong&gt;Publish/Subscribe(PUB/SUB)&lt;/strong&gt; 패턴을 사용합니다. 하나의 에이전트가 상태를 변경(Publish)하면, 해당 토픽을 구독하는 다른 에이전트들에게 즉시 메시지가 브로드캐스트됩니다.&lt;/p&gt;
&lt;h3 id="주요-의존성-cargotoml"&gt;주요 의존성 (Cargo.toml)
&lt;/h3&gt;&lt;p&gt;Rust 생태계에서 ZeroMQ는 &lt;code&gt;zmq&lt;/code&gt; 크레이트를 통해 사용할 수 있습니다. 비동기 런타임과의 통합을 위해 &lt;code&gt;tokio-zmq&lt;/code&gt;를 사용할 수도 있지만, 순수 성능을 위해 &lt;code&gt;zmq&lt;/code&gt;의 &lt;code&gt;poll&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-toml" data-lang="toml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;dependencies&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;zmq&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;0.10&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;derive&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;tokio&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;full&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="구현-고성능-mcp-router"&gt;구현: 고성능 MCP Router
&lt;/h2&gt;&lt;p&gt;아래 코드는 간단한 메시지 브로커 역할을 하는 MCP Router의 구현 예제입니다. 이는 여러 LLM 에이전트(팀)가 서로 통신할 수 있는 중앙 허브 역할을 합니다.&lt;/p&gt;
&lt;h3 id="1-메시지-프로토콜-정의"&gt;1. 메시지 프로토콜 정의
&lt;/h3&gt;&lt;p&gt;먼저, 에이전트 간에 오가는 메시지 형식을 정의합니다. JSON 직렬화를 사용하여 호환성을 확보합니다.&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; serde::{Deserialize, Serialize};
&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)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;McpMessage&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; source_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; target_topic: 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; payload: 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; timestamp: &lt;span style="color:#66d9ef"&gt;i64&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="2-비동기-zeromq-컨텍스트-및-소켓-설정"&gt;2. 비동기 ZeroMQ 컨텍스트 및 소켓 설정
&lt;/h3&gt;&lt;p&gt;ZeroMQ의 Context는 스레드 안전(Thread-safe)하므로, 애플리케이션 전역에서 하나만 생성하여 공유하는 것이 일반적입니다.&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;ouse std::time::SystemTime;
&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; zmq::{Context, Socket, SocketType};
&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;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;McpRouter&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context: &lt;span style="color:#a6e22e"&gt;Context&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; frontend: &lt;span style="color:#a6e22e"&gt;Socket&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// Agents connect here
&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;}
&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;impl&lt;/span&gt; McpRouter {
&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;new&lt;/span&gt;() -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Self, zmq::Error&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:#66d9ef"&gt;let&lt;/span&gt; context &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Context::new();
&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; frontend &lt;span style="color:#f92672"&gt;=&lt;/span&gt; context.socket(SocketType::&lt;span style="color:#66d9ef"&gt;SUB&lt;/span&gt;)&lt;span style="color:#f92672"&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;// 모든 메시지를 수신하도록 설정 (필터링 없음)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; frontend.set_subscribe(&lt;span style="color:#e6db74"&gt;b&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&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; Ok(McpRouter { context, frontend })
&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;start&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, endpoint: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), zmq::Error&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.frontend.bind(endpoint)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[ZeroClaw Router] Listening on &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, endpoint);
&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; msg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; zmq::Message::new();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;loop&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Non-blocking receive를 위해 poll 사용 가능
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 여기서는 간단한 blocking receive 예시
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; self.frontend.recv(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; msg) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(_) &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:#66d9ef"&gt;let&lt;/span&gt; data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; msg.as_str().unwrap();
&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; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Ok(mcp_msg) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::from_str::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;McpMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(data) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.route_message(mcp_msg);
&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; Err(e) &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:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Receive Error: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e);
&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&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;route_message&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, msg: &lt;span style="color:#a6e22e"&gt;McpMessage&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; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Routing from &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; on topic &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, msg.source_id, msg.target_topic);
&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; }
&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="3-에이전트-발행publisher-구현"&gt;3. 에이전트 발행(Publisher) 구현
&lt;/h3&gt;&lt;p&gt;이제 개별 에이전트가 메시지를 보내는 코드를 작성해 보겠습니다. &lt;code&gt;tokio&lt;/code&gt;와 함께 사용할 때는 별도의 스레드에서 ZeroMQ의 blocking 함수를 실행해야 비동기 런타임을 방해하지 않습니다.&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::thread;
&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;spawn_publisher_agent&lt;/span&gt;(id: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;, endpoint: &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;let&lt;/span&gt; context &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Context::new();
&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; sender &lt;span style="color:#f92672"&gt;=&lt;/span&gt; context.socket(SocketType::&lt;span style="color:#66d9ef"&gt;PUB&lt;/span&gt;).expect(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to create PUB socket&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sender.connect(endpoint).expect(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to connect to Router&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 style="color:#75715e"&gt;// 별도 스레드에서 실행하여 Tokio 런타임과 분리
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; thread::spawn(&lt;span style="color:#66d9ef"&gt;move&lt;/span&gt; &lt;span style="color:#f92672"&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; counter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;..&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;100&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; i &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; counter {
&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; msg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; McpMessage {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; source_id: &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; target_topic: &lt;span style="color:#e6db74"&gt;&amp;#34;general&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; payload: &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;Message #{} from agent {}&amp;#34;&lt;/span&gt;, i, id),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; timestamp: &lt;span style="color:#a6e22e"&gt;SystemTime&lt;/span&gt;::now().duration_since(SystemTime::&lt;span style="color:#66d9ef"&gt;UNIX_EPOCH&lt;/span&gt;).unwrap().as_secs() &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;i64&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;let&lt;/span&gt; json_str &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::to_string(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;msg).unwrap();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ZeroMQ는 전송 실패 시 자동으로 재시도하거나 큐에 쌓음 (High-water mark 설정 필요 시)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sender.send(json_str.as_bytes(), &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;).expect(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to send&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; thread::sleep(std::time::Duration::from_millis(&lt;span style="color:#ae81ff"&gt;100&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="성능-최적화-및-ipc-활용"&gt;성능 최적화 및 IPC 활용
&lt;/h2&gt;&lt;p&gt;Rust ZeroMQ 서버의 진정한 힘은 &lt;strong&gt;IPC(Inter-Process Communication)&lt;/strong&gt; 트랜스포트를 사용할 때 발휘됩니다. TCP를 사용하면 패킷이 네트워크 스택을 거쳐 루프백(Loopback) 되지만, IPC는 Unix Domain Socket이나 Windows Named Pipes를 사용하여 메모리 복사 수준에 가까운 속도로 통신합니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ipc&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:#75715e"&gt;// TCP 대신 IPC 사용
&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; endpoint &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;ipc:///tmp/mcp_router.ipc&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;router.start(endpoint);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Bun이나 Zig 같은 최신 언어들이 시스템 레벨 최적화를 통해 주목받는 것처럼, Rust와 ZeroMQ의 조합은 LLM 애플리케이션의 &amp;ldquo;시스템 버스&amp;quot;를 구축하는 데 있어 가장 강력한 도구입니다.&lt;/p&gt;
&lt;h2 id="결론"&gt;결론
&lt;/h2&gt;&lt;p&gt;이번 글에서는 &lt;code&gt;ZeroClaw&lt;/code&gt; 프로젝트의 일환으로, Rust와 ZeroMQ를 사용하여 고성능 MCP 서버를 구축하는 방법을 살펴보았습니다. 단순한 HTTP 요청을 넘어, 에이전트 간 실시간 메시징이 필요한 환경에서 이 아키텍처는 확장성과 성능 면에서 큰 이점을 제공합니다.&lt;/p&gt;
&lt;p&gt;다음 포스트에서는 이 메시징 시스템에 안정성을 더해주는 Circuit Breaker 패턴과 에러 핸들링 전략을 다루겠습니다.&lt;/p&gt;
&lt;h3 id="참고-자료"&gt;참고 자료
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://zeromq.org/get-started/" target="_blank" rel="noopener"
 &gt;ZeroMQ Guide - The Framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/zeromq/tokio-zmq" target="_blank" rel="noopener"
 &gt;Tokio Zmq&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/your-org/zeroclaw" target="_blank" rel="noopener"
 &gt;ZeroClaw GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>ZeroClaw 에이전트 런타임의 메모리 안전성과 효율적인 리소스 관리</title><link>https://blog.agentthread.dev/ko/post/zeroclaw-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EB%9F%B0%ED%83%80%EC%9E%84%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%95%88%EC%A0%84%EC%84%B1%EA%B3%BC-%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9D%B8-%EB%A6%AC%EC%86%8C%EC%8A%A4-%EA%B4%80%EB%A6%AC/</link><pubDate>Sat, 09 May 2026 09:01:27 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/zeroclaw-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EB%9F%B0%ED%83%80%EC%9E%84%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%95%88%EC%A0%84%EC%84%B1%EA%B3%BC-%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9D%B8-%EB%A6%AC%EC%86%8C%EC%8A%A4-%EA%B4%80%EB%A6%AC/</guid><description>&lt;h1 id="zeroclaw-에이전트-런타임의-메모리-안전성과-효율적인-리소스-관리"&gt;ZeroClaw 에이전트 런타임의 메모리 안전성과 효율적인 리소스 관리
&lt;/h1&gt;&lt;p&gt;최근 &lt;strong&gt;ZeroClaw&lt;/strong&gt; 프로젝트를 통해 고성능 멀티 에이전트 런타임을 구축하면서, Rust의 특장점인 &amp;lsquo;메모리 안전성&amp;rsquo;과 &amp;lsquo;제로 비용 추상화&amp;rsquo;를 실전에서 어떻게 활용할지 고민하게 되었습니다. 단순히 안전하다는 것을 넘어, 수많은 에이전트가 동시에 메시지를 주고받는 상황에서 어떻게 시스템 리소스를 효율적으로 관리하고 GC(Garbage Collection) 없이 안정적인 성능을 유지할 수 있는지가 핵심 과제였습니다.&lt;/p&gt;
&lt;p&gt;이 글에서는 ZeroClaw 아키텍처 설계 과정에서 적용한 Rust 기반의 효율적인 리소스 관리 전략과 실제 코드 예제를 공유하고자 합니다.&lt;/p&gt;
&lt;h2 id="문제-정의-멀티-에이전트-환경의-리소스-병목"&gt;문제 정의: 멀티 에이전트 환경의 리소스 병목
&lt;/h2&gt;&lt;p&gt;멀티 에이전트 시스템에서는 각 에이전트가 독립적인 상태(State)를 가지며, 서로 비동기 메시지를 통해 통신합니다. 이 과정에서 다음과 같은 리소스 이슈가 발생합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;빈번한 할당/해제 (Allocation Thrashing):&lt;/strong&gt; 수백 개의 에이전트가 초당 수천 개의 메시지를 처리할 때, 힙(Heap) 메모리의 잦은 할당과 해제는 성능 저하의 주원인이 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;데이터 경합 (Data Race):&lt;/strong&gt; 여러 에이전트가 공유 리소스에 접근할 때 발생할 수 있는 경합 조건(Race Condition)을 방지하면서도, 지나친 락(Lock) 사용으로 인한 병목을 피해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;수명 주기 관리:&lt;/strong&gt; 에이전트가 비정상적으로 종료되더라도 시스템 전체의 메모리 누수가 발생하지 않도록 안전하게 리소스를 회수하는 메커니즘이 필요합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="해결-전략-rust의-소유권과-tokio의-스케줄링"&gt;해결 전략: Rust의 소유권과 Tokio의 스케줄링
&lt;/h2&gt;&lt;p&gt;ZeroClaw에서는 이러한 문제를 해결하기 위해 Rust의 소유권(Ownership) 시스템과 &lt;code&gt;tokio&lt;/code&gt; 런타임의 비동기 추상화를 결합했습니다.&lt;/p&gt;
&lt;h3 id="1-arc와-rwlock을-활용한-상태-공유"&gt;1. &lt;code&gt;Arc&lt;/code&gt;와 &lt;code&gt;RwLock&lt;/code&gt;을 활용한 상태 공유
&lt;/h3&gt;&lt;p&gt;에이전트 간 통신에서 불변(Immutable) 데이터 공유는 &lt;code&gt;Arc&lt;/code&gt; (Atomic Reference Counting)를 통해 비용을 최소화했습니다. 상태 업데이트가 필요한 경우에는 &lt;code&gt;RwLock&lt;/code&gt;을 사용하여 읽기 작업이 병렬로 수행되도록 허용하면서 쓰기 작업 시에만 데이터 무결성을 보장했습니다.&lt;/p&gt;
&lt;h3 id="2-채널channel-기반-메시지-전달"&gt;2. 채널(Channel) 기반 메시지 전달
&lt;/h3&gt;&lt;p&gt;공유 메모리 상태를 직접 제어하는 대신, &lt;code&gt;tokio::sync::mpsc&lt;/code&gt; 채널을 통해 메시지를 전달하는 방식(Actor 모델)을 채택했습니다. 이는 각 에이전트가 자신의 상태를 독점적으로 관리하게 하여 데이터 경합을 근본적으로 차단합니다.&lt;/p&gt;
&lt;h2 id="실전-코드-예제"&gt;실전 코드 예제
&lt;/h2&gt;&lt;p&gt;다음은 ZeroClaw의 통신 계층에서 사용하는 간단한 에이전트 메시지 핸들러의 구현 예제입니다.&lt;/p&gt;
&lt;h3 id="에이전트-메시지-정의-및-핸들러-구조"&gt;에이전트 메시지 정의 및 핸들러 구조
&lt;/h3&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; tokio::sync::{mpsc, RwLock};
&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; std::sync::Arc;
&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; std::time::Duration;
&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;// 에이전트가 처리할 명령 타입 정의
&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)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentCommand&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ProcessTask(String),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; UpdateStatus(String),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Shutdown,
&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;// 에이전트의 상태 구조체
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentState&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; status: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; processed_tasks: &lt;span style="color:#66d9ef"&gt;u64&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;// 에이전트 실행기 구조체
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentExecutor&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; state: &lt;span style="color:#a6e22e"&gt;Arc&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;RwLock&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentState&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; receiver: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentCommand&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&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;impl&lt;/span&gt; AgentExecutor {
&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; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;new&lt;/span&gt;(id: String, receiver: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentCommand&lt;span style="color:#f92672"&gt;&amp;gt;&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; state: &lt;span style="color:#a6e22e"&gt;Arc&lt;/span&gt;::new(RwLock::new(AgentState {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; status: &lt;span style="color:#e6db74"&gt;&amp;#34;Initialized&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; processed_tasks: &lt;span style="color:#ae81ff"&gt;0&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; receiver,
&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;// 메시지 수신 및 처리 루프 시작
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Agent &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; started.&amp;#34;&lt;/span&gt;, self.state.read().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;.id);
&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;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(cmd) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.receiver.recv().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; cmd {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AgentCommand::ProcessTask(task_id) &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;// 비동기 작업 시뮬레이션 (예: 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;let&lt;/span&gt; task_id_clone &lt;span style="color:#f92672"&gt;=&lt;/span&gt; task_id.clone();
&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; state_clone &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Arc::clone(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self.state);
&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;// 백그라운드 작업으로 처리하여 메시지 루프 차단 방지
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::spawn(&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;move&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::time::sleep(Duration::from_millis(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;)).&lt;span style="color:#66d9ef"&gt;await&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; state &lt;span style="color:#f92672"&gt;=&lt;/span&gt; state_clone.write().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; state.processed_tasks &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; state.status &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Processing &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, task_id_clone);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Task &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; processed by Agent &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;. Total: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&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; task_id_clone, state.id, state.processed_tasks);
&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; AgentCommand::UpdateStatus(new_status) &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:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; state &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.state.write().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; state.status &lt;span style="color:#f92672"&gt;=&lt;/span&gt; new_status;
&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; AgentCommand::Shutdown &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:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Agent &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; shutting down...&amp;#34;&lt;/span&gt;, self.state.read().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;.id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&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&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;tokio::select!&lt;/code&gt; 매크로를 사용하여 그레이스풀 셧다운(Graceful Shutdown)을 구현합니다.&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:#75715e"&gt;#[tokio::main]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 여러 에이전트를 관리하기 위한 송신자(Sender) 목록 저장
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 에이전트가 종료될 때를 대비해 Vec으로 관리
&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; agent_senders &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Vec::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 style="color:#75715e"&gt;// 3개의 에이전트 스폰
&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; i &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;..&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&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; (tx, rx) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mpsc::channel(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 버퍼 크기 100
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agent_senders.push(tx);
&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; executor &lt;span style="color:#f92672"&gt;=&lt;/span&gt; AgentExecutor::new(&lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Agent-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, i), rx);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::spawn(executor.run());
&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;// 시스템 전체의 종료 신항 (Ctrl+C 등 대응)
&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; (shutdown_tx, &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; shutdown_rx) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mpsc::channel::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;()&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&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;// 작업 분산 로직 (시뮬레이션)
&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; task_distributor &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tokio::spawn(&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;move&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; task_counter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;loop&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; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; shutdown_rx.try_recv().is_ok() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Task distributor stopping...&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;break&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;// 라운드 로빈 방식으로 에이전트들에게 작업 전송
&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; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;agent_senders.is_empty() {
&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; target_index &lt;span style="color:#f92672"&gt;=&lt;/span&gt; task_counter &lt;span style="color:#f92672"&gt;%&lt;/span&gt; agent_senders.len();
&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; task_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Task-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, task_counter);
&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;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Err(_) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; agent_senders[target_index].send(AgentCommand::ProcessTask(task_id)).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to send task. Agent might be dead.&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;span style="display:flex;"&gt;&lt;span&gt; task_counter &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::time::sleep(Duration::from_millis(&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;)).&lt;span style="color:#66d9ef"&gt;await&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&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 5초 후 시스템 종료 시뮬레이션
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::time::sleep(Duration::from_secs(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;)).&lt;span style="color:#66d9ef"&gt;await&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;// 1. 작업 분배 종료
&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; _ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; shutdown_tx.send(()).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task_distributor.&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;.unwrap();
&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;// 2. 모든 에이전트에게 종료 명령 전송
&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; tx &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; agent_senders {
&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; _ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tx.send(AgentCommand::Shutdown).&lt;span style="color:#66d9ef"&gt;await&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;// 리소스 정리 대기
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::time::sleep(Duration::from_millis(&lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;)).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;System shutdown complete.&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="핵심-포인트-분석"&gt;핵심 포인트 분석
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Arc&amp;lt;RwLock&amp;lt;State&amp;gt;&amp;gt;&lt;/code&gt; 패턴:&lt;/strong&gt;
&lt;code&gt;AgentExecutor&lt;/code&gt;는 상태를 &lt;code&gt;Arc&amp;lt;RwLock&amp;gt;&lt;/code&gt;으로 감싸서 보관합니다. &lt;code&gt;tokio::spawn&lt;/code&gt;으로 생성된 비동기 태스크는 이 &lt;code&gt;Arc&lt;/code&gt;를 클론(&lt;code&gt;clone&lt;/code&gt;)하여 가져옵니다. 이때 데이터 자체가 복사되는 것이 아니라 참조 카운터만 증가하므로 매우 가볍습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MPSC 채널의 소유권 이동:&lt;/strong&gt;
&lt;code&gt;tx&lt;/code&gt; (Sender) 끝은 메인 루프가 소유하고, &lt;code&gt;rx&lt;/code&gt; (Receiver) 끝은 &lt;code&gt;AgentExecutor&lt;/code&gt;가 소유합니다. 이렇게 명확하게 소유권을 분리함으로써, 누가 메시지를 보내고 받는지 컴파일 타임에 보장할 수 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;비동기 I/O와 락의 조화:&lt;/strong&gt;
&lt;code&gt;state.write().await&lt;/code&gt;를 사용할 때, 해당 코드는 데이터를 쓰기 위해 잠금(Lock)을 획득할 때까지 현재 태스크를 일시 중단(Yield)합니다. 이는 OS 스레드가 블로킹되는 것과 다르며, 다른 태스크가 CPU를 사용할 수 있게 하여 멀티코어 활용도를 높입니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="결론"&gt;결론
&lt;/h2&gt;&lt;p&gt;Rust의 메모리 관리 메커니즘은 단순한 안전성을 넘어, 고성능 서버 아키텍처 설계의 강력한 도구가 됩니다. &lt;strong&gt;ZeroClaw&lt;/strong&gt; 프로젝트에서는 이를 통해 에이전트 간의 통신 오버헤드를 최소화하고, 예측 가능한 지연 시간(Latency)을 확보할 수 있었습니다. 특히 &lt;code&gt;tokio&lt;/code&gt; 런타임과 결합된 채널 기반 아키텍처는 수천 개의 에이전트가 상호작용하는 복잡한 시스템에서도 안정성을 유지하는 기반이 되고 있습니다.&lt;/p&gt;
&lt;p&gt;다음 포스트에서는 이러한 에이전트 간 통신을 확장하여, 파일 기반의 영속성(Persistence)을 구현하는 아키텍처에 대해 다루겠습니다.&lt;/p&gt;
&lt;h2 id="참고-링크"&gt;참고 링크
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://example.com/zeroclaw-intro" target="_blank" rel="noopener"
 &gt;ZeroClaw 소개 - 고성능 Rust 에이전트 런타임&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://tokio.rs/" target="_blank" rel="noopener"
 &gt;Tokio 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>에이전트 개발의 다음 단계: 제어 흐름(Control Flow) 도입하기</title><link>https://blog.agentthread.dev/ko/post/%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EA%B0%9C%EB%B0%9C%EC%9D%98-%EB%8B%A4%EC%9D%8C-%EB%8B%A8%EA%B3%84-%EC%A0%9C%EC%96%B4-%ED%9D%90%EB%A6%84control-flow-%EB%8F%84%EC%9E%85%ED%95%98%EA%B8%B0/</link><pubDate>Fri, 08 May 2026 09:01:23 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EA%B0%9C%EB%B0%9C%EC%9D%98-%EB%8B%A4%EC%9D%8C-%EB%8B%A8%EA%B3%84-%EC%A0%9C%EC%96%B4-%ED%9D%90%EB%A6%84control-flow-%EB%8F%84%EC%9E%85%ED%95%98%EA%B8%B0/</guid><description>&lt;h1 id="에이전트-개발의-다음-단계-제어-흐름control-flow-도입하기"&gt;에이전트 개발의 다음 단계: 제어 흐름(Control Flow) 도입하기
&lt;/h1&gt;&lt;p&gt;최근 &amp;lsquo;Agents need control flow, not more prompts&amp;rsquo;라는 글을 보며 깊이 공감했습니다. 초기 LLM 기반 에이전트를 개발할 때는 프롬프트 엔지니어링이 곧 개발의 전부인 것처럼 느껴졌습니다. 하지만 시스템이 복잡해지고 ZeroClaw와 같은 멀티 에이전트 런타임을 다루게 되면서, &lt;strong&gt;&amp;lsquo;프롬프트&amp;rsquo;가 아닌 &amp;lsquo;구조&amp;rsquo;가 핵심&lt;/strong&gt;임을 절실히 깨닫게 되었습니다.&lt;/p&gt;
&lt;p&gt;이번 글에서는 복잡한 프롬프트를 덜어내고, 확장 가능한 에이전트 시스템을 위해 **제어 흐름(Control Flow)**을 아키텍처에 도입하는 방법을 실제 코드 예제와 함께 정리해 보겠습니다.&lt;/p&gt;
&lt;h2 id="문제-정의-프롬프트-한계와-의존성-지옥"&gt;문제 정의: 프롬프트 한계와 &amp;lsquo;의존성 지옥&amp;rsquo;
&lt;/h2&gt;&lt;p&gt;단일 에이전트에게 &amp;ldquo;A 작업을 하고, 결과가 양수면 B를, 음수면 C를 실행한 뒤, 마지막으로 D를 요약해&amp;quot;라고 프롬프트로 지시하는 것은 쉽지 않습니다. LLM은 문맥을 잃어버리거나, 논리적 분기(if/else)를 무시하고 직행해버리는 경우가 빈번하기 때문입니다.&lt;/p&gt;
&lt;p&gt;특히 [ZeroClaw] 멀티 에이전트 아키텍처 설계안에서 논의된 것처럼, 여러 에이전트가 협력하는 환경에서는 프롬프트만으로는 다음과 같은 문제가 발생합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;비결정성(Non-determinism):&lt;/strong&gt; 같은 입력이라도 LLM이 다른 경로를 선택할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;디버깅 난이도:&lt;/strong&gt; 에러가 발생했을 때 프롬프트의 어느 부분이 잘못된 지 찾기 어렵습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;확장성 부족:&lt;/strong&gt; 새로운 단계를 추가할 때마다 기존의 거대한 프롬프트를 수정해야 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="해결책-그래프-기반-제어-흐름-graph-based-control-flow"&gt;해결책: 그래프 기반 제어 흐름 (Graph-based Control Flow)
&lt;/h2&gt;&lt;p&gt;해결책은 LLM에게 &amp;ldquo;무엇(What)&amp;ldquo;을 할지 결정하게 하고, &amp;ldquo;어떻게(How)&amp;rdquo; 실행할지는 외부의 상태 머신(State Machine)이나 그래프 워크플로우에 위임하는 것입니다. 이를 통해 우리는 에이전트의 사고 자체를 제어하는 것이 아니라, 에이전트 간의 &lt;strong&gt;데이터 흐름과 실행 순서&lt;/strong&gt;를 제어하게 됩니다.&lt;/p&gt;
&lt;p&gt;Rust와 같은 안정적인 언어로 이러한 런타임을 구성하면 [ZeroClaw]에서 목표로 하는 고성능 및 안정성을 확보할 수 있습니다.&lt;/p&gt;
&lt;h3 id="구현-예제-rust로-간단한-상태-머신-러너-만들기"&gt;구현 예제: Rust로 간단한 상태 머신 러너 만들기
&lt;/h3&gt;&lt;p&gt;복잡한 프레임워크 없이, Rust의 Enum을 활용해 간단한 에이전트 워크플로우를 구현해 보겠습니다. 이 코드는 에이전트가 수행해야 할 단계(Step)를 정의하고, 이전 단계의 결과에 따라 다음 단계를 결정하는 구조입니다.&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:#75715e"&gt;// 1. 에이전트의 상태와 실행 컨텍스트 정의
&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, 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;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentContext&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; current_data: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; step_count: &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&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;// 2. 워크플로우의 각 단계(Step) 정의
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;WorkflowStep&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Initialize,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ProcessData,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ValidateResult, &lt;span style="color:#75715e"&gt;// 결과에 따라 다음 단계가 결정됨
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Finalize,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Complete,
&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;// 3. 각 단계별 실행 로직 구제화
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; WorkflowStep {
&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;execute&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, ctx: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;mut&lt;/span&gt; AgentContext) -&amp;gt; &lt;span style="color:#a6e22e"&gt;WorkflowStep&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; self {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::Initialize &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:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[Step 1] 데이터 초기화 중...&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ctx.current_data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Sample Input Data&amp;#34;&lt;/span&gt;.to_string();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ctx.step_count &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::ProcessData
&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; WorkflowStep::ProcessData &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:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[Step 2] LLM을 통해 데이터 처리 중: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, ctx.current_data);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 실제로는 여기서 MCP 클라이언트 등을 호출하여 LLM 추론을 수행
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ctx.current_data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Processed: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, ctx.current_data);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ctx.step_count &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::ValidateResult
&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; WorkflowStep::ValidateResult &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:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[Step 3] 결과 검증 중...&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 비즈니스 로직: 예를 들어 결과 길이가 10보다 작으면 재시작(혹은 에러 처리)
&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; ctx.current_data.len() &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;데이터가 부족하여 초기화 단계로 돌아갑니다.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::Initialize &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 style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;검증 통과. 완료 단계로 이동합니다.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::Finalize
&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; WorkflowStep::Finalize &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:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[Step 4] 최종 결과 저장: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, ctx.current_data);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::Complete
&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; WorkflowStep::Complete &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:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;워크플로우 완료.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::Complete &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&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;// 4. 메인 실행 루프 (Runner)
&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;run_agent_workflow&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; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; ctx &lt;span style="color:#f92672"&gt;=&lt;/span&gt; AgentContext {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; current_data: String::new(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; step_count: &lt;span style="color:#ae81ff"&gt;0&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;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; current_step &lt;span style="color:#f92672"&gt;=&lt;/span&gt; WorkflowStep::Initialize;
&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;// 최대 10회 반복 방지 (Safety Breaker)
&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; _ &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;..&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&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; &lt;span style="color:#a6e22e"&gt;matches!&lt;/span&gt;(current_step, WorkflowStep::Complete) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&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; current_step &lt;span style="color:#f92672"&gt;=&lt;/span&gt; current_step.execute(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; ctx);
&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;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; run_agent_workflow();
&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;h2 id="코드를-통한-얻는-이점"&gt;코드를 통한 얻는 이점
&lt;/h2&gt;&lt;p&gt;위의 예제처럼 단순히 &lt;code&gt;match&lt;/code&gt; 문과 &lt;code&gt;Enum&lt;/code&gt;을 사용하더라도 얻을 수 있는 효과는 큽니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;명확한 흐름 시각화:&lt;/strong&gt; 코드만 보고도 시스템이 어떻게 흘러가는지 파악할 수 있습니다. [Discord MCP Gateway 아키텍처]처럼 복잡한 요청을 처리할 때 유지보수성이 크게 향상됩니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;상태 관리:&lt;/strong&gt; &lt;code&gt;AgentContext&lt;/code&gt; 구조체를 통해 메모리 상태를 명시적으로 관리합니다. LLM의 컨텍스트 윈도우가 터지더라도 Rust 런타임은 현재 단계를 정확히 알고 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;에러 핸들링:&lt;/strong&gt; 특정 단계에서 실패했을 때, 프롬프트 재시도가 아니라 코드 레벨에서 &lt;code&gt;Retry&lt;/code&gt; 로직이나 &lt;code&gt;Fallback&lt;/code&gt; 단계로 쉽게 넘어갈 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="결론-에이전트는-소프트웨어다"&gt;결론: 에이전트는 소프트웨어다
&lt;/h2&gt;&lt;p&gt;우리는 LLM을 &amp;lsquo;마법&amp;rsquo;처럼 다루는 시대를 지나, LLM을 &amp;lsquo;하나의 모듈&amp;rsquo;로 바라보는 시대로 넘어가고 있습니다. [Cloud Monitor]나 [LLM 설정 개선] 프로젝트에서 겪었던 시행착오들은 결국 견고한 소프트웨어 아키텍처 위에 AI를 얹어야 한다는 것을 보여줍니다.&lt;/p&gt;
&lt;p&gt;프롬프트를 더 길게 작성하는 대신, Rust나 Python으로 제어 흐름을 명확히 정의하는 런타임을 구축해 보세요. 에이전트의 행동이 예측 가능해지고, 시스템이 튼튼해지는 것을 느끼실 수 있을 것입니다.&lt;/p&gt;
&lt;p&gt;다음 포스트에서는 이러한 제어 흐름 위에서 실제로 여러 LLM 호출을 병렬로 처리하여 성능을 극대화하는 방법에 대해 다루어보겠습니다.&lt;/p&gt;</description></item><item><title>[ZeroClaw] 2026 상반기 발전방향 회의록</title><link>https://blog.agentthread.dev/ko/post/2026-02-28-001-zeroclaw-2026-h1-roadmap-meeting/</link><pubDate>Sat, 28 Feb 2026 09:55:15 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/2026-02-28-001-zeroclaw-2026-h1-roadmap-meeting/</guid><description>&lt;h1 id="zeroclaw-2026-상반기-발전방향-팀-회의록"&gt;ZeroClaw 2026 상반기 발전방향 팀 회의록
&lt;/h1&gt;&lt;p&gt;&lt;strong&gt;회의 일시&lt;/strong&gt;: 2026-02-28
&lt;strong&gt;참석자&lt;/strong&gt;: 아키텍트, 보안 리드, 프로덕트 오너, DevOps 리드
&lt;strong&gt;회의 장소&lt;/strong&gt;: ZeroClaw 개발팀 회의실
&lt;strong&gt;작성자&lt;/strong&gt;: ZeroClaw Team&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-회의-개요"&gt;1. 회의 개요
&lt;/h2&gt;&lt;p&gt;본 회의는 ZeroClaw 프로젝트의 2026년 상반기 발전방향을 논의하고, 각 영역별 로드맵과 우선순위를 수립하기 위해 개최되었다.&lt;/p&gt;
&lt;h3 id="11-회의-안건"&gt;1.1 회의 안건
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;멀티 에이전트 아키텍처 발전 방향&lt;/li&gt;
&lt;li&gt;보안 강화 및 컴플라이언스 대응&lt;/li&gt;
&lt;li&gt;제품 경쟁력 강화 및 사용자 경험 개선&lt;/li&gt;
&lt;li&gt;DevOps 및 인프라 고도화&lt;/li&gt;
&lt;li&gt;종합 로드맵 및 우선순위 합의&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="2-아키텍처-발전방향-논의"&gt;2. 아키텍처 발전방향 논의
&lt;/h2&gt;&lt;h3 id="21-아키텍트-발언"&gt;2.1 아키텍트 발언
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;&amp;ldquo;현재 ZeroClaw는 Phase 1(인프로세스 위임)을 완료하고 Phase 2(파일 기반 멀티 에이전트) 구현 중에 있습니다. 2026년 상반기에는 다음과 같은 기술적 목표를 달성해야 합니다.&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="211-멀티-에이전트-오케스트레이션-고도화"&gt;2.1.1 멀티 에이전트 오케스트레이션 고도화
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;제안 사항:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DAG 기반 워크플로우 실행 엔진 구현&lt;/li&gt;
&lt;li&gt;순차/병렬/조건/반복 실행 패턴 지원&lt;/li&gt;
&lt;li&gt;에이전트 간 작업 분배 알고리즘 개선&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 높음 (P1)&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:#75715e"&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Workflow&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; nodes: Vec&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;WorkflowNode&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:#66d9ef"&gt;pub&lt;/span&gt; edges: Vec&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;WorkflowEdge&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:#66d9ef"&gt;pub&lt;/span&gt; start_node: 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; end_nodes: Vec&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&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:#66d9ef"&gt;pub&lt;/span&gt; error_handling: &lt;span style="color:#a6e22e"&gt;ErrorHandlingPolicy&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="212-ipc-통신-프로토콜-개선"&gt;2.1.2 IPC 통신 프로토콜 개선
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;제안 사항:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;현재 stdout 기반 통신을 구조화된 IPC로 전환&lt;/li&gt;
&lt;li&gt;Unix Socket, gRPC, WebSocket 다중 전송 계층 지원&lt;/li&gt;
&lt;li&gt;메시지 직렬화 최적화 (JSON → MessagePack/CBOR)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 중간 (P2)&lt;/p&gt;
&lt;h4 id="213-확장성-및-모듈화"&gt;2.1.3 확장성 및 모듈화
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;제안 사항:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;플러그인 아키텍처 도입 검토&lt;/li&gt;
&lt;li&gt;Wasm 실행 모드 구현 (샌드박싱 강화)&lt;/li&gt;
&lt;li&gt;외부 에이전트 등록 API 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 낮음 (P3)&lt;/p&gt;
&lt;h4 id="214-성능-최적화"&gt;2.1.4 성능 최적화
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;제안 사항:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Zero-copy 메시지 전달&lt;/li&gt;
&lt;li&gt;연결 풀링 및 캐싱 전략&lt;/li&gt;
&lt;li&gt;비동기 I/O 최적화&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 중간 (P2)&lt;/p&gt;
&lt;h3 id="22-토의-내용"&gt;2.2 토의 내용
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;보안 리드:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;IPC 프로토콜 개선 시 보안 채널 적용이 선행되어야 합니다. 에이전트 간 통신에 대한 암호화와 인증이 필요합니다.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;프로덕트 오너:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;사용자 관점에서는 에이전트 정의가 더 직관적이어야 합니다. YAML 스키마를 단순화하는 것도 고려해봅시다.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;DevOps 리드:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;성능 최적화 작업은 관찰성 향상과 병행되어야 합니다. 메트릭 수집이 먼저 확보되어야 최적화 효과를 측정할 수 있습니다.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="3-보안-발전방향-논의"&gt;3. 보안 발전방향 논의
&lt;/h2&gt;&lt;h3 id="31-보안-리드-발언"&gt;3.1 보안 리드 발언
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;&amp;ldquo;ZeroClaw는 이미 강력한 보안 기반을 갖추고 있으나, OWASP Top 10 관점에서 보완이 필요한 영역이 있습니다. 특히 샌드박스 격리와 감사 로깅 강화가 시급합니다.&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="311-샌드박스-강화"&gt;3.1.1 샌드박스 강화
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;현재 문제점:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Docker 샌드박스: &lt;code&gt;--read-only&lt;/code&gt;, &lt;code&gt;--cap-drop&lt;/code&gt;, seccomp 미적용&lt;/li&gt;
&lt;li&gt;Firejail: 네트워크 격리 미적용 (&lt;code&gt;--net=none&lt;/code&gt; 누락)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;제안 사항:&lt;/strong&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:#75715e"&gt;// Docker 강화 프로필
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker_cmd.args([
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;run&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;--rm&amp;#34;&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;--read-only&amp;#34;&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;--security-opt&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;no-new-privileges&amp;#34;&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;--cap-drop&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;ALL&amp;#34;&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;--network&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;none&amp;#34;&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;--memory&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;256m&amp;#34;&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;--pids-limit&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;64&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 높음 (P1)&lt;/p&gt;
&lt;h4 id="312-감사-로깅-강화"&gt;3.1.2 감사 로깅 강화
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;제안 사항:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;로그 서명 (Log Signing) 도입으로 변조 방지&lt;/li&gt;
&lt;li&gt;실시간 보안 알림 웹훅 연동&lt;/li&gt;
&lt;li&gt;Prometheus 메트릭 노출&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 중간 (P2)&lt;/p&gt;
&lt;h4 id="313-ssrf-방어"&gt;3.1.3 SSRF 방어
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;제안 사항:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;외부 요청 시 HTTPS 강제&lt;/li&gt;
&lt;li&gt;사설 IP 대역 차단&lt;/li&gt;
&lt;li&gt;도메인 허용목록 검증 강화&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 중간 (P2)&lt;/p&gt;
&lt;h4 id="314-toctou-취약점-수정"&gt;3.1.4 TOCTOU 취약점 수정
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;제안 사항:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;경로 검증과 정규화를 원자적으로 수행&lt;/li&gt;
&lt;li&gt;심볼릭 링크 레이스 컨디션 방지&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 높음 (P1)&lt;/p&gt;
&lt;h3 id="32-토의-내용"&gt;3.2 토의 내용
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;아키텍트:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;샌드박스 강화는 Wasm 실행 모드와 연계하여 진행하면 더 강력한 격리를 제공할 수 있습니다.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;DevOps 리드:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;Prometheus 메트릭은 Grafana 대시보드와 연동하여 운영 가시성을 크게 개선할 수 있습니다.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;프로덕트 오너:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;보안 강화로 인한 사용자 경험 저하가 없도록 기본값은 안전하게, 고급 사용자는 유연하게 설정할 수 있어야 합니다.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="4-제품-발전방향-논의"&gt;4. 제품 발전방향 논의
&lt;/h2&gt;&lt;h3 id="41-프로덕트-오너-발언"&gt;4.1 프로덕트 오너 발언
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;&amp;ldquo;ZeroClaw의 핵심 가치는 &amp;lsquo;고성능&amp;rsquo;, &amp;lsquo;확장성&amp;rsquo;, &amp;lsquo;보안&amp;rsquo;입니다. 2026년 상반기에는 이를 더욱 강화하면서 사용자 경험을 개선해야 합니다.&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="411-사용자-경험-개선"&gt;4.1.1 사용자 경험 개선
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;CLI 개선:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;zeroclaw agent list&lt;/code&gt; 출력 개선 (테이블 포맷)&lt;/li&gt;
&lt;li&gt;대화형 에이전트 실행 모드&lt;/li&gt;
&lt;li&gt;진행 상황 시각화&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;설정 단순화:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;에이전트 정의 YAML 스키마 단순화&lt;/li&gt;
&lt;li&gt;sensible defaults 제공&lt;/li&gt;
&lt;li&gt;설정 검증 및 오류 메시지 개선&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 높음 (P1)&lt;/p&gt;
&lt;h4 id="412-문서화-및-온보딩-강화"&gt;4.1.2 문서화 및 온보딩 강화
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;제안 사항:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quickstart 가이드 개선&lt;/li&gt;
&lt;li&gt;API 참조 문서 자동 생성&lt;/li&gt;
&lt;li&gt;예제 시나리오 확장&lt;/li&gt;
&lt;li&gt;다국어 문서 (한국어, 일본어, 중국어)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 중간 (P2)&lt;/p&gt;
&lt;h4 id="413-커뮤니티-성장-전략"&gt;4.1.3 커뮤니티 성장 전략
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;제안 사항:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CONTRIBUTING.md 개선&lt;/li&gt;
&lt;li&gt;Good first issue 라벨링&lt;/li&gt;
&lt;li&gt;정기 릴리즈 노트 발행&lt;/li&gt;
&lt;li&gt;Discord/Slack 커뮤니티 채널&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 중간 (P2)&lt;/p&gt;
&lt;h4 id="414-차별화-포인트-강화"&gt;4.1.4 차별화 포인트 강화
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;제안 사항:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;하드웨어 페리퍼럴 지원 강화 (STM32, RPi)&lt;/li&gt;
&lt;li&gt;특화 도메인 에이전트 템플릿&lt;/li&gt;
&lt;li&gt;성능 벤치마크 공개&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 낮음 (P3)&lt;/p&gt;
&lt;h3 id="42-토의-내용"&gt;4.2 토의 내용
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;아키텍트:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;CLI 개선은 ergonomics 측면에서 중요합니다. structopt 대신 clap 4.x로 업그레이드하는 것도 검토해봅시다.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;보안 리드:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;다국어 문서 작성 시 보안 관련 내용은 정확한 번역이 중요합니다. 용어집을 먼저 작성하는 것을 권장합니다.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;DevOps 리드:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;커뮤니티 채널은 GitHub Discussions부터 시작하는 것이 좋습니다. 별도 인프라 없이 시작할 수 있습니다.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="5-devops-발전방향-논의"&gt;5. DevOps 발전방향 논의
&lt;/h2&gt;&lt;h3 id="51-devops-리드-발언"&gt;5.1 DevOps 리드 발언
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;&amp;ldquo;안정적인 배포와 운영을 위해 CI/CD 파이프라인과 모니터링 시스템을 고도화해야 합니다.&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="511-cicd-파이프라인-고도화"&gt;5.1.1 CI/CD 파이프라인 고도화
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;현재 상태:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub Actions 기반 CI&lt;/li&gt;
&lt;li&gt;cargo fmt, clippy, test 자동화&lt;/li&gt;
&lt;li&gt;Docker 빌드&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;제안 사항:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cargo audit 통합 (취약점 스캔)&lt;/li&gt;
&lt;li&gt;크로스 플랫폼 빌드 (Linux, macOS, Windows)&lt;/li&gt;
&lt;li&gt;릴리즈 자동화 (cargo-release)&lt;/li&gt;
&lt;li&gt;배포 전 스모크 테스트&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 높음 (P1)&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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 제안하는 CI 워크플로우&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Security audit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;run&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cargo audit&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:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Cross-platform build&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;strategy&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;matrix&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;os&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;ubuntu-latest, macos-latest, windows-latest]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;runs-on&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;${{ matrix.os }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="512-모니터링-및-관찰성"&gt;5.1.2 모니터링 및 관찰성
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;제안 사항:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prometheus 메트릭 엔드포인트&lt;/li&gt;
&lt;li&gt;Grafana 대시보드 템플릿&lt;/li&gt;
&lt;li&gt;분산 추적 (OpenTelemetry)&lt;/li&gt;
&lt;li&gt;로그 집계 (ELK/Loki)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 중간 (P2)&lt;/p&gt;
&lt;h4 id="513-배포-자동화-및-롤백"&gt;5.1.3 배포 자동화 및 롤백
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;제안 사항:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Blue-Green 배포 지원&lt;/li&gt;
&lt;li&gt;자동 롤백 임계값 설정&lt;/li&gt;
&lt;li&gt;Canary 릴리즈 옵션&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 중간 (P2)&lt;/p&gt;
&lt;h4 id="514-개발-환경-개선"&gt;5.1.4 개발 환경 개선
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;제안 사항:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;devcontainer 구성&lt;/li&gt;
&lt;li&gt;git hooks 자동 설정&lt;/li&gt;
&lt;li&gt;개발용 설정 프로파일&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;우선순위:&lt;/strong&gt; 낮음 (P3)&lt;/p&gt;
&lt;h3 id="52-토의-내용"&gt;5.2 토의 내용
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;아키텍트:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;OpenTelemetry 통합은 멀티 에이전트 추적에 필수적입니다. 에이전트 간 호출 체인을 시각화할 수 있어야 합니다.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;보안 리드:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;cargo audit은 CI에 반드시 포함되어야 합니다. 또한 의존성 라이선스 검사도 추가하는 것이 좋습니다.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;프로덕트 오너:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;devcontainer는 신규 기여자 온보딩에 큰 도움이 될 것입니다. 우선순위를 높여도 좋습니다.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="6-종합-로드맵-및-우선순위"&gt;6. 종합 로드맵 및 우선순위
&lt;/h2&gt;&lt;h3 id="61-2026년-상반기-로드맵"&gt;6.1 2026년 상반기 로드맵
&lt;/h3&gt;&lt;h4 id="q1-3월-4월"&gt;Q1 (3월-4월)
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;항목&lt;/th&gt;
					&lt;th&gt;담당&lt;/th&gt;
					&lt;th&gt;우선순위&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Docker/Firejail 샌드박스 강화&lt;/td&gt;
					&lt;td&gt;보안&lt;/td&gt;
					&lt;td&gt;P1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;TOCTOU 취약점 수정&lt;/td&gt;
					&lt;td&gt;보안&lt;/td&gt;
					&lt;td&gt;P1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;CI/CD 보안 스캔 통합&lt;/td&gt;
					&lt;td&gt;DevOps&lt;/td&gt;
					&lt;td&gt;P1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;CLI 개선 및 UX 향상&lt;/td&gt;
					&lt;td&gt;프로덕트&lt;/td&gt;
					&lt;td&gt;P1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;DAG 기반 워크플로우 엔진&lt;/td&gt;
					&lt;td&gt;아키텍트&lt;/td&gt;
					&lt;td&gt;P1&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="q2-5월-6월"&gt;Q2 (5월-6월)
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;항목&lt;/th&gt;
					&lt;th&gt;담당&lt;/th&gt;
					&lt;th&gt;우선순위&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;IPC 통신 프로토콜 개선&lt;/td&gt;
					&lt;td&gt;아키텍트&lt;/td&gt;
					&lt;td&gt;P2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;감사 로깅 강화&lt;/td&gt;
					&lt;td&gt;보안&lt;/td&gt;
					&lt;td&gt;P2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;SSRF 방어 구현&lt;/td&gt;
					&lt;td&gt;보안&lt;/td&gt;
					&lt;td&gt;P2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Prometheus 메트릭 노출&lt;/td&gt;
					&lt;td&gt;DevOps&lt;/td&gt;
					&lt;td&gt;P2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;문서화 및 온보딩 개선&lt;/td&gt;
					&lt;td&gt;프로덕트&lt;/td&gt;
					&lt;td&gt;P2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;커뮤니티 인프라 구축&lt;/td&gt;
					&lt;td&gt;프로덕트&lt;/td&gt;
					&lt;td&gt;P2&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="62-합의된-원칙"&gt;6.2 합의된 원칙
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;보안 우선&lt;/strong&gt;: 모든 새로운 기능은 보안 리뷰를 거쳐야 함&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;점진적 배포&lt;/strong&gt;: 큰 변경은 단계적으로 롤아웃&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;롤백 가능&lt;/strong&gt;: 모든 변경은 쉽게 롤백 가능해야 함&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;문서 동기화&lt;/strong&gt;: 기능 변경 시 문서 업데이트 필수&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;테스트 커버리지&lt;/strong&gt;: 새로운 코드는 테스트 필수&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="63-리스크-및-대응"&gt;6.3 리스크 및 대응
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;리스크&lt;/th&gt;
					&lt;th&gt;확률&lt;/th&gt;
					&lt;th&gt;영향&lt;/th&gt;
					&lt;th&gt;대응 방안&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;샌드박스 호환성 문제&lt;/td&gt;
					&lt;td&gt;중간&lt;/td&gt;
					&lt;td&gt;높음&lt;/td&gt;
					&lt;td&gt;폴백 메커니즘 구현&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;성능 회귀&lt;/td&gt;
					&lt;td&gt;낮음&lt;/td&gt;
					&lt;td&gt;중간&lt;/td&gt;
					&lt;td&gt;벤치마크 자동화&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;의존성 취약점&lt;/td&gt;
					&lt;td&gt;중간&lt;/td&gt;
					&lt;td&gt;높음&lt;/td&gt;
					&lt;td&gt;cargo audit 자동화&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;문서 부실&lt;/td&gt;
					&lt;td&gt;높음&lt;/td&gt;
					&lt;td&gt;중간&lt;/td&gt;
					&lt;td&gt;문서 PR 필수화&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="7-결론-및-다음-단계"&gt;7. 결론 및 다음 단계
&lt;/h2&gt;&lt;h3 id="71-회의-결론"&gt;7.1 회의 결론
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;아키텍처&lt;/strong&gt;: 멀티 에이전트 오케스트레이션 고도화를 최우선으로 진행&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;보안&lt;/strong&gt;: 샌드박스 강화와 TOCTOU 수정을 즉시 착수&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;제품&lt;/strong&gt;: CLI UX 개선으로 사용자 경험 향상&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DevOps&lt;/strong&gt;: CI/CD 보안 강화와 모니터링 기반 구축&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="72-액션-아이템"&gt;7.2 액션 아이템
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;#&lt;/th&gt;
					&lt;th&gt;항목&lt;/th&gt;
					&lt;th&gt;담당자&lt;/th&gt;
					&lt;th&gt;기한&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;Docker 샌드박스 보안 프로필 적용&lt;/td&gt;
					&lt;td&gt;보안 리드&lt;/td&gt;
					&lt;td&gt;2026-03-07&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;TOCTOU 경로 검증 수정&lt;/td&gt;
					&lt;td&gt;보안 리드&lt;/td&gt;
					&lt;td&gt;2026-03-10&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;CI cargo audit 통합&lt;/td&gt;
					&lt;td&gt;DevOps 리드&lt;/td&gt;
					&lt;td&gt;2026-03-05&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;CLI agent list 개선&lt;/td&gt;
					&lt;td&gt;프로덕트 오너&lt;/td&gt;
					&lt;td&gt;2026-03-12&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;워크플로우 엔진 설계 문서&lt;/td&gt;
					&lt;td&gt;아키텍트&lt;/td&gt;
					&lt;td&gt;2026-03-15&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="73-다음-회의-일정"&gt;7.3 다음 회의 일정
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;일시&lt;/strong&gt;: 2026-03-14 10:00&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;안건&lt;/strong&gt;: Q1 진행 상황 리뷰 및 Q2 상세 계획&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="부록-참고-문서"&gt;부록: 참고 문서
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docs/project/multi-agent-architecture-design.md&lt;/code&gt; - 멀티 에이전트 아키텍처 설계&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docs/project/multi-agent-communication-protocols.md&lt;/code&gt; - 통신 프로토콜 설계&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docs/security/security-improvements.md&lt;/code&gt; - 보안 개선 보고서&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; - 엔지니어링 프로토콜&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;회의록 작성일&lt;/strong&gt;: 2026-02-28
&lt;strong&gt;승인자&lt;/strong&gt;: ZeroClaw Team Lead
&lt;strong&gt;배포&lt;/strong&gt;: ZeroClaw 개발팀 전체&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;영어 버전:&lt;/strong&gt; &lt;a class="link" href="https://blog.agentthread.dev/post/2026-02-28-001-zeroclaw-2026-h1-roadmap-meeting/" &gt;English Version&lt;/a&gt;&lt;/p&gt;</description></item><item><title>[ZeroClaw] 멀티 에이전트 아키텍처 설계안</title><link>https://blog.agentthread.dev/ko/post/2026-02-27-011-zeroclaw-multi-agent-architecture-design/</link><pubDate>Fri, 27 Feb 2026 22:58:08 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/2026-02-27-011-zeroclaw-multi-agent-architecture-design/</guid><description>&lt;h1 id="zeroclaw-멀티-에이전트-아키텍처-설계안"&gt;ZeroClaw 멀티 에이전트 아키텍처 설계안
&lt;/h1&gt;&lt;h2 id="개요"&gt;개요
&lt;/h2&gt;&lt;p&gt;ZeroClaw의 멀티 에이전트 아키텍처는 단일 에이전트 모델에서 진화하는 고급 협력 시스템을 구현합니다.&lt;/p&gt;
&lt;h3 id="현재-상태"&gt;현재 상태
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Phase 1&lt;/strong&gt;: In-Process Delegation (완료)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phase 2&lt;/strong&gt;: File-Based Multi-Agent Architecture (개발 중)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="1-설계-철학"&gt;1. 설계 철학
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;원칙&lt;/th&gt;
					&lt;th&gt;적용&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;KISS&lt;/td&gt;
					&lt;td&gt;단순 통신 프로토콜&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;YAGNI&lt;/td&gt;
					&lt;td&gt;필수 기능만 구현&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;SRP&lt;/td&gt;
					&lt;td&gt;단일 책임 에이전트&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Secure&lt;/td&gt;
					&lt;td&gt;최소 권한 원칙&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="2-아키텍처-구조"&gt;2. 아키텍처 구조
&lt;/h2&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-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Application Layer: Research │ Code │ Test Agent
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Message Bus Layer: NATS/Redis Pub/Sub
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Transport Layer: gRPC │ WebSocket │ Unix Socket
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="3-에이전트-정의"&gt;3. 에이전트 정의
&lt;/h2&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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;agent&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;id&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;researcher&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Research Agent&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 style="color:#f92672"&gt;execution&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;mode&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;subprocess&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:#f92672"&gt;provider&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;openrouter&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;model&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;claude-sonnet-4-6&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="4-cli-명령어"&gt;4. CLI 명령어
&lt;/h2&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw agent list
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw agent show &amp;lt;id&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw agent run --agent-id researcher
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="5-보안"&gt;5. 보안
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;모드&lt;/th&gt;
					&lt;th&gt;격리&lt;/th&gt;
					&lt;th&gt;용도&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Subprocess&lt;/td&gt;
					&lt;td&gt;프로세스&lt;/td&gt;
					&lt;td&gt;신뢰된 에이전트&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Docker&lt;/td&gt;
					&lt;td&gt;컨테이너&lt;/td&gt;
					&lt;td&gt;파일 작업&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Wasm&lt;/td&gt;
					&lt;td&gt;메모리&lt;/td&gt;
					&lt;td&gt;높은 보안&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;영어 버전:&lt;/strong&gt; &lt;a class="link" href="https://blog.agentthread.dev/post/2026-02-27-011-zeroclaw-multi-agent-architecture-design/" &gt;English Version&lt;/a&gt;&lt;/p&gt;</description></item><item><title>[ZeroClaw] 소개 - 고성능 Rust 에이전트 런타임</title><link>https://blog.agentthread.dev/ko/post/2026-02-27-introducing-zeroclaw/</link><pubDate>Fri, 27 Feb 2026 19:30:00 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/2026-02-27-introducing-zeroclaw/</guid><description>&lt;h1 id="zeroclaw-소개-고성능-rust-에이전트-런타임"&gt;ZeroClaw 소개: 고성능 Rust 에이전트 런타임
&lt;/h1&gt;&lt;p&gt;ZeroClaw는 Rust로 구축된 &lt;strong&gt;고성능 자율 에이전트 런타임&lt;/strong&gt;으로, AI 기반 애플리케이션에서 속도, 효율성, 안정성이 필요한 개발자를 위해 설계되었습니다.&lt;/p&gt;
&lt;h2 id="핵심-기능"&gt;핵심 기능
&lt;/h2&gt;&lt;h3 id="성능-우선"&gt;성능 우선
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rust 네이티브&lt;/strong&gt;: 가능한 한 할당 없음&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tokio 기반 Async/await&lt;/strong&gt;: 효율적인 동시 작업&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;스트리밍 지원&lt;/strong&gt;: 실시간 응답 스트리밍&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="확장성"&gt;확장성
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Trait + Factory 아키텍처&lt;/strong&gt;: Trait 구현으로 확장&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;25개 이상의 내장 도구&lt;/strong&gt;: Shell, 파일 작업, 메모리, 브라우저, HTTP&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;플러그인 친화적&lt;/strong&gt;: 코어 수정 없이 Provider, Channel, Tool 추가 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="기본-보안"&gt;기본 보안
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;샌드박스 지원&lt;/strong&gt;: Firejail, Bubblewrap, Landlock, Docker&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;페어링 프로토콜&lt;/strong&gt;: 6자리 CSPRNG 코드&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;비밀 저장소&lt;/strong&gt;: ChaCha20-Poly1305 AEAD 암호화&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="멀티-플랫폼"&gt;멀티 플랫폼
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;20개 이상의 메시징 채널&lt;/strong&gt;: Telegram, Discord, Slack, WhatsApp, Signal, Matrix&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;13개 이상의 LLM Provider&lt;/strong&gt;: OpenAI, Anthropic, Gemini, Ollama, Bedrock, OpenRouter&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="빠른-시작"&gt;빠른 시작
&lt;/h2&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cargo install zeroclaw
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw config init
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw run --channel telegram
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="아키텍처"&gt;아키텍처
&lt;/h2&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-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ZeroClaw Agent
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Providers (OpenAI, Anthropic, Gemini, Ollama)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Channels (Telegram, Discord, Slack, WhatsApp)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Tools (Shell, File, Memory, Browser, HTTP)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Memory (SQLite, PostgreSQL, Markdown)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── Security (Policy, Sandbox, Secret Store)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="로드맵"&gt;로드맵
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1단계&lt;/strong&gt;: 향상된 멀티 에이전트 (진행 중)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2단계&lt;/strong&gt;: 더 많은 통합&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3단계&lt;/strong&gt;: 엔터프라이즈 기능&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;영어 버전:&lt;/strong&gt; &lt;a class="link" href="https://blog.agentthread.dev/post/2026-02-27-010-introducing-zeroclaw/" &gt;English Version&lt;/a&gt;&lt;/p&gt;</description></item><item><title>[Multi-Agent] 파일 기반 아키텍처 설계</title><link>https://blog.agentthread.dev/ko/post/2026-02-27-001-file-based-multi-agent-architecture-design/</link><pubDate>Fri, 27 Feb 2026 09:30:57 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/2026-02-27-001-file-based-multi-agent-architecture-design/</guid><description>&lt;h1 id="파일-기반-멀티-에이전트-아키텍처-설계"&gt;파일 기반 멀티 에이전트 아키텍처 설계
&lt;/h1&gt;&lt;p&gt;&lt;strong&gt;상태:&lt;/strong&gt; 설계 제안
&lt;strong&gt;작성자:&lt;/strong&gt; multi-agent-architect
&lt;strong&gt;날짜:&lt;/strong&gt; 2026-02-24
&lt;strong&gt;유형:&lt;/strong&gt; 대안 아키텍처 (프로세스-단위-에이전트)&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="개요"&gt;개요
&lt;/h2&gt;&lt;p&gt;이 문서는 각 에이전트가 별도의 설정 파일로 정의되고 독립적인 프로세스로 실행되는 &lt;strong&gt;파일 기반, 프로세스-단위-에이전트&lt;/strong&gt; 아키텍처를 정의합니다. 에이전트는 필요시 호출되어 메인 코디네이터 에이전트에게 결과를 보고합니다.&lt;/p&gt;
&lt;h3 id="핵심-원칙"&gt;핵심 원칙
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;파일 기반 에이전트 정의&lt;/strong&gt;: 각 에이전트는 &lt;code&gt;agents/&lt;/code&gt; 디렉토리의 &lt;code&gt;.toml&lt;/code&gt; 파일&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로세스 격리&lt;/strong&gt;: 각 에이전트는 자체 프로세스에서 실행&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;온디맨드 호출&lt;/strong&gt;: 메인 에이전트가 필요시 서브프로세스 에이전트 생성&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;보고 프로토콜&lt;/strong&gt;: IPC를 통한 구조화된 결과 보고&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;제로-설정 디스커버리&lt;/strong&gt;: 에이전트 정의 자동 감지&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="1-에이전트-정의-파일-구조"&gt;1. 에이전트 정의 파일 구조
&lt;/h2&gt;&lt;h3 id="11-디렉토리-레이아웃"&gt;1.1 디렉토리 레이아웃
&lt;/h3&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-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;~/.zeroclaw/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── config.toml # 메인 설정
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── agents/ # 에이전트 정의 디렉토리
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── researcher.toml # 리서치 에이전트
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── coder.toml # 코드 생성 에이전트
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── tester.toml # 테스팅 에이전트
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── reviewer.toml # 코드 리뷰 에이전트
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── summarizer.toml # 요약 에이전트
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── agents.d/ # 선택사항: 추가 에이전트 디렉토리
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── custom/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── my_agent.toml
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── workspace/ # 공유 워크스페이스
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="12-에이전트-파일-스키마"&gt;1.2 에이전트 파일 스키마
&lt;/h3&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-toml" data-lang="toml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# agents/researcher.toml&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;# 에이전트 메타데이터&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;agent&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;researcher&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;Research Agent&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;description&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;Conducts research on given topics using web search and knowledge bases&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 style="color:#75715e"&gt;# 실행 설정&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;agent&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;execution&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 에이전트 실행 방식: &amp;#34;subprocess&amp;#34; | &amp;#34;wasm&amp;#34; | &amp;#34;docker&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;mode&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;subprocess&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 style="color:#75715e"&gt;# 실행 명령어 (템플릿 변수: {agent_id}, {workspace}, {config_dir})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;command&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;zeroclaw&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;args&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;agent&amp;#34;&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;run&amp;#34;&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;--agent-id&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;{agent_id}&amp;#34;&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;--config&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;{config}/agents/researcher.toml&amp;#34;&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;--workspace&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;{workspace}&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;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;&lt;span style="color:#a6e22e"&gt;working_dir&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;{workspace}&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 style="color:#75715e"&gt;# 서브프로세스 환경변수&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;agent&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;execution&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;env&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ZEROCLAW_AGENT_MODE&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;worker&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ZEROCLAW_AGENT_ID&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;researcher&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 style="color:#75715e"&gt;# 프로바이더 설정 (메인 설정 오버라이드)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;provider&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;openrouter&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;model&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;anthropic/claude-sonnet-4-6&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;api_key&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;null&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;&lt;span style="color:#a6e22e"&gt;temperature&lt;/span&gt; = &lt;span style="color:#ae81ff"&gt;0.3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;max_tokens&lt;/span&gt; = &lt;span style="color:#ae81ff"&gt;4096&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;# 이 에이전트에서 사용 가능한 도구&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[[&lt;span style="color:#a6e22e"&gt;tools&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;web_search&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;enabled&lt;/span&gt; = &lt;span style="color:#66d9ef"&gt;true&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:#a6e22e"&gt;tools&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;web_fetch&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;enabled&lt;/span&gt; = &lt;span style="color:#66d9ef"&gt;true&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;# 이 에이전트에서 명시적으로 거부된 도구&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[[&lt;span style="color:#a6e22e"&gt;tools&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;deny&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;shell&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;reason&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;Research agent should not execute shell commands&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 style="color:#75715e"&gt;# 시스템 프롬프트&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;system&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;prompt&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;You are a Research Agent. Your role is to:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;1. Search for and gather information from credible sources
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;2. Synthesize findings into structured reports
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;3. Cite sources and provide references
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;4. Avoid speculation - stick to verified information
&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;&amp;#34;&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 style="color:#75715e"&gt;# 메모리 설정&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;memory&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;backend&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;shared&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;# &amp;#34;shared&amp;#34; | &amp;#34;isolated&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;category&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;research&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 style="color:#75715e"&gt;# 보고 설정&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;reporting&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;mode&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;ipc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;format&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;json&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;# &amp;#34;json&amp;#34; | &amp;#34;markdown&amp;#34; | &amp;#34;both&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;timeout_seconds&lt;/span&gt; = &lt;span style="color:#ae81ff"&gt;300&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;# 재시도 설정&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;retry&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;max_attempts&lt;/span&gt; = &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;backoff_ms&lt;/span&gt; = &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="2-에이전트-레지스트리"&gt;2. 에이전트 레지스트리
&lt;/h2&gt;&lt;p&gt;AgentRegistry는 에이전트 정의를 발견하고 관리합니다:&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentRegistry&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agents_dir: &lt;span style="color:#a6e22e"&gt;PathBuf&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agents: &lt;span style="color:#a6e22e"&gt;HashMap&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, AgentDefinition&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; security: &lt;span style="color:#a6e22e"&gt;Arc&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;SecurityPolicy&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&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;impl&lt;/span&gt; AgentRegistry {
&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;(agents_dir: &lt;span style="color:#a6e22e"&gt;PathBuf&lt;/span&gt;, security: &lt;span style="color:#a6e22e"&gt;Arc&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;SecurityPolicy&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Self&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:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;discover&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) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;()&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:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, id: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; Option&lt;span style="color:#f92672"&gt;&amp;lt;&amp;amp;&lt;/span&gt;AgentDefinition&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:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;list&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self) -&amp;gt; Vec&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="3-프로세스-간-통신-ipc"&gt;3. 프로세스 간 통신 (IPC)
&lt;/h2&gt;&lt;h3 id="태스크-메시지-메인--에이전트"&gt;태스크 메시지 (메인 → 에이전트)
&lt;/h3&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentTask&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; task_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; from_agent: 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; to_agent: 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; prompt: 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; context: &lt;span style="color:#a6e22e"&gt;HashMap&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, serde_json::Value&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:#66d9ef"&gt;pub&lt;/span&gt; input: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;serde_json::Value&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:#66d9ef"&gt;pub&lt;/span&gt; timestamp: &lt;span style="color:#a6e22e"&gt;chrono&lt;/span&gt;::DateTime&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;chrono::Utc&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:#66d9ef"&gt;pub&lt;/span&gt; deadline: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;chrono::DateTime&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;chrono::Utc&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;h3 id="결과-메시지-에이전트--메인"&gt;결과 메시지 (에이전트 → 메인)
&lt;/h3&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;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentResult&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; task_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; agent_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; status: &lt;span style="color:#a6e22e"&gt;AgentStatus&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; data: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;serde_json::Value&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:#66d9ef"&gt;pub&lt;/span&gt; output: 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; error: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&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:#66d9ef"&gt;pub&lt;/span&gt; metrics: &lt;span style="color:#a6e22e"&gt;AgentMetrics&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; artifacts: Vec&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Artifact&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:#66d9ef"&gt;pub&lt;/span&gt; timestamp: &lt;span style="color:#a6e22e"&gt;chrono&lt;/span&gt;::DateTime&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;chrono::Utc&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="4-보안-고려사항"&gt;4. 보안 고려사항
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;실행 모드&lt;/th&gt;
					&lt;th&gt;격리 수준&lt;/th&gt;
					&lt;th&gt;사용 사례&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Subprocess&lt;/td&gt;
					&lt;td&gt;프로세스 수준&lt;/td&gt;
					&lt;td&gt;신뢰할 수 있는 에이전트&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Docker&lt;/td&gt;
					&lt;td&gt;컨테이너&lt;/td&gt;
					&lt;td&gt;신뢰할 수 없는, 파일 작업&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Wasm&lt;/td&gt;
					&lt;td&gt;메모리 전용&lt;/td&gt;
					&lt;td&gt;높은 보안 요구사항&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="5-cli-명령어"&gt;5. CLI 명령어
&lt;/h2&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-bash" data-lang="bash"&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;zeroclaw agent list
&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;# 에이전트 상세 정보&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw agent show &amp;lt;agent_id&amp;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;# 에이전트 직접 실행 (테스트용)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw agent run --agent-id researcher --prompt &lt;span style="color:#e6db74"&gt;&amp;#34;Research X&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 style="color:#75715e"&gt;# 템플릿에서 새 에이전트 생성&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw agent create --id my-agent --name &lt;span style="color:#e6db74"&gt;&amp;#34;My Agent&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 style="color:#75715e"&gt;# 에이전트 정의 검증&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw agent validate &amp;lt;agent_id&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="6-성공-기준"&gt;6. 성공 기준
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 에이전트 정의 파일 로드 시 검증&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 서브프로세스 에이전트 생성 및 태스크 완료&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; IPC 프로토콜 1GB 이상 데이터 지원&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 메인 에이전트가 도구를 통해 워커 에이전트 호출 가능&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 실패한 에이전트가 메인 에이전트 크래시 유발하지 않음&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 에이전트별 보안 정책 적용&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; 에이전트 관리 CLI 명령어&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;영어 버전:&lt;/strong&gt; &lt;a class="link" href="https://blog.agentthread.dev/post/2026-02-27-001-file-based-multi-agent-architecture-design/" &gt;English Version&lt;/a&gt;&lt;/p&gt;</description></item><item><title>[ZeroClaw] 멀티 에이전트 통신 프로토콜 설계</title><link>https://blog.agentthread.dev/ko/post/2026-02-26-003-zeroclaw-multi-agent-protocol-design/</link><pubDate>Thu, 26 Feb 2026 23:37:59 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/2026-02-26-003-zeroclaw-multi-agent-protocol-design/</guid><description>&lt;h1 id="zeroclaw-멀티-에이전트-통신-프로토콜-설계"&gt;ZeroClaw 멀티 에이전트 통신 프로토콜 설계
&lt;/h1&gt;&lt;p&gt;&lt;em&gt;2026년 2월 26일 작성&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="개요"&gt;개요
&lt;/h2&gt;&lt;p&gt;ZeroClaw의 멀티 에이전트 시스템을 위한 통신 프로토콜 설계안입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-설계-목표"&gt;1. 설계 목표
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;메시지 형식 표준화&lt;/strong&gt; - 일관된 봉투 기반 메시징&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;유연한 라우팅&lt;/strong&gt; - 직접, 브로드캐스트, Pub/Sub 패턴&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;동기 + 비동기&lt;/strong&gt; - 블로킹 및 논블로킹 통신 지원&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;이벤트 기반 조정&lt;/strong&gt; - 시스템 이벤트에 반응&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;상태 공유&lt;/strong&gt; - 안전한 공유 메모리 및 분산 상태&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="2-메시지-타입-12가지"&gt;2. 메시지 타입 (12가지)
&lt;/h2&gt;&lt;p&gt;Task, TaskResult, Query, QueryResponse, Stream, Event, Heartbeat, Ack, Error, Control, Sync, SyncResponse&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="3-통신-패턴"&gt;3. 통신 패턴
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Direct (1:1)&lt;/li&gt;
&lt;li&gt;Broadcast (1:N)&lt;/li&gt;
&lt;li&gt;Request-Response&lt;/li&gt;
&lt;li&gt;Pub/Sub&lt;/li&gt;
&lt;li&gt;Streaming&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="4-구현-로드맵"&gt;4. 구현 로드맵
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Phase&lt;/th&gt;
					&lt;th&gt;내용&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;핵심 메시징 레이어&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;상태 저장소&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;DelegateTool 통합&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;Pub/Sub 및 스트리밍&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;분산 환경 지원&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;이 문서는 ZeroClaw 개발 팀의 협업으로 작성되었습니다.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;영어 버전:&lt;/strong&gt; &lt;a class="link" href="https://blog.agentthread.dev/post/2026-02-26-003-zeroclaw-multi-agent-protocol-design/" &gt;English Version&lt;/a&gt;&lt;/p&gt;</description></item><item><title>[ZeroClaw] 코드베이스 아키텍처 분석</title><link>https://blog.agentthread.dev/ko/post/2026-02-26-001-zeroclaw-codebase-architecture-analysis/</link><pubDate>Thu, 26 Feb 2026 10:07:29 +0900</pubDate><guid>https://blog.agentthread.dev/ko/post/2026-02-26-001-zeroclaw-codebase-architecture-analysis/</guid><description>&lt;h1 id="zeroclaw-코드베이스-아키텍처-분석-보고서"&gt;ZeroClaw 코드베이스 아키텍처 분석 보고서
&lt;/h1&gt;&lt;p&gt;&lt;em&gt;2026년 2월 26일 작성&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="개요"&gt;개요
&lt;/h2&gt;&lt;p&gt;ZeroClaw는 Rust로 작성된 고성능 자율 에이전트 런타임입니다. 이 보고서는 코드베이스 구조와 보안 아키텍처에 대한 분석 결과를 정리합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-핵심-아키텍처-패턴"&gt;1. 핵심 아키텍처 패턴
&lt;/h2&gt;&lt;p&gt;ZeroClaw는 **트레이트 기반 확장성(Trait-driven extensibility)**을 핵심 설계 원칙으로 채택하고 있습니다.&lt;/p&gt;
&lt;h3 id="11-주요-트레이트-7개"&gt;1.1 주요 트레이트 (7개)
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;트레이트&lt;/th&gt;
					&lt;th&gt;위치&lt;/th&gt;
					&lt;th&gt;역할&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Provider&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;src/providers/traits.rs&lt;/td&gt;
					&lt;td&gt;AI 모델 프로바이더 인터페이스&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Channel&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;src/channels/traits.rs&lt;/td&gt;
					&lt;td&gt;통신 채널 인터페이스&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Tool&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;src/tools/traits.rs&lt;/td&gt;
					&lt;td&gt;도구 실행 인터페이스&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Memory&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;src/memory/traits.rs&lt;/td&gt;
					&lt;td&gt;메모리 백엔드 인터페이스&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Observer&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;src/observability/traits.rs&lt;/td&gt;
					&lt;td&gt;관측 가능성 인터페이스&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;RuntimeAdapter&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;src/runtime/traits.rs&lt;/td&gt;
					&lt;td&gt;런타임 어댑터 인터페이스&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Peripheral&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;src/peripherals/traits.rs&lt;/td&gt;
					&lt;td&gt;하드웨어 주변장치 인터페이스&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="2-보안-아키텍처"&gt;2. 보안 아키텍처
&lt;/h2&gt;&lt;p&gt;ZeroClaw는 &lt;strong&gt;다층 방어(Defense-in-Depth)&lt;/strong&gt; 전략을 통해 보안을 구현합니다.&lt;/p&gt;
&lt;h3 id="21-보안-레이어-6개"&gt;2.1 보안 레이어 (6개)
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;SecurityPolicy Core&lt;/strong&gt; - 자율성 수준 관리&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gateway Security&lt;/strong&gt; - Bearer 토큰 인증&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tool Validation&lt;/strong&gt; - 인젝션 방지&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Runtime Sandbox&lt;/strong&gt; - Landlock/Firejail/Docker&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secret Management&lt;/strong&gt; - ChaCha20-Poly1305&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audit Logging&lt;/strong&gt; - 이벤트 추적&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="22-핵심-보안-경계"&gt;2.2 핵심 보안 경계
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;명령어 허용 목록: 15개&lt;/li&gt;
&lt;li&gt;속도 제한: 20회/시간&lt;/li&gt;
&lt;li&gt;환경 변수: 8개만 허용&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="3-멀티-에이전트-시스템"&gt;3. 멀티 에이전트 시스템
&lt;/h2&gt;&lt;h3 id="구현-로드맵"&gt;구현 로드맵
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Phase&lt;/th&gt;
					&lt;th&gt;기간&lt;/th&gt;
					&lt;th&gt;내용&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1주&lt;/td&gt;
					&lt;td&gt;코어 트레이트, DelegateTool 확장&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;2-3주&lt;/td&gt;
					&lt;td&gt;Docker/Wasm 실행 모드&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;4주+&lt;/td&gt;
					&lt;td&gt;분산 메시지 버스, 합의 알고리즘&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="결론"&gt;결론
&lt;/h2&gt;&lt;p&gt;ZeroClaw는 확장성, 보안, 성능, 유지보수성 측면에서 우수한 아키텍처를 가지고 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;이 보고서는 ZeroClaw 개발 팀의 협업 분석 결과를 바탕으로 작성되었습니다.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;영어 버전:&lt;/strong&gt; &lt;a class="link" href="https://blog.agentthread.dev/post/2026-02-26-001-zeroclaw-codebase-architecture-analysis/" &gt;English Version&lt;/a&gt;&lt;/p&gt;</description></item></channel></rss>