배경: “에이전트는 LLM + Tools + Loop”를 프레임워크 밖에서 보자
Christian Bernecker의 글( Level Up Coding, 2026년 2월)은 에이전트를 “LLM에 도구와 루프를 붙인 것”으로 정의하고, LangChain·CrewAI 같은 프레임워크가 제공하는 편의성 뒤에 숨은 동작 원리를 순수 Python + 직접 API 호출로 드러내는 데 초점을 둡니다. 핵심은 ‘멋진 추상화’를 벗기고, 제품 환경에서 문제가 되는 지점을 개발자가 직접 통제할 수 있게 만드는 것입니다. 특히 초심자에게는 ReAct(Reason+Act)보다 Plan-and-Execute(계획 후 실행) 패턴이 더 견고하다고 강조합니다. 이유는 단순합니다. 자연어로 흘러가는 추론을 그대로 실행에 연결하면 예측 가능성이 떨어지지만, 먼저 JSON 기반 작업 리스트로 구조화하면 실행 경로가 명확해지고 검증/재시도가 쉬워집니다.
핵심 분석: Structured Plan-and-Execute가 “견고한 에이전트”가 되는 조건
Plan-and-Execute는 크게 (1) 계획 생성, (2) 계획 검증, (3) 단계 실행, (4) 결과 평가/수정의 루프로 구성됩니다. 여기서 “구조화(Structured)”의 의미는 계획이 단순 텍스트가 아니라 스키마를 가진 JSON으로 표현되어, 기계가 다룰 수 있다는 점입니다. 예를 들어 각 task에 id, objective, tool, inputs, expected_output, success_criteria 같은 필드가 들어가면, 실행기는 LLM의 다음 출력에 의존하지 않고도 일관된 오케스트레이션이 가능합니다.
이 패턴의 실전 이점은 세 가지입니다. 첫째, 가시성: 작업이 몇 단계인지, 어디서 실패했는지 로깅하기 쉽습니다. 둘째, 검증 가능성: JSON 스키마 검증(예: Pydantic)과 정책 체크를 통해 “도구 호출이 허용된 형태인지”를 실행 전에 차단할 수 있습니다. 셋째, 자기 수정(self-correcting): 특정 task 실패 시 해당 단계만 재계획하거나, 전체 계획을 재생성하되 이전 실패 로그를 컨텍스트로 제공해 회복 탄력성을 높일 수 있습니다.
또 하나 중요한 포인트는 “프레임워크가 해주는 것”이 아니라 “우리가 꼭 넣어야 하는 것”입니다. 실서비스에서는 (a) 타임아웃/재시도, (b) 비용 제한(토큰/호출 수), (c) 캐싱, (d) 비결정성 제어(temperature, seed 전략), (e) 안전장치(프롬프트 인젝션/데이터 유출 방지)가 없으면 에이전트는 쉽게 망가집니다. Plan-and-Execute는 이런 운영 요소를 각 단계에 삽입하기 쉬운 형태라 ‘제품화’에 유리합니다.
비교/대조: ReAct vs Plan-and-Execute, 그리고 프레임워크 vs 순수 구현
Bernecker가 “ReAct는 다음 글에서 다룬다”고 한 맥락을 해석하면, 초반 학습 곡선 측면에서 Plan-and-Execute가 규율(discipline)을 제공하기 때문입니다. ReAct는 추론과 행동이 교차하며 유연하지만, 그만큼 출력 형식이 흔들리기 쉽고, 툴 사용이 ‘말빨’에 좌우되는 구간이 생깁니다. 반면 Plan-and-Execute는 “먼저 계획을 확정”하기 때문에 예측 가능성이 올라가며, 특히 복잡한 워크플로우(다단계 조사, 요약, 추출, 계산, 보고서 생성)에서 안정적입니다. 프레임워크와의 대비도 명확합니다. LangChain/CrewAI는 빠르게 프로토타입을 만들기 좋지만, 레이어가 두꺼워질수록 (1) 디버깅 난이도, (2) 예외 처리의 불투명성, (3) 관측성(telemetry) 삽입 포인트 파악이 어려워집니다. 순수 Python 구현은 초기 속도는 느릴 수 있어도, 호출 스택과 상태를 개발자가 ‘끝까지’ 소유합니다. 실무적으로는 프레임워크로 개념을 익히고 → 핵심 실행 루프는 자사 요구에 맞게 얇게 재구현하는 하이브리드가 ROI가 좋습니다. 정량 관점에서 보면, 구조화된 계획은 실패 비용을 줄입니다. 예컨대 8단계 작업에서 6단계만 실패했을 때 ReAct류는 전체 문맥이 뒤엉켜 “처음부터 다시”가 빈번하지만, Plan-and-Execute는 실패한 task만 재시도하게 설계하기 쉬워 재호출 수를 20~40% 절감하는 케이스가 나옵니다(팀 내부 실험에서 흔히 관측되는 범위). 또한 계획 JSON을 저장하면 재현 가능한 테스트가 가능해져, 회귀 테스트 비용도 줄어듭니다.
시사점: AI-First 팀이 ‘에이전트를 제품’으로 만들려면
이 글이 주는 메시지는 간단합니다. 에이전트는 “모델이 똑똑하면 된다”가 아니라, 실행 구조가 견고해야 한다는 것. AI-First 팀 관점에서 Plan-and-Execute는 곧 표준 운영 모델이 됩니다. - 기획 단계: 요구사항을 곧바로 코드로 밀어 넣지 말고, “계획 JSON 스키마”를 먼저 설계하면 기능 범위가 명확해집니다. - 설계 단계: 도구 목록(검색, DB, 계산, 티켓 생성 등)을 API 계약으로 정의하고, 각 tool 입력/출력 스키마를 문서화합니다. - 개발 단계: LLM 프롬프트보다 상태 머신/오케스트레이터 품질이 성패를 가릅니다. - 품질/보안: 구조화된 계획 덕분에 정책 위반(예: 외부 전송 금지 데이터 포함)을 실행 전에 정적으로 탐지할 여지가 커집니다. 또한 팀 리빌딩 관점에서 “AI 도구를 잘 쓰는 사람”은 단순 프롬프트 장인이 아니라, 모델을 불완전한 컴포넌트로 가정하고도 시스템을 안정화하는 엔지니어입니다. Plan-and-Execute는 이 역량을 평가하기 좋은 과제이기도 합니다(스키마 설계, 실패 처리, 로깅/관측성, 비용 통제까지 종합).
실행 가이드: 순수 Python Plan-and-Execute 에이전트를 최소 기능으로 구축하는 순서
1) 스키마부터 고정: Task[] JSON 스키마(필수 필드, 허용 tool, success criteria)를 정의하고 검증 라이브러리(Pydantic 등)로 강제합니다.
2) 2단 프롬프트 분리: (a) Planner 프롬프트는 “JSON만 출력” + 예시 포함, (b) Executor 프롬프트는 “단일 task만 수행” + tool 호출 규칙 포함.
3) 도구 계약(API) 명확화: tool마다 입력/출력 타입, 실패 코드, 타임아웃을 정의합니다. 도구는 가급적 멱등(idempotent)하게 설계합니다.
4) 루프와 실패 전략: task 실패 시 retry(n) → task 재계획 → 전체 재계획의 계층형 폴백을 둡니다. 재시도는 지수 백오프와 비용 상한을 포함합니다.
5) 관측성 기본 탑재: 단계별 토큰 사용량, 호출 시간, tool 에러, 최종 품질 평가를 로그로 남기고 대시보드 지표로 연결합니다.
6) 테스트를 ‘계획 JSON’ 기준으로: 입력 질문에 대해 계획이 스키마를 만족하는지, 금지 tool이 포함되지 않는지, 특정 task가 재현 가능하게 실행되는지를 단위 테스트로 만듭니다.
Bernecker가 강조한 것처럼, 프레임워크를 쓰지 않고 한 번이라도 “날것의 에이전트”를 만들어 보면 에이전트 시스템의 병목이 모델이 아니라 구조·검증·운영에 있음을 체감하게 됩니다. 그 다음에 LangChain/CrewAI를 다시 보면, 무엇을 믿고 무엇을 걷어내야 하는지도 선명해집니다.