본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 27. 09:24

신뢰할 수 있는 TypeScript AI 에이전트: 4B 모델이나 Claude에서도 동일한 코드가 완료되고 실행 중 충돌에서도 살아남는 방법

요약

소형 로컬 모델에서도 Claude와 동일한 성능을 내는 신뢰할 수 있는 TypeScript AI 에이전트 프레임워크인 Reactive Agents를 소개합니다. 모델 자체를 수정하는 대신, 도구 호출 오류나 실행 중 충돌을 견딜 수 있는 견고한 하네스(harness) 구축에 집중합니다.

핵심 포인트

  • 소형 모델의 잘못된 도구 호출(Tool Call) 문제를 해결하는 하네스 구축 방식 제안
  • Reactive Agents의 3대 핵심 요소: 신뢰성, 투명성, 조립성
  • 4B 로컬 모델과 Claude에서 동일한 코드로 안정적인 에이전트 루프 구현 가능
  • Think-Act-Observe 루프를 통한 에이전트 실행의 안정성 확보

모든 에이전트 프레임워크 데모는 잘 작동합니다. 몇 가지 도구 (tools)를 연결하고, 프런티어 모델 (frontier model)을 지정한 뒤, 무언가를 물어보면 완벽하게 해냅니다. 트위터(tweet)에 올리기에는 아주 좋아 보이죠.

하지만 더 작은 모델을 사용하여 실제 작업에 적용하면, 세 번째 도구 호출 (tool call)에서 무너지는 것을 보게 됩니다.

저의 지난 봄 대부분이 그러했습니다. Claude를 상대로는 에이전트가 아주 잘 작동하게 만들었다가, 토큰당 비용을 지불하지 않기 위해 로컬 모델 (local model)로 교체하면, 모델은 거의 맞지만 틀린 도구 호출을 내뱉었습니다. 예를 들어 get_service_health 대신 getServiceHealth라는 이름의 도구를 호출하거나, service 대신 svc라는 파라미터 (param)를 사용하거나, 경로에 잘못된 따옴표가 포함되는 식이었죠. 그러면 루프 (loop)는 그냥 죽어버립니다. 다시 프롬프트 (re-prompt)를 주고, 재시도 (retry)하고, 아무것도 하지 못한 채 반복 (iterations)만 거듭하다가 결국 포기하게 됩니다. 모델은 작업을 수행할 수 있었습니다. 하지만 모델을 둘러싼 하네스 (harness)가 루프를 유지하여 그 사실을 알아낼 만큼 충분히 버티지 못했던 것입니다.

그래서 저는 모델을 고치려는 시도를 멈추고 하네스를 구축했습니다. 이것은 Reactive Agents라고 불리며, 제가 다른 프레임워크들이 해주기를 계속 바랐던 세 가지 요소를 중심으로 구성되어 있습니다:

  • 신뢰성 (Reliability) — 루프가 실제로 완료됩니다.
  • 투명성 (Transparency) — 블랙박스 (black box)를 추측하는 대신 모든 단계를 보고 조종할 수 있습니다.
  • 조립성 (Composability) — 필요한 것은 추가하고 필요 없는 것은 건너뜁니다.

신뢰성은 제가 가장 자랑스럽게 생각하는 부분이므로, 말로 설명하는 대신 직접 보여드리겠습니다. 여기 동일한 에이전트 — 서비스 경고 조사, 두 개의 도구 호출, 데이터 상관관계 분석, 해결책 권장 — 가 4B 로컬 모델과 Claude에서 실행되는 모습이 있습니다. 두 실행 사이에서 바뀌는 유일한 것은 단 한 줄뿐입니다:

The same agent completing a tool-using investigation on a local 4B Ollama model and on Claude

동일한 빌더, 두 개의 모델

import { ReactiveAgents } from "reactive-agents";

const agent = await ReactiveAgents.create()
...

if (local) 분기가 없습니다. 두 번째 코드 경로도 없습니다. 에이전트는 동일한 생각(think) → 행동(act) → 관찰(observe) 루프를 실행하며, get_service_healthget_recent_deploys를 호출하고, 성능 저하가 12분 전의 배포(deploy)와 일치한다는 점을 인지한 뒤 다음과 같이 말합니다:

이것은 Effect-TS를 기반으로 구축되었습니다. 보통 이 이름을 들으면 사람들이 신음 소리를 내곤 하기에, 미리 말씀드리겠습니다. 이것을 사용하기 위해 Effect를 작성할 필요는 없습니다. 빌더(builder)와 훅(hooks)은 일반적인 비동기 함수(async functions)입니다.

무료로 얻게 되는 것은 엔드 투 엔드(end-to-end)로 타입이 지정된 런타임(runtime)입니다. 도구 호출(tool call) 실패나 모델 타임아웃(timeout)은 명시적인 에러 채널(error channel) 내의 타입화된 값(typed value)으로 처리됩니다. 즉, 새벽 2시에 운영 환경(prod)에서 처음 마주하게 되는 예외(exception)가 아닙니다. 재시도(retries)와 폴백(fallbacks)은 조합(compose) 가능합니다. 구조화된 출력(Structured output)은 사용자에게 전달되기 전에 스키마 검사(schema-checked)를 거칩니다.

.withHook({
  phase: "act",
  timing: "after",
...

에이전트가 무엇을 하고 있는지 볼 수 있습니다

이것은 제가 다른 모든 곳에서 가장 그리워했던 부분입니다. 모든 실행은 부트스트랩(bootstrap), 가드레일(guardrail), 비용 경로(cost-route), 사고(think), 실행(act), 관찰(observe), 검증(verify) 등과 같이 고정된 12단계 라이프사이클(lifecycle)을 따르며, 모든 단계에는 before / after / on-error 훅(hooks)이 있습니다. 저는 트레이스(traces)를 누군가의 대시보드로 전송하지 않고도 로컬에서 모든 단계를 관찰하고 제어할 수 있습니다.

import { ReactiveAgents, HarnessProfile } from "reactive-agents";

const agent = await ReactiveAgents.create()
...

메모리(Memory), MCP 도구(MCP tools), 멀티 에이전트(multi-agent), 내구성 있는 재개(durable resume) — 모두 동일한 엔진 위에서 선택적으로 적용할 수 있는 레이어(layers)입니다. 원하는 것만 추가하세요.

실행 도중 프로세스가 종료되어도, 중단된 지점부터 다시 시작합니다

이것이 신뢰성의 나머지 절반이며, 솔직히 말해서 오래 실행되는 작업(long-running)에 대해 제가 가장 먼저 내세우고 싶은 기능입니다. 에이전트는 충돌(crash)합니다. 서버가 재부팅되거나, 컨테이너가 재스케줄링되거나, 배포(deploy)로 인해 프로세스가 교체될 수 있습니다. 보통 이는 전체 실행을 처음부터 다시 시작해야 함을 의미하며, 이미 소비한 모든 도구 호출과 토큰(token) 비용을 다시 지불해야 한다는 뜻입니다.

.withDurableRuns()를 사용하면 모든 반복(iteration)이 디스크에 체크포인트(checkpointed)로 저장됩니다. 실행 도중 프로세스를 종료하더라도, 새로운 프로세스가 마지막 체크포인트로부터 정확히 해당 실행을 이어받아 완료합니다. 이미 실행된 도구들은 다시 실행되지 않습니다.

An agent checkpointing each step, getting killed mid-run, then a fresh process reconstructing the run from its last checkpoint and finishing it

// 프로세스 A — 작동하며, 각 단계를 체크포인트(checkpoint)하고, 이후 강제 종료(hard-kill)됨.
const a = await build();                       // .withDurableRuns({ dir })
for await (const _ of a.runStream(task)) { /* ...실행 도중 프로세스 사망... */ }
...

동일한 체크포인트(checkpoint) 메커니즘은 인간 참여형(human-in-the-loop) 방식도 내구성 있게 만듭니다. 게이트가 설정된 도구 호출(tool call)은 실행을 일시 중지하고 저장하며, 완전히 다른 프로세스에서 누군가가 이를 승인하거나 거부하여 다시 실행을 이어갈 수 있습니다.

이 방식을 사용하지 말아야 할 때

여러분의 시간을 아껴드리겠습니다.

  • 단일 제공자(provider)를 사용하며 단순한 루프(loop)가 필요한가요? 해당 벤더의 Agent SDK를 사용하세요. 하네스(harness)는 필요 없으며, 저는 서운해하지 않습니다.
  • 오늘 당장 가장 큰 생태계와 가장 많은 튜토리얼를 원하시나요? 그것은 LangChain이나 Mastra이지, 제가 아닙니다. 이 기술은 초기 단계입니다.
  • 지금 당장 수천 개의 프로덕션 배포 환경에서 검증된(battle-tested) 무언가가 필요한가요? 아직은 그렇지 않습니다 — v0.12, MIT 라이선스, 약 6,500개의 테스트를 보유하고 있습니다. 여러분이 3주 후에 직접 깨닫게 하기보다는 차라리 제가 솔직하게 말씀드리는 편이 낫겠습니다.

비교를 원하신다면, 문서에 LangGraph, Mastra, Vercel AI SDK, 그리고 벤더별 Agent SDK와의 정직한 비교표가 준비되어 있습니다.

사용해 보기

bun add reactive-agents
# 또는: npm install reactive-agents

로컬 모델(local-model) 경로를 실행하신다면, 어떤 모델을 시도하셨는지, 그리고 복구(healing)가 제대로 유지되었는지 꼭 알고 싶습니다. 그 부분이 제가 사람들이 실제 워크로드(workload)를 투입해 주길 가장 바라는 부분입니다. 이슈(Issues)와 피드백은 언제나 환영하며, 모두 읽어보고 있습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0