포스트

스스로 “검색→판단→재검색→검증”까지 도는 Agentic RAG 자율 에이전트, 2026년 1월 기준 구현 패턴

스스로 “검색→판단→재검색→검증”까지 도는 Agentic RAG 자율 에이전트, 2026년 1월 기준 구현 패턴

들어가며

기존 RAG는 “질문 1회 → 벡터 검색 1회 → 답변 1회”의 정적 파이프라인이 많습니다. 하지만 실무 질문은 대개 모호하거나(용어 불일치), 여러 출처를 교차 확인해야 하고(정책/규정/버전), 검색 결과가 노이즈로 오염되기도 합니다. 그래서 2025~2026 흐름에서는 Agentic RAG—즉, LLM이 언제 검색할지, 어떻게 쿼리를 바꿀지, 검색이 실패하면 어떻게 복구할지를 루프 안에서 자율적으로 결정하는 방식이 빠르게 주류가 되고 있습니다. Microsoft TechCommunity는 이를 “정적 RAG의 진화”로 정의하며, 에이전트가 retrieval 여부 판단·전략 조정·도구 오케스트레이션·반복적 개선을 수행한다고 정리합니다. (techcommunity.microsoft.com)

또한 2026년 1월 arXiv의 RAGShaper는 “현실적 검색 환경(노이즈/방해문서)에서 에이전트가 오류 수정과 noise rejection을 학습해야 한다”는 문제를 정면으로 다룹니다. 즉, Agentic RAG는 이제 단순 기능이 아니라 견고성(robustness)의 게임이 되고 있습니다. (arxiv.org)


🔧 핵심 개념

주요 개념 정의

  • Agentic RAG: RAG 파이프라인 내부에 Planner/Controller 역할의 agent loop를 넣어, 검색·재검색·요약·검증을 상황에 따라 반복하는 패턴. (필요 없으면 검색을 건너뛰고, 부족하면 더 찾는 구조) (techcommunity.microsoft.com)
  • Autonomous retrieval loop: (1) 사용자 질문 해석 → (2) 검색 계획 수립 → (3) tool 호출(벡터/키워드/웹/DB) → (4) 근거 평가 → (5) 부족하면 쿼리 변형/범위 확장 → (6) 최종 답 생성.
  • Context Provider / Retrieval Tool: 에이전트가 호출하는 검색 인터페이스. Microsoft Agent Framework는 AI Context Provider를 붙여 agent에 RAG를 주입하는 방식을 제공하며, TextSearchProvider 같은 기본 구현을 소개합니다. (learn.microsoft.com)
  • Multi-agent orchestration(선택): retrieval, rerank, summarize, critique를 분리한 여러 에이전트를 두고 planner가 조합하는 형태. 2025 논문 MAO-ARAG는 planner가 workflow를 동적으로 선택해 품질과 비용을 균형화하는 방향을 제안합니다. (arxiv.org)

어떻게 작동하는지 (실무적으로 중요한 포인트)

  1. Retrieve or not 결정: 질문이 “정의/상식”인지 “사내 문서/최신 정책”인지 구분. (불필요한 retrieval은 비용/지연만 증가)
  2. Query rewriting: 첫 검색이 부정확하면 에이전트가 쿼리를 좁히거나 넓혀 재시도(동의어, 제품명/버전, 날짜 범위).
  3. Grounding & attribution: 답변에 인용 가능한 evidence를 유지. RAG가 hallucination을 줄이고 감사 가능성을 올린다는 점은 Microsoft에서도 반복 강조됩니다. (microsoft.com)
  4. Failure recovery: 노이즈가 많은 결과에서 “그럴듯하지만 틀린” 문장을 걸러내는 루프가 핵심인데, RAGShaper가 바로 이 지점을 데이터/학습 관점에서 강조합니다. (arxiv.org)

💻 실전 코드

아래는 “planner(LLM) + retriever(tool) + evaluator(충분성 판단)”의 최소 Agentic RAG 루프 예제입니다. 특정 프레임워크에 종속되지 않게 Python 표준 + (선택) OpenAI/임의 LLM 클라이언트 형태로 구성했습니다. 실제 배포에서는 Microsoft Agent Framework의 Context Provider 개념처럼 “에이전트에 RAG 공급자”를 붙이는 방식으로 확장하면 됩니다. (learn.microsoft.com)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# language: python
# Agentic RAG minimal loop (framework-agnostic)
# - 로컬 문서(또는 사내 위키 dump)를 BM25 + 간단 임베딩(대체 가능)으로 검색한다고 가정
# - 핵심은 "retrieve 여부 결정 + 반복 검색 + 충분성 평가" 루프

from dataclasses import dataclass
from typing import List, Dict, Tuple
import re

@dataclass
class Doc:
    doc_id: str
    text: str

# --- 1) Retriever (여기선 매우 단순: 키워드 매칭 점수)
def retrieve(query: str, corpus: List[Doc], k: int = 5) -> List[Doc]:
    q_tokens = set(re.findall(r"[A-Za-z0-9_.-]+", query.lower()))
    scored: List[Tuple[int, Doc]] = []
    for d in corpus:
        d_tokens = set(re.findall(r"[A-Za-z0-9_.-]+", d.text.lower()))
        score = len(q_tokens & d_tokens)
        if score > 0:
            scored.append((score, d))
    scored.sort(key=lambda x: x[0], reverse=True)
    return [d for _, d in scored[:k]]

# --- 2) "LLM" Stub: 실제로는 OpenAI/Claude/Azure OpenAI 등으로 교체
# 여기서는 구조만 보여주기 위해 rule-based로 흉내냅니다.
def llm_plan(user_question: str, last_context: str, attempt: int) -> Dict:
    """
    반환 예:
    {
      "action": "retrieve" | "answer" | "clarify",
      "query": "...",              # action=retrieve일 때
      "note": "why",
    }
    """
    # 1차엔 원 질문으로 검색, 2차엔 키워드 강화(예: 'implementation', 'architecture' 추가)
    if attempt == 0:
        return {"action": "retrieve", "query": user_question, "note": "need grounding"}
    if attempt == 1:
        return {"action": "retrieve", "query": user_question + " implementation architecture pitfalls", "note": "refine query"}
    # 2번 검색했는데도 근거가 빈약하면 사용자에게 추가 조건을 요구
    if len(last_context.strip()) < 200:
        return {"action": "clarify", "query": "", "note": "insufficient evidence"}
    return {"action": "answer", "query": "", "note": "enough evidence"}

def llm_answer(user_question: str, evidence: str) -> str:
    # 실제에선: evidence 기반으로 요약/인용/제약(출처, 날짜) 포함해 답변 생성
    return (
        "최종 답변(요약):\n"
        f"- 질문: {user_question}\n"
        "- 핵심은 planner가 검색 여부/재검색을 결정하고, evidence 품질을 평가하면서 루프를 도는 것입니다.\n"
        "- 아래는 수집된 근거 일부:\n"
        + evidence[:800]
    )

def is_sufficient(evidence_docs: List[Doc]) -> bool:
    # 충분성 평가: (1) 문서 수, (2) 겹치는 키워드 다양성, (3) 길이 등
    total_len = sum(len(d.text) for d in evidence_docs)
    return len(evidence_docs) >= 3 and total_len >= 800

def agentic_rag(user_question: str, corpus: List[Doc], max_iters: int = 3) -> str:
    evidence_docs: List[Doc] = []
    for attempt in range(max_iters):
        context = "\n\n".join([f"[{d.doc_id}] {d.text}" for d in evidence_docs])

        plan = llm_plan(user_question, context, attempt)

        if plan["action"] == "retrieve":
            new_docs = retrieve(plan["query"], corpus, k=5)
            # 중복 제거
            seen = {d.doc_id for d in evidence_docs}
            for d in new_docs:
                if d.doc_id not in seen:
                    evidence_docs.append(d)

            # 충분하면 바로 답 생성(루프 조기 종료)
            if is_sufficient(evidence_docs):
                break

        elif plan["action"] == "clarify":
            return (
                "추가 질문이 필요합니다:\n"
                "- 대상 데이터 소스(사내 문서/웹/논문)와 최신성 요구(예: 2026-01 기준)를 알려주세요.\n"
                "- 답변 형식(설계/코드/운영 팁)과 제약(비용/지연/보안)도 지정하면 더 정확합니다."
            )
        else:  # answer
            break

    evidence = "\n\n".join([f"[{d.doc_id}] {d.text}" for d in evidence_docs])
    return llm_answer(user_question, evidence)

if __name__ == "__main__":
    # 데모 코퍼스(실무에선 사내 문서/정책/SDK 문서/ADR 등)
    corpus = [
        Doc("doc1", "Agentic RAG introduces an agent that decides when/how/what to retrieve and iteratively refines the answer."),
        Doc("doc2", "Robustness requires handling noisy retrieval results, rejecting distractors, and performing error correction loops."),
        Doc("doc3", "A context provider pattern attaches retrieval capability to an agent; tools expose search over text or vector stores."),
        Doc("doc4", "Multi-agent orchestration can separate planner, retriever, reranker, and critic to balance cost and quality."),
        Doc("doc5", "Best practice: keep citations, track retrieved snippets, and stop early when evidence is sufficient."),
    ]

    print(agentic_rag("How to implement an Agentic RAG autonomous retrieval agent?", corpus))

이 코드의 의도는 “정답 생성”이 아니라 구조입니다. 실전에서는 llm_plan, llm_answer, is_sufficient를 모델 호출/스코어러/guardrail로 바꾸고, retriever를 vector DB + reranker로 교체하면 됩니다. AutoGen의 RetrieveUserProxyAgent처럼 retrieval 전용 agent를 두는 방식도 동일한 패턴의 구현체라고 보면 됩니다. (microsoft.github.io)


⚡ 실전 팁

  • Stop condition을 명확히: “근거 문서 N개 + 총 토큰/길이 + 출처 다양성 + 최근 날짜 포함” 같은 조건이 없으면 에이전트가 불필요하게 재검색을 반복합니다(비용 폭발).
  • Query rewriting을 ‘정책화’: 무작정 “더 찾아봐”가 아니라, 1) 좁히기(버전/날짜/제품명) 2) 넓히기(동의어/약어/관련 키워드) 3) 다른 소스(웹→내부문서→API) 순서를 룰로 둡니다. TechCommunity가 말하는 “retrieve 전략을 동적으로 관리”를 운영 가능한 형태로 만드는 작업입니다. (techcommunity.microsoft.com)
  • Noise rejection은 선택이 아니라 필수: 2026년 1월 RAGShaper가 강조하듯 “retrieval 실패/방해문서”는 현실 기본값입니다. reranker, source trust score, contradiction check(간단한 NLI나 self-consistency)를 최소 1단 넣어야 합니다. (arxiv.org)
  • Framework 선택 기준
    • 팀이 멀티 에이전트 대화/오케스트레이션이 필요하면 AutoGen 계열(예: retrieval agent 구성)이 빠릅니다. (microsoft.github.io)
    • “에이전트에 RAG를 플러그인” 같은 엔터프라이즈 패턴은 Microsoft Agent Framework의 Context Provider 모델이 깔끔합니다. (learn.microsoft.com)
    • 문서 중심 워크플로우(추출→교차검증→리포트)는 LlamaIndex의 agentic 전략/워크플로우 접근이 잘 맞습니다. (docs.llamaindex.ai)

🚀 마무리

Agentic RAG의 핵심은 “RAG에 LLM을 붙인다”가 아니라, LLM이 retrieval을 운영하는 루프(계획-검색-평가-복구)를 설계하는 것입니다. 2026년 1월 기준 흐름을 한 문장으로 요약하면: 정적 RAG 최적화만으로는 부족하고, 실패를 전제로 한 자율 루프와 견고성 메커니즘이 경쟁력이 된다입니다. (techcommunity.microsoft.com)

다음 학습 추천:

  • (실무 구현) Context Provider / Tool 기반으로 “retrieve loop + stop condition + citation”부터 고정
  • (고급) multi-agent planner(워크플로우 선택), reranker/critic, contradiction check 추가
  • (연구 관점) 노이즈 환경에서의 robust agent 학습(RAGShaper/MAO-ARAG 류) 트렌드 따라가기 (arxiv.org)
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.