AI 에이전트란? 챗봇을 넘어 스스로 도구를 쓰는 AI의 원리와 한계

AI 에이전트란? 챗봇을 넘어 스스로 도구를 쓰는 AI의 원리와 한계

한 번 답하고 멈추지 않는 AI

AI 에이전트(AI agent)는 사람이 던진 목표 하나를 받아, 그 목표에 도달할 때까지 스스로 여러 단계를 계획하고 실행하며 필요한 도구를 골라 쓰는 대규모 언어모델(LLM) 기반 실행 시스템이다. 한 문장으로 줄이면, '한 번 시키면 한 번 답하는 챗봇'을 '한 번 시키면 알아서 끝까지 처리해 오는 일꾼'으로 바꿔 놓은 구조다.

구분을 또렷이 해 두자. 챗봇은 보통 한 번의 요청에 한 번 답하고 멈춘다. 질문을 넣으면 답을 내고, 거기서 멈춘다. 반면 에이전트는 '이 주제로 자료를 조사해 표로 정리해 줘' 같은 목표를 받으면 곧바로 답을 반환하고 종료하지 않는다. 검색을 돌리고, 결과를 읽고, 부족하면 다시 찾고, 정리한 뒤 표로 만드는 여러 단계를 스스로 이어간다.

그러나 겉모습이 화려해도 내부 원리는 이 코스가 내내 다뤄 온 그 기계와 같다. 에이전트도 매 순간 '확률로 그럴듯한 다음'을 예측하는 언어모델일 뿐이다. 달라진 것은 모델의 본질이 아니라, 모델을 감싸고 여러 번 돌리는 바깥의 제어 구조다. 이 점을 놓치면 에이전트를 '스스로 생각하는 지능'으로 오해하기 쉽다.

그래서 에이전트를 제대로 이해하려면 두 축을 같이 봐야 한다. 하나는 도구를 호출하는 능력, 다른 하나는 그 호출을 사람이 매번 지시하지 않아도 스스로 반복하는 자율성이다. 이 두 가지가 결합하면서 안내 데스크에 머물던 AI가 실무 담당자로 옮겨 갔다.

챗봇과 에이전트의 차이 — 도구 사용과 자율성

왜 지금 에이전트가 등장했나

에이전트라는 발상 자체는 인공지능 연구에서 오래된 것이다. 다만 최근 몇 년 사이에 실제로 쓸 만해진 이유가 있다. 언어모델의 추론 능력이 올라가면서, 자연어로 된 목표를 잘게 쪼개고 다음에 무엇을 할지 스스로 계획하는 일이 어느 정도 가능해졌기 때문이다.

언어모델 단독의 한계도 등장의 배경이다. LLM은 학습 시점에 갇힌 지식만 갖고 있고, 계산이나 최신 정보 조회에 약하며, 무엇보다 '자신 있게 틀리는' 환각(hallucination)에서 자유롭지 못하다. 이 약점을 모델 바깥의 도구로 메우자는 흐름이 자연스럽게 이어졌다. 검색 엔진, 계산기, 코드 실행기, 데이터베이스를 모델이 직접 부르게 하면, 모델은 모르는 것을 찾아보고 계산은 계산기에 맡길 수 있다.

여기에 프롬프트 기법의 발전이 결정적으로 맞물렸다. 생각의 과정을 말로 풀어내는 사고 사슬(chain-of-thought)과, 추론과 행동을 번갈아 수행하는 ReAct 계열의 기법이 제안되면서, 모델이 '무엇을 할지 판단하고 → 실제로 실행하고 → 결과를 보고 다시 판단하는' 절차를 언어로 표현할 길이 열렸다.

요약하면 에이전트는 세 흐름의 합류점에서 태어났다. 추론이 강해진 언어모델, 그 약점을 메우는 외부 도구, 그리고 이 둘을 반복 절차로 엮는 프롬프트·제어 기법이다. 어느 하나만으로는 부족했고, 셋이 만나면서 '스스로 여러 단계를 처리하는 실행기'가 현실이 됐다.

생각·행동·관찰이 스스로 도는 자율 루프

에이전트가 수행하는 '여러 단계'의 심장에는 하나의 반복 구조가 있다. 생각하고(Reason), 행동하고(Act), 결과를 관찰하고(Observe), 다시 생각하는 사이클이다. 추론과 행동을 합쳐 흔히 ReAct라 부른다(Yao et al., 2022).

구체적으로 보자. 먼저 '생각' 단계에서 모델은 지금 상황과 목표를 놓고 다음에 무엇을 해야 할지 언어로 궁리한다. '이 정보를 찾으려면 검색을 해야겠다' 같은 판단이 여기 나온다. 이어 '행동' 단계에서 모델은 실제 도구를 호출한다. 검색어를 만들어 검색 도구에 넘기는 식이다. 그러면 '관찰' 단계에서 도구가 돌려준 결과가 모델 앞에 놓인다. 모델은 그 결과를 읽고 다시 '생각'으로 돌아가, 목표에 닿았는지 아니면 한 바퀴 더 돌아야 하는지 판단한다.

챗봇과 갈리는 지점이 바로 여기다. 이 루프 자체는 프롬프트를 다룰 때 이미 본 구조지만, 에이전트는 이 사이클을 사람이 매번 시키지 않아도 스스로 여러 번 돌린다. 목표를 잘게 쪼개고, 언제 어떤 도구를 쓸지 스스로 정하고, 몇 바퀴를 돌지도 스스로 판단한다. 자율성은 새 원리가 아니라 익숙한 루프에 '반복'과 '스스로'를 얹은 것이다.

여기서 흔한 오해 하나를 짚자. 모델이 '생각한다'는 말은 인간처럼 의식적으로 사고한다는 뜻이 아니다. '생각' 단계 역시 확률로 그럴듯한 문장을 이어 붙이는 예측일 뿐이다. 다만 그 예측을 절차 형태로 강제하니, 결과적으로 계획을 세우고 실행하는 것처럼 보이는 행동이 나온다. 이 차이를 분명히 해야 뒤에 나오는 한계를 제대로 이해할 수 있다.

ReAct 루프 — 생각·행동·관찰의 반복

계획·도구·메모리 — 에이전트를 이루는 세 기둥

루프가 돌아가려면 이를 떠받치는 부품이 필요하다. 에이전트의 구조를 뜯어보면 대개 계획, 도구, 메모리라는 세 기둥이 보인다. 언어모델은 이 세 기둥을 지휘하는 두뇌 역할을 한다.

첫째, 계획(planning)이다. 큰 목표를 실행 가능한 작은 단위로 쪼개는 능력이다. '보고서를 써 줘'라는 목표는 그대로는 실행할 수 없다. 자료 조사 → 개요 작성 → 초안 → 검토처럼 순서 있는 작은 일로 나눠야 도구를 붙일 수 있다. 사고 사슬이나 여러 갈래를 탐색하는 생각의 나무(Tree of Thoughts, 2023) 같은 기법이 이 계획 단계를 돕는다.

둘째, 도구(tools)다. 모델이 자기 힘으로 못 하는 일을 위임하는 창구다. 웹 검색, 계산기, 코드 실행, 파일 읽기·쓰기, 외부 API 호출 등이 도구가 된다. 흥미로운 점은 모델에게 도구 사용법을 스스로 배우게 하는 시도도 있다는 것이다. Toolformer(2023)는 언어모델이 언제 어떤 도구를 호출하면 예측이 좋아지는지를 스스로 학습하도록 했다.

셋째, 메모리(memory)다. 여러 단계를 이어가려면 지금까지 한 일과 관찰한 결과를 기억해야 한다. 짧게는 한 작업 안에서 대화 맥락을 유지하는 단기 기억이 있고, 길게는 벡터 임베딩으로 과거 경험을 저장해 두었다가 필요할 때 검색해 오는 장기 기억이 있다. 검색 증강 생성(RAG)에서 쓰는 임베딩·벡터 검색 기술이 여기서 그대로 활용된다.

AI 에이전트의 구조 — 계획·도구·메모리

도구를 언제 어떤 것으로 부를까 — 의사결정의 실제

에이전트의 실력은 '무슨 도구를 쓸 수 있느냐'보다 '언제 어떤 도구를 골라 쓰느냐'에서 갈린다. 도구를 여럿 붙여 놓아도 판단이 서툴면 엉뚱한 도구를 부르거나, 검색으로 해결될 일을 혼자 지어내며 환각을 낸다.

실무에서 도구 선택은 대체로 이렇게 굴러간다. 프롬프트에 각 도구의 이름, 용도, 입력 형식을 설명으로 넣어 둔다. 모델은 현재 상황을 보고 '지금은 검색이 필요하다'고 판단한 뒤, 미리 약속된 형식(예: JSON)으로 도구 이름과 인자를 출력한다. 바깥의 실행기가 그 출력을 파싱해 실제 함수를 부르고, 반환값을 다시 모델에게 관찰로 돌려준다. 요즘 API의 함수 호출(function calling) 기능이 바로 이 흐름을 구조화한 것이다.

간단한 예를 들어 보자. 사용자가 '지금 서울 날씨와 뉴욕 시각의 차이를 알려 줘'라고 물으면, 잘 만든 에이전트는 두 번의 도구 호출을 계획한다. 먼저 날씨 API를 get_weather(city="Seoul")로 부르고, 이어 시간대 계산을 위해 별도 도구나 계산기를 부른 뒤, 두 관찰 결과를 합쳐 최종 답을 만든다. 반대로 '피보나치 수열의 20번째 값'처럼 계산이 필요한 질문에는 머릿속으로 어림하지 않고 코드 실행 도구에 맡기는 편이 정확하다.

여기서 디코딩 파라미터도 슬쩍 얼굴을 내민다. 도구 이름과 인자를 정확한 형식으로 뽑아야 하는 순간에는 무작위성을 낮춰야 한다. 온도(temperature)를 0에 가깝게 두고, top-p나 top-k로 후보를 좁혀 형식이 흔들리지 않게 한다. 반대로 아이디어를 발산하는 계획 단계에서는 온도를 조금 높여 다양한 갈래를 탐색하기도 한다. 같은 모델이라도 단계마다 디코딩 설정을 달리하는 것이 에이전트 안정성의 숨은 요령이다.

에이전트가 도구를 선택하는 의사결정

코드로 감 잡는 최소 루프

개념을 코드의 골격으로 옮겨 보면 감이 확실히 잡힌다. 아래는 실제 라이브러리를 걷어낸, ReAct 루프의 뼈대만 남긴 의사코드다. 핵심은 '모델 호출 → 도구 실행 → 관찰을 다시 모델에 투입'이 반복된다는 점이다.

goal = "2024년 노벨 물리학상 수상자와 소속을 표로 정리"
history = [system_prompt(tools=[search, finish])]

for step in range(MAX_STEPS):          # 오류 누적을 막는 반복 상한
    thought, action = llm(history, temperature=0)   # 생각 + 행동 결정
    if action.name == "finish":
        answer = action.args["text"]
        break
    observation = run_tool(action)     # 실제 도구 실행(검색 등)
    history.append((thought, action, observation))   # 관찰을 기록해 다음 판단에 사용

눈여겨볼 대목이 몇 있다. 우선 for 문의 반복 상한(MAX_STEPS)이다. 이걸 두지 않으면 에이전트가 답을 못 찾고 무한히 루프를 돌거나 비용을 태울 수 있다. 다음으로 도구 결정 시 temperature=0을 준 점이다. 앞서 말한, 형식을 흔들지 않으려는 선택이다. 마지막으로 매 단계의 생각·행동·관찰을 history에 쌓는다. 이 누적된 맥락이 곧 단기 메모리이고, 모델은 이를 보고 다음 수를 정한다.

여기에 반성(reflection)을 더하면 한층 똑똑해진다. Reflexion(2023)은 시도가 실패했을 때 그 원인을 언어로 스스로 되짚어 다음 시도에 반영하게 했다. 코드로 보면 루프 끝에 '방금 결과가 목표에 맞았는가, 아니면 무엇을 고쳐야 하는가'를 모델에게 한 번 더 묻고, 그 자기 평가를 메모리에 넣는 단계가 추가되는 셈이다. 값비싼 재학습 없이 언어만으로 학습 효과를 흉내 내는 접근이다.

혼자보다 팀 — 멀티 에이전트와 감독자 구조

하나의 에이전트가 모든 일을 도맡기보다, 역할을 나눈 여러 에이전트가 협업하도록 설계하기도 한다. 이를 멀티 에이전트(multi-agent) 구조라 부른다. 큰 문제를 여러 전문가에게 나눠 맡기는 조직도와 비슷하다.

가장 흔한 형태가 감독자(supervisor) 구조다. 오케스트레이터 역할을 하는 상위 에이전트가 목표를 잘게 나눠 하위 에이전트에게 배분하고, 각자의 결과를 모아 종합한다. 예컨대 시장 조사 보고서를 만든다면, 조사 담당·초안 작성 담당·검증 담당을 따로 두고 감독자가 이들을 지휘하는 식이다. 역할이 분리되니 각 에이전트의 프롬프트와 도구를 더 좁고 정확하게 다듬을 수 있다.

다만 멀티 에이전트가 만능은 아니다. 에이전트를 늘릴수록 호출 비용과 지연이 커지고, 서로 주고받는 과정에서 오해와 오류가 번질 여지도 생긴다. 앤스로픽의 실무 지침(Building effective agents)도 결이 비슷한 조언을 준다. 화려한 구조를 먼저 세우기보다 가장 단순한 방법으로 문제가 풀리는지부터 확인하고, 정말 필요할 때만 복잡도를 올리라는 것이다.

실제로 많은 문제는 완전 자율 에이전트가 아니라, 정해진 순서로 LLM 호출을 엮는 워크플로만으로도 충분히 풀린다. 자율성이 높아질수록 성능의 상한도, 통제의 어려움도 같이 오른다. 자율성과 예측 가능성은 맞바꿈 관계에 있다는 감각을 갖고 설계 수준을 고르는 편이 현명하다.

감독자 구조의 멀티 에이전트

아직 넘지 못한 벽 — 신뢰성·오류 누적·감독

도약이 분명한 만큼 한계도 분명하다. 그리고 그 한계는 별난 데서 오는 게 아니라, 앞서 말한 '확률로 예측하는 기계'라는 본질에서 곧장 따라 나온다. 첫째는 신뢰성이다. 에이전트의 각 단계는 결국 그럴듯한 다음을 고르는 예측이므로, 한 단계가 그럴듯하게 틀릴 수 있다. 검색어를 엉뚱하게 짜거나, 관찰 결과를 잘못 읽는 식이다.

둘째는 오류 누적이다. 이게 에이전트 특유의 무서운 지점이다. 한 단계의 작은 오차가 다음 단계의 전제가 되고, 그 위에 또 오차가 쌓인다. 각 단계의 정확도가 제법 높아도 단계가 길게 이어지면 전체가 목표에서 크게 벗어날 수 있다. 초반의 사소한 오독 하나가 열 단계 뒤에는 완전히 틀린 결론으로 불어나는 것이다. 반복 상한을 두고, 중간중간 자기 점검을 넣는 이유가 여기 있다.

셋째는 감독의 필요다. 파일 삭제, 결제, 메일 발송처럼 되돌릴 수 없는 행동은 에이전트에게 온전히 맡기기 위험하다. 그래서 그런 행동 앞에는 사람이 확인하고 승인하는 관문을 둔다. 이를 사람 개입(human-in-the-loop)이라 부른다. 자동화의 효율과 안전을 맞바꾸는 대신, 위험이 큰 지점에만 선택적으로 사람을 끼워 넣는 절충이다.

결국 에이전트는 강력한 실행기이되 아직 감독이 필요한 실행기다. '초안은 기계, 판단은 사람'이라는 분업 원칙이 여기서도 그대로다. 오히려 여러 단계를 자동으로 처리하는 만큼, 사람의 감독은 덜 중요해지는 게 아니라 더 중요해진다. 자율성을 얻은 대가로 감독 설계라는 새로운 숙제가 생긴 셈이다.

사람 개입(human-in-the-loop) 안전장치

실무에서 에이전트를 다루는 법

현장에 적용할 때는 몇 가지 원칙이 반복해서 통한다. 먼저 가장 단순한 것부터 시작한다. 단발 프롬프트로 되면 그걸로 끝내고, 안 되면 고정된 워크플로를 짜고, 그래도 부족할 때 비로소 자율 에이전트를 꺼낸다. 자율성을 기본값으로 삼으면 디버깅이 지옥이 된다.

다음으로 도구와 프롬프트를 명확하게 설계한다. 각 도구가 무엇을 하고 언제 써야 하는지, 입력 형식은 무엇인지를 오해 없이 적어 준다. 모델이 도구를 잘못 고르는 문제의 상당수는 사실 설명이 모호했던 탓이다. 되돌릴 수 없는 행동에는 사람 승인 관문을 반드시 끼우고, 반복 상한과 예산 상한을 걸어 폭주를 막는다.

관측 가능성도 실무의 핵심이다. 에이전트가 어느 단계에서 무엇을 생각하고 어떤 도구를 어떤 인자로 불렀는지, 관찰 결과가 무엇이었는지를 모두 로그로 남긴다. 여러 단계를 거치는 만큼 실패 지점을 추적하려면 이 기록이 있어야 한다. 각 단계에서 평가 지표를 정해 두고, 자주 실패하는 패턴을 찾아 프롬프트나 도구를 개선하는 반복이 결국 품질을 만든다.

비용과 지연도 염두에 둬야 한다. 한 목표를 처리하는 데 모델을 여러 번 부르므로, 단발 챗봇보다 비용과 응답 시간이 몇 배로 늘어날 수 있다. 매 단계 온도를 낮춰 형식을 고정하고, 불필요한 단계를 쳐내고, 반복 상한을 현실적으로 잡는 것이 곧 비용 관리다.

에이전트의 눈과 손 — 함수 호출과 구조화 출력

에이전트가 도구를 부르려면 언어모델이 '자유로운 문장'이 아니라 '기계가 파싱할 수 있는 형식'으로 답해야 한다. 초기에는 프롬프트에 "도구를 쓸 때는 Action: search[검색어] 형식으로 쓰라"고 지시하고, 모델이 뱉은 문자열을 정규식으로 잘라 썼다. 문제는 모델이 형식을 조금씩 어긴다는 데 있다. 대괄호를 빼먹거나, 설명을 덧붙이거나, 인자 순서를 바꾼다. 파싱이 깨지면 루프 전체가 멈춘다. 이 취약함을 없애려고 등장한 것이 함수 호출(function calling), 요즘 표현으로는 도구 호출(tool calling)이다.

함수 호출의 핵심은 도구의 명세를 JSON 스키마로 모델에 미리 넘겨주는 데 있다. 이름, 설명, 각 인자의 타입과 필수 여부를 스키마로 적으면, 모델은 그 형식에 맞춰 인자를 채운 JSON을 출력한다. 예를 들어 get_weather 도구에 {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["c", "f"]}} 같은 스키마를 주면, 모델은 "서울 날씨"라는 요청을 받아 {"city": "Seoul", "unit": "c"}를 만들어낸다. 모델을 도구 호출용으로 파인튜닝해 스키마 형식에 맞춰 출력하도록 학습시키기 때문에, 문자열 파싱 시절보다 형식 오류가 크게 줄었다.

한 걸음 더 나가면 제약 디코딩(constrained decoding)이 있다. 모델이 다음 토큰을 고를 때 확률 분포 전체에서 뽑는 대신, 문법(JSON 스키마나 정규식으로 표현한 유한 상태 기계)이 허용하는 토큰만 남기고 나머지 확률을 0으로 눌러버린다. 여는 중괄호 다음에는 키 문자열만, 콜론 다음에는 값만 나올 수 있게 강제하는 식이다. 이렇게 하면 문법적으로 틀린 JSON은 아예 나올 수 없다. Outlines나 llama.cpp의 GBNF 문법 지원이 이 방식을 쓴다. 형식은 보장되지만 내용의 정확성까지 보장하지는 않는다는 점은 기억해야 한다. 스키마에 맞는 엉뚱한 도시 이름은 여전히 나올 수 있다.

실무에서 도구 스키마를 설계할 때 흔히 놓치는 부분이 인자 설명이다. 모델은 함수 이름과 인자 설명을 거의 자연어 프롬프트처럼 읽는다. query라고만 적은 인자와 "사용자가 찾으려는 핵심 키워드. 불용어를 뺀 명사 위주로"라고 적은 인자는 채워지는 값의 질이 다르다. 도구를 늘릴수록 이름이 헷갈리게 겹치지 않도록 하고, 비슷한 기능은 인자로 분기시켜 하나로 합치는 편이 오호출을 줄인다. 도구가 열 개를 넘어가면 모델이 어떤 것을 골라야 할지 헷갈리기 시작하므로, 상황별로 노출할 도구 집합을 동적으로 줄이는 도구 라우팅도 함께 고려한다.

컨텍스트 창이라는 예산 — 토큰을 어디에 쓸 것인가

에이전트가 여러 단계를 돌면 대화 기록, 도구 호출 결과, 관찰 내용이 계속 쌓인다. 이 모든 것이 컨텍스트 창(context window)에 들어가는데, 창의 크기는 유한하다. 최근 모델은 12만 8천 토큰, 일부는 100만 토큰까지 지원하지만, 무한이 아니다. 게다가 넣을 수 있다고 다 넣는 것이 좋은 것도 아니다. 컨텍스트를 예산으로 보고 관리해야 한다는 관점이 에이전트 설계의 핵심 감각이다.

첫 번째 함정은 '중간이 사라지는 현상(lost in the middle)'이다. 긴 컨텍스트를 주면 모델은 맨 앞과 맨 뒤에 있는 정보는 잘 활용하지만, 한가운데 놓인 정보는 놓치는 경향을 보인다. 검색으로 스무 개 문서를 그러모아 순서 없이 밀어넣으면, 정작 정답이 담긴 문서가 열 번째쯤에 묻혀버릴 수 있다. 그래서 재순위화(re-ranking)로 가장 관련 높은 문서를 앞뒤 끝에 배치하거나, 애초에 넣는 문서 수를 줄이는 편이 정확도에 유리하다. 무작정 많이 넣는 전략은 비용만 늘고 성능은 떨어뜨린다.

두 번째 함정은 컨텍스트 오염이다. 앞 단계에서 도구가 엉뚱한 결과를 반환했는데 그것이 그대로 컨텍스트에 남으면, 뒤 단계의 추론이 그 오답을 사실로 믿고 진행한다. 오류가 눈덩이처럼 커지는 배경에는 이런 오염이 있다. 이를 완화하려고 도구 결과를 요약해서 넣거나, 실패한 시도는 컨텍스트에서 잘라내고 교훈만 한 줄로 남기는 압축 기법을 쓴다. 긴 작업에서는 주기적으로 대화 전체를 요약해 새 컨텍스트로 갈아끼우는 방법도 흔하다.

비용 측면도 무시할 수 없다. 대부분의 API는 입력 토큰과 출력 토큰에 각각 요금을 매긴다. 에이전트가 열 단계를 도는데 매 단계 컨텍스트에 전체 기록을 다시 넣으면, 토큰 사용량이 단계 수의 제곱에 가깝게 불어난다. 이를 줄이려면 프롬프트 캐싱이 유용하다. 시스템 프롬프트와 도구 명세처럼 바뀌지 않는 앞부분을 캐시해두면, 반복 호출에서 그 부분의 입력 비용과 지연이 크게 줄어든다. 자주 쓰는 접두부는 컨텍스트 앞쪽에 고정 배치하는 설계가 캐시 적중률을 높이는 요령이다.

에이전트 vs 워크플로 vs RAG — 헷갈리기 쉬운 경계

실무 논의에서 자주 뒤섞이는 세 개념이 있다. 정해진 순서로 LLM을 여러 번 호출하는 워크플로, 외부 지식을 검색해 답에 붙이는 RAG(검색 증강 생성), 그리고 스스로 다음 행동을 정하는 에이전트다. 셋의 결정적 차이는 '경로를 누가 정하느냐'에 있다. 워크플로는 개발자가 흐름을 코드로 못박아둔다. 에이전트는 모델이 매 단계 다음 행동을 스스로 판단한다. RAG는 그 자체로는 검색 한 번을 답에 결합하는 패턴일 뿐, 자율 루프와는 별개 축이다.

이 차이를 표로 정리하면 선택 기준이 분명해진다.

구분 경로 결정 주체 반복 여부 적합한 문제 예측 가능성
고정 워크플로 개발자(코드) 정해진 횟수 절차가 명확한 정형 작업 높음
RAG 개발자(검색→생성) 보통 1회 사내 문서 기반 질의응답 높음
에이전트 모델(런타임) 조건 충족까지 절차가 미리 안 정해진 개방형 작업 낮음

여기서 얻을 실무 교훈은 '에이전트가 항상 정답은 아니다'라는 점이다. 절차가 명확하고 예외가 적은 일을 굳이 자율 에이전트로 만들면, 통제하기 어렵고 비용만 더 든다. 고객 문의를 분류해 세 갈래로 보내는 일이라면 조건 분기 워크플로가 낫다. 반대로 '이 버그를 찾아 고쳐라'처럼 어떤 파일을 봐야 할지 미리 알 수 없는 작업은 에이전트의 자율성이 빛난다. 실전에서는 순수한 에이전트보다, 큰 틀은 워크플로로 잡고 특정 노드만 에이전트에게 맡기는 하이브리드 구조가 안정적인 경우가 많다.

RAG와 에이전트의 관계도 명확히 해둘 필요가 있다. 검색을 도구로 등록해두면 에이전트는 필요할 때 스스로 검색을 반복 호출한다. 첫 검색 결과가 부실하면 질의를 바꿔 다시 검색하는 식이다. 이렇게 검색을 자율 루프 안으로 끌어들인 것을 흔히 '에이전틱 RAG'라 부른다. 즉 RAG는 에이전트에 흡수될 수 있는 하위 요소이지, 대립하는 개념이 아니다.

표준화의 물결 — 도구 연결 규약과 상호운용성

에이전트가 실제로 유용하려면 외부 세계와 연결되어야 한다. 파일 시스템, 데이터베이스, 사내 API, SaaS 서비스 같은 것들 말이다. 초기에는 서비스마다 제각각 통합 코드를 짰다. 도구가 열 개면 열 개의 서로 다른 어댑터를 만들고 유지해야 했다. 에이전트 프레임워크가 바뀌면 그 통합을 또 다시 짜야 했다. 이 반복 노동을 줄이려는 표준화 시도가 최근 빠르게 자리 잡고 있다.

대표적인 것이 모델 컨텍스트 프로토콜(MCP, Model Context Protocol)이다. 도구·데이터 소스를 제공하는 쪽을 서버로, 에이전트 애플리케이션을 클라이언트로 두고, 그 사이 통신 규약을 표준화한 것이다. 파일 접근이나 특정 API를 MCP 서버로 한 번 구현해두면, 이 규약을 따르는 어떤 에이전트든 그 도구를 그대로 붙여 쓸 수 있다. USB 규격이 여러 기기를 같은 포트로 연결하게 해준 것과 비슷한 발상이다. 통합의 조합 폭발(n×m)을 n+m으로 줄이는 데 목적이 있다.

표준화가 주는 실익은 재사용만이 아니다. 도구를 프로세스 밖으로 분리하면 권한과 격리를 다루기 쉬워진다. 파일 시스템 접근 서버에 읽기 권한만 부여하거나, 특정 디렉터리로 접근 범위를 묶는 식의 통제를 규약 계층에서 걸 수 있다. 에이전트 코드 본체를 건드리지 않고 도구의 보안 경계를 관리한다는 점이 운영 관점에서 크다.

다만 표준이 하나로 굳었다고 보기엔 아직 이르다. 도구 연결 규약 외에도 에이전트 사이 협업을 다루는 프로토콜 논의가 여러 진영에서 동시에 진행 중이다. 규약이 정착 단계라는 사실 자체가 에이전트 기술이 실험실을 벗어나 실제 소프트웨어 인프라로 편입되고 있다는 신호다. 새 도구를 붙일 때 자체 어댑터를 짜기 전에, 표준 규약을 지원하는 서버가 이미 있는지 먼저 확인하는 습관이 앞으로는 기본이 될 것이다.

얼마나 잘하는지 어떻게 재나 — 에이전트 평가의 난제

일반 LLM은 정답과 출력을 견주는 방식으로 평가하기 쉽다. 하지만 에이전트는 다르다. 최종 답만 봐서는 왜 맞았고 왜 틀렸는지 알 수 없다. 정답에 도달했더라도 도구를 열 번 헛발질하며 돌아왔다면 좋은 에이전트가 아니다. 반대로 경로는 완벽했는데 마지막 도구가 죽어서 실패했을 수도 있다. 그래서 에이전트 평가는 최종 결과와 과정(궤적, trajectory)을 함께 봐야 한다.

평가 축을 나눠보면 최소 네 가지를 따로 재게 된다. 과제 성공률(정해진 목표를 실제로 달성했는가), 궤적 품질(불필요한 단계 없이 효율적으로 갔는가), 도구 호출 정확도(맞는 도구에 맞는 인자를 넣었는가), 그리고 비용·지연(토큰과 시간을 얼마나 썼는가)이다. 이 넷은 종종 서로 충돌한다. 성공률을 높이려고 단계를 늘리면 비용과 지연이 나빠진다. 어느 지점에서 균형을 잡을지는 문제 성격이 정한다.

실무에서 궤적 평가는 크게 두 방식으로 한다. 하나는 기대 궤적을 미리 정해두고 실제 궤적과 도구 호출 순서·인자를 비교하는 규칙 기반 방식이다. 결정적이고 재현 가능하지만, 정답 경로가 여러 개일 수 있는 개방형 문제에는 잘 안 맞는다. 다른 하나는 강한 모델을 심판으로 세워 궤적을 평가하게 하는 LLM-as-a-judge 방식이다. 유연하지만 심판 모델 자체의 편향과 비용이 문제로 남는다. 두 방식을 섞어 정형 지표는 규칙으로, 주관적 품질은 모델 심판으로 재는 절충이 흔하다.

공개 벤치마크로는 코딩 에이전트를 실제 깃허브 이슈로 시험하는 SWE-bench, 웹 브라우징 능력을 보는 WebArena 계열, 복잡한 도구 사용을 평가하는 여러 데이터셋이 쓰인다. 하지만 벤치마크 점수를 실제 성능으로 곧이 믿으면 곤란하다. 벤치마크에 과적합된 에이전트가 실무의 지저분한 입력 앞에서 무너지는 일이 흔하기 때문이다. 결국 자기 도메인의 대표 시나리오로 자체 평가셋을 만들어 회귀 검사처럼 매 배포마다 돌리는 것이 가장 믿을 만하다. 프롬프트 한 줄, 모델 버전 하나만 바뀌어도 궤적이 통째로 달라질 수 있으므로, 평가 자동화 없이는 에이전트를 안정적으로 운영하기 어렵다.

더 깊이 파고들려면

에이전트를 제대로 공부하려면 인접 개념부터 단단히 다지는 편이 빠르다. 언어모델이 다음 토큰을 확률 분포에서 고르는 원리, 토큰화와 임베딩, 자기어텐션(self-attention)을 축으로 하는 트랜스포머(Transformer) 구조를 알면 '왜 그럴듯하게 틀리는가'가 자연스레 설명된다. 온도, top-k, top-p 같은 디코딩 파라미터가 출력의 형식과 다양성을 어떻게 좌우하는지도 함께 익혀 두면 좋다.

프롬프트 기법은 에이전트의 언어 그 자체다. 예시를 주지 않는 제로샷(zero-shot), 몇 개를 주는 퓨샷(few-shot), 생각을 풀어내는 사고 사슬(CoT), 추론과 행동을 엮는 ReAct의 차이를 아래 표로 비교해 두면 설계 감각이 잡힌다.

기법 핵심 방식 도구 사용 대표 쓰임새
Zero-shot 예시 없이 지시만 없음 단순 질의응답
Few-shot 예시 몇 개 제시 없음 형식·스타일 고정
CoT 추론 과정을 단계로 서술 없음 복잡한 추론 문제
ReAct 추론과 도구 실행을 번갈아 있음 에이전트의 기본 루프

원전에 직접 닿아 보는 것도 권한다. 추론과 행동을 결합한 ReAct(arXiv 2210.03629), 모델이 도구 사용을 스스로 배우는 Toolformer(2302.04761), 실패를 언어로 되짚는 Reflexion(2303.11366), 여러 갈래를 탐색하는 Tree of Thoughts(2305.10601), 사람 행동을 흉내 내는 에이전트 사회를 다룬 Generative Agents(2304.03442)를 읽으면 흐름이 잡힌다. 설계 실무는 앤스로픽의 'Building effective agents'가 균형 잡힌 지침을 준다.

마지막으로 기억할 결론은 이 코스가 처음부터 말해 온 그것이다. 에이전트가 아무리 스스로 움직여도, 그 바닥에는 확률로 다음을 예측하는 기계가 있다. 원리를 아는 사람만이 이 강력한 실행기를 언제 믿고 언제 감독해야 하는지 판단할 수 있다. 결국 원리를 아는 것이 곧 AI 리터러시다.

출처

  1. ReAct: Synergizing Reasoning and Acting
  2. Toolformer: LMs Can Teach Themselves to Use Tools
  3. Reflexion: Language Agents with Verbal Reinforcement Learning
  4. Generative Agents: Interactive Simulacra of Human Behavior
  5. Tree of Thoughts
  6. Building effective agents
뉴스레터로 매주 받아보기 ← 기술블로그 목록