7장 - 에이전트 LLM
7장. 에이전트 LLM
LLM을 바깥 세계와 연결하면 단순한 텍스트 생성기에서 행동하는 시스템으로 도약한다. RAG로 지식의 한계를 넘고, 도구 호출로 실세계에 개입하며, 에이전트 루프로 복잡한 목표를 자율적으로 추구할 수 있다. — Shervine Amidi
7.1 지식 한계와 RAG의 동기
지금까지 다룬 LLM은 사전 훈련 데이터에 포함된 지식만 활용할 수 있었다. 이번 장에서는 LLM을 외부 시스템과 연결하여 최신 정보를 검색하고, 도구를 호출하며, 복잡한 과제를 자율적으로 수행하는 방법을 살펴본다.
지식 컷오프 문제
모든 LLM에는 **지식 컷오프(knowledge cutoff)**가 존재한다. 사전 훈련에 사용된 데이터의 마지막 시점 이후에 발생한 사건에 대해서는 정확히 답할 수 없다. 예를 들어 GPT-5의 지식 컷오프는 2024년 9월 30일이다. 이 날짜 이후에 일어난 선거 결과나 뉴스를 물으면, 기본 모델은 정확한 답을 제공하지 못한다.
왜 지속적 훈련으로 해결하지 않는가
직관적으로는 새로운 데이터로 추가 훈련을 하면 될 것 같지만, 실제로는 여러 이유로 어렵다.
첫째, 지식 변경의 회귀 위험이다. LLM의 지식을 부분적으로 갱신하면 기존에 잘 작동하던 다른 능력에 회귀(regression)가 발생하기 쉽다. 모델의 가중치를 직접 수정하여 지식을 주입하는 것은 매우 까다로운 작업이다.
둘째, 유지보수 오버헤드가 크다. 하나의 기본 모델로부터 여러 용도별 미세 조정 모델을 운영하는 경우를 생각해 보자. 기본 모델의 가중치를 갱신하면, 이로부터 파생된 모든 미세 조정 모델에도 동일한 작업을 반복해야 한다. 이는 막대한 유지보수 부담이다.
이러한 이유로 실무에서는 추가 훈련 대신 프롬프트에 외부 정보를 주입하는 방식을 선호한다.
모든 정보를 프롬프트에 넣으면 안 되는가
그렇다면 컷오프 이후의 모든 정보를 프롬프트에 넣으면 어떨까? 이 순진한 접근에는 세 가지 근본적 문제가 있다.
컨텍스트 길이 제한. 모델의 컨텍스트 윈도우는 유한하다. GPT-5의 경우 약 400,000 토큰이다. 1 토큰이 대략 4자(영문 기준)이므로, 수백 페이지 분량의 텍스트를 담을 수 있지만, 세상의 모든 새로운 정보를 넣기에는 턱없이 부족하다.
Needle-in-a-Haystack 문제. 설령 컨텍스트가 무한하다 하더라도, 대량의 무관한 정보를 함께 제공하면 LLM의 성능이 떨어진다. 이를 입증하는 실험이 Needle-in-a-Haystack 테스트다. 긴 프롬프트(건초 더미) 안에 하나의 사실(바늘)을 숨긴 뒤, 모델에게 그 사실을 찾으라고 요청한다. 프롬프트 길이와 사실의 위치를 변화시키며 실험한 결과, 두 가지 명확한 경향이 나타난다.
- 프롬프트가 일정 토큰 수를 초과하면 정확도가 급격히 하락한다.
- 사실이 프롬프트의 전반부에 위치할수록 검색 실패율이 높아진다.
GPT-4에 대해 수행된 이 실험의 히트맵에서, x축은 프롬프트 길이, y축은 사실의 위치(document depth)다. 특정 길이 이상에서 모델이 정보를 올바르게 검색하지 못하는 영역이 분명히 존재한다.
비용 문제. LLM API 호출은 토큰 단위로 과금된다. GPT-5의 경우 대략 100만 토큰당 1달러 수준이다. 모든 프롬프트에 방대한 컨텍스트를 붙이면 비용이 급격히 증가한다.
이 세 가지 이유로, 모든 정보를 한꺼번에 프롬프트에 넣는 대신 관련 정보만 선별하여 주입하는 더 영리한 방법이 필요하다. 이것이 바로 RAG의 핵심 동기다.
7.2 RAG: 검색 증강 생성
**RAG(Retrieval-Augmented Generation, 검색 증강 생성)**는 프롬프트에 관련 정보를 보강하여 LLM의 응답 품질을 높이는 기법이다. 이름 자체가 세 단계를 설명한다.
3단계 파이프라인
단계 |
영문 |
설명 |
|---|---|---|
1. 검색(Retrieve) |
Retrieve |
질문과 관련된 문서를 지식 베이스에서 찾는다 |
2. 보강(Augment) |
Augment |
검색된 정보를 프롬프트에 추가한다 |
3. 생성(Generate) |
Generate |
보강된 프롬프트를 LLM에 입력하여 응답을 생성한다 |
예를 들어 "지난 선거의 승자는 누구인가?"라는 질문이 들어오면, (1) 지식 베이스에서 해당 선거 관련 문서를 검색하고, (2) "이 선거는 언제 열렸고, 결과는 이러하다"라는 정보를 프롬프트에 삽입한 뒤, (3) LLM이 이를 읽고 자연어로 답변을 생성한다. 본질적으로 답을 프롬프트 안에 넣어 주는 것이다.
RAG의 핵심은 검색 단계의 품질에 달려 있다. 잘못된 문서를 검색하면 잘못된 답변이 생성된다. 따라서 RAG 시스템을 구축할 때 대부분의 노력은 검색기(retriever)의 성능 향상에 집중된다.
7.3 지식 베이스 구축: 청킹과 임베딩
검색을 수행하려면 먼저 문서들을 검색 가능한 형태로 가공해야 한다. 이 과정을 지식 베이스(knowledge base) 구축이라 한다.
청킹(Chunking)
문서를 수집한 뒤, 각 문서를 **청크(chunk)**라는 작은 단위로 분할한다. 청크는 문서의 부분 집합으로, 최대 토큰 수로 크기가 정해진다.
청킹에는 세 가지 핵심 하이퍼파라미터가 있다.
하이퍼파라미터 |
일반적 값 |
설명 |
|---|---|---|
임베딩 크기 |
~1,500차원 |
복잡한 문서에는 큰 값이 유리하나, 저장 공간과 계산 비용이 증가 |
청크 크기 |
~500 토큰 |
너무 작으면 문맥이 손실되고, 너무 크면 임베딩이 내용을 의미 있게 표현하지 못함 |
겹침(overlap) |
100~200 토큰 |
인접 청크 간 겹치는 부분. 이전 청크의 맥락을 유지하여 문맥 단절 방지 |
청크 크기가 약 500 토큰인 이유는 트레이드오프에 있다. 청크가 너무 작으면 텍스트가 맥락에서 벗어날 수 있고, 너무 크면 단일 임베딩 벡터가 다양한 내용을 충분히 표현하지 못한다. 겹침은 연속된 청크 사이의 문맥 단절을 방지한다. 한 청크의 끝 부분이 다음 청크의 시작 부분과 겹치므로, 문장이 청크 경계에서 잘려도 맥락이 유지된다.
임베딩 계산
각 청크를 고정 크기의 벡터(임베딩)로 변환한다. 이 임베딩은 청크의 의미를 수치적으로 표현하며, 이후 유사도 검색의 기반이 된다. 임베딩 모델은 사전 훈련된 것을 사용할 수도 있고, 용도에 맞게 직접 훈련할 수도 있다.
문서 형식에 따라 청킹 전략이 달라져야 한다. JSON, 마크다운, HTML 등 구조화된 문서는 그 구조를 고려하여 청킹해야 한다. 순진하게 토큰 수만으로 자르면 의미 단위가 깨질 수 있다.
7.4 후보 검색: 유사도 검색과 키워드 검색
지식 베이스가 구축되면, 주어진 질의에 대해 관련 문서를 찾아야 한다. 이 과정은 추천 시스템이나 정보 검색 분야와 동일한 2단계 구조를 따른다.
단계 |
목표 |
특성 |
|---|---|---|
1단계: 후보 검색(Candidate Retrieval) |
수백만 청크 → 수백 개로 축소 |
빠른 연산. 재현율(recall) 최대화 |
2단계: 순위 재조정(Re-ranking) |
수백 개 → 최종 상위 K개 |
정밀한 연산. 정밀도 최대화 |
1단계에서는 속도가 핵심이므로 가볍고 빠른 방법을 사용한다. 2단계에서는 후보 수가 적으므로 더 정교한 모델을 적용할 수 있다.
의미 유사도 검색 (SBERT 바이 인코더)
**의미 유사도 검색(semantic similarity search)**은 질의와 청크를 각각 임베딩한 뒤, 벡터 간 유사도를 계산하여 관련 문서를 찾는 방법이다.
- 질의를 인코더에 통과시켜 임베딩 벡터를 얻는다.
- 지식 베이스의 모든 청크 임베딩과 유사도를 계산한다.
- 유사도가 높은 상위 문서를 후보로 선택한다.
유사도 측정에는 **코사인 유사도(cosine similarity)**가 가장 널리 쓰인다.
\[\text{cosine similarity}(\mathbf{q}, \mathbf{d}) = \frac{\mathbf{q} \cdot \mathbf{d}}{\|\mathbf{q}\| \, \|\mathbf{d}\|}\]
여기서 \(\mathbf{q}\)는 질의 임베딩, \(\mathbf{d}\)는 문서 청크 임베딩이다. 두 벡터가 같은 방향을 가리킬수록 값이 1에 가까워지고, 무관할수록 0에 가까워진다. L2 거리를 사용하는 경우도 있지만, 벡터가 정규화되어 있으면 코사인 유사도와 본질적으로 동일하다.
이 구조를 **바이 인코더(bi-encoder)**라 부른다. 질의와 문서를 각각 독립적으로 인코딩하기 때문이다. 질의는 질의 인코더를 통과하고, 문서는 문서 인코더를 통과하며, 두 인코더는 동일 모델일 수도 있고 별도 모델일 수도 있다.
대표적인 임베딩 모델이 **Sentence-BERT(SBERT)**다. BERT의 확장으로, 시퀀스 단위 임베딩을 유사도 검색에 최적화하여 계산한다. 훈련 시 관련 있는 쌍의 코사인 유사도는 높이고, 관련 없는 쌍의 코사인 유사도는 낮추는 손실 함수를 사용한다.
근사 최근접 이웃 (ANN)
지식 베이스가 수백만 개의 청크를 포함할 수 있으므로, 모든 청크와 일일이 유사도를 계산하는 선형 검색은 비현실적이다. 대신 근사 최근접 이웃(Approximate Nearest Neighbor, ANN) 기법을 사용한다. ANN은 지식 베이스 구축 시 임베딩을 미리 분할(partitioning)해 두어, 검색 시 전체 공간을 탐색하지 않고도 빠르게 유사한 벡터를 찾을 수 있게 한다. FAISS(Facebook AI Similarity Search) 등의 라이브러리가 대표적이다.
BM25 키워드 검색
의미 유사도 검색은 의미가 비슷한 문서를 찾지만, 키워드 일치를 보장하지 않는다. "cuddly는 어디에 있나?"라고 물었을 때, 의미 유사도 검색은 "huggy"에 관한 문서를 반환할 수 있다. 둘 다 인형 이름이라 의미적으로 유사하기 때문이다. 하지만 사용자는 정확히 "cuddly"를 포함한 문서를 원할 수 있다.
BM25는 질의와 문서 간 키워드 겹침에 기반한 휴리스틱 점수다. 질의의 단어가 문서에 얼마나 많이, 얼마나 의미 있게 등장하는지를 수식으로 계산한다. BM25의 장점은 키워드 매칭이 보장된다는 것이고, 단점은 의미적 유사성을 포착하지 못한다는 것이다.
하이브리드 접근: 임베딩 + BM25
실무에서는 두 방법을 결합한 하이브리드 검색을 많이 사용한다. 임베딩 기반 의미 유사도 검색과 BM25 키워드 검색의 점수를 조합하여, 의미적으로도 관련 있고 키워드도 일치하는 문서를 함께 검색한다. 이 접근은 사용 사례에 따라 두 방법의 가중치를 조절할 수 있어 유연하다.
7.5 검색 품질 향상 기법
기본적인 검색 파이프라인을 구축한 뒤에도, 검색 품질을 높이기 위한 여러 확장 기법이 있다.
HyDE: 가상 문서 임베딩
질의와 문서는 본질적으로 성격이 다르다. 질의는 짧은 질문이고, 문서는 서술적인 문장들이다. 동일한 인코더로 두 가지를 임베딩하면, 임베딩 공간에서의 비교가 정확하지 않을 수 있다.
**HyDE(Hypothetical Document Embeddings)**는 이 문제를 완화하는 기법이다. 질의를 직접 임베딩하는 대신, LLM을 호출하여 질의에 대한 가상의 답변 문서를 먼저 생성한다. 그런 다음 이 가상 문서를 임베딩하여 지식 베이스와 비교한다. 가상 문서는 실제 문서와 형태가 유사하므로, 동일 인코더를 사용해도 더 의미 있는 비교가 가능하다.
HyDE가 항상 효과적인 것은 아니다. LLM이 생성한 가상 문서가 부정확하면 오히려 검색 품질이 떨어질 수 있다. 또 다른 대안은 질의 인코더와 문서 인코더를 아예 별도로 훈련하는 것이지만, 유지보수 부담이 커서 실무에서는 드물다.
컨텍스트 검색(Contextual Retrieval)
순진한 청킹은 문맥 단절을 야기할 수 있다. 한 청크가 원래 문서의 맥락에서 분리되면, 그 자체로는 의미가 불완전할 수 있다. **컨텍스트 검색(contextual retrieval)**은 각 청크에 문맥 요약을 앞에 덧붙여 이 문제를 해결한다.
구체적인 절차는 다음과 같다.
- 전체 문서와 특정 청크를 LLM에 입력한다.
- "이 청크를 이해하는 데 필요한 짧은 문맥을 제공하라"고 요청한다.
- 생성된 문맥 설명을 청크 앞에 붙인 뒤 임베딩을 계산한다.
이 방법의 문제점은 청크 수만큼 LLM 호출이 필요하다는 것이다. 문서 하나에 수백 개의 청크가 있다면 비용이 상당하다. 이를 해결하는 것이 프롬프트 캐싱이다.
프롬프트 캐싱(Prompt Caching)
컨텍스트 검색에서 모든 LLM 호출의 입력은 동일한 접두어(전체 문서 텍스트)를 공유하고, 뒤에 달라지는 부분(특정 청크)만 다르다. 디코더 전용 모델에서는 동일한 접두어가 동일한 중간 활성화(activation)를 생성한다.
프롬프트 캐싱은 이 공통 접두어의 활성화를 한 번만 계산하여 저장한 뒤, 이후 호출에서는 저장된 값을 조회(lookup)만 하는 최적화다. 새로 계산이 필요한 것은 접두어 이후의 부분뿐이다.
실제 API 요금에서도 이를 반영한다. 예를 들어 캐시된 입력 토큰의 가격은 일반 입력 토큰의 1/10 수준이다. 따라서 프롬프트 설계 시 여러 호출에서 반복되는 부분을 프롬프트의 앞쪽에 배치하면 비용을 크게 절감할 수 있다.
7.6 순위 재조정: 크로스 인코더
후보 검색(1단계)이 수백 개의 잠재적 관련 문서를 반환했다면, **순위 재조정(re-ranking, 2단계)**은 이들을 더 정밀하게 순위 매겨 최종 상위 K개를 선별하는 과정이다.
바이 인코더 vs 크로스 인코더
바이 인코더는 질의와 문서를 독립적으로 인코딩한다. 두 임베딩 사이에 직접적인 상호작용이 없다. 반면 **크로스 인코더(cross-encoder)**는 질의와 문서를 하나의 입력으로 연결(concatenate)하여 단일 인코더에 함께 통과시킨다.
특성 |
바이 인코더 |
크로스 인코더 |
|---|---|---|
입력 |
질의, 문서를 각각 독립적으로 인코딩 |
질의 + 문서를 결합하여 함께 인코딩 |
상호작용 |
임베딩 간 유사도 비교만 수행 |
어텐션을 통해 질의-문서 간 직접 상호작용 |
출력 |
두 개의 임베딩 벡터 |
단일 관련성 점수 (스칼라) |
속도 |
빠름. 문서 임베딩 사전 계산 가능 |
느림. 매 쌍마다 새로 계산 |
적용 단계 |
1단계 후보 검색 (대규모) |
2단계 순위 재조정 (소규모) |
크로스 인코더가 더 정확한 이유는 명확하다. 모델 내부에서 질의와 문서 사이의 어텐션이 계산되므로, 단순한 벡터 유사도로는 포착할 수 없는 세밀한 관련성을 감지할 수 있다. 다만 계산 비용이 크므로, 수백만 개의 청크에 직접 적용하기에는 비현실적이다. 이것이 2단계 구조가 필요한 이유다.
Sentence-BERT 프로젝트에서 바이 인코더와 크로스 인코더 모두에 대한 사전 훈련 모델과 문서를 제공하므로, 실무에서 좋은 출발점이 된다.
7.7 검색 평가 지표
검색기의 품질을 정량적으로 평가하려면 표준화된 지표가 필요하다. 검색 평가의 기본 설정은 다음과 같다. 시스템이 상위 K개의 청크를 "관련 있음"으로 반환하고, 실제 정답 레이블(ground truth)과 비교한다.
NDCG (Normalized Discounted Cumulative Gain)
NDCG는 검색 결과의 순위 품질을 측정하는 핵심 지표다. 관련 문서가 순위에서 높은 위치에 있을수록 점수가 높아진다.
먼저 **DCG(Discounted Cumulative Gain)**를 정의한다.
\[\text{DCG}@K = \sum_{i=1}^{K} \frac{\text{rel}_i}{\log_2(i + 1)}\]
여기서 \(\text{rel}_i\)는 순위 \(i\)에 위치한 문서의 관련성 점수다. 이진 관련성의 경우, 관련 있으면 1, 없으면 0이다. 분모 \(\log_2(i + 1)\)이 할인(discount) 요소다. 순위가 낮아질수록(즉 \(i\)가 커질수록) 분모가 커져서, 같은 관련 문서라도 높은 순위에 있을 때 더 큰 기여를 한다. "누적(cumulative)"이란 1위부터 K위까지의 기여를 모두 더한다는 뜻이다.
그런데 DCG의 절대값은 실제 관련 문서의 수에 따라 달라지므로 직접 비교하기 어렵다. 이를 정규화하기 위해 **이상적 DCG(Ideal DCG, IDCG)**를 계산한다. IDCG는 관련 문서가 완벽하게 상위에 배치된 경우의 DCG 값이다.
\[\text{NDCG}@K = \frac{\text{DCG}@K}{\text{IDCG}@K}\]
NDCG의 범위는 0에서 1이다. 1이면 검색 결과가 최적의 순위와 완벽히 일치한다는 뜻이다.
MRR (Mean Reciprocal Rank)
**역순위(Reciprocal Rank, RR)**는 더 단순한 지표로, 최초의 관련 문서가 몇 번째 순위에 등장하는지만 고려한다.
\[\text{RR} = \frac{1}{\text{rank of first relevant document}}\]
예를 들어 상위 K개 결과 중 첫 번째 관련 문서가 2위에 있다면, \(\text{RR} = 1/2 = 0.5\)이다. 여러 질의에 대해 RR을 평균한 것이 **MRR(Mean Reciprocal Rank)**이다. 이 지표는 첫 번째 관련 문서 이후의 결과는 무시하므로, NDCG보다 단순하지만 실무에서 잘 상관(correlate)된다.
정밀도@K와 재현율@K
분류 문제의 정밀도와 재현율을 검색에 적용한 것이다.
\[\text{Precision}@K = \frac{\text{상위 K에서 실제 관련 문서 수}}{K}\]
\[\text{Recall}@K = \frac{\text{상위 K에서 실제 관련 문서 수}}{\text{전체 관련 문서 수}}\]
정밀도@K는 "내가 검색한 K개 중 몇 개가 진짜 관련 있는가?"를, 재현율@K는 "전체 관련 문서 중 몇 개를 내가 찾았는가?"를 묻는다.
MTEB 벤치마크
검색기의 성능을 표준적으로 비교하려면 **MTEB(Massive Text Embedding Benchmark)**를 사용한다. 이 벤치마크에서 다양한 임베딩 모델과 검색 전략을 NDCG, MRR, Precision@K, Recall@K 등의 지표로 평가할 수 있다.
7.8 도구 호출(Tool Calling)
RAG는 비구조화된 문서(텍스트)를 검색하여 프롬프트에 주입하는 방법이다. 반면, 외부 데이터가 구조화되어 있고 특정 함수를 실행해야 하는 경우에는 **도구 호출(tool calling)**이 필요하다.
도구 호출의 정의
IBM의 정의를 빌리면, 도구 호출이란 자율 시스템이 외부 자원에 동적으로 접근하고 활용하여 복잡한 과제를 완수하는 능력이다. 핵심 요소 두 가지는 (1) 과제를 완수한다는 것, 그리고 (2) 외부 자원에 의존할 수 있다는 것이다.
도구 호출의 활용 영역은 세 가지로 분류된다.
영역 |
예시 |
|---|---|
정보 검색 |
실시간 뉴스, 날씨, 주가 조회 |
계산 |
질의를 코드로 변환하여 실행하고 결과 반환 |
행동 실행 |
이메일 발송, 일정 추가, 기기 제어 |
2단계 프로세스
도구 호출은 두 번의 LLM 호출과 한 번의 함수 실행으로 이루어진다.
1단계 — 도구 선택과 인자 예측. 시스템 프롬프트에 사용 가능한 도구의 API 정의(함수 이름, 설명, 매개변수)를 포함시킨다. 구현 코드 자체는 포함하지 않는다. LLM이 사용자의 질의를 분석하여, 어떤 함수를 호출할지, 어떤 인자를 전달할지 결정한다.
예를 들어 "내 근처에서 테디베어를 찾아 줘"라는 질의가 들어오면, LLM은 사용자의 위치 정보(예: 스탠퍼드 좌표)를 인자로 하여 find_teddy_bear(latitude=37.43, longitude=-122.17) 같은 함수 호출을 생성한다.
함수 실행. 생성된 함수 호출을 시스템이 실제로 실행한다. 이 단계는 LLM과 무관하다. 함수가 외부 API를 호출하고, 구조화된 결과(예: JSON)를 반환한다.
2단계 — 결과 해석과 응답 생성. 함수의 반환값을 대화 이력과 함께 LLM에 다시 입력한다. LLM은 구조화된 결과를 자연어로 변환하여 사용자에게 전달한다. 이때 LLM은 원래 질의의 맥락, 도구 호출 이력, 반환된 결과를 모두 참고하여 응답을 생성한다.
[1단계] 사용자 질의 + 도구 API 정의 → LLM → 함수 호출 생성
↓
[실행] 함수 실행 → 구조화된 결과
↓
[2단계] 대화 이력 + 함수 결과 → LLM → 자연어 응답
도구 호출 훈련
LLM이 도구를 올바르게 사용하도록 훈련하는 방법은 두 가지다.
SFT 기반 훈련. 두 종류의 SFT 데이터 쌍을 준비한다. 첫 번째 쌍은 (질의 + 도구 API → 올바른 함수 호출)이고, 두 번째 쌍은 (대화 이력 + 함수 결과 → 최종 응답)이다. 다양한 질의 형태, 다중 턴 대화 등을 포함시켜 일반화 능력을 높인다.
프롬프트 기반 접근. 최근의 강력한 LLM은 코드를 깊이 이해하므로, SFT 없이도 상세한 설명(프롬프트)만으로 도구 사용법을 가르칠 수 있다. 이 접근에서는 SFT 데이터 쌍을 평가 세트로 활용한다. 현재 프롬프트로 평가 세트를 실행하여 성공과 실패를 확인한 뒤, 그 결과를 추론 모델에 입력하여 프롬프트를 자동으로 개선한다. 직접 프롬프트를 작성하는 것보다 추론 모델에게 위임하는 것이 실무에서 훨씬 효과적이다.
7.9 도구 선택과 확장성
실제 시스템에서는 하나의 도구만 사용하지 않는다. 뉴스 검색, 날씨 조회, 이메일 발송, 일정 관리 등 수십에서 수백 개의 도구가 존재할 수 있다. 모든 도구의 API를 프롬프트에 넣으면 두 가지 문제가 발생한다.
- Needle-in-a-Haystack 문제의 재현. 너무 많은 도구 정의가 프롬프트에 들어가면, LLM이 관련 도구를 제대로 식별하지 못한다.
- 컨텍스트 윈도우 한계. 수백 개의 도구 정의는 컨텍스트를 빠르게 소진시킨다.
도구 선택기(Tool Selector)
Google DeepMind의 기술 논문에서 제안한 **도구 선택기(tool selector)**는 2단계 접근으로 이 문제를 해결한다.
1단계: 질의와 함께 모든 도구의 이름 및 간략한 설명(1~2줄)만 LLM에 제시한다. LLM이 관련될 수 있는 도구를 선별한다.
2단계: 선별된 도구의 전체 API 정의만 프롬프트에 포함하여 실제 도구 호출을 수행한다.
이 과정은 RAG와 유사하다. 도구의 설명을 임베딩하여 질의와의 유사도로 검색할 수도 있다. 핵심은 전체 도구 목록을 프롬프트에 넣는 대신, 관련 도구만 선별하여 컨텍스트를 효율적으로 사용하는 것이다.
7.10 MCP: 모델 컨텍스트 프로토콜
도구 호출의 또 다른 문제는 표준화다. 각 LLM 제공업체마다 도구를 정의하고 노출하는 방식이 다르면, 개발자는 동일한 도구를 LLM마다 반복 구현해야 한다.
**MCP(Model Context Protocol)**는 Anthropic이 제안한 개방형 프로토콜로, 도구를 모델에 노출하는 방식을 표준화한다. MCP의 핵심 구성 요소는 다음과 같다.
구성 요소 |
설명 |
|---|---|
MCP 서버 |
도구를 제공하는 인스턴스. 보통 해당 도메인의 전문 제공자가 구현 |
도구(Tools) |
실제 함수 구현 |
프롬프트(Prompts) |
도구 사용법을 보여주는 템플릿 |
리소스(Resources) |
도구가 참조하는 외부 데이터베이스 |
MCP 클라이언트 |
LLM 호스트 측에서 MCP 서버와 1:1로 연결되는 인프라 |
예를 들어 도서 추천 서비스를 생각해 보자. 도서 제공업체가 MCP 서버를 구현하고, "도서 검색"과 "도서 추천" 도구를 노출한다. 프롬프트 템플릿은 "제목으로 검색하는 방법"이나 "사용자 취향에 맞는 추천 요청 방법"을 보여준다. 리소스로는 사용자의 독서 이력이나 베스트셀러 목록이 사용될 수 있다. LLM 호스트(예: Claude)는 MCP 클라이언트를 통해 이 서버에 연결하여, 표준화된 방식으로 도구를 호출한다.
MCP의 가치는 한 번 구현한 도구를 모든 MCP 호환 LLM에서 재사용할 수 있다는 점이다. 도구 제공자는 단일 MCP 서버만 유지하면 되고, LLM 호스트는 표준 프로토콜을 따르기만 하면 된다.
7.11 ReAct 에이전트: 관찰-계획-행동 루프
도구 호출이 단일 함수 실행이라면, **에이전트(agent)**는 여러 도구 호출과 추론을 반복적으로 결합하여 복잡한 목표를 자율적으로 추구하는 시스템이다.
에이전트의 정의
에이전트란 사용자를 대신하여 자율적으로 목표를 추구하고 과제를 완수하는 시스템이다. 도구 호출과의 핵심 차이는 **반복(loop)**과 고수준 추론이 포함된다는 것이다. 에이전트는 한 번의 도구 호출로 끝나지 않고, 결과를 관찰하고, 다음 행동을 계획하고, 실행하고, 다시 관찰하는 과정을 목표 달성까지 반복한다.
ReAct 프레임워크
**ReAct(Reason + Act)**는 에이전트 루프를 형식화한 대표적 논문이다. 복잡한 과제를 원자적 하위 단계로 분해하여 반복적으로 처리한다. 각 루프는 세 단계로 구성된다.
관찰(Observe). 현재 상황을 해석한다. 사용자의 질의나 이전 행동의 결과를 분석하여, 어떤 정보가 알려져 있고 어떤 정보가 누락되었는지 파악한다.
계획(Plan). 관찰에 기반하여 다음 행동을 결정한다. 누락된 정보를 어떻게 얻을지, 어떤 도구를 사용할지 계획한다.
행동(Act). 계획에 따라 실제 도구를 호출하거나 연산을 수행한다. 행동의 결과는 다음 관찰 단계의 입력이 된다.
논문마다 단계의 이름이 다를 수 있다. ReAct 원 논문은 Think-Observe-Act라는 용어를 사용한다. 고수준의 직관은 동일하다.
구체적 예시: 실내 온도 조절
사용자가 "내 테디베어가 추워하고 있어, 어떻게 해 줘"라고 요청했다고 하자.
루프 1:
단계 |
내용 |
|---|---|
관찰 |
사용자의 테디베어가 추워하고 있다. 현재 방의 온도가 알려져 있지 않다. |
계획 |
방의 현재 온도를 확인해야 한다. |
행동 |
|
루프 2:
단계 |
내용 |
|---|---|
관찰 |
현재 온도가 65°F로 예상보다 낮다. 온도를 올려야 한다. |
계획 |
온도를 5°F 올린다. |
행동 |
|
루프 종료 판단:
단계 |
내용 |
|---|---|
관찰 |
온도가 70°F로 적절하게 설정되었다. 목표가 달성되었다. |
출력 |
"온도를 5°F 올려 70°F로 설정했습니다. 테디베어가 이제 더 따뜻할 거예요!" |
핵심은 LLM이 매 루프마다 목표 달성 여부를 판단한다는 것이다. 목표가 달성되면 루프를 탈출하고 최종 응답을 생성한다.
사용자 질의
↓
┌─→ 관찰(Observe): 현재 상황 해석
│ ↓
│ 계획(Plan): 다음 행동 결정
│ ↓
│ 행동(Act): 도구 호출 / 연산 수행
│ ↓
│ 목표 달성? ──No──┐
│ │
└─────────────────────┘
│Yes
↓
최종 응답 생성
다중 에이전트와 Agent-to-Agent 프로토콜
하나의 시스템에 여러 에이전트가 공존할 수 있다. 온도 조절 에이전트, 에너지 관리 에이전트, 공기 질 에이전트 등이 독립적으로 작동하면서 서로 통신할 수 있다. 각 에이전트는 고유한 추론 루프를 가지며, 다른 에이전트와는 입출력으로만 소통한다.
이러한 에이전트 간 통신을 표준화하기 위해 Google이 Agent-to-Agent(A2A) 프로토콜을 2025년 초에 발표했다. 이 프로토콜에서 각 에이전트는 자신이 제공하는 스킬(skill) 목록을 노출하고, 다른 에이전트의 요청을 실행하거나 취소하는 표준 메서드를 구현한다. MCP가 LLM과 도구 사이의 프로토콜이라면, A2A는 에이전트와 에이전트 사이의 프로토콜이다.
7.12 안전성 고려사항
에이전트와 도구 호출은 LLM에 강력한 능력을 부여하지만, 동시에 새로운 안전 위험을 야기한다. 외부 세계에 실제로 행동을 취할 수 있는 시스템은 악용될 경우 심각한 결과를 초래할 수 있다.
주요 위험
데이터 유출(Data Exfiltration). 이메일 발송 도구에 접근할 수 있는 에이전트가 프롬프트 인젝션을 통해 사용자의 비밀번호나 개인정보를 외부로 전송하도록 조작될 수 있다.
무단 행동 실행. 에이전트가 사용자의 의도와 다른 행동을 취할 수 있다. 파일 삭제, 금융 거래 등 되돌릴 수 없는 행동이 특히 위험하다.
오류 전파. 에이전트의 추론 루프에서 한 단계의 실수가 이후 모든 단계에 전파된다. 도구 호출의 인자 예측이 잘못되거나, 결과 해석이 잘못되면 전체 작업이 실패한다. 이것이 현재 대규모 에이전트가 아직 보편화되지 않은 주요 이유다.
완화 전략
훈련 단계 방어. SFT와 강화학습 데이터에 안전성 관련 예시를 포함한다. 무해성(harmlessness) 보상을 훈련 목표에 반영한다.
추론 단계 방어. 안전성 분류기(safety classifier)를 배치하여 대화 내용을 실시간으로 모니터링하고, 위험한 출력을 차단한다.
벤치마크. ToolSword와 AgentSafetyBench 같은 벤치마크가 도구 사용 및 에이전트 시나리오에서의 안전 위험을 체계적으로 평가한다.
실제 사례로, 2025년 Anthropic은 Claude의 도구 및 에이전트 기능을 악용한 대규모 사이버 공격의 표적이 되었음을 공개하고, 공격 과정과 방어 조치를 상세히 보고했다. 이는 에이전트 안전성이 이론적 문제가 아니라 현실적 위협임을 보여준다.
7.13 실무 조언
에이전트 시스템을 구축할 때의 실질적 지침은 다음과 같다.
작게 시작하라. 가장 단순한 단일 도구 사용 사례부터 시작한다. 예를 들어 "근처 매장 찾기"처럼 명확한 입출력을 가진 도구 하나를 완벽히 작동시킨 뒤 확장한다.
강한 모델로 시작하라. 가장 능력이 뛰어난 모델로 먼저 구현하여 달성 가능한 성능의 상한을 파악한다. 그 후에 더 작고 빠른 모델로 최적화한다.
추론 과정을 관찰하라. LLM은 추론 체인을 출력한다. 에이전트가 잘못된 결과를 낸다면, 각 루프의 관찰-계획-행동 출력을 검토하여 어느 단계에서 문제가 발생했는지 진단한다.
핵심 정리
개념 |
핵심 |
|---|---|
지식 컷오프 |
모든 LLM에 존재. 추가 훈련 대신 외부 정보 주입으로 해결 |
Needle-in-a-Haystack |
긴 프롬프트에서 정보 검색 능력 저하. 관련 정보만 선별 필요 |
RAG 3단계 |
Retrieve → Augment → Generate. 검색 품질이 전체 성능 결정 |
청킹 |
~500 토큰 단위, 100~200 토큰 겹침. 문서 구조 고려 필요 |
바이 인코더 (SBERT) |
질의·문서 각각 독립 인코딩 → 코사인 유사도 비교. 빠름 |
ANN |
대규모 지식 베이스에서 근사 최근접 이웃 검색. FAISS 등 |
BM25 |
키워드 겹침 기반 휴리스틱 점수. 의미 유사도와 상호 보완 |
HyDE |
질의 대신 가상 문서를 생성하여 임베딩. 질의-문서 형태 불일치 완화 |
컨텍스트 검색 |
각 청크에 문맥 요약 추가. 프롬프트 캐싱으로 비용 절감 |
크로스 인코더 |
질의+문서를 함께 인코딩. 어텐션 상호작용으로 정밀 순위 조정 |
NDCG |
\(\text{DCG}@K / \text{IDCG}@K\). 관련 문서의 상위 배치를 평가 |
MRR |
첫 관련 문서의 역순위 평균. 단순하지만 효과적 |
도구 호출 |
2단계: 인자 예측 → 함수 실행 → 결과 해석. SFT 또는 프롬프트로 훈련 |
MCP |
Anthropic 표준. 도구를 모델에 노출하는 프로토콜 |
ReAct |
관찰-계획-행동 루프. 목표 달성까지 반복. 에이전트의 핵심 구조 |
에이전트 안전성 |
데이터 유출·오류 전파 위험. 훈련+추론 양면 방어 필요 |
다음 장: 8장 - LLM 평가