11. 도구 기반 에이전트
검색과 생성을 항상 실행하는 RAG와 달리 도구 기반 에이전트는 모델이 필요한 기능을 선택한다. 다만 선택은 모델의 역할이고 실제 실행은 프로그램의 역할이다. 이 구분을 따라가면 에이전트가 무엇을 했는지 추적하기 쉬워진다.
11.1 도구 하나를 가진 여행 정보 에이전트
먼저 여행 문서를 검색하는 도구 하나를 제공한다. 모델이 질문을 보고 검색을 요청하면 프로그램이 검색하고 그 결과를 돌려준다.
11.1.1 프로젝트 구성
도구 구현, 모델 설정, 상태와 그래프 구성을 구분한다. 개별 도구를 직접 호출해 확인할 수 있어야 모델의 선택 오류와 도구 자체의 오류를 나눌 수 있다.
예제는 실행 원리를 보여 주기 위한 작은 프로그램이다. 외부 호출의 시간 제한이나 인증, 입력 검증을 실제 서비스에서 생략해도 된다는 뜻은 아니다.
11.1.2 환경 변수
모델 API와 추적 서비스에 필요한 키를 실행 환경에서 읽는다. 없는 키와 잘못된 키를 구분해 오류를 드러내야 한다.
환경 변수의 이름과 실행 위치도 중요하다. IDE에서 실행할 때와 터미널에서 실행할 때 읽는 설정 파일과 작업 디렉터리가 다르면 다른 환경으로 동작할 수 있다.
11.1.3 여행 정보 저장소
여행 문서를 읽고 나눠 벡터 저장소를 만든다. 매 질문마다 전체 원문을 다시 내려받고 임베딩하면 불필요한 시간과 비용이 발생한다.
책은 공통 저장소 인스턴스를 재사용한다. 재사용과 영속화는 다른 성질이다. 한 프로세스에서 한 번 만들었다고 프로세스 재시작이나 원문 갱신까지 해결되지는 않는다.
11.2 도구 호출
11.2.1 Function calling에서 tool calling으로
모델의 응답이 자연어 문장뿐 아니라 도구 호출 요청을 포함할 수 있다. 함수명과 구조화된 인자를 반환하고 프로그램이 실행하는 방식이다.
도구의 종류와 제공자에 따라 실행 주체는 달라질 수 있다. 사용자 정의 함수는 보통 애플리케이션이 실행하고, 일부 제공자 내장 도구는 제공자 쪽에서 실행될 수 있다. 응답 프로토콜과 실행 경계를 구분해야 한다.
11.2.2 도구 정의
@tool 같은 구성을 사용하면 함수 이름, 설명과 인자 스키마를 모델에 제공할 수 있다. 모델은 함수 본문을 읽고 실행하는 것이 아니라 이 정의를 보고 선택한다.
설명에는 언제 사용하는지, 필요한 입력과 반환값이 무엇인지 들어가야 한다. “검색 도구”처럼 막연한 설명보다 “현재 저장된 여행 문서에서 장소와 교통 정보를 찾는 도구”가 범위를 드러낸다.
함수의 타입 힌트도 입력의 의미까지 전부 보장하지는 않는다. 문자열이라는 조건을 만족해도 존재하지 않는 장소나 허용 범위 밖의 경로일 수 있다. 실행 전에 업무 조건과 권한을 확인해야 한다.
11.2.3 모델에 바인딩
bind_tools는 모델 호출에 도구 정의를 연결한다. 이 시점에 도구 함수가 실제 실행되는 것은 아니다.
모델이 도구 호출을 지원하는지, 사용하는 API와 라이브러리가 그 응답을 어떻게 표현하는지 확인해야 한다. 도구를 등록했어도 모델은 호출 없이 자기 지식으로 답하려 할 수 있다.
11.2.4 에이전트 상태
기본 상태는 메시지 목록이다. 사용자 질문, 모델의 도구 호출 요청, 도구 결과와 최종 답이 순서대로 들어간다.
새 노드의 메시지를 목록에 합칠 reducer가 필요하다. 목록을 통째로 덮어쓰면 직전 도구 요청이나 사용자 질문을 잃을 수 있다.
동시에 여러 도구 요청이 생기면 각각을 구분할 호출 ID가 중요하다. 어떤 결과가 어떤 요청에 대응하는지 연결해야 모델이 다음 판단을 할 수 있다.
11.2.5 도구 실행
실행 노드는 모델의 마지막 메시지에서 호출 요청을 꺼낸다. 허용된 이름인지와 인자를 검증하고 해당 함수를 실행한 뒤, 결과를 ToolMessage로 만들어 요청 ID와 연결한다.
도구 결과가 “자료 없음”인지 “외부 서비스 실패”인지 구분해야 한다. 둘을 같은 빈 문자열로 바꾸면 모델이 실패한 조회를 정상적인 부재로 해석할 수 있다.
부작용이 있는 도구는 재시도를 더 신중히 다뤄야 한다. 조회는 다시 해도 되지만 예약이나 결제 요청은 중복 실행될 수 있다. 도구 호출 ID와 업무상의 중복 방지 키가 같은 의미인지도 확인해야 한다.
11.2.6 모델 노드
모델 노드는 현재 메시지와 지침을 보내 새 응답을 받는다. 결과에 도구 호출 요청이 있으면 실행 노드로, 더 이상 없으면 종료로 보낸다.
도구 호출과 자연어 내용이 함께 반환될 수도 있으므로 응답 전체를 단순 문자열이라고 가정하지 않는다. 스트리밍이라면 호출 인자가 여러 조각으로 도착할 수도 있다.
11.3 그래프 조립
시작점은 모델 노드다. 조건부 경로가 도구 요청 유무를 확인하고, 도구 실행 뒤에는 다시 모델로 돌아간다.

그림은 작은 구조지만 실제 모델 호출은 여러 번 생길 수 있다. 도구 호출을 결정하는 첫 응답과 도구 결과를 읽고 최종 답을 만드는 다음 응답은 다른 호출이다.
11.4 실행 구조
ReAct는 판단과 행동, 관측 결과를 반복해서 사용하는 패턴이다. 이 구현에서는 메시지에 나타난 도구 요청과 실행 결과를 통해 반복을 확인할 수 있다.
모델이 내놓는 설명을 내부 사고의 완전한 기록처럼 취급할 필요는 없다. 실제로 검증할 수 있는 것은 어떤 도구를 어떤 인자로 요청했고 프로그램이 무엇을 실행해 어떤 결과를 받았는지다.
종료 조건도 필요하다. 모델이 계속 같은 도구를 호출하면 반복 횟수와 시간, 비용 예산으로 중단할 수 있어야 한다. 중단한 상태를 최종 답변 완료와 구분한다.
11.5 REPL
REPL은 입력을 읽고 실행하고 결과를 보여 주는 반복 인터페이스다. 콘솔에서 사용자의 질문을 받아 메시지로 만들고 그래프 결과를 출력한다.
반복 인터페이스가 있다고 이전 대화가 저장되는 것은 아니다. 매번 새 상태로 호출하면 각 질문은 독립적이다. 대화 이력과 체크포인트는 따로 연결해야 한다.
11.6 요청 하나 따라가기
11.6.1 단계별 디버깅
한 요청에서 최소한 다음 항목을 확인할 수 있어야 한다.
| 위치 | 확인할 내용 |
|---|---|
| 입력 | 실제 사용자 질문과 system 지침 |
| 모델 응답 | 호출한 도구 이름과 인자, 호출 ID |
| 실행 노드 | 어떤 함수가 실제 실행됐는지 |
| 도구 결과 | 원문, 값과 오류 상태 |
| 다음 모델 호출 | 도구 결과가 올바른 역할과 ID로 들어갔는지 |
| 종료 | 최종 답인지 예산 초과나 실패인지 |
도구를 실행하지 않았는데 답이 나왔다면 모델이 추측했을 수 있다. 반대로 도구를 실행했어도 결과를 잘못 사용하면 답이 틀릴 수 있다. 도구 사용률 자체가 정답률은 아니다.
11.7 날씨 도구 추가
11.7.1 모의 날씨 서비스
책은 처음에 임의의 날씨와 온도를 반환하는 모형을 사용한다. 목적은 현재 날씨의 정확성을 확인하는 것이 아니라 도구 선택과 여러 호출의 흐름을 관찰하는 것이다.
모의 데이터를 실제 관측값처럼 해석하면 안 된다. 테스트를 반복 가능하게 하려면 무작위 결과보다 고정된 응답을 사용하는 경우도 유용하다.
11.7.2 날씨 도구
도구는 장소를 받아 해당 장소의 조건과 온도를 반환한다. 장소를 찾을 수 없는 경우와 서비스가 실패한 경우를 구분한다.
실제 서비스로 바꾸면 날짜와 시간대, 온도 단위, 현재 관측과 예보의 차이도 필요하다. “날씨가 좋다”는 판단에는 어떤 시간과 기준을 사용했는지 드러나야 한다.
11.7.3 여러 도구 등록
여행 검색과 날씨 도구를 모델에 함께 등록한다. 그래프의 기본 루프는 유지하면서 모델이 도구를 선택할 수 있다.
그러나 도구 수가 늘면 역할이 겹치거나 입력을 잘못 전달하는 경우도 늘어난다. 도구 설명과 출력 규격을 명확히 하고 조합 요청을 따로 시험해야 한다.
11.8 여러 도구 실행
11.8.1 초기 동작
모델은 “좋은 날씨의 해안 마을”을 묻는 질문에 관광지를 자기 지식으로 정하고 날씨만 조회할 수 있다. 그러면 저장된 여행 자료를 사용한다는 의도가 지켜지지 않을 수 있다.
도구를 제공하는 것과 반드시 근거로 사용하게 만드는 것은 다르다. 실제 트레이스에서 어떤 단계를 생략했는지 확인해야 한다.
11.8.2 System 지침 보완
장소는 여행 검색 도구에서 찾고, 날씨는 날씨 도구로 확인하도록 지침과 설명을 구체화한다. 호출 순서를 반드시 지켜야 하는 요구라면 그래프에서도 그 순서를 강제할 수 있다.
자연어 지침은 동작을 유도하지만 권한이나 강제 정책의 대체물이 아니다. 외부 행동의 허용 범위는 실행 코드에서 검사해야 한다.
11.9 사전 구성 에이전트
11.9.1 기본 루프 재사용
책은 수동으로 만든 도구 실행 루프를 사전 구성 ReAct 에이전트로 바꾼다. 반복 코드가 줄어들지만 어떤 상태 스키마와 종료 규칙을 사용하는지 이해해야 한다.
사전 구성 에이전트의 생성 함수와 import 경로는 버전에 따라 달라질 수 있다. 책의 API와 현재 LangChain, LangGraph 문서의 권장 API를 섞지 않는다.
11.9.2 실행 결과
자연어 문자열뿐 아니라 텍스트 블록 등 구조화된 응답이 나올 수 있다. 화면에 출력할 본문과 추적할 메타데이터를 분리한다.
추상화를 바꾼 뒤에는 이전과 같은 입력으로 도구 선택과 최종 결과가 유지되는지 비교해야 한다. 코드가 짧아졌다는 사실은 기능 동등성의 증거가 아니다.
11.9.3 LangSmith 관측
프레임워크 내부 루프를 직접 디버깅하기 어려울 때 트레이스로 모델과 도구 호출을 연결한다. 결과가 어느 도구의 값에 의존했는지와 어디서 시간이 걸렸는지 볼 수 있다.
11.9.4 추적 설정
추적 프로젝트와 인증 정보를 설정한 뒤 실제 요청이 기록되는지 확인한다. 기록이 활성화되면 사용자 질문과 도구 결과도 외부 추적 시스템에 전송될 수 있다.
민감한 입력을 무조건 모두 남기지 않고 수집 범위와 접근 권한, 보존 정책을 정한다. 관측을 위해 정보를 모으는 일에도 데이터 경계가 필요하다.
질문
도구를 바인딩하면 함수가 바로 실행되는가?
정의만 모델 호출에 전달된다. 실제 호출 요청을 받아 검증하고 실행하는 과정은 별도로 필요하다.
도구를 항상 호출하게 만들면 답의 정확성이 보장되는가?
검색 결과가 틀리거나 인자와 해석이 잘못될 수 있다. 선택, 실행 결과, 최종 답을 각각 확인해야 한다.