효과적인 에이전트 구축하기
핵심 요약
LLM 에이전트를 구축할 때 복잡한 프레임워크보다 단순하고 조합 가능한 패턴을 활용하여 효율적이고 디버깅하기 쉬운 시스템을 만드는 방법을 배우고, 예측 가능한 작업을 위한 '워크플로우'와 유연한 의사결정이 필요한 '에이전트'를 구분하여 적절하게 사용하는 실용적인 전략을 제시합니다.
주요 인사이트
- 복잡성보다는 단순성을 우선시하라: LLM 애플리케이션 개발 시 직접적인 API 호출로 시작하고, 성능 향상이 입증될 때만 다단계 에이전트 시스템이나 복잡한 프레임워크를 도입해야 합니다.
- 워크플로우와 에이전트의 명확한 구분: 예측 가능하고 잘 정의된 하위 작업에는 '워크플로우'가 적합하며, 유연한 모델 기반 의사결정이 필요한 개방형 문제에는 '에이전트'가 더 효과적입니다.
- 도구 설계와 프롬프트 엔지니어링의 중요성: 에이전트의 성공은 LLM이 외부 서비스 및 API와 상호작용하는 '도구'의 명확하고 사려 깊은 설계 및 문서화, 그리고 '에이전트-컴퓨터 인터페이스(ACI)' 최적화에 달려 있습니다.
왜 중요한가
이 가이드는 LLM 에이전트 개발자들이 불필요한 복잡성을 피하고, 신뢰할 수 있고 유지보수 가능한 시스템을 구축하는 데 필요한 실용적인 원칙을 제공합니다. 올바른 아키텍처 패턴을 선택하고 도구를 효과적으로 설계함으로써 개발자는 에이전트의 잠재력을 최대한 활용하여 실제 문제를 해결하고 궁극적으로 비즈니스 가치를 높일 수 있습니다.
개발자 뉴스레터를 받아보세요
제품 업데이트, 사용법 안내, 커뮤니티 소식 등을 매월 받은 편지함으로 보내드립니다.
지난 한 해 동안, 우리는 다양한 산업 분야에서 대규모 언어 모델(LLM) 에이전트를 구축하는 수십 개의 팀과 협력해 왔습니다. 일관되게 가장 성공적인 구현 사례들은 복잡한 프레임워크나 전문 라이브러리를 사용하지 않았습니다. 대신, 단순하고 조합 가능한 패턴으로 구축되었습니다.
이 게시물에서 우리는 고객들과 함께 작업하고 직접 에이전트를 구축하면서 배운 점들을 공유하고, 효과적인 에이전트를 구축하려는 개발자들에게 실질적인 조언을 제공합니다.
'에이전트'는 여러 가지 방식으로 정의될 수 있습니다. 일부 고객들은 에이전트를 다양한 도구를 사용하여 복잡한 작업을 장기간 독립적으로 수행하는 완전 자율 시스템으로 정의합니다. 또 다른 고객들은 미리 정의된 워크플로우를 따르는 더 규범적인 구현을 설명하는 데 이 용어를 사용합니다. 앤트로픽에서는 이러한 모든 변형을 에이전틱 시스템으로 분류하지만, 워크플로우와 에이전트 간의 중요한 아키텍처적 구분을 둡니다.
아래에서 두 가지 유형의 에이전틱 시스템을 자세히 살펴보겠습니다. 부록 1('실제 에이전트')에서는 고객들이 이러한 종류의 시스템 사용에서 특별한 가치를 발견한 두 가지 도메인을 설명합니다.
에이전틱 시스템을 언제 사용해야 할까요?
LLM으로 애플리케이션을 구축할 때, 가능한 가장 간단한 솔루션을 찾고 필요할 때만 복잡성을 늘릴 것을 권장합니다. 이는 에이전틱 시스템을 전혀 구축하지 않는 것을 의미할 수도 있습니다. 에이전틱 시스템은 종종 더 나은 작업 성능을 위해 레이턴시와 비용을 희생하므로, 이러한 트레이드오프가 타당한 시점을 고려해야 합니다.
더 많은 복잡성이 필요할 때, 워크플로우는 잘 정의된 작업에 대한 예측 가능성과 일관성을 제공하는 반면, 에이전트는 유연성과 모델 기반 의사결정이 대규모로 필요할 때 더 나은 선택입니다. 그러나 많은 애플리케이션의 경우 검색(Retrieval)과 인컨텍스트(in-context) 예시를 통해 단일 LLM 호출을 최적화하는 것만으로도 충분합니다.
프레임워크 vs. 직접 API 호출
에이전틱 시스템 구현을 쉽게 만들어주는 많은 프레임워크들이 있습니다. 예를 들면:
이러한 프레임워크들은 LLM 호출, 도구 정의 및 파싱, 호출 연결과 같은 표준적인 저수준 작업을 단순화하여 쉽게 시작할 수 있도록 합니다. 하지만 종종 기본 프롬프트와 응답을 모호하게 만들 수 있는 추가적인 추상화 계층을 생성하여 디버깅을 어렵게 만듭니다. 또한 더 간단한 설정으로 충분할 때 복잡성을 추가하고 싶은 유혹을 불러일으킬 수 있습니다.
우리는 개발자들이 LLM API를 직접 사용하여 시작할 것을 제안합니다. 많은 패턴을 몇 줄의 코드로 구현할 수 있습니다. 프레임워크를 사용하는 경우, 기본 코드를 이해해야 합니다. 내부 작동 방식에 대한 잘못된 가정은 고객 오류의 흔한 원인입니다.
샘플 구현을 보려면 쿡북을 참조하세요.
에이전틱 시스템: 일반적인 패턴
이 섹션에서는 프로덕션에서 확인된 에이전틱 시스템의 일반적인 패턴을 살펴보겠습니다. 우리는 기본 구성 요소인 증강된 LLM(augmented LLM)부터 시작하여, 단순한 조합형 워크플로우에서 자율 에이전트에 이르기까지 점진적으로 복잡성을 늘려나갈 것입니다.
증강된 LLM (Augmented LLM)
에이전틱 시스템의 기본 구성 요소는 검색(retrieval), 도구(tools), 메모리(memory)와 같은 증강 기능으로 강화된 LLM입니다. 현재 모델들은 이러한 기능을 적극적으로 사용할 수 있습니다. 자체 검색 쿼리를 생성하고, 적절한 도구를 선택하며, 어떤 정보를 유지할지 결정하는 식입니다.
우리는 구현의 두 가지 핵심 측면에 집중할 것을 권장합니다. 이러한 기능을 특정 사용 사례에 맞게 조정하고, LLM에 쉽고 잘 문서화된 인터페이스를 제공하도록 보장하는 것입니다. 이러한 증강 기능을 구현하는 방법은 여러 가지가 있지만, 한 가지 접근 방식은 최근 출시된 모델 컨텍스트 프로토콜(Model Context Protocol)을 통해 이루어집니다. 이 프로토콜은 개발자들이 간단한 클라이언트 구현으로 성장하는 서드파티 도구 생태계와 통합할 수 있도록 합니다.
이 게시물의 나머지 부분에서는 각 LLM 호출이 이러한 증강 기능에 접근할 수 있다고 가정합니다.
프롬프트 연결(Prompt Chaining)
프롬프트 연결은 작업을 일련의 단계로 분해하며, 각 LLM 호출은 이전 호출의 출력을 처리합니다. 프로세스가 여전히 올바른 경로에 있는지 확인하기 위해 중간 단계에 프로그래밍 방식의 검사(아래 다이어그램의 '게이트' 참조)를 추가할 수 있습니다.
이 워크플로우를 사용해야 할 때: 이 워크플로우는 작업을 고정된 하위 작업으로 쉽고 깔끔하게 분해할 수 있는 상황에 이상적입니다. 주된 목표는 각 LLM 호출을 더 쉬운 작업으로 만들어 레이턴시를 희생하여 더 높은 정확도를 얻는 것입니다.
프롬프트 연결이 유용한 예시:
- 복잡한 고객 요청에서 관련 정보 추출하기
- 문서 요약 및 후속 질문에 답변하기
라우팅(Routing)
라우팅은 입력을 분류하고 전문화된 후속 작업으로 전달합니다. 이 워크플로우는 관심사 분리를 가능하게 하고, 더 전문화된 프롬프트를 구축할 수 있도록 합니다. 이 워크플로우가 없으면 한 종류의 입력에 최적화하는 것이 다른 입력의 성능을 저해할 수 있습니다.
이 워크플로우를 사용해야 할 때: 라우팅은 서로 다른 범주가 별도로 처리될 때 더 잘 작동하는 복잡한 작업에 적합하며, LLM 또는 보다 전통적인 분류 모델/알고리즘에 의해 분류가 정확하게 처리될 수 있는 경우에 좋습니다.
라우팅이 유용한 예시:
- 고객 문의를 적절한 부서나 전문 LLM으로 라우팅하기
- 콘텐츠 생성에서 입력된 텍스트의 종류(예: 뉴스 기사, 이메일)에 따라 다른 생성 파이프라인으로 라우팅하기
병렬화(Parallelization)
LLM은 때때로 한 가지 작업을 동시에 수행하고 그 결과를 프로그래밍 방식으로 집계할 수 있습니다. 이 병렬화 워크플로우는 두 가지 주요 변형으로 나타납니다.
- 여러 시도 (Multiple attempts): 동일한 프롬프트로 LLM을 여러 번 호출하여 다양한 응답을 얻습니다. 그런 다음 이러한 응답을 평가하고, 가장 좋은 것을 선택하거나 (예: 가장 낮은 [환각(hallucination)] 비율), 결과를 통합합니다.
- 여러 관점 (Multiple perspectives): 동일한 입력에 대해 다양한 관점을 가진 여러 LLM을 프롬프트합니다 (예: 각 LLM에 특정 페르소나를 부여). 그런 다음 결과는 결합되거나 집계됩니다.
이 워크플로우를 사용해야 할 때: 병렬화는 분할된 하위 작업을 속도를 위해 병렬화할 수 있거나, 더 높은 신뢰도의 결과를 위해 여러 관점이나 시도가 필요한 경우에 효과적입니다. 여러 가지 고려 사항이 있는 복잡한 작업의 경우, LLM은 각 고려 사항이 별도의 LLM 호출로 처리될 때 일반적으로 더 나은 성능을 보이므로, 각 특정 측면에 집중할 수 있습니다.
병렬화가 유용한 예시:
- 복잡한 코드 베이스 변경에 대한 여러 솔루션 초안 작성 및 비교
- 다양한 스토리 아이디어를 브레인스토밍하고 가장 좋은 것을 선택하기
오케스트레이터-워커스(Orchestrator-Workers)
오케스트레이터-워커스 워크플로우에서는 중앙 LLM이 동적으로 작업을 분해하고, 이를 워커 LLM에 위임하며, 그 결과를 종합합니다.
이 워크플로우를 사용해야 할 때: 이 워크플로우는 필요한 하위 작업을 예측할 수 없는 복잡한 작업에 매우 적합합니다 (예를 들어, 코딩에서 변경해야 하는 파일의 수와 각 파일의 변경 특성은 작업에 따라 달라질 수 있습니다). 지형학적으로는 유사하지만, 병렬화와의 주요 차이점은 유연성입니다. 하위 작업은 미리 정의되지 않고, 특정 입력에 따라 오케스트레이터에 의해 결정됩니다.
오케스트레이터-워커스가 유용한 예시:
- 소프트웨어 개발에서 복잡한 코드 변경을 계획하고 실행하기. 여기서 오케스트레이터는 전체 변경 사항을 계획하고, 이를 여러 워커 LLM(예: 파일 변경, 테스트 작성)에 위임한 다음, 그들의 출력을 종합합니다.
평가자-최적화기(Evaluator-Optimizer)
평가자-최적화기 워크플로우에서는 하나의 LLM 호출이 응답을 생성하고 다른 LLM 호출이 루프 내에서 평가 및 피드백을 제공합니다.
이 워크플로우를 사용해야 할 때: 이 워크플로우는 명확한 평가 기준이 있고, 반복적인 개선이 측정 가능한 가치를 제공할 때 특히 효과적입니다. 적합성의 두 가지 신호는, 첫째, 인간이 피드백을 명확하게 표현할 때 LLM 응답이 현저하게 개선될 수 있다는 점입니다. 둘째, LLM이 그러한 피드백을 제공할 수 있다는 점입니다. 이는 인간 작가가 세련된 문서를 작성할 때 거칠 수 있는 반복적인 작성 과정과 유사합니다.
평가자-최적화기가 유용한 예시:
- 마케팅 캠페인 콘텐츠 생성. 여기서 한 LLM은 초기 초안을 만들고, 다른 LLM은 특정 KPI(예: 클릭률)에 대한 잠재적 영향을 평가하고 개선 사항을 제안합니다.
- 전략적 기획에서 잠재적 결정의 장단점 평가 및 개선.
자율 에이전트
에이전트는 복잡한 입력을 이해하고, 추론 및 계획에 참여하며, 도구를 안정적으로 사용하고, 오류에서 복구하는 등 LLM의 주요 기능이 성숙함에 따라 프로덕션에서 등장하고 있습니다. 에이전트는 인간 사용자의 명령 또는 상호 작용적 논의를 통해 작업을 시작합니다. 일단 작업이 명확해지면 에이전트는 독립적으로 계획하고 작동하며, 추가 정보나 판단을 위해 인간에게 돌아올 수도 있습니다. 실행 중에는 각 단계에서 환경으로부터 '그라운드 트루스(ground truth)'(예: 도구 호출 결과 또는 코드 실행)를 얻어 진행 상황을 평가하는 것이 중요합니다. 에이전트는 체크포인트에서 또는 블로커(blocker)를 만났을 때 인간 피드백을 위해 일시 중지할 수 있습니다. 작업은 종종 완료 시 종료되지만, 통제를 유지하기 위해 중단 조건(예: 최대 반복 횟수)을 포함하는 것도 일반적입니다.
에이전트는 정교한 작업을 처리할 수 있지만, 그 구현은 종종 간단합니다. 일반적으로 환경 피드백을 기반으로 루프에서 도구를 사용하는 LLM에 불과합니다. 따라서 도구 세트와 그 문서를 명확하고 사려 깊게 설계하는 것이 중요합니다. 도구 개발을 위한 모범 사례는 부록 2('도구 프롬프트 엔지니어링')에서 자세히 설명합니다.
에이전트를 사용해야 할 때: 에이전트는 필요한 단계 수를 예측하기 어렵거나 불가능하고, 고정된 경로를 하드코딩할 수 없는 개방형 문제에 사용될 수 있습니다. LLM은 잠재적으로 여러 턴 동안 작동할 수 있으므로, 그 의사결정에 어느 정도 신뢰를 가져야 합니다. 에이전트의 자율성은 신뢰할 수 있는 환경에서 작업을 확장하는 데 이상적입니다.
에이전트의 자율적 특성은 더 높은 비용과 복합적인 오류의 가능성을 의미합니다. 우리는 샌드박스 환경에서 광범위한 테스트와 적절한 안전장치(guardrails)를 권장합니다.
에이전트가 유용한 예시:
- 사용자 피드백에 기반한 웹 애플리케이션 개선
- 복잡한 데이터 분석 및 보고서 생성
다음 예시는 자체 구현 사례입니다.
모두 통합하기
이러한 구성 요소들은 규범적이지 않습니다. 그것들은 개발자들이 다양한 사용 사례에 맞게 형태를 만들고 조합할 수 있는 일반적인 패턴입니다. 다른 LLM 기능과 마찬가지로 성공의 열쇠는 성능을 측정하고 구현을 반복하는 것입니다. 다시 강조하지만, 오직 결과가 확연히 개선될 때만 복잡성을 추가하는 것을 고려해야 합니다.
LLM 분야에서의 성공은 가장 정교한 시스템을 구축하는 것이 아닙니다. 여러분의 필요에 맞는 올바른 시스템을 구축하는 것입니다. 간단한 프롬프트로 시작하고, 포괄적인 평가로 이를 최적화하며, 더 간단한 솔루션이 부족할 때만 다단계 에이전틱 시스템을 추가하세요.
에이전트를 구현할 때 우리는 세 가지 핵심 원칙을 따르려고 노력합니다.
- 단순하게 시작하고, 필요할 때만 복잡성을 추가하라.
- 측정하고, 반복하라.
- 코드와 도구를 명확하고 신중하게 설계하라.
프레임워크는 빠르게 시작하는 데 도움이 될 수 있지만, 프로덕션으로 전환할 때는 추상화 계층을 줄이고 기본 구성 요소로 구축하는 것을 주저하지 마세요. 이러한 원칙을 따르면 강력할 뿐만 아니라 신뢰할 수 있고 유지보수 가능하며 사용자가 신뢰하는 에이전트를 만들 수 있습니다.
Erik S.와 Barry Zhang이 작성했습니다. 이 작업은 앤트로픽에서 에이전트를 구축한 경험과 고객들이 공유해주신 소중한 통찰력을 바탕으로 합니다. 깊이 감사드립니다.
부록 1: 실제 에이전트
고객들과의 작업에서 위에서 논의된 패턴의 실질적인 가치를 보여주는 AI 에이전트의 두 가지 특히 유망한 응용 분야가 드러났습니다. 두 애플리케이션 모두 에이전트가 대화와 행동이 모두 필요하고, 명확한 성공 기준이 있으며, 피드백 루프를 가능하게 하고, 의미 있는 인간 감독이 통합된 작업에 가장 큰 가치를 더하는 방법을 보여줍니다.
고객 지원 (Customer Support)
고객 지원은 익숙한 챗봇 인터페이스와 도구 통합을 통한 향상된 기능을 결합합니다. 이는 다음과 같은 이유로 더 개방형 에이전트에 자연스럽게 적합합니다.
- 다양한 고객 문제: 고객 문제는 광범위하며, 예측하기 어렵고, 구조화되지 않은 형태인 경우가 많습니다.
- 복잡한 작업: 문제가 해결되기까지 여러 단계의 대화와 작업(예: 계정 조회, 주문 변경)이 필요할 수 있습니다.
- 명확한 성공 기준: 고객 만족도 또는 문제 해결과 같은 명확한 성공 지표가 있습니다.
여러 회사들이 성공적인 해결에 대해서만 요금을 부과하는 사용량 기반 가격 모델을 통해 이 접근 방식의 타당성을 입증하며, 에이전트의 효과에 대한 자신감을 보여주고 있습니다.
소프트웨어 개발 (Software Development)
소프트웨어 개발 분야는 코드 완성에서 자율적인 문제 해결에 이르기까지 LLM 기능의 놀라운 잠재력을 보여주었습니다. 에이전트는 다음과 같은 이유로 특히 효과적입니다.
- 예측할 수 없는 문제: 소프트웨어 버그는 예측할 수 없으며 해결을 위해 여러 번의 수정 및 테스트 반복이 필요할 수 있습니다.
- 복잡한 도구 사용: 코드 베이스 탐색, 변경 적용, 테스트 실행과 같은 복잡한 도구 사용이 필요합니다.
- 의사결정 및 계획: 에이전트가 독립적으로 변경 계획을 수립하고, 테스트를 수행하며, 필요에 따라 작업을 재계획할 수 있도록 합니다.
자체 구현에서 에이전트는 이제 풀 리퀘스트 설명만으로 SWE-bench Verified 벤치마크의 실제 GitHub 문제를 해결할 수 있습니다. 그러나 자동화된 테스트가 기능 검증에 도움이 되지만, 솔루션이 더 광범위한 시스템 요구 사항과 일치하는지 확인하기 위해서는 인간 검토가 여전히 중요합니다.
부록 2: 도구 프롬프트 엔지니어링
어떤 에이전틱 시스템을 구축하든, 도구는 에이전트의 중요한 부분이 될 가능성이 높습니다. 도구는 클로드가 API에서 정확한 구조와 정의를 지정함으로써 외부 서비스 및 API와 상호작용할 수 있도록 합니다. 클로드가 응답할 때, 도구를 호출할 계획이라면 API 응답에 도구 사용 블록을 포함할 것입니다. 도구 정의 및 사양은 전체 프롬프트만큼이나 프롬프트 엔지니어링에 주의를 기울여야 합니다. 이 간략한 부록에서는 도구를 프롬프트 엔지니어링하는 방법을 설명합니다.
도구 형식 (Tool Format)
종종 동일한 동작을 지정하는 여러 방법이 있습니다. 예를 들어, diff를 작성하거나 전체 파일을 다시 작성하여 파일 편집을 지정할 수 있습니다. 구조화된 출력의 경우, 마크다운 내부 또는 JSON 내부에 코드를 반환할 수 있습니다. 소프트웨어 공학에서는 이러한 차이가 겉모습에 불과하며 손실 없이 서로 변환될 수 있습니다. 그러나 일부 형식은 다른 형식보다 LLM이 작성하기 훨씬 더 어렵습니다. diff를 작성하려면 새 코드가 작성되기 전 청크 헤더에서 변경되는 줄 수를 알아야 합니다. JSON 내부에 코드(마크다운과 비교하여)를 작성하려면 새 줄 및 따옴표에 대한 추가 이스케이프가 필요합니다.
도구 형식을 결정하기 위한 제안은 다음과 같습니다.
- 간단한 형식으로 시작하세요. 마크다운은 JSON보다 더 읽기 쉽고 쓰기 쉽습니다.
- 변환 가능한 경우, LLM에게 더 쉬운 형식을 사용하세요. diff를 작성하는 것보다 전체 파일을 다시 작성하는 것이 LLM에게 더 쉽습니다.
- LLM에게 추가적인 제약을 부과하지 마세요. 예를 들어, "코드 블록은 10줄을 넘지 않아야 합니다"와 같은 제약은 LLM에게 불필요한 인지 부하를 추가합니다.
에이전트-컴퓨터 인터페이스(ACI) (Agent-Computer Interfaces (ACI))
한 가지 경험 법칙은 인간-컴퓨터 인터페이스(HCI)에 얼마나 많은 노력이 들어가는지 생각하고, 좋은 에이전트-컴퓨터 인터페이스(ACI)를 만드는 데도 똑같이 많은 노력을 투자할 계획을 세우는 것입니다. 다음은 그렇게 하는 방법에 대한 몇 가지 생각입니다.
- 도구에 좋은 이름과 설명을 부여하세요. 이는 LLM이 도구의 목적을 이해하는 데 도움이 됩니다. 예를 들어, '편집' 대신 '파일 편집'을 사용하세요.
- 관련성을 위해 도구를 묶으세요. 예를 들어, 파일 콘텐츠를 나열하고 편집하고 저장하는 도구를 '파일 관리' 도구 세트로 묶을 수 있습니다.
- LLM이 도구에서 받은 피드백을 해석할 수 있도록 하세요. 예를 들어, '오류'만 반환하는 대신 '오류: 파일이 존재하지 않습니다'와 같이 더 설명적인 오류 메시지를 반환하세요.
- LLM에 대한 명확한 사용 예시를 제공하세요. 이는 LLM이 도구를 올바르게 호출하는 방법을 학습하는 데 도움이 됩니다. 예시는 구체적이고 현실적이어야 합니다.
SWE-bench 에이전트를 구축하는 동안, 우리는 전체 프롬프트보다 도구를 최적화하는 데 더 많은 시간을 보냈습니다. 예를 들어, 에이전트가 루트 디렉터리를 벗어난 후 상대 파일 경로를 사용하는 도구에서 모델이 실수를 한다는 것을 발견했습니다. 이를 해결하기 위해 도구가 항상 절대 파일 경로를 요구하도록 변경했고, 모델이 이 방법을 완벽하게 사용한다는 것을 알게 되었습니다.
개발자 뉴스레터를 받아보세요
제품 업데이트, 사용법 안내, 커뮤니티 소식 등을 매월 받은 편지함으로 보내드립니다.