지난 1년 동안 Anthropic은 여러 산업에 걸쳐 LLM(large language model) 에이전트를 만드는 수십 개 팀과 함께 일했다. 그 과정에서 가장 잘 굴러간 구현체들은 복잡한 프레임워크나 특수한 라이브러리를 거의 쓰지 않았다. 단순하고 조합 가능한 패턴 위에서 만들어진 것들이었다.
이 글에서는 고객사와의 협업, 그리고 우리 스스로 에이전트를 만들어 본 경험에서 배운 내용을 정리하고, 효과적인 에이전트를 만들려는 개발자에게 실용적인 조언을 건넨다.
에이전트란 무엇인가
"에이전트(Agent)"는 여러 방식으로 정의된다. 어떤 고객은 다양한 도구를 사용해 복잡한 과제를 장기간 자율적으로 수행하는 시스템을 가리켜 에이전트라 부른다. 또 어떤 이는 미리 정해진 워크플로를 따라 움직이는, 보다 처방적인 구현을 같은 단어로 부른다. Anthropic에서는 이 모든 변형을 에이전트형 시스템(agentic systems) 으로 묶어 부르되, 워크플로(workflow) 와 에이전트(agent) 사이에는 중요한 구조적 차이가 있다고 본다.
- 워크플로는 LLM과 도구가 미리 정의된 코드 경로를 통해 조율되는 시스템이다.
- 에이전트는 LLM이 자기 프로세스와 도구 사용 방식을 스스로 정하면서, 과제를 어떻게 풀어 나갈지에 대한 통제권을 직접 쥐는 시스템이다.
아래에서 두 가지 형태를 모두 자세히 살펴본다. 부록 1("실전 속의 에이전트")에서는 고객들이 특히 큰 가치를 본 두 가지 도메인을 소개한다.
언제 에이전트를 써야 하고, 언제 쓰지 말아야 하는가
LLM으로 애플리케이션을 만들 때는 가능한 한 가장 단순한 해법부터 시작하고, 필요할 때만 복잡도를 높이는 편을 권한다. 경우에 따라 에이전트형 시스템을 아예 쓰지 않는 결정도 나올 수 있다. 에이전트형 시스템은 보통 더 나은 과제 성능을 얻는 대가로 지연 시간과 비용을 더 치른다. 이 거래가 합리적인 상황인지 따져 봐야 한다.
복잡도를 늘릴 만하다 싶을 때, 잘 정의된 과제에서는 워크플로가 예측 가능성과 일관성을 제공한다. 반면 유연성과 모델 주도의 의사 결정이 대규모로 필요한 상황이라면 에이전트가 더 나은 선택이다. 다만 많은 응용에서는 검색(retrieval)과 인컨텍스트 예제로 단일 LLM 호출을 잘 다듬는 것만으로도 충분하다.
프레임워크는 언제, 어떻게 써야 하는가
에이전트형 시스템 구현을 돕는 프레임워크는 여럿이다. 예를 들면 다음과 같다.
- Claude Agent SDK
- Strands Agents SDK by AWS
- Rivet, 드래그 앤드 드롭 GUI 기반 LLM 워크플로 빌더
- Vellum, 복잡한 워크플로를 만들고 테스트하는 또 다른 GUI 도구
이런 프레임워크는 LLM 호출, 도구 정의와 파싱, 호출 체이닝 같은 표준적인 저수준 작업을 단순화해 시작을 쉽게 만들어 준다. 다만 추가적인 추상화 계층이 끼면서 실제 프롬프트와 응답이 가려지는 경우가 많아, 디버깅을 어렵게 한다. 더 단순한 구성으로 충분한 상황에 굳이 복잡도를 더하고 싶어지게 만들기도 한다.
우리가 권하는 출발점은 LLM API를 직접 호출하는 것이다. 많은 패턴이 단 몇 줄의 코드로 구현된다. 프레임워크를 쓰기로 했다면, 그 안에서 무슨 일이 벌어지는지 반드시 이해해 두어야 한다. 내부 동작에 대한 잘못된 가정은 고객사에서 자주 보이는 실수의 원인이다.
샘플 구현은 우리 cookbook을 참고하면 된다.
빌딩 블록, 워크플로, 그리고 에이전트
이 절에서는 운영 환경에서 자주 본 에이전트형 시스템 패턴을 살펴본다. 토대가 되는 빌딩 블록인 augmented LLM에서 출발해, 단순한 조합 워크플로에서부터 자율 에이전트까지 점진적으로 복잡도를 올려 간다.
빌딩 블록: augmented LLM
에이전트형 시스템의 기본 빌딩 블록은 검색, 도구, 메모리 같은 보강 기능을 갖춘 LLM이다. 현재 모델들은 이런 능력을 능동적으로 활용한다. 직접 검색 질의를 만들어 내고, 적절한 도구를 골라 쓰며, 어떤 정보를 기억해 둘지 판단한다.

그림 1: augmented LLM
구현에서는 두 가지에 집중하길 권한다. 먼저 이 기능들을 구체적인 사용 사례에 맞게 다듬을 것, 그리고 LLM이 다루기 쉬운 잘 문서화된 인터페이스를 보장할 것이다. 보강 기능을 구현하는 길은 여러 갈래지만, 한 가지 접근은 최근 공개된 Model Context Protocol을 통하는 것이다. 이를 쓰면 간단한 클라이언트 구현만으로 점차 늘어나는 서드파티 도구 생태계와 통합할 수 있다.
이 글의 나머지 부분에서는 모든 LLM 호출이 이러한 보강 능력에 접근할 수 있다고 가정한다.
워크플로: 프롬프트 체이닝(Prompt chaining)
프롬프트 체이닝은 한 과제를 단계의 시퀀스로 쪼개는 방식이다. 각 LLM 호출은 이전 호출의 출력을 처리한다. 중간 단계에 프로그래밍적인 점검(아래 그림의 "gate")을 끼워 넣어 진행이 궤도를 벗어나지 않도록 통제할 수 있다.

그림 2: 프롬프트 체이닝 워크플로
언제 쓰면 좋은가: 과제를 깔끔하게 고정된 하위 작업들로 분해할 수 있을 때 적합하다. 핵심 목표는 각 LLM 호출을 더 쉬운 과제로 만들어 정확도를 끌어올리고, 그 대가로 지연 시간을 받아들이는 데 있다.
프롬프트 체이닝이 유용한 예:
- 마케팅 카피를 만들고 그것을 다른 언어로 번역하기.
- 문서 개요를 쓰고, 개요가 일정한 기준을 만족하는지 검사한 뒤, 그 개요에 따라 문서를 작성하기.
워크플로: 라우팅(Routing)
라우팅은 입력을 분류해 특화된 후속 작업으로 보내는 방식이다. 관심사를 분리하고 각 경로마다 더 특화된 프롬프트를 만들 수 있다. 라우팅 없이 한 가지 입력에 맞춰 최적화하면 다른 입력의 성능이 깎이기 쉽다.

그림 3: 라우팅 워크플로
언제 쓰면 좋은가: 서로 구분되는 카테고리가 있어 따로따로 처리하는 편이 더 나은 복잡한 과제, 그리고 분류 자체가 LLM이든 전통적인 분류 모델/알고리즘이든 정확하게 수행될 수 있는 과제에서 잘 동작한다.
라우팅이 유용한 예:
- 고객 상담 질의를 유형별(일반 문의, 환불 요청, 기술 지원)로 갈라 서로 다른 후속 프로세스, 프롬프트, 도구로 보내기.
- 쉬운/흔한 질문은 Claude Haiku 4.5 같은 작고 비용 효율적인 모델로, 어렵거나 드문 질문은 Claude Sonnet 4.5 같은 더 강력한 모델로 라우팅해 성능을 최적화하기.
워크플로: 병렬화(Parallelization)
LLM은 한 과제를 동시에 여러 갈래로 처리할 수 있고, 그 결과를 프로그래밍적으로 합칠 수 있다. 이 워크플로, 곧 병렬화는 두 가지 형태로 자주 나타난다.
- 섹셔닝(Sectioning): 과제를 독립적인 하위 작업으로 나누어 동시에 실행한다.
- 보팅(Voting): 같은 작업을 여러 번 돌려 다양한 결과를 모은다.

그림 4: 병렬화 워크플로
언제 쓰면 좋은가: 나뉜 하위 작업이 속도를 위해 병렬화될 수 있을 때, 또는 더 높은 신뢰도를 얻기 위해 여러 관점이나 시도가 필요할 때 효과적이다. 고려할 점이 많은 복잡한 과제에서는 각 고려 사항을 별도의 LLM 호출로 다루는 편이 보통 더 잘 작동한다. 각 측면에 집중력을 온전히 쏟을 수 있기 때문이다.
병렬화가 유용한 예:
- 섹셔닝:
- 한 모델 인스턴스가 사용자 질의를 처리하는 동안, 다른 인스턴스가 부적절한 콘텐츠나 요청을 걸러 내도록 하는 가드레일 구성. 같은 LLM 호출 하나에 가드레일과 본 응답을 동시에 맡기는 방식보다 결과가 좋아지는 경향이 있다.
- LLM 성능 평가 자동화. 각 LLM 호출이 주어진 프롬프트에 대한 모델의 다른 측면을 평가한다.
- 보팅:
- 코드의 보안 취약점 검토. 서로 다른 프롬프트들이 코드를 검토하고, 문제를 찾으면 표시한다.
- 어떤 콘텐츠가 부적절한지 판단할 때, 여러 프롬프트가 다른 측면을 평가하거나 서로 다른 투표 임계치를 요구해 거짓 양성과 거짓 음성 사이의 균형을 잡기.
워크플로: 오케스트레이터-워커(Orchestrator-workers)
오케스트레이터-워커 워크플로에서는 중앙의 LLM이 과제를 동적으로 분해해 워커 LLM들에 위임하고, 그 결과를 종합한다.

그림 5: 오케스트레이터-워커 워크플로
언제 쓰면 좋은가: 필요한 하위 작업을 미리 예측할 수 없는 복잡한 과제에 잘 맞는다. 예를 들어 코딩에서는 손대야 할 파일 수와 각 파일의 변경 성격이 과제에 따라 달라진다. 위상은 병렬화와 비슷해 보이지만, 핵심 차이는 유연성에 있다. 하위 작업이 미리 정해져 있지 않고 입력에 따라 오케스트레이터가 결정한다.
오케스트레이터-워커가 유용한 예:
- 매번 여러 파일에 걸친 복잡한 변경을 만드는 코딩 제품.
- 잠재적으로 관련 있을 정보를 여러 출처에서 모아 분석해야 하는 검색 과제.
워크플로: 평가자-최적화기(Evaluator-optimizer)
평가자-최적화기 워크플로에서는 한 LLM 호출이 응답을 만들고, 다른 호출이 그것을 평가하고 피드백을 주는 과정을 루프로 돌린다.

그림 6: 평가자-최적화기 워크플로
언제 쓰면 좋은가: 평가 기준이 명확하고, 반복적인 다듬기가 측정 가능한 가치를 더해 줄 때 특히 효과적이다. 잘 들어맞는다는 두 가지 신호가 있다. 첫째, 사람이 피드백을 말로 표현해 주면 LLM 응답이 분명히 좋아지는가. 둘째, LLM 자신이 그런 피드백을 만들 수 있는가. 이는 사람 작가가 다듬어진 글을 만드는 반복적 글쓰기 과정과 닮아 있다.
평가자-최적화기가 유용한 예:
- 번역자 LLM이 처음에 잡지 못하는 미묘한 결을 평가자 LLM이 비평으로 잡아내 줄 수 있는 문학 번역.
- 충분한 정보를 모으기 위해 여러 차례 검색과 분석을 거쳐야 하는 복잡한 검색 과제. 추가 검색이 더 필요한지 평가자가 판단한다.
에이전트(Agents)
LLM이 핵심 능력에서 성숙해 가면서 에이전트가 운영 환경에 등장하기 시작했다. 복잡한 입력을 이해하고, 추론과 계획에 참여하며, 도구를 안정적으로 사용하고, 오류로부터 회복하는 능력이다. 에이전트는 사람의 명령이나 대화로 일을 시작한다. 과제가 분명해지면 에이전트는 독립적으로 계획하고 수행하면서, 추가 정보나 판단이 필요할 때만 사람에게 돌아온다. 실행 중에는 매 단계마다 환경으로부터 "ground truth"(예: 도구 호출 결과나 코드 실행)를 얻어 진척을 가늠하는 일이 결정적이다. 그런 다음 체크포인트나 막힘 지점에서 사람의 피드백을 위해 잠시 멈출 수 있다. 과제는 보통 완료와 함께 끝나지만, 통제력을 유지하기 위해 종료 조건(예: 최대 반복 횟수)을 함께 두는 것도 흔한 일이다.
에이전트는 정교한 과제를 다룰 수 있지만, 구현 자체는 단순한 경우가 많다. 보통은 환경의 피드백에 따라 도구를 쓰는 LLM이 루프를 도는 형태일 뿐이다. 그래서 도구 묶음과 그 문서화를 명확하고 사려 깊게 설계하는 일이 결정적이다. 도구 개발 모범 사례는 부록 2("도구를 위한 프롬프트 엔지니어링")에서 자세히 다룬다.

그림 7: 자율 에이전트
언제 에이전트를 써야 하는가: 필요한 단계 수를 예측하기 어렵거나 불가능하고, 고정된 경로를 미리 박아 둘 수 없는 열린 문제에 에이전트를 쓸 수 있다. LLM이 여러 턴에 걸쳐 작동할 수 있으므로, 그 의사 결정에 어느 정도 신뢰를 둘 수 있어야 한다. 에이전트의 자율성 덕분에 신뢰할 수 있는 환경에서 과제를 확장하는 데 잘 맞는다.
자율적이라는 성격은 비용이 더 들고 오류가 누적될 수 있다는 뜻이기도 하다. 우리는 샌드박스 환경에서의 충분한 테스트와 적절한 가드레일을 함께 권한다.
에이전트가 유용한 예 (모두 우리가 직접 만들어 본 사례):
- SWE-bench 과제를 푸는 코딩 에이전트. 과제 설명에 따라 여러 파일을 편집한다.
- Claude가 컴퓨터를 직접 써서 과제를 수행하는 우리의 "computer use" 레퍼런스 구현.

그림 8: 코딩 에이전트의 상위 흐름
패턴을 조합하고 변형하기
이 빌딩 블록들은 처방이 아니다. 개발자가 사용 사례에 맞춰 빚고 조합할 수 있는 흔한 패턴이다. 다른 LLM 기능과 마찬가지로 성공의 열쇠는 성능을 측정하면서 구현을 거듭 다듬는 데 있다. 다시 강조하자면, 복잡도는 결과가 분명히 나아질 때 만 더해야 한다.
정리
LLM 영역의 성공은 가장 정교한 시스템을 만드는 일이 아니다. 필요에 맞는 시스템을 만드는 일이다. 단순한 프롬프트로 시작하고, 충실한 평가로 다듬은 뒤, 더 단순한 해법으로는 부족할 때만 다단계 에이전트형 시스템을 더해 가라.
에이전트를 구현할 때 우리는 세 가지 핵심 원칙을 따르려 한다.
- 에이전트의 설계에서 단순성(simplicity) 을 지킬 것.
- 에이전트의 계획 단계를 명시적으로 드러내 투명성(transparency) 을 우선할 것.
- 도구 문서화와 테스트를 통해 에이전트-컴퓨터 인터페이스(agent-computer interface, ACI)를 정성껏 다듬을 것.
프레임워크는 빠르게 출발하는 데 도움이 되지만, 운영으로 옮겨 갈 때는 추상화 계층을 줄이고 기본 구성 요소로 다시 짜는 일을 망설이지 말자. 이 원칙들을 지키면 강력하면서도 신뢰할 수 있고, 유지 보수하기 좋으며, 사용자에게 신뢰받는 에이전트를 만들 수 있다.
감사의 글
작성: Erik S., Barry Zhang. 이 글은 Anthropic에서 에이전트를 만들어 온 우리 자신의 경험과 고객들이 나눠 준 귀한 통찰에 빚지고 있다. 깊이 감사드린다.
부록 1: 실전 속의 에이전트
고객사와의 작업에서 AI 에이전트가 특히 유망함을 보여 준 두 가지 응용을 발견했다. 위에서 다룬 패턴들의 실용적 가치를 잘 드러내는 사례다. 두 응용 모두 대화와 행동을 모두 요구하고, 성공 기준이 명확하며, 피드백 루프가 가능하고, 의미 있는 사람의 감독을 결합할 수 있는 과제에서 에이전트가 가장 큰 가치를 더한다는 점을 보여 준다.
A. 고객 지원
고객 지원은 친숙한 챗봇 인터페이스에 도구 통합을 통한 확장된 능력을 결합한다. 다음과 같은 이유로 더 열린 형태의 에이전트에 자연스럽게 어울린다.
- 지원 상호작용은 자연스럽게 대화 흐름을 따르면서도 외부 정보와 행동에 접근해야 한다.
- 도구를 붙여 고객 데이터, 주문 이력, 지식 베이스 문서를 끌어올 수 있다.
- 환불 처리나 티켓 갱신 같은 행동은 프로그래밍적으로 다룰 수 있다.
- 사용자가 정의한 해결 여부로 성공을 분명히 측정할 수 있다.
여러 회사가 성공적으로 해결된 건에 한해서만 비용을 청구하는 사용량 기반 가격 모델로 이 접근의 실현 가능성을 보여 줬다. 자기 에이전트의 효과에 그만큼 자신이 있다는 뜻이다.
B. 코딩 에이전트
소프트웨어 개발 영역은 LLM 기능에서 두드러진 잠재력을 보여 줬다. 능력이 코드 자동 완성에서 자율적 문제 해결로 옮겨 가고 있다. 이 영역에서 에이전트가 특히 효과적인 이유는 다음과 같다.
- 코드 솔루션은 자동화된 테스트로 검증할 수 있다.
- 에이전트는 테스트 결과를 피드백 삼아 솔루션을 다듬을 수 있다.
- 문제 공간이 잘 정의되고 구조화되어 있다.
- 산출물의 품질을 객관적으로 측정할 수 있다.
우리 자신의 구현에서는 이제 풀 리퀘스트 설명만으로 SWE-bench Verified 벤치마크의 실제 GitHub 이슈를 풀어낸다. 다만 자동 테스트가 기능을 검증해 주더라도, 솔루션이 더 넓은 시스템 요구사항과 맞물리는지 확인하는 데는 사람의 검토가 여전히 결정적이다.
부록 2: 도구를 위한 프롬프트 엔지니어링
어떤 에이전트형 시스템을 만들든 도구는 핵심 부품이 될 가능성이 크다. 도구(tools)는 우리 API에서 정확한 구조와 정의를 명시함으로써 Claude가 외부 서비스 및 API와 상호작용하도록 한다. Claude가 응답할 때 도구를 호출할 계획이라면, API 응답에 tool use 블록이 포함된다. 도구 정의와 명세에는 전체 프롬프트만큼이나 프롬프트 엔지니어링의 공을 들여야 한다. 이 짧은 부록에서는 도구를 어떻게 프롬프트 엔지니어링할지 정리한다.
같은 동작을 표현하는 길은 여러 가지일 때가 많다. 예를 들어 파일 편집은 diff로 적을 수도 있고, 파일 전체를 다시 쓸 수도 있다. 구조화된 출력은 마크다운 안의 코드로 돌려줄 수도 있고, JSON 안에 담을 수도 있다. 소프트웨어 공학에서 이런 차이는 표면적이라 한 형태에서 다른 형태로 손실 없이 변환된다. 그러나 어떤 형식은 LLM이 작성하기에 훨씬 더 어렵다. diff를 쓰려면 새 코드가 적히기 전에 청크 헤더에 몇 줄이 바뀌는지를 미리 알아야 한다. JSON 안에 코드를 쓰려면 마크다운에 비해 줄바꿈과 따옴표 이스케이프를 추가로 처리해야 한다.
도구 형식 결정에 대한 우리의 권고는 다음과 같다.
- 모델이 스스로를 막다른 곳에 몰아넣기 전에 "생각할" 토큰을 충분히 줄 것.
- 모델이 인터넷의 글에서 자연스럽게 마주쳐 온 형태와 가까운 형식을 유지할 것.
- 수천 줄짜리 코드 줄 수를 정확히 세거나, 작성하는 모든 코드를 문자열 이스케이프해야 하는 식의 형식상 "오버헤드"를 두지 말 것.
한 가지 어림짐작 규칙은 사람-컴퓨터 인터페이스(human-computer interfaces, HCI)에 들이는 노력만큼 에이전트-컴퓨터 인터페이스(ACI)를 다듬는 데도 노력을 들이는 것이다. 그렇게 하기 위한 몇 가지 생각이다.
- 모델의 입장에 서 보라. 설명과 매개변수만 보고도 이 도구를 어떻게 쓰는지 분명한가, 아니면 한참을 따져 봐야 하는가? 후자라면 모델에게도 마찬가지일 가능성이 크다. 좋은 도구 정의에는 보통 사용 예시, 엣지 케이스, 입력 형식 요구사항, 다른 도구와의 명확한 경계가 담긴다.
- 매개변수 이름이나 설명을 어떻게 바꾸면 더 분명해질까? 팀의 주니어 개발자에게 좋은 docstring을 쓰는 일이라고 생각해 보라. 비슷한 도구가 여럿일 때 특히 중요하다.
- 모델이 도구를 어떻게 쓰는지 시험해 보라. 우리 workbench에서 다양한 입력을 돌려 보면서 모델이 어떤 실수를 하는지 관찰하고 반복해 다듬어라.
- 도구를 poka-yoke하라. 인자를 바꿔서 실수가 더 어려워지도록 하라.
SWE-bench용 에이전트를 만들 때, 우리는 전체 프롬프트보다 도구를 다듬는 데 더 많은 시간을 들였다. 한 예로, 에이전트가 루트 디렉터리 밖으로 이동한 뒤에는 상대 파일 경로를 쓰는 도구에서 모델이 실수를 하는 모습이 보였다. 이를 고치려고 도구가 항상 절대 경로를 요구하도록 바꿨더니, 모델이 이 방식을 흠결 없이 따랐다.