Burt.K

Awesome Discovery

효과적인 에이전트 구축하기

작성일 — 2025년 1월 31일

Table of Contents

알림: Building effective agents를 번역한 글입니다.

지난 1년간 우리는 여러 산업 분야에서 대규모 언어 모델(LLM) 에이전트를 구축하는 수많은 팀과 협력했다. 놀랍게도 가장 성공적인 구현 사례들은 복잡한 프레임워크나 특수 라이브러리를 사용하지 않았다. 대신 간단하고 조합(합성) 가능한 패턴을 활용해 구축했다.

이 글에서는 고객사들과 협력하고 직접 에이전트를 구축하면서 얻은 교훈을 공유하고, 개발자들이 효과적인 에이전트를 구축하는 데 필요한 실용적인 조언을 제공한다.

에이전트란 무엇인가?

“에이전트(Agent)“는 여러 관점에서 정의할 수 있다. 일부 고객은 에이전트를 복잡한 작업을 수행하기 위해 다양한 도구를 활용하여 장시간 독립적으로 운영되는 완전 자율 시스템으로 정의한다. 반면 다른 고객들은 미리 정의된 워크플로우를 따르는 좀 더 제한적인 구현을 에이전트로 간주한다. Anthropic에서는 이러한 모든 변형을 에이전트 시스템(agentic systems) 으로 분류하지만, 워크플로우(workflows)에이전트(agents) 사이에 중요한 구조적 차이를 둔다:

아래에서 이러한 두 가지 유형의 에이전트 시스템을 자세히 살펴볼 것이다. 부록 1(“실전에서의 에이전트”)에서는 고객들이 이러한 시스템을 특히 유용하게 활용한 두 가지 영역을 설명한다.

에이전트의 활용 시점과 제한사항

LLM 애플리케이션을 구축할 때는 가능한 한 단순한 해결책을 먼저 찾고, 필요한 경우에만 복잡도를 높이는 것이 바람직하다. 때로는 에이전트 시스템을 전혀 사용하지 않는 것이 더 나을 수 있다. 에이전트 시스템은 대개 더 나은 작업 성능을 위해 지연 시간과 비용을 희생하므로, 이러한 trade-off가 언제 의미있는지 신중히 고려해야 한다.

복잡한 구현이 필요한 경우, 워크플로우는 잘 정의된 작업에 대해 예측 가능성과 일관성을 제공한다. 반면 에이전트는 유연성과 모델 기반의 의사결정이 대규모로 필요할 때 더 나은 선택이 된다. 하지만 대부분의 애플리케이션에서는 검색(retrieval)과 문맥 내 예제(in-context examples)를 활용한 단일 LLM 호출만으로도 충분하다.

프레임워크의 활용 시점과 방법

에이전트 시스템을 쉽게 구현할 수 있도록 도와주는 다양한 프레임워크가 있다:

이러한 프레임워크는 LLM 호출, 도구 정의와 파싱, 호출 체인 구성과 같은 표준적인 저수준 작업을 단순화하여 시작하기 쉽게 만든다. 하지만 이들은 종종 기본 프롬프트와 응답을 가리는 추가적인 추상화 계층을 만들어 디버깅을 어렵게 만든다. 또한 더 단순한 구성으로도 충분한 상황에서 불필요한 복잡성을 추가하도록 유도할 수 있다.

개발자는 먼저 LLM API를 직접 사용하는 것부터 시작하는 것이 좋다. 많은 패턴은 몇 줄의 코드로도 구현할 수 있다. 프레임워크를 사용하더라도 기반이 되는 코드를 반드시 이해해야 한다. 실제 동작 방식에 대한 잘못된 가정은 고객 오류의 주요 원인이 된다.

구현 예제는 우리의 쿡북을 참고하면 된다.

구성 요소, 워크플로우, 에이전트

이 섹션에서는 실제 프로덕션 환경에서 발견한 에이전트 시스템의 일반적인 패턴을 살펴본다. 기본 구성 요소인 증강 LLM(augmented LLM)에서 시작하여 단순한 조합형 워크플로우부터 자율형 에이전트까지 점진적으로 복잡도를 높여가며 설명한다.

핵심 구성 요소: 증강 LLM

에이전트 시스템의 기본 구성 요소는 검색, 도구, 메모리와 같은 증강 기능을 갖춘 향상된 LLM이다. 현재 모델은 이러한 기능을 능동적으로 활용할 수 있다. 스스로 검색 쿼리를 생성하고, 적절한 도구를 선택하며, 어떤 정보를 보관할지 결정한다.

증강 LLM

구현 시에는 다음 두 가지 핵심 사항에 집중할 것을 권장한다. 첫째, 특정 사용 사례에 맞게 이러한 기능을 조정하는 것이고, 둘째, LLM이 쉽게 사용할 수 있는 잘 문서화된 인터페이스를 제공하는 것이다. 이러한 증강 기능을 구현하는 방법은 다양하지만, 최근 공개된 모델 컨텍스트 프로토콜(Model Context Protocol)을 활용하는 것도 하나의 방법이다. 이 프로토콜은 간단한 클라이언트 구현을 통해 점점 늘어나는 서드파티 도구 생태계와 통합할 수 있게 해준다.

이 글의 나머지 부분에서는 각 LLM 호출이 이러한 증강된 기능에 접근할 수 있다고 가정하고 설명을 진행한다.

프롬프트 체이닝 워크플로우 이해

프롬프트 체이닝은 하나의 큰 작업을 여러 단계로 나누어 처리하는 방식이다. 각 단계에서 LLM(Large Language Model)은 이전 단계의 출력을 입력으로 받아 처리한다. 아래 다이어그램에서 볼 수 있는 “게이트”와 같은 프로그래밍 검증 단계를 중간에 추가하여 작업이 올바른 방향으로 진행되는지 확인할 수 있다.

프롬프트 체이닝 워크플로우

활용 시기

이 워크플로우는 작업을 명확하고 고정된 하위 작업들로 나눌 수 있을 때 가장 효과적이다. 각 LLM 호출을 더 단순한 작업으로 만들어 처리 시간은 늘어나더라도 정확도를 높이는 것이 주요 목표다.

활용 예시

라우팅 워크플로우 이해

라우팅은 입력을 분류하고 이를 전문화된 후속 작업으로 전달하는 과정이다. 이러한 워크플로우는 관심사를 분리하고 더욱 전문화된 프롬프트를 구축할 수 있게 한다. 라우팅 워크플로우가 없다면, 한 종류의 입력에 대한 최적화가 다른 입력의 성능을 저하시킬 수 있다.

라우팅 워크플로우

활용 시점

라우팅은 다음과 같은 상황에서 효과적이다: - 서로 다른 카테고리를 개별적으로 처리하는 것이 더 효율적인 복잡한 작업 - LLM이나 전통적인 분류 모델/알고리즘으로 정확한 분류가 가능한 경우

활용 사례

병렬 워크플로우 이해

LLM은 때때로 하나의 작업을 동시에 처리하고, 그 결과를 프로그래밍 방식으로 취합할 수 있다. 이러한 병렬 워크플로우는 다음 두 가지 주요 방식으로 구현된다:

병렬 워크플로우

활용 시점

병렬화는 다음과 같은 경우에 효과적이다: - 분할된 하위 작업을 병렬로 처리하여 속도를 높일 수 있는 경우 - 더 높은 신뢰도의 결과를 위해 다양한 관점이나 여러 번의 시도가 필요한 경우 - 복잡한 작업에서 여러 고려사항이 있을 때, 각 측면을 개별 LLM 호출로 처리하면 더 나은 성능을 얻을 수 있다.

활용 사례

섹션 분할의 예
  1. 가드레일 구현

    • 한 모델 인스턴스는 사용자 쿼리를 처리
    • 다른 인스턴스는 부적절한 내용이나 요청을 검사
    • 이는 하나의 LLM이 가드레일과 핵심 응답을 모두 처리하는 것보다 효과적이다
  2. LLM 성능 평가 자동화

    • 각 LLM 호출이 주어진 프롬프트에 대한 모델 성능의 서로 다른 측면을 평가한다
투표 방식의 예
  1. 코드 취약점 검토

    • 여러 다른 프롬프트가 코드를 검토하고 문제 발견 시 플래그를 표시한다
  2. 콘텐츠 적절성 평가

    • 여러 프롬프트가 다양한 측면을 평가
    • 오탐과 미탐의 균형을 맞추기 위해 서로 다른 투표 임계값을 적용한다

오케스트레이터-워커 워크플로우 이해

오케스트레이터-워커(Orchestrator-workers) 워크플로우에서는 중앙 LLM이 작업을 동적으로 분할하고, 워커 LLM에게 작업을 할당한 뒤, 그 결과를 종합한다.

오케스트레이터-워커 워크플로우

활용 시점

이 워크플로우는 사전에 필요한 하위 작업을 예측할 수 없는 복잡한 작업에 적합하다. 예를 들어, 코딩 작업에서 수정이 필요한 파일의 수와 각 파일의 변경 내용은 대개 주어진 작업에 따라 달라진다. 병렬화와 구조적으로는 비슷하지만, 핵심적인 차이점은 유연성에 있다. 하위 작업이 미리 정의되지 않고 오케스트레이터가 특정 입력을 기반으로 결정한다.

활용 사례

  1. 코드 제품 개발

    • 매번 여러 파일에 복잡한 변경이 필요한 경우에 효과적이다
    • 각 파일의 변경 사항을 동적으로 조정할 수 있다
  2. 정보 검색 작업

    • 여러 출처에서 정보를 수집하고 분석하는 경우
    • 관련 있는 정보를 찾기 위해 다양한 소스를 검토해야 하는 상황

평가자-최적화자 워크플로우의 이해

평가자-최적화자(Evaluator-optimizer) 워크플로우에서는 하나의 LLM이 응답을 생성하고, 다른 LLM이 순환 구조로 평가와 피드백을 제공한다.

평가자-최적화자 워크플로우

활용 시점

이 워크플로우는 다음과 같은 상황에서 특히 효과적이다: - 명확한 평가 기준이 있을 때 - 반복적인 개선이 측정 가능한 가치를 제공할 때

적합한 워크플로우인지 판단하는 두 가지 기준은 다음과 같다: 1. 사람이 피드백을 제시했을 때 LLM의 응답이 명백하게 개선되는가 2. LLM이 그러한 피드백을 제공할 수 있는가

이는 작가가 문서를 완성하기까지 거치는 반복적인 글쓰기 과정과 유사하다.

활용 사례

  1. 문학 번역

    • 번역 LLM이 처음에는 포착하지 못할 수 있는 미묘한 뉘앙스가 있는 경우
    • 평가자 LLM이 유용한 비평을 제공할 수 있는 상황
  2. 복잡한 검색 작업

    • 포괄적인 정보를 수집하기 위해 여러 차례의 검색과 분석이 필요한 경우
    • 평가자가 추가 검색의 필요성을 판단하는 역할 수행

에이전트 (Agents)

대규모 언어 모델(LLM)이 복잡한 입력 이해, 추론과 계획 수립, 도구의 안정적 사용, 오류 복구 등 핵심 기능에서 성숙도를 높임에 따라 에이전트가 실제 환경에서 활용되기 시작했다. 에이전트는 사용자와의 직접적인 명령이나 대화를 통해 작업을 시작한다. 작업의 목표가 명확해지면 에이전트는 독립적으로 계획을 수립하고 실행하며, 필요한 경우 사용자에게 추가 정보나 판단을 요청한다. 실행 과정에서 에이전트는 각 단계마다 도구 호출 결과나 코드 실행과 같은 환경으로부터 “실제 데이터”를 확보하여 진행 상황을 평가한다. 에이전트는 체크포인트나 장애물에 도달했을 때 사용자의 피드백을 받기 위해 일시 중지할 수 있다. 작업은 대개 완료되면 종료되지만, 제어권을 유지하기 위해 최대 반복 횟수와 같은 중단 조건을 포함하는 것이 일반적이다.

에이전트는 복잡한 작업을 처리할 수 있지만, 구현 방식은 대체로 단순하다. 일반적으로 환경 피드백을 기반으로 도구를 사용하는 LLM의 반복 구조로 이루어진다. 따라서 도구 세트와 문서를 명확하고 신중하게 설계하는 것이 매우 중요하다. 도구 개발을 위한 모범 사례는 부록 2(“도구를 위한 프롬프트 엔지니어링”)에서 자세히 다룬다.

에이전트

에이전트 사용 시기

에이전트는 필요한 단계 수를 예측하기 어렵거나 불가능하며, 고정된 경로를 하드코딩할 수 없는 개방형 문제에 활용할 수 있다. LLM은 여러 차례의 작업을 수행할 수 있으며, 이 과정에서 의사 결정에 대한 일정 수준의 신뢰가 필요하다. 에이전트의 자율성은 신뢰할 수 있는 환경에서 작업을 확장하는 데 이상적이다.

에이전트의 자율적 특성으로 인해 비용이 증가하고 오류가 누적될 수 있다. 따라서 샌드박스 환경에서 광범위한 테스트를 수행하고 적절한 안전장치를 마련할 것을 권장한다.

에이전트 활용 사례

다음은 실제 구현한 예시들이다:

High-level flow of a coding agent

요약

LLM 분야에서 성공의 핵심은 가장 정교한 시스템을 구축하는 것이 아니라, 필요에 맞는 적절한 시스템을 구축하는 데 있다. 간단한 프롬프트로 시작하여 종합적인 평가를 통해 최적화하고, 더 단순한 해결책으로 부족할 때만 다단계 에이전트 시스템을 추가한다.

에이전트를 구현할 때는 다음 세 가지 핵심 원칙을 따른다:

  1. 에이전트 설계에서 단순성을 유지한다.
  2. 에이전트의 계획 단계를 명확히 보여줌으로써 투명성을 우선시한다.
  3. 철저한 도구 문서화와 테스트를 통해 에이전트-컴퓨터 인터페이스(ACI)를 신중하게 설계한다.

프레임워크는 빠른 시작에 도움이 되지만, 실제 운영 환경으로 전환할 때는 추상화 계층을 줄이고 기본 구성 요소로 구축하는 것을 주저하지 말아야 한다. 이러한 원칙을 따르면 강력하면서도 신뢰할 수 있고 유지 관리가 쉬우며 사용자의 신뢰를 얻을 수 있는 에이전트를 만들 수 있다.

감사의 글

이 문서는 Erik Schluntz와 Barry Zhang이 작성했다. 이 연구는 Anthropic에서 에이전트를 구축한 경험과 고객들이 공유한 소중한 통찰을 바탕으로 한다. 귀중한 피드백을 제공한 모든 분들께 깊은 감사를 표한다.

부록 1: 실전에서의 에이전트 활용

고객사와의 협업을 통해 앞서 논의한 패턴의 실용적 가치를 입증하는 두 가지 특히 유망한 AI 에이전트 응용 사례를 발견했다. 두 사례 모두 에이전트가 대화와 행동이 모두 필요하고, 명확한 성공 기준이 있으며, 피드백 순환이 가능하고, 의미 있는 인간의 감독이 통합된 작업에서 가장 큰 가치를 더한다는 점을 보여준다.

B. 코딩 에이전트

소프트웨어 개발 분야는 LLM 기능에서 놀라운 잠재력을 보여주고 있다. 단순한 코드 자동 완성에서 시작해 자율적인 문제 해결까지 그 능력이 진화했다. 다음과 같은 이유로 에이전트가 특히 효과적이다:

우리가 구현한 에이전트는 이제 풀 리퀘스트 설명만으로도 SWE-bench Verified 벤치마크에서 실제 GitHub 이슈를 해결할 수 있다. 하지만 자동화된 테스트가 기능성을 검증하는 데 도움이 되더라도, 해결책이 전체 시스템 요구사항과 부합하는지 확인하려면 여전히 사람의 검토가 매우 중요하다.

부록 2: 도구를 위한 프롬프트 엔지니어링

어떤 에이전트 시스템을 구축하더라도 도구는 에이전트의 핵심 요소가 된다. 도구는 API에서 정확한 구조와 정의를 지정함으로써 Claude가 외부 서비스 및 API와 상호 작용할 수 있게 한다. Claude가 도구를 호출하려 할 때는 API 응답에 도구 사용 블록을 포함한다. 도구 정의와 명세는 전체 프롬프트만큼 세심한 프롬프트 엔지니어링이 필요하다. 이 부록에서는 도구를 위한 프롬프트 엔지니어링 방법을 설명한다.

동일한 작업을 지정하는 방법은 여러 가지가 있다. 예를 들어 파일 편집은 차이점(diff)을 작성하거나 전체 파일을 다시 작성하는 방식으로 지정할 수 있다. 구조화된 출력의 경우 마크다운이나 JSON 안에 코드를 넣을 수 있다. 소프트웨어 공학에서 이러한 차이는 표면적이며 서로 간에 손실 없이 변환할 수 있다. 그러나 일부 형식은 LLM이 작성하기에 훨씬 더 어려울 수 있다. 차이점을 작성하려면 새 코드를 작성하기 전에 청크 헤더에서 변경되는 줄 수를 알아야 한다. JSON 안에 코드를 작성하면 (마크다운과 비교했을 때) 줄바꿈과 따옴표를 추가로 이스케이프해야 한다.

도구 형식을 결정할 때 다음 사항을 권장한다:

경험칙 중 하나는 인간-컴퓨터 인터페이스(HCI)에 들어가는 노력을 생각해보고, 좋은 에이전트-컴퓨터 인터페이스(ACI)를 만드는 데도 그만큼의 노력을 투자하는 것이다. 이를 위한 방법은 다음과 같다:

SWE-bench용 에이전트를 만들 때, 실제로 전체 프롬프트보다 도구를 최적화하는 데 더 많은 시간을 할애했다. 예를 들어 에이전트가 루트 디렉토리를 벗어난 후 상대 경로를 사용하는 도구에서 모델이 실수를 하는 것을 발견했다. 이를 해결하기 위해 도구가 항상 절대 경로를 요구하도록 변경했고, 모델이 이 방식을 완벽하게 사용하는 것을 확인했다.