도구를 하나씩 부르지 않고 묶어서 실행하면, 에이전트의 병목이 달라진다

GitHub 이슈 분류와 Sentry 조회를 코드로 묶은 실제 Pi 세션을 살펴봅니다. 중간 결과를 매번 모델에 돌려주지 않는 설계와 작업·제어 환경의 권한 경계를 설명합니다.

조회와 분류의 반복 호출을 코드에서 실행하고 가공한 결과만 모델에 전달하는 역할 구분
아르민 로나허의 실제 Pi 세션 코드에 근거한 자체 도식

GitHub 이슈를 읽고 감정을 분류하는 일을 에이전트에게 맡겼다고 하자. 이슈 하나를 조회하고, 답을 읽고, 다음 도구를 부르는 과정이 대화에 계속 쌓이면 정작 마지막에 필요한 목록보다 중간 과정이 더 길어진다. 반복 규칙이 이미 정해진 일에도 모델이 매번 다음 호출을 결정해야 한다.

아르민 로나허는 10월 6일 글에서 자신이 코딩 에이전트 Pi로 실제 수행한 작업을 공개했다. 코드모드(Codemode)는 모델이 여러 도구 호출을 묶는 코드를 작성하고, 그 코드가 반복과 결과 가공을 맡는 방식이다. 그는 GitHub 이슈를 분류하고 Sentry 조직별 프로젝트를 조회하는 코드를 예로 들었다. 모델을 더 빨리 답하게 만드는 대신, 중간 결과가 모델로 돌아오는 횟수와 양을 줄인다.

도구 하나의 결과가 왜 매번 대화로 돌아와야 할까

보통의 도구 호출에서는 모델이 호출을 지시하고, 실행 결과를 받아 다음 행동을 정한다. 코드모드에서는 모델이 먼저 작은 프로그램을 쓴다. 프로그램 안에서 도구를 여러 번 부르고, JSON을 읽고, 필요한 항목만 골라 반환할 수 있다. 모든 호출 결과를 주 에이전트의 대화에 펼칠 필요가 없다.

로나허의 설명에 따르면 Pi의 일반 bash 도구는 출력의 마지막 2,000줄을 모델 문맥에 넣고, 나머지는 별도 파일로 남긴다. 코드모드로 같은 도구를 부르면 더 큰 출력을 구조화된 형태로 받아 코드 안에서 처리할 수 있다. 출력이 커서 잘리는 문제를 해결하려고 다시 파일을 읽게 하는 왕복도 줄일 여지가 생긴다.

Cloudflare가 외부 도구 연결 규약인 MCP를 설명하며 공개한 비교 그림에도 이 차이가 나타난다. 모델이 도구 호출용 특수 텍스트를 출력하는 경로 대신 API를 사용하는 코드를 쓰고, 샌드박스에서 그 코드를 실행한다. 그림의 Dynamic Isolate는 Cloudflare 구현이다. 뒤에서 설명할 Pi의 실행기와는 다르다.

Cloudflare의 기존 MCP와 Code Mode 연결 관계를 한글로 재구성한 구조도
원문 기반 한글 재구성. 출처: Cloudflare

GitHub 이슈는 모아서 분류하고, 모델에는 12건만 돌려줬다

로나허가 공개한 실제 세션 코드는 gh issue list로 열린 이슈를 최대 100건 가져온다. 번호와 제목, 본문, 댓글이 JSON으로 돌아온다. 이어서 Jev라는 분류 모델에 각 이슈의 감정, 불만 정도, 이슈 종류를 묻는다. 주 에이전트가 이슈마다 긴 답변을 만들며 분류하는 흐름과는 다르다.

분류 입력에도 범위를 정했다. 본문은 앞 4,000자까지만, 댓글은 최근 5개에서 각각 앞 800자까지만 쓴다. 감정은 긍정·중립·부정 중 하나, 종류는 버그·기능 요청·질문·기타 중 하나로 받는다. 불만 정도는 점수로 받아 정렬한다. 분류 모델에 판단을 맡기되, 무엇을 읽고 어떤 형태로 답할지는 코드가 정한다.

코드는 Promise.all로 분류 요청을 모으고, 결과 전체를 store("sentiment_results", results)로 세션 기록에 저장한다. 오류가 없는 결과를 불만 점수 순으로 정렬한 뒤 상위 12건만 짧은 목록으로 반환한다. 다음 코드모드 호출은 저장한 전체 결과를 다시 읽을 수 있다. 100건은 조회 상한이고 12건은 반환 상한이지, 실제 처리 건수나 분류 정확도를 뜻하지 않는다.

최대 100건의 GitHub 이슈를 Jev로 분류하고 전체 결과를 저장한 뒤 상위 12건만 반환하는 실제 세션 코드의 흐름
출처: 아르민 로나허의 실제 Pi 세션 코드

PM이 고객 요청을 먼저 읽어 볼 순서를 정하거나 기술 사업자가 지원 이슈를 묶어 보는 업무에 적용한다면, 이 패턴을 참고할 수 있다. 분류 기준과 읽을 범위를 먼저 정하고, 기계적인 정렬과 저장은 코드에 맡긴다. 본문과 댓글을 잘랐기 때문에 뒤쪽에 있는 반전이나 해결 내용은 분류 입력에서 빠질 수 있다. 반환된 우선순위로 이슈를 닫거나 고객에게 답하기 전에는 원문을 열어 봐야 한다.

Sentry 조회에서는 실패한 조직까지 결과에 남겼다

두 번째 사례는 오류 추적 서비스 Sentry의 MCP 서버를 조회한 작업이다. 코드는 먼저 조직 목록을 받고, 각 조직의 프로젝트 목록을 요청한다. 이때 조직 식별자인 slug와 해당 조직의 regionUrl을 함께 넘긴다. 조직마다 필요한 입력을 코드가 전달하므로, 주 에이전트가 목록을 읽고 요청을 하나씩 다시 쓰지 않아도 된다.

여기서는 Promise.allSettled를 썼다. 일부 요청이 실패해도 나머지 요청의 결과를 모을 수 있다. 코드는 요청 자체의 실패와 도구 응답의 isError를 각각 확인해 해당 조직의 오류로 남긴다. 성공한 조직은 프로젝트 이름 목록으로 축약한다. 이 사례가 한 일은 조직과 프로젝트 조회이며, 오류의 원인 진단이나 복구까지 수행한 것은 아니다.

두 사례의 병목도 같지 않다. GitHub 이슈 분류에는 분류 모델의 처리 시간과 입력 범위가 남고, Sentry에는 서버 응답과 조직별 오류가 남는다. Pi는 동시에 실행하는 도구를 4개로 제한하고 나머지를 큐에 넣는다고 로나허는 설명한다. 코드에 병렬 구문을 썼다고 모든 외부 요청이 제한 없이 동시에 실행되는 구조는 아니다.

작업용 샌드박스를 잠갔다고 제어 환경까지 잠기는 것은 아니다

코드모드는 단순히 작업용 컴퓨터에서 bash 스크립트를 돌리는 것과 다르다. 로나허는 에이전트를 제어하는 하네스를 '두뇌', 도구가 작업하는 실행 환경을 '손'으로 구분한다. 두 환경은 같은 컴퓨터일 수도 있지만 파일시스템과 신뢰 수준이 다를 수 있다. 작업용 bash를 Gondolin 같은 샌드박스 안에 넣어도 하네스 자체가 그 안으로 들어가지는 않는다.

Pi의 코드모드는 하네스 쪽에서 별도 샌드박스로 실행된다. WASM 런타임 안의 QuickJS를 사용하며 직접 네트워크, 파일시스템, 타이머에 접근하지 못하고 메모리에도 제한이 있다. 대신 노출된 도구를 부를 수 있다. 따라서 실행기 자체의 제한과 그 도구가 가진 권한은 따로 봐야 한다. 코드가 직접 파일을 못 읽어도 파일을 읽는 도구를 허용했다면 그 경로로 읽을 수 있기 때문이다.

Pi의 하네스 측 코드모드 샌드박스와 bash 작업 실행 환경의 분리 및 허용된 도구를 통한 접근 경계
출처: 아르민 로나허

제품을 설계할 때는 작업 환경의 디스크와 네트워크를 제한하는 설정에 더해, 제어 환경이 어떤 도구를 노출하는지 점검해야 한다. 조회용 도구와 데이터를 바꾸는 도구를 구분하고, 변경 작업의 승인 지점이 묶음 실행 안에서도 유지되는지 확인할 필요가 있다. 세션 기록에 저장한 조회 결과를 누가 읽을 수 있는지도 제어 환경의 권한 문제다.

왕복을 줄인 뒤에는 응답 형식과 재실행이 문제가 된다

코드가 데이터를 직접 처리하려면 도구 응답이 일정해야 한다. 로나허는 5개 항목을 조회할 때는 잘 작동하던 코드가 최대 배치를 받자 실패할 수 있다고 지적한다. 서버가 결과 개수에 따라 토큰을 줄이려고 응답 형식을 바꾸는 경우다. 처음 몇 건으로 구조를 살펴본 뒤 반복 처리하는 방식에는, 같은 필드와 타입을 유지하는 JSON 응답이 필요하다. MCP의 outputSchema도 이 목적에 도움이 된다.

코드모드를 MCP 서버 안에서도 구현하면 또 다른 비용이 생긴다. Pi에서 Cloudflare MCP를 부르는 예에서는 바깥 JavaScript가 안쪽 JavaScript 코드를 문자열로 전달한다. JSON 이스케이프가 겹치고, 안쪽 코드는 바깥 도구를 부를 수 없다. 호출을 묶는 기능이 두 군데 있다고 조합이 더 쉬워지는 것은 아니다.

긴 작업이 중간에 끊겼을 때 어디서부터 다시 실행할지도 남는다. 로나허는 호출 상태를 스냅샷으로 남기는 내구성 있는 워크플로 엔진의 아이디어를 검토할 수 있다고 썼다. 이는 해결된 기능의 소개가 아니라 남은 설계 문제다. 조회와 분류부터 이 방식을 적용하고, 데이터 변경까지 맡길 때는 완료한 항목의 기록과 중복 실행 방지 방법을 함께 정하는 편이 낫다. 왕복이 줄어든 뒤에는 외부 서비스의 제한, 응답의 일관성, 실패한 작업의 재실행 방식이 처리량을 좌우한다.

출처: 아르민 로나허, What is Codemode · Cloudflare, Code Mode · Sentry MCP