에이전트 RAG를 작은 모델로 짜는 법: 도구 선택은 코드가, 답은 모델이
에이전트 RAG라는 말을 처음 들었을 때 떠올린 그림은, 모델이 스스로 판단해 도구를 부르는 거였습니다. "이 질문은 검색을, 이 질문은 DB 조회를" 모델이 결정하고, 그 결과를 받아 다시 답을 쓰는 구조. 그런데 막상 작은 로컬 모델로 이걸 짜려니 한 가지가 걸렸습니다. 도구를 고르는 결정을 모델에게 맡길 수가 없었습니다. 작은 모델은 이 질문이 검색을 필요로 하는지, DB 직조회로 끝나는지 자주 틀렸습니다.
그래서 택한 길이 있습니다. 도구를 고르는 건 코드가 하고, 모델은 주어진 결과를 읽고 답만 씁니다. 이 글은 그 "가벼운 에이전트" 구조를 어떻게 짰는지 적은 겁니다.
도구 선택을 모델에게 맡기면 생기는 일
정석적인 에이전트는 모델이 function calling으로 도구를 부릅니다. 모델이 질문을 보고 "이건 검색 도구를 써야겠다", "이건 재고 조회 도구를 써야겠다" 결정하죠. 큰 모델(GPT-4, Claude)이면 이 결정이 믿을 만합니다.
그런데 제가 쓰는 qwen 35B 같은 모델에게 맡기면, 결정이 흔들립니다. 분명히 재고 질문인데 RAG를 부르거나, 문서 질문인데 DB를 찌릅니다. 도구를 잘못 고르면 그 뒤는 다 틀립니다. 검색이 빈 결과를 가져와 답이 텅 비거나, DB에 없는 걸 찾느라 에러가 납니다.
결국 도구 선택의 정확도가 전체 정확도를 지배한다는 걸 알게 됐습니다. 그리고 그 정확도를 작은 모델에게 기대긴 어려웠습니다. 그래서 이 결정만큼은 코드에게 맡기기로 했습니다.
코드가 인텐트를 판별하고 도구를 고른다
질문이 들어오면 가장 먼저 코드가 인텐트를 판별합니다. 정규식과 단어 사전으로, 이 질문이 재고 조회인지, 지식 질문인지 가립니다. 재고 질문이면 RAG(생성)를 건너뛰고 Prisma로 직접 DB를 찌릅니다. 지식 질문이면 RAG로 넘어갑니다.
판별 규칙은 단순합니다. "뭐 있어", "목록", "표로", "재고", "수량" 같은 단어가 있으면 목록 조회 인텐트로 봅니다. "방법", "어떻게", "왜", "비교" 같은 단어가 있으면 지식 질문으로 봅니다. 그리고 "어디 있어" 같은 물건 위치 질문은 또 다른 도구(이름 검색)로 보냅니다.
이 판별은 모델보다 정확합니다. 단어가 들어있으면 그 인텐트인 게 거의 확실하기 때문입니다. 모델은 문맥을 해석하다 엇나가지만, 정규식은 안 엇나갑니다. 작고 확실한 규칙이 크고 흔들리는 모델보다 나은 자리가 있습니다.
찾기는 좁게, 읽기는 넓게
RAG로 넘어간 뒤에도 에이전트적 결정이 들어갑니다. 검색은 청크 단위로 합니다. 청크가 짧을수록 임베딩이 한 가지 뜻만 담아 정확합니다. 그런데 답변에 넣을 때도 그 짧은 크기 그대로면, 근거가 문장 몇 줄뿐이라 모델이 무슨 얘기 중이었는지를 모릅니다. 표의 헤더, 절차의 앞 단계, 조건문의 전제가 죄다 옆 청크에 있습니다.
그래서 "찾기는 좁게, 읽기는 넓게"로 나눴습니다. 검색은 짧은 청크로 정확하게 하고, 답변에 넣을 때는 고른 청크의 앞뒤를 한 칸씩 붙입니다. 코드 주석에 적은 대로, "검색 정확도는 건드리지 않고 근거량만 늘리는 방법이라 재색인이 필요 없다."
이게 에이전트의 한 축입니다. "검색하라"는 한 번의 도구 호출이 아니라, 검색 → 선별 → 확장의 여러 단계로 이루어진 파이프라인이고, 각 단계를 코드가 조율합니다. 모델은 마지막에 확장된 근거를 받아 답만 씁니다.
쿼리 재작성: 후속 질문을 독립 검색어로
후속 질문이 들어올 때도 코드가 개입합니다. "그럼 그건 얼마야?" 같은 질문은 그대로 임베딩하면 검색이 엉뚱한 곳을 짚습니다. "그건"이 뭔지 모르니까요. 이걸 임베딩에 넘기기 전에, 이전 대화를 참고해 독립적인 검색 문장으로 바꿉니다.
이 재작성은 모델에게 맡깁니다. 단, 결괏값을 검사합니다. 작은 모델은 앞 답변을 그대로 베끼는 버릇이 있어서, 인용 번호나 "DB 수정일" 같은 답변 전용 표시가 들어있으면 그건 검색어가 아니라 답변 조각이니 버립니다. 원래 질문으로 검색합니다.
여기서 흥미로운 점은, 재작성은 "보조 장치"라는 태도입니다. 실패하면 원래 질문으로 검색해도 되니 오류를 위로 던지지 않습니다. 도구가 도움을 주면 좋고, 못 주면 없는 셈 치고 가는 구조. 에이전트가 도구 실패에 무너지지 않게 하는 방어입니다.
왜 이게 "에이전트"인가
정리하면, 이 시스템에서 모델이 직접 하는 일은 "주어진 근거를 읽고 답을 쓰는 것"뿐입니다. 도구 선택, 검색어 재작성, 결과 선별, 앞뒤 확장, 이 모든 결정은 코드가 내립니다. 그럼 이걸 에이전트라고 부를 수 있을까요?
저는 부른다고 봅니다. 에이전트의 본질은 "여러 도구를 상황에 따라 쓰고, 결과를 합쳐 답을 만드는 것"입니다. 그 본질은 코드가 다 하고 있습니다. 다만 그 "상황 판단"을 모델이 아니라 규칙이 하고, "결과 합성"의 마지막 단계만 모델에게 맡긴 겁니다.
이렇게 나눈 가장 큰 이유는 신뢰입니다. 작은 모델은 도구 선택을 자주 틀리지만, 주어진 텍스트를 읽고 답을 쓰는 일은 꽤 잘합니다. 즉 모델이 잘하는 일(읽고 쓰기)과 못하는 일(선택하기)을 가른 뒤, 잘하는 일만 남기는 구조입니다. 모델을 에이전트의 "판단부"에 두지 않고 "생성부"에만 둡니다.
한계와 남은 자리
이 구조의 한계는 분명합니다. 질문이 복잡해져서 "먼저 문서를 찾고, 그 안의 숫자를 DB에서 확인하고, 다시 문서로 돌아가 부연설명" 같은 여러 단계가 필요하면, 지금 구조로는 안 됩니다. 코드가 정해둔 분기(재고냐 지식이냐) 안에서만 움직이니까요. 진짜 다단계 추론(multi-step reasoning)이 필요한 순간이 오면, 결국 모델에게 판단을 맡기는 쪽으로 가야 합니다. 그때는 더 큰 모델을 쓰거나, 도구 호출을 위한 전용 모델을 따로 두는 수밖에 없습니다.
하지만 지금 제 질문의 대부분은 한 번의 도구 호출로 닿습니다. 재고면 DB, 지식이면 RAG. 그 사이에서 헷갈리는 복잡한 질문은 드뭅니다. 그래서 "코드가 도구를 고르고 모델은 답만 쓰는" 가벼운 구조가 지금은 가장 들어맞습니다.
에이전트 RAG를 "모델이 도구를 부르는 화려한 기술"로만 보면, 작은 로컬 모델에서는 무리하게 됩니다. 하지만 "도구 선택과 결과 합성의 파이프라인"으로 보면, 오늘 당장 코드로 짤 수 있고, 작은 모델로도 정확합니다. 화려함을 줄이고 신뢰를 늘리는 쪽이, 혼자 쓰는 시스템에는 더 맞았습니다.
함께 읽기
- RAG 운영: 전체 재색인을 피하고 캐시는 본 요청을 막지 않는 법처음 RAG를 짤 때는 문서를 고칠 때마다 전체를 다시 색인했습니다. 문서가 백 개쯤 될 때는 그래도 됐습니다. 잠깐 기다리면 끝났거든요. 그런데 문서가 천 개를 넘고, 거기에 재고 아이템까지 색인에 들어가니 얘기가 달라졌습니다. 전체를 다시 임베딩하면 수천 번 모델을 부르는 셈이고, 그 사이에 질문이 들어오면 답이 늦…
- 한국어 RAG에서 벡터만 쓰면 안 되는 이유: 하이브리드 검색 설계처음 RAG를 짤 때는 벡터 검색만 썼습니다. 코사인 유사도 하나로 충분할 줄 알았죠. 그런데 한국어 질문에서 이상한 일이 잦았습니다. 분명 문서에 있는 단어를 물었는데 검색이 안 됩니다. 비슷한 의미의 다른 문서만 계속 위에 뜹니다. 원인을 찾다 보니, 벡터 검색이 "의미가 비슷한가"는 잘 재는데 "그 단어가 실제로 …
- RAG 답변 품질을 메트릭 없이 지키는 법: 출처·임계값·방어 코드RAG 답변 품질을 재는 정량 프레임워크가 있습니다. RAGAS, TruLens 같은 도구가 답변의 충실도(faithfulness), 관련성, 맥락 적합성을 점수로 냅니다. 처음엔 이런 걸 달아야 하나 고민했습니다. 그런데 막상 혼자 쓰는 RAG를 짜고 보니, 정량 점수보다 답이 거짓말을 안 하게 만드는 "코드"가 먼저…
- 멀티모달 RAG의 현실: 모달을 섞지 않고 텍스트로 환원하는 이유멀티모달 RAG라는 말을 처음 들었을 때, 이미지를 임베딩해서 문서 텍스트와 같은 벡터 공간에 올리는 걸 상상했습니다. CLIP 같은 모델로 그림과 글을 하나의 공간에 두면, "이런 느낌의 다이어그램 찾아줘" 같은 질문도 답이 나올 것 같았죠.
- 문서 RAG에 재고 981건을 같이 색인한 방법: 구조화 데이터의 텍스트화RAG를 "문서 검색"이라고만 생각하면 놓치는 게 많습니다. 제가 실제로 자연어로 묻고 싶은 질문의 절반은 문서가 아니라 데이터베이스에 들어있는 구조화된 데이터에 대한 것이었습니다. "이 철제장에 뭐 있지", "이 브랜드 물건 중 정리 대기 걸린 건 뭐지", "유효기간 지난 거 있어?". 이런 건 문서로 안 적어둡니다.…