오늘 배운 것만으로 — 첫 RAG 를 완성한다
박수현 · (사)한국정보공학기술사회 · 2026
embed() — 문장 → 벡터cosine() — 유사도search() — Top-K 검색🎯 새 개념 없음. 조립만 한다.
💡 Session 6 의 RAG 3단계(R·A·G)가 그대로 코드가 됨.
text = open("faq.txt", encoding="utf-8").read()
# 가장 단순한 분할 — 빈 줄(문단) 기준
chunks = [c.strip() for c in text.split("\n\n") if c.strip()]
# 각 조각을 미리 임베딩 (한 번만)
chunk_vecs = [embed(c) for c in chunks]
print(f"{len(chunks)}개 조각 준비 완료")
📁 참고:
2.langchain/7.RAG/2.loaders/
def ask(question):
hits = search(question, chunks, chunk_vecs, k=3) # Top-3 근거
context = "\n".join(c for _, c in hits)
prompt = f"""아래 자료에 근거해서만 답하세요.
자료에 없으면 "자료에 없습니다"라고 답하세요.
[자료]
{context}
[질문] {question}"""
return client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
).choices[0].message.content
🔑 RAG 의 본질이 이 한 함수에 다 있음: 검색 → 근거 주입 → 생성.

손코딩 RAG · 청크와 질문을 같은 차원으로 임베딩→코사인 Top-K로 근거 청크를 찾아 프롬프트에 주입
💡 프레임워크의 한 줄 호출 뒤에서 일어나는 일이 바로 이 그림.
Q: "우리 회사 환불 기간은?"
A: "보통 14일입니다" (지어냄 — 모름)
Q: "우리 회사 환불 기간은?"
A: "7일 이내 가능합니다 (FAQ 3항 근거)"
k 값을 1 ↔ 5 로 바꿔 답 품질 변화 관찰1/(1+거리) 0~1 점수면 0.2, 코사인(−1~1)이면 0.7~0.8 등 — 척도에 맞춰 컷오프)💡 이 세 가지 실험이 곧 Day2 의 튜닝 포인트(k, chunk, retriever).
| 지금의 한계 | 다음에 해결 |
|---|---|
| 매번 전체 비교 (느림) | Day2 — FAISS/Chroma 인덱스 |
| 껐다 켜면 임베딩 사라짐 | Day2 — 영속화 |
| TXT 만, PDF·DOCX 못 읽음 | Day2 — Document Loader |
| 프롬프트 직접 문자열 조립 | Day2 — LangChain LCEL |
| 출처·점수 표시 약함 | Day2 — citation, Day3 — 웹 UI |
| CLI 만 | Day3 — Flask 업로드 서비스 |