📚 Agentic AI - 기업용 자율 에이전트 개발 6장 · 에이전트 ④ RAG 문서검색 Agentic AI란

정리 & 체크리스트

한 줄 요약

에이전트 네 종류를 모두 만들었습니다. 1장에서 못 풀던 세 질문도 전부 풀렸습니다. 7장에서는 여기에 기억을 붙이고, 8장에서 하나의 팀으로 묶습니다.


1. 6장에서 만든 것

code/ch06_rag_agent.py에이전트 ④ RAG 문서검색

연결 대상 : 사내 문서 PDF (긴 글)
핵심 기술 : 임베딩 · 벡터검색
대표 질문 : "불량 상품 반품 기간이 며칠이죠?"
만든 것 하는 일
build_index() PDF → 조각 → 벡터 인덱스 (있으면 불러오기)
retriever 질문 → 관련 조각 4개
PROMPT "문서에 적힌 것만 근거로"
answer(question) 답변 + 출처
policy_tool 8장에서 쓸 도구 형태

2. 이 장의 핵심 내용 — 말로 설명할 수 있어야 할 것들

  1. 표에 든 숫자는 계산하고, 문서에 쓰인 문장은 검색해서 근거로 쓴다. 이 구분이 흐려지면 환각이다.
  2. 문서를 통째로 넣는 것은 양이 늘면 무너진다 — 비용 · 정확도 · 출처 세 가지 문제.
  3. RAG = 검색 + 증강 + 생성. 필요한 조각만 골라 프롬프트에 넣는다.
  4. 검색이 어려운 이유는 단어가 안 겹치기 때문이다. "반품"과 "청약철회"처럼.
  5. 임베딩은 문장을 숫자 목록(벡터)으로 바꾼다. 뜻이 비슷하면 숫자도 비슷하다.
  6. 비슷한 정도는 코사인 유사도로 잰다. 점수의 절대값이 아니라 순위를 본다.
  7. chunk_size 는 검색 정확도와 근거의 양 사이의 균형을 정한다. 기준은 "답 하나가 들어갈 만한 크기".
  8. chunk_overlap 은 문장이 경계에서 잘려도 뜻이 남게 하는 안전망이다.
  9. k 는 근거를 빠짐없이 찾는 것과 관련 없는 내용을 줄이는 것 사이의 균형을 정한다. 검색은 항상 k 개를 돌려준다 — "없다"고 말해 주지 않는다.
  10. 인덱스는 파일로 저장한다. 문서·chunk_size·임베딩 모델이 바뀌면 반드시 다시 만든다.
  11. 캐시의 함정 — 원본이 바뀌었는데 안 지우면 오류 없이 옛날 답이 나온다.
  12. "문서에 없으면 '찾을 수 없습니다'라고 답한다" 한 문장이 환각을 크게 줄인다.
  13. 검색에는 LLM이 안 쓰인다. LLM은 찾은 것을 문장으로 정리하는 데만 쓴다. 정확도의 대부분은 검색 단계에서 결정된다.
  14. 출처를 함께 보여 주면 사람이 검증할 수 있다. 마지막 방어선이다.
  15. create_retriever_tool 로 검색을 도구로 만들면 다른 도구와 함께 쓸 수 있다.
  16. 도구로 만들면 출처 표시가 사라진다. 되찾으려면 반환 문자열에 출처를 넣는다.

3. 체크리스트

  • [ ] python code/ch06_rag_agent.py 가 끝까지 돌아간다
  • [ ] 첫 실행과 두 번째 실행의 속도 차이를 확인했다
  • [ ] data/policy_index 폴더가 만들어진 것을 확인했다
  • [ ] 검색 결과만 따로 찍어 봤다 (LLM 없이)
  • [ ] "해외 배송"처럼 문서에 없는 질문에 "찾을 수 없다"고 하는 것을 확인했다
  • [ ] 답의 근거를 실제 PDF에서 대조해 봤다
  • [ ] CSV 분석과 RAG를 언제 쓰는지 설명할 수 있다

4. 진행 상황 — 네 종류 완성

[에이전트 네 종류]

  ✓ ① 사내 데이터 조회    3장   함수 도구
  ✓ ② 웹검색             4장   외부 API + ReAct 루프
  ✓ ③ CSV 데이터분석      5장   코드 생성·실행 + LangChain
  ✓ ④ RAG 문서검색        6장   임베딩 · 벡터검색

[1장에서 못 푼 세 질문]

  ✓ 사내 데이터   "주문 O001203은?"        → 3장
  ✓ 최신 정보     "요즘 시장 어때요?"       → 4장
  ✓ 사내 문서     "반품 며칠 이내?"        → 6장

1장에서 그린 지도를 다 채웠습니다.


5. 아직 남은 것 둘

① 대화가 이어지지 않는다

고객: P0003 스마트워치 재고가 얼마나 남았나요?
봇  : 3개 남았습니다.
고객: 그거 재주문 기준은요?
봇  : "그거"가 무엇인지 모르겠습니다.

지금까지 만든 네 에이전트는 전부 한 번 묻고 답하면 끝입니다.

2장에서 손으로 대화를 쌓아 봤죠. 실제 서비스에서는 손님이 수백 명이라 손님마다 기록을 따로 보관하고 꺼내 오는 일을 직접 짜야 합니다.

→ 7장에서 LangGraph가 이걸 대신합니다.

② 한 종류만으로는 답이 안 나오는 질문

"승승 스마트워치 Fit 5, 지금 어떻게 대응해야 할까요?"
  • CSV만 보면 → "재고 3개, 평점 3.8" 에서 끝
  • 문서만 보면 → "배터리 7일/18시간" 에서 끝
  • 웹만 보면 → "시장 동향" 에서 끝

셋을 나란히 놓아야 판단이 나옵니다.

→ 8장에서 하나의 팀으로 묶습니다.


6. 7장 예고 — 기억을 붙입니다

7장에서는 LangGraph 로 넘어갑니다.

아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.

from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver

chatbot = graph.compile(checkpointer=InMemorySaver())

핵심은 세 가지입니다.

개념 무엇 2장으로 치면
상태(State) 계속 들고 다니는 값 history 리스트
노드(node) 상태를 받아 일을 하는 함수 chat_multi()
체크포인터 상태를 자동 저장 history.append(...)

그리고 thread_id 로 손님을 구분합니다.

아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.

chatbot.invoke({"messages": [...]}, {"configurable": {"thread_id": "손님-오지우"}})

2장에서 손으로 하던 일을 라이브러리에게 넘기는 장입니다. 그래서 2장에서 일부러 손으로 해 봤습니다.

그리고 5장에서 만든 CSV 에이전트에 기억을 붙이면 — 한 줄입니다.

아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.

create_agent(llm, tools=[run_pandas], system_prompt=SYSTEM,
             checkpointer=InMemorySaver())      # ← 이 한 줄
손님: P0003 스마트워치 재고가 얼마나 남았나요?
봇  : P0003 스마트워치 재고는 3개 남았습니다.
손님: 그거 재주문 기준은요?
봇  : P0003 스마트워치의 재주문 기준은 30개입니다.
손님: 그럼 지금 발주해야 하나요?
봇  : 네, 발주해야 합니다.

"그거"가 통합니다.

← 이전 절09. CSV 분석과 RAG 무엇을 언제 쓰나