회고코드를 밖으로 보낼 수 없을 때: 로컬 LLM 에이전트 IDE 야누스
· 야누스
- #local-llm
- #harness
- #agent
- #mlx
제조업 기반 기업의 AX 교육에 보조로 참여한 적이 있습니다. 그곳은 보안 문제가 무엇보다 중요했어요. 코드를 사내망 밖으로 내보낼 수 없어서 외부 AI 서비스를 쓰기 어려웠습니다.
금융업에서 일하는 개발자 지인도 사정이 비슷했습니다. AI를 쓰고는 있지만 제약이 많다고 했어요.
그러던 중 Qwen3.8이 나왔고 반응이 좋았습니다. 로컬에서도 코딩 에이전트를 돌릴 수 있지 않을까 하는 생각에 실험 삼아 만들기 시작한 게 야누스입니다. 로컬 LLM 기반의 에이전트 코딩 IDE예요.
출발점: 로컬 모델의 약한 성능
로컬 모델은 Claude나 Codex보다 성능이 떨어질 수밖에 없습니다. 야누스의 기본 모델은 Qwen3.8 27B를 4-bit로 줄여 MLX(애플 실리콘용 머신러닝 프레임워크)로 돌리는 구성이에요. 48GB 맥에서 모델만 16GB를 쓰고, 요청을 동시에 여러 개 처리하면 요청마다 KV 캐시(이전 토큰 계산을 저장해 두는 메모리)가 따로 쌓입니다.
모델은 바꿀 수 없으니, 모델을 감싸는 하네스(실행·검증·예산을 관리하는 장치)로 성능을 얼마나 끌어올릴 수 있는지를 고민했습니다.
27B
로컬 모델
Qwen3.8 · MLX 4-bit
44/45
고정 과제 통과
과제 3개 × 위임 방식 3개 × 5회
0
외부로 나가는 코드
로컬 경로 기준
모델 밖에서 내리는 완료 판단
성능이 낮은 모델은 일을 끝냈다고 답해 놓고 테스트를 돌리지 않거나, 테스트가 실패한 상태로 끝나는 경우가 있습니다. 그래서 야누스에서는 모델의 답변이 끝나도 작업이 끝난 것으로 보지 않습니다.
에이전트 실행
답변이 끝나도 아직 완료 아님Git diff
실제 저장소에서 변경을 다시 계산검증
테스트·lint·수용 명령을 하네스가 실행리뷰
사람이 diff와 결과를 보고 수락커밋
기록한 커밋과 HEAD가 같을 때만 push
실행 종료, 검증 완료, 리뷰 수락, 커밋 성공을 각각 다른 상태로 기록합니다. 변경 내용은 별도 스냅샷이 아니라 실제 저장소의 Git diff로 계산하고, 변경 내용 전체로 만든 식별값(revision)이 바뀌면 앞서 한 리뷰와 검증은 다시 해야 합니다. 검증을 통과하지 않으면 커밋할 수 없어요.
예산을 건 위임
처음에는 큰 작업을 하위 에이전트(worker)에게 나눠 맡기면 성능이 낮은 모델도 더 잘할 거라고 예상했습니다. 실제 모델로 측정한 결과는 예상과 달랐어요.
자율 위임
15회 모두 통과했지만 평균 72.5초로 63% 느려졌습니다. 여러 파일을 고치는 과제에서는 5회 모두 필요 없는 worker를 만들었습니다.
조사 과제를 worker 하나에
5회 모두 실패했습니다. worker가 매번 토큰 한도(8,192)를 다 썼고, 같은 하위 작업을 반복 생성하다 4회는 시간 초과, 1회는 검증 실패로 끝났습니다.
그래서 위임은 기본으로 막고, 사용자가 요청했을 때만 예산을 정해 허용하도록 바꿨습니다.
- worker 수와 토큰·시간·단계 예산에 상한을 두고, 같은 역할은 처음 1회와 교정 2회까지만 다시 만들 수 있게 했습니다.
- 예산을 다 쓴 worker의 변경과 중간 결과는 상위 에이전트가 이어받아, 같은 작업을 다시 시키지 않도록 했습니다.
- 파일을 고치는 역할은 하나만 두고, 조사·검증 역할에는 읽기 도구만 줍니다. 받지 않은 쓰기 도구를 호출하면 실행 단계에서 거부합니다.
- 실패 원인별로 재시도 방식을 나눴습니다. 검증이 실패하면 읽기만 하는 하위 에이전트가 원인을 찾고 파일을 고치는 하위 에이전트가 수정하며, 예산 초과·시간 초과·도구 오류는 각각 다르게 다음 시도를 구성합니다.
로컬 자원을 아끼는 장치
로컬에서는 모델이 생성하는 양을 줄이는 만큼 빨라지기 때문에, 같은 내용을 다시 보내거나 생성하지 않도록 했습니다.
- 오래된 대화는 도구 호출과 결과를 짝지어 남기면서 요약합니다. 긴 대화를 흉내 낸 테스트에서 입력이 40% 넘게 줄었습니다.
- 바뀌지 않는 앞부분(시스템 지시와 요약)을 모델 서버의 프리픽스 캐시(같은 앞부분의 계산 결과를 다시 쓰는 기능)에 연결했습니다. 같은 세션 두 번째 턴에서 프롬프트 57토큰 중 36토큰이 캐시에서 처리됐습니다.
- 동시 생성 수는 5에서 3으로 줄였습니다. 요청마다 KV 캐시가 따로 쌓이고 GPU가 하나라 2~3개를 넘기면 이득이 없었고, 실제로도 동시 생성이 3을 넘은 적이 없었습니다.
측정으로만 내리는 개선 판단
하네스를 바꿀 때마다 미리 정해 둔 과제 묶음(과제마다 완료 여부를 판정하는 테스트가 붙어 있습니다)을 같은 모델·위임 방식으로 기존 설정과 바꾼 설정에서 반복 실행해 비교했습니다. 이때 통과율이 떨어지면 시간과 토큰이 줄어도 개선으로 보지 않기로 정했어요. 작업 순서를 정하는 스케줄러를 바꾼 설정은 통과율이 44/45에서 40/45로 떨어져서 적용하지 않았습니다.
worker를 하나만 쓰는 방식은 통과율을 유지한 채 시간과 토큰이 줄어서 적용했습니다.
14/15
수용 검증 통과
개선 전과 같음
88.1초
소요 시간
-19.8%
10,993
프롬프트 토큰
-26.0%
777
생성 토큰
-36.7%
회고: 하네스가 메운 것과 못 메운 것
완료 여부를 검증으로 판단하고, 위임에 상한을 두고, 바꾼 설정을 측정으로 확인한 덕분에 27B 모델로도 과제 45개 중 44개를 통과했습니다.
그래도 모델 자체의 한계는 남습니다. 깊은 조사나 여러 파일에 걸친 판단은 결국 모델 성능에 달려 있고, Claude나 Codex와 같이 써 보면 차이가 바로 보입니다. 그래서 야누스에서는 이미 로그인해 둔 Claude Code·Codex CLI를 로컬 모델 대신 쓸 수 있게 했고, 경로마다 통제할 수 있는 범위가 어떻게 다른지 문서에 적어 두었습니다.