RAG 시스템 구축하기 — 도구 사용 (Tool Use): LLM이 자율적으로 검색하게 만들기
요약
RAG 시스템에 도구 사용(Tool Use) 기능을 도입하여 LLM이 자율적으로 검색 여부와 쿼리를 결정하는 방법을 설명합니다. 단순 하드코딩된 흐름을 넘어 에이전틱 루프를 통해 다중 도구를 활용하는 단계를 다룹니다.
핵심 포인트
- 도구 사용을 통해 LLM이 검색 필요성을 스스로 판단 가능
- 함수 시그니처와 설명을 활용한 프롬프트 엔지니어링의 중요성
- 단일 도구에서 다중 도구, 에이전틱 루프로 발전하는 단계적 구현
- 질문의 성격에 따라 검색 없이 직접 답변하거나 여러 번 검색 수행 가능
이전 기사에서 우리는 RAG 파이프라인 뒤에 숨겨진 설계 결정 사항들을 살펴보았습니다. 이제 우리는 LLM에게 검색 함수를 자율적으로 호출할 수 있는 능력을 부여할 것입니다. 이것이 바로 도구 사용 (Tool Use) 입니다.
도구 사용(Tool Use)으로 무엇이 변하는가
지금까지의 RAG 파이프라인에서는 답변을 생성하기 전에 항상 search()를 호출했습니다. 흐름은 다음과 같이 하드코딩되어 있었습니다:
질문 → search() → generate_answer()
도구 사용 (Tool Use)을 도입하면, LLM이 검색을 할지, 무엇을 검색할지, 그리고 답변을 하기에 충분한 정보가 모였는지를 스스로 결정합니다:
질문 → LLM이 결정 → 필요 시 search() → LLM이 결정 → 답변
이는 다음과 같은 상황에서 중요합니다:
- 질문이 검색(retrieval) 없이도 이미 답변 가능한 경우
- 적절한 검색 쿼리(search query)가 사용자의 질문과 다른 경우
- 서로 다른 쿼리로 여러 번 검색을 수행할 때 답변의 질이 향상되는 경우
도구 사용(Tool Use)의 작동 원리
LLM에게는 시그니처(signature)와 설명이 포함된 사용 가능한 함수 목록이 제공됩니다. LLM은 다음 중 하나로 응답합니다:
function_call— "이 인자들을 사용하여 이 함수를 호출하세요"- 텍스트 답변 — "직접 답변하기에 충분한 정보를 가지고 있습니다"
여러분의 코드는 함수 호출을 실행하고 그 결과를 다시 보냅니다. 그러면 LLM은 다른 함수를 또 호출할지, 아니면 최종 답변을 생성할지를 결정합니다.
사용자 → LLM: "사용 가능한 도구 목록 + 사용자 질문"
LLM → 사용자: function_call { name: "search_documents", args: { query: "F1 score" } }
사용자 → execute search_documents("F1 score") 실행 → 결과 반환
...
1단계: 기본 도구 사용 — 06_tool_basic.py
# 06_tool_basic.py
import psycopg2
from google import genai
...
python 06_tool_basic.py
# 질문: F1 score를 어떻게 계산하나요?
# → LLM 호출: search_documents({'query': 'F1 score calculation'})
...
LLM은 언제 검색을 해야 하고 언제 하지 말아야 하는지를 정확하게 결정합니다.
2단계: 다중 도구 — 07_tool_multi.py
이제 LLM에게 두 가지 도구를 제공합니다. 하나는 일반 검색용이고, 다른 하나는 카테고리 필터링 검색용입니다. LLM은 질문에 따라 적절한 도구를 선택합니다.
# 07_tool_multi.py (주요 추가 사항)
def search_by_category(query: str, category: str, top_k: int = 3) -> list[dict]:
...
설명(description)이 곧 라우팅 로직입니다. LLM은 어떤 도구를 호출할지 결정하기 위해
description필드를 읽습니다. 각 도구를 언제 사용해야 하는지 명확하게 구분하는 설명을 작성하세요. 이것이 도구 선택을 위한 프롬프트 엔지니어링 (Prompt Engineering)입니다.
3단계: 에이전틱 루프 (Agentic Loop) — 08_tool_agent.py
도구 사용 (Tool Use)의 진정한 힘은 **에이전틱 루프 (agentic loop)**에 있습니다. LLM은 여러 도구를 순차적으로 호출하여, 최종 답변을 생성하기 전에 문맥 (context)을 쌓아 올릴 수 있습니다.
# 08_tool_agent.py
def dispatch(func_name: str, func_args: dict):
...
# 작업: ML 모델에 대해 사용 가능한 평가 지표는 무엇인가요?...
# [1단계] → search_by_category({'query': 'ML evaluation metrics', 'category': 'ML'})
...
에이전트는 서로 다른 쿼리로 두 번 검색하여 상호 보완적인 정보를 수집한 다음, 종합적인 답변을 합성해냈습니다.
핵심 패턴
대화 기록 (conversation history)은 에이전트의 메모리입니다. 각 도구 호출과 그 결과는 contents에 추가됩니다. LLM은 매 단계마다 전체 기록을 확인하며, 이를 통해 이미 무엇을 검색했는지와 여전히 무엇이 필요한지를 파악합니다.
dispatch()는 가교 역할을 합니다. 이는 함수 이름(LLM으로부터 전달된 문자열)을 실제 파이썬 (Python) 함수로 매핑합니다. 단순하고 포괄적으로 유지하세요. LLM이 호출할 수 있는 모든 도구는 반드시 여기에 등록되어 있어야 합니다.
description 필드가 라우팅을 수행합니다. 도구 설명에 시간을 투자하세요. 모호한 설명은 무작위적인 도구 선택으로 이어집니다. 정밀한 설명("카테고리가 명시적으로 언급되었을 때 이것을 사용하세요")은 거의 매번 정확한 라우팅을 이끌어냅니다.
추가된 내용
도구 사용 전:
하드코딩됨: 질문 → 검색 → 답변
...
다음 기사에서는 메모리, 계획 (planning), 그리고 여러 도구가 함께 작동하는 완전한 **AI 에이전트 (AI Agent)**를 구축해 보겠습니다.
전체 소스 코드: github.com/qameqame/pgvector-tutorial
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기