Pydantic AI가 하네스(harness) 라이브러리를 출시했다. 거창한 프레임워크가 아닌, 순수한 라이브러리 형태다. 레고 블록처럼 에이전트에 조립할 수 있는 30가지의 독립된 역량(capabilities)을 제공한다. 공식 문서 전체를 꼼꼼히 읽어보았고, 그중 실질적으로 중요한 핵심들을 정리했다.

핵심 아이디어

Pydantic AI 코어(core)는 에이전트 루프, 모델 프로바이더, 그리고 몇 가지 기본 기능(웹 검색, 도구 검색, 생각(thinking), MCP)을 제공한다. 그 외의 모든 것은 pydantic-ai-harness에 담겨 있다. 경량화된 pydantic-ai-slim과 함께 설치한 뒤 필요한 기능만 골라 쓰면 된다.

uv add pydantic-ai-harness

가장 핵심적인 아키텍처 패턴은 “상향 지원(fall up)“이다. 기능들은 먼저 모든 모델에서 동작하는 로컬 구현체로 시작하고, 프로바이더가 네이티브 기능을 지원하면 그쪽으로 자연스럽게 전환된다. 웹 검색, 웹 페치, 이미지 생성은 이미 코어에서 이 방식으로 동작하고 있으며, 스킬(Skills), 코드 모드(Code Mode), 컴팩션(Compaction) 역시 이 방향으로 나아가고 있다.

가장 돋보이는 기능: 코드 모드 (Code Mode)

도구 호출(tool calling)에 대한 멘탈 모델을 완전히 바꿔놓는 기능이다. 모델이 액션마다 도구를 하나씩 호출하여 매번 왕복(round-trip) 비용을 치르는 대신, 코드 모드는 모든 것을 단 하나의 run_code 도구로 감싼다. 모델은 등록된 도구들을 파이썬 함수처럼 직접 호출하는 코드를 작성한다.

# 모델이 run_code 내부에서 작성하는 파이썬 코드:
paris, tokyo = await asyncio.gather(
    get_weather(city='Paris'),
    get_weather(city='Tokyo'),
)
# 로컬 계산 수행 후 최종 결과 반환
paris_c = round((paris['temp_f'] - 32) * 5 / 9, 1)
{'paris': paris_c, 'tokyo': tokyo_c}

두 날씨 API 호출이 병렬로 실행되고, 단위 변환은 샌드박스 내부에서 즉시 이루어진다. 세 번의 모델 턴이 단 한 번의 왕복으로 끝난다. 샌드박스로는 Monty가 사용된다. 써드파티 임포트가 차단되고, 시스템 시계 원어가 없으며, 마운트 포인트를 통해 파일시스템 접근이 엄격히 통제되는 제한된 파이썬 런타임이다.

코드 모드는 향후 Pydantic AI 코어로 편입될 유력한 후보다. 이는 개발팀이 에이전트 아키텍처의 미래를 어떻게 바라보고 있는지를 잘 보여준다.

멀티 에이전트 오케스트레이션: 두 가지 층위

하네스는 서로 다른 추상화 수준에서 두 가지 위임(delegation) 역량을 제공한다:

SubAgents: delegate_task(agent_name, task)라는 단일 도구를 노출한다. 각 위임은 독립된 도구 호출과 모델 턴으로 처리된다. 위임 대상별 예산 설정(사용량 한도, 타임아웃, 최대 호출 횟수), 설정 가능한 메뉴를 통한 모델 선택, 오류 격리 기능을 갖췄다. 위임이 가끔 발생하거나 부모 에이전트가 각 단계마다 판단을 내려야 할 때 적합하다.

Dynamic Workflow: 조율 로직을 코드 자체로 옮겨온다. 모델이 하위 에이전트들을 비동기 함수처럼 호출하는 파이썬 스크립트를 작성한다. 팬아웃(fan-out), 체이닝, 투표, 재시도 루프가 단 한 번의 도구 호출 안에서 끝난다. 중간 결과물은 부모 에이전트의 컨텍스트를 어지럽히지 않는다. 도구에 적용했던 코드 모드의 발상을 통째로 에이전트 단위로 끌어올린 셈이다.

처음에는 SubAgents로 시작하고, 오케스트레이션 자체가 복잡한 핵심 작업이 될 때 Dynamic Workflow로 전환하는 접근을 권한다.

컨텍스트 관리: 세 가지 방어선

오래 실행되는 에이전트는 대개 세 가지 이유로 무너진다. 하네스는 세 가지 모두에 대한 해법을 제시한다:

컴팩션 (Compaction): 매 요청 전에 메시지 기록을 다듬는 전략 모음이다(슬라이딩 윈도우, 요약, 중복 제거, 계층형 에스컬레이션 등). 모든 수정 사항은 영구 보존되며, 도구 호출과 반환값 쌍(tool-call / tool-return)의 정합성을 철저히 유지한다.

도구 출력 제한 (Tool Output Limits): 너무 방대한 도구 반환값이 생성되는 즉시 가로챈다. 세 가지 모드가 있다: 잘라내기(Truncate, LLM 호출 없음, 손실 압축), 외부 저장(Spill, LLM 호출 없음, 무손실, 필요시 다시 읽기), 요약(Summarize, 1회 LLM 호출). 도구별 오버라이드가 가능한 크기 대역(size band)을 설정할 수 있다.

시스템 리마인더 (System Reminders): 실행 도중 지시문이 희석(instruction fade)되는 현상을 막기 위해 행동 지침을 중간에 재주입한다. 주기적인 정적 리마인더나 동적 콜러블(비용이 들지 않는 목표 재고정 또는 LLM 기반 넛지 포함)을 활용한다. 이는 CachePoint 뒤편의 일시적 꼬리(ephemeral tail) 파트로 주입되어, 디스크에 영구 저장되지 않고 프롬프트 캐시를 무효화하지도 않는다.

이 마지막 설계 디테일은 대단히 중요하다. 여러 역량이 이 일시적 꼬리 패턴을 채택하고 있다. 변경 가능한 콘텐츠를 CachePoint 뒤에 붙임으로써, 앞단의 지속적인 프롬프트 접두사(prefix)를 턴 간에 바이트 단위까지 완벽하게 동일하게 유지한다. Planning, System Reminders, Memory가 모두 이 방식을 쓴다. 단순한 데모용 토이 프로젝트와 상용 수준의 에이전트 인프라를 가르는 차이가 바로 이런 엔지니어링 디테일에 있다.

영속성과 메모리 (Persistence & Memory)

스텝 영속성 (Step Persistence): 각 경계 지점에서 모든 상태를 기록한다. 추가 전용(append-only) 스텝 이벤트, 재개 가능한 스냅샷, 도구 영향 원장(tool-effect ledger)이 포함된다. 시스템이 비정상 종료되더라도 어떤 도구가 시작되었고 완료되지 못했는지 정확히 알 수 있다. 인메모리, 파일, SQLite, MongoDB 등 4가지 백엔드를 지원하며, 대용량 페이로드 미디어는 자동으로 외부 분리 저장된다.

메모리 (Memory): 낙관적 동시성 제어, 네임스페이스 격리, 크기 제한이 적용된 프롬프트 주입 기능을 갖춘 에이전트용 영구 노트북을 제공한다. 모델은 전체 저장소가 아니라 MEMORY.md의 정선된 요약본과 파일 목록만 본다. 읽기, 쓰기, 삭제, 검색을 위한 온디맨드 도구가 제공된다. 저장소로는 파일(원자적 마크다운 + SQLite 저널), SQLite, PostgreSQL을 지원한다.

대화 검색 (Conversation Search): Step Persistence에 저장된 과거 기록 위에 순수 파이썬 BM25 검색을 얹었다. 컴팩션으로 인해 날아간 이전 턴이나 같은 저장소 내 과거 실행 기록을 의존성 없이 검색해 되살려낼 수 있다.

그 밖에 주목할 기능들

파일시스템(FileSystem)과 셸(Shell): 화이트리스트/블랙리스트 제어, 환경 변수 정제(실행된 명령어에서 LLM API 키를 제거하는 프리셋 포함), 백그라운드 프로세스 자동 정리 기능을 갖춘 샌드박스 I/O를 제공한다.

레포 컨텍스트 (Repo Context): 워크스페이스 트리에서 CLAUDE.md나 AGENTS.md를 자동으로 로드하고, 레포지토리 내 코딩 어시스턴트 자산들의 인벤토리 도구를 노출한다. 트리 순회 중 디렉터리별 지침을 동적으로 띄워주는 기능도 지원한다.

가드레일 (Guardrails): 프롬프트 입력, 도구 호출, 최종 출력이라는 에이전트 실행의 세 가지 경계면을 모두 검증하며, 허용/차단/대체/재시도/승인의 판정을 내린다. 즉시 사용 가능한 시크릿 및 개인정보(PII) 탐지기가 포함되어 있다.

계획 (Planning): 하위 작업, 의존성 관계, 캐시 안전 실시간 리마인더를 갖춘 구조화된 작업 목록을 제공한다. 영구 저장소 기반으로 기획자-실행자 분리(planner/executor split)가 가능하다. 한 에이전트가 계획을 수립하고 다른 에이전트가 이를 실행하며, 두 에이전트 사이의 유일한 공유 상태는 저장소뿐이다.

브라우저 유즈 (Browser Use): 자율형 브라우저 서브 에이전트에게 개방형 웹 작업을 위임한다. 단 하나의 browse_web 도구로 실제 Chromium을 제어하며, 도메인 허용 목록과 모델에 노출되지 않는 보안 시크릿 처리를 지원한다. 정해진 정형화된 플로우는 Playwright 스타일 스크립트 도구가 낫지만, 알 수 없는 웹페이지에서 유연한 목표를 달성할 때는 Browser Use가 제격이다.

어드바이저 (Advisor): 실행 에이전트가 별도의 조언자 모델에게 자문을 구할 수 있게 한다. Anthropic이나 OpenRouter에서는 프로바이더 네이티브로 동작하며, 그 외 환경에서는 로컬 폴백을 지원한다. 로컬 방식은 부모 에이전트와 사용량 계정을 공유한다.

런타임 역량 생성 (Runtime Capability Creation): 에이전트가 실행 중에 새로운 Pydantic AI 역량을 직접 작성하고, 검증하고, 저장하여 다음 실행 때 활성화한다. 에이전트가 스스로를 확장하는 것이다. 활성화 경계는 의도적으로 분리되어 있어, 새로 생성된 역량은 현재 실행이 아닌 다음 agent.run()부터 반영된다.

아쉬운 점과 한계

하네스는 아직 0.x 버전이다. 향후 API 브레이킹 체인지가 발생할 수 있다. 특히 다음 사항들을 유의해야 한다:

  • 스트리밍 조합 부재: Dynamic Workflow는 하위 에이전트를 한 번의 도구 호출로 끝까지 실행하므로, 완료되기 전까지 중간 진행 상황을 스트리밍으로 볼 수 없다. 팀에서도 이를 인지하고 있다.
  • ACP의 실험적 상태: 에디터(Zed 등)를 위한 에이전트 클라이언트 프로토콜(ACP) 어댑터는 동작하지만 아직 불안정하다.
  • 모든 경로의 영구성 미보장: 로컬 어드바이저 자문, Browser Use의 'agent' 세션 스코프, Memory의 자동 주입 등은 Temporal, Prefect, DBOS 같은 지속 실행 프레임워크와 결합할 때 영속성(durability)에 제약이 있다.

맺으며

Pydantic AI Harness는 지금까지 살펴본 에이전트 역량 라이브러리 중 가장 세심하게 설계된 결과물이다. 캐시 안전성을 고려한 패턴, 명확한 신뢰 경계, 모델 프로바이더에 따라 유연하게 진화하는 ‘상향 지원’ 접근 방식은 실제로 프로덕션 환경에서 에이전트를 운영하며 고통을 겪어본 개발자들의 노하우에서 비롯되었다. 30가지 역량은 입력 검증부터 도구 오케스트레이션, 컨텍스트 관리, 영속성, 메모리, 멀티 에이전트 위임, 출력 제어에 이르기까지 에이전트 생명주기 전체를 포괄한다.

Pydantic AI를 기반으로 개발하고 있다면 이 라이브러리는 필수다. 여러 에이전트 프레임워크를 저울질 중이라 하더라도, 순수 모델 API 위에 모든 것을 바닥부터 직접 만들지 않고 Pydantic AI를 진지하게 고려하게 만드는 가장 강력한 이유가 바로 이 하네스다.

설치해 보라. 필요한 역량 3가지를 골라 적용하고, 프로덕션으로 배포해 보길 권한다.