RAG 타로 —
프롬프트에서
컨텍스트 엔지니어링까지
이 실습이 끝나면 같은 모델, 같은 카드에서 4가지 프롬프트 기법이 얼마나 다른 답을 내는지 한 화면에서 비교하는 타로 해석 앱이 생긴다. 3H의 프롬프트 기법(역할 부여·CoT·Few-shot)과 4H의 RAG 컨텍스트 주입을 하나의 앱으로 잇는 5단계 실습이다. 코드는 직접 쓰지 않는다 — AI에게 무엇을 만들지 정확히 설명하는 것이 과제다.
하나의 앱을 다섯 번 진화시킨다
Zero-shot 베이스라인에서 출발해 RAG, CoT, Few-shot을 한 층씩 얹고, 마지막에 4가지를 나란히 비교한다. 같은 모델이라도 프롬프트 설계에 따라 결과가 크게 달라진다는 것이 결론이다.
코드를 쓰지 않고 앱을 만든다 — 바이브코딩
이 실습은 코드를 직접 작성하지 않는다. AI에게 무엇을 만들지 설명하면 AI가 코드를 짠다(바이브코딩). 목표는 개념 이해 → AI에게 정확히 요청 → 결과 비교의 사이클이다.
매 단계에서 같은 사이클을 반복한다. Claude에게 요청 → 앱 실행 → 이전 결과와 비교. 타로 해석 AI 앱이라는 하나의 소재를 붙잡고, 프롬프트에 무엇을 넣어 주는가만 단계적으로 바꾼다. 3H에서 배운 프롬프트 기법과 4H에서 배우는 RAG가 결국 같은 질문 — LLM에게 어떤 컨텍스트를 어떻게 설계해서 줄 것인가 — 의 답이라는 것을 몸으로 확인하게 된다.
| 단계 | 기법 | 무엇이 달라지나 |
|---|---|---|
| Step 1 🔵 | Zero-shot | 카드 이름만 줘서 해석 요청 — 베이스라인 |
| Step 2 🟡 | RAG Basic | 카드 의미 DB를 검색해서 LLM에 전달 |
| Step 3 🟢 | RAG + CoT | 역할 부여 + 단계별 추론 + 형식 지정 |
| Step 4 🟣 | Few-shot | 예시를 보여주며 스타일 제어 |
| Step 5 🏆 | 4가지 비교 | 한 화면에서 모든 결과 동시 비교 |
순서에 의미가 있다. Step 1은 아무것도 주지 않은 상태의 실력을 기록하는 베이스라인이다. 비교 대상이 없으면 "RAG가 좋아졌다"는 판단 자체가 불가능하므로, 첫 결과의 스크린샷을 남겨 두는 것까지가 Step 1이다. Step 2는 모델 바깥의 지식을 넣어 주고(무엇을 아는가), Step 3·4는 같은 지식을 두고 답하는 방식을 바꾼다(어떻게 답하는가). 정보의 문제와 형식의 문제를 분리해서 하나씩 통제하는 이 구조가, 실무에서 프롬프트를 디버깅할 때 그대로 쓰는 사고방식이다.
환경 점검 세 가지
안티그래비티 환경에서 tarot 폴더를 확인하고, 패키지와 HuggingFace 토큰을 준비한다.
- 안티그래비티 환경에서 tarot 폴더를 확인한다.
- 필요한 패키지를 설치한다.
- HuggingFace 토큰을 준비한다 (huggingface.co/settings/tokens).
pip install gradio sentence-transformers faiss-cpu huggingface_hub pillow -q
시작 전 확인
- tarot/data/tarot_cards.json 파일이 존재한다
- tarot/data/iimg/ 폴더에 카드 이미지가 존재한다
- hf_ 로 시작하는 HuggingFace 토큰이 준비되었다
카드 이름만 주고 물어보기
예시도, 배경 지식도 없이 카드 이름만 전달한다. 이 결과가 이후 모든 단계와 비교할 베이스라인이 된다.
Zero = 예시 0개
LLM에게 카드 이름만 알려주고 해석을 요청한다. 처음 만난 점술사에게 "이 카드 3장 해석해줘"라고 하는 것과 같다.
모델은 사전학습에서 얻은 일반 지식만으로 답해야 한다. 이때 해석이 얼마나 구체적인지, 얼마나 막연한지를 기록해 두는 것이 이 단계의 목적이다. 아래 프롬프트를 Claude에게 그대로 전달한다.
타로 카드 해석 Gradio 앱을 만들어줘. 조건: - data/tarot_cards.json 에서 카드 데이터를 불러와 - HuggingFace Inference API로 Qwen/Qwen3-8B 모델을 사용해 - 사용자가 고민을 입력하면 카드 3장을 랜덤으로 뽑아 정방향/역방향을 정해 - data/iimg/ 폴더에서 카드 이미지를 불러와서 표시해 (역방향은 180도 회전) - 프롬프트는 카드 이름과 방향만 LLM에 전달하는 Zero-shot 방식으로 만들어 - Gradio UI는 왼쪽에 고민 입력+토큰 입력, 오른쪽에 카드 이미지 3장+해석 결과 - 파일명은 step1_zero_shot.py 로 저장해줘
실행
python step1_zero_shot.py
실행 후 gradio.live 링크 또는 localhost:7860 을 연다.
확인 포인트
- 카드 3장이 표시되는가
- 역방향 카드의 이미지가 뒤집혀 있는가
- 해석이 카드 이름과 관련되어 있는가
- 해석이 구체적인가, 막연한가
- 결과 스크린샷을 저장했는가 (2단계와 비교용)
지금 모델은 카드 이름에서 연상되는 일반 지식만으로 해석했다. 만약 카드의 의미를 정확히 적은 문서를 함께 전달한다면 어떻게 될까? 카드마다 정방향·역방향의 키워드와 상징이 정리된 자료가 이미 tarot_cards.json 안에 있다. 이 자료를 프롬프트에 넣어 주는 것 — 그것이 다음 단계의 RAG다.
검색해서 컨텍스트를 주입한다
카드 의미 DB를 벡터 인덱스로 만들고, 뽑힌 카드의 상세 의미를 검색해 프롬프트에 넣는다. 해석이 눈에 띄게 구체적으로 바뀐다.
점술사에게 카드 의미가 적힌 책을 펼쳐 준다
RAG(Retrieval-Augmented Generation)는 tarot_cards.json의 상세 의미를 벡터 DB(FAISS)에 저장해 두고, 카드가 뽑힐 때마다 검색해서 LLM에 전달하는 방식이다.
비유하면 이렇다. Step 1은 점술사에게 카드만 보여주는 것이고, Step 2는 카드 의미가 적힌 책도 함께 펼쳐 주는 것이다. RAG는 세 단계 구조로 움직인다.
step1_zero_shot.py를 기반으로 RAG를 추가한 step2_rag_basic.py를 만들어줘. 추가할 내용: - sentence-transformers의 paraphrase-multilingual-MiniLM-L12-v2 모델로 tarot_cards.json의 각 카드를 정방향/역방향으로 나눠 44개 청크를 만들어 - 각 청크에는 카드명(한/영), 방향, 키워드, 의미, 상징 정보를 포함해 - faiss-cpu로 벡터 인덱스를 구축해 (IndexFlatIP, L2 정규화 적용) - 카드가 뽑히면 FAISS에서 해당 카드+방향의 상세 의미를 검색해 - 검색된 의미를 프롬프트에 [RAG 검색 결과] 섹션으로 주입해 - Gradio UI에 'RAG 검색 결과 보기' 아코디언을 추가해서 어떤 정보가 주입됐는지 확인 가능하게 해줘 - 파일명은 step2_rag_basic.py 로 저장해줘
실행
python step2_rag_basic.py
첫 실행 시 임베딩 모델 다운로드와 인덱스 구축에 1~2분이 걸린다.
확인 포인트
- 'RAG 검색 결과 보기' 아코디언에 카드의 상세 의미가 나타나는가
- 해석에 구체적 키워드('급격한 변화', '혼란', '계시' 등)가 반영되는가
- Step 1 결과보다 구체적이고 정확한가
정보는 좋아졌는데 형식이 들쭉날쭉하지 않은가? 어떤 때는 카드별로, 어떤 때는 한 덩어리로 답한다. 모델에게 "어떻게 생각하고 어떤 형식으로 답하라"고 말해 주면 어떻게 될까? 그것이 다음 단계다 — 역할 부여, 단계별 추론(CoT), 구조화 출력.
역할·추론·형식, 세 기법을 조합한다
같은 RAG 정보를 두고 프롬프트 설계만 바꾼다. "단계별로 생각해보세요" 한 마디가 답변 품질을 크게 끌어올린다.
같은 정보, 다른 답 — 프롬프트 설계의 힘
이 단계에서는 세 가지 기법을 하나의 프롬프트에 조합한다. 역할 부여, Chain-of-Thought, 구조화 출력이다.
핵심 인사이트는 이것이다. '단계별로 생각해보세요' 한 마디만으로 답변 품질이 크게 오른다 — 이것이 CoT의 핵심이다.
step2_rag_basic.py를 기반으로 프롬프트를 업그레이드한 step3_rag_cot.py를 만들어줘.
프롬프트에 추가할 내용 (3가지 기법 조합):
1. 역할 부여: '당신은 20년 경력의 타로 전문 점술사입니다. 카드의 상징과
심리적 의미를 깊이 이해하며 통찰력 있는 해석을 제공합니다.'
2. Chain-of-Thought 지시문 추가:
'1단계: 각 카드를 시간적 위치(과거/현재/미래)에서 개별 분석합니다.
2단계: 세 카드의 연결 고리와 흐름을 파악합니다.
3단계: 질문자의 관심사와 통합하여 메시지를 전달합니다.'
3. 구조화 출력 형식 명시:
**과거 카드**: 카드명 (방향) (2~3문장 해석)
**현재 카드**: 카드명 (방향) (2~3문장 해석)
**미래 카드**: 카드명 (방향) (2~3문장 해석)
**종합 메시지** (3~4문장)
나머지 코드(FAISS, 이미지, Gradio UI)는 step2와 동일하게 유지해줘.
파일명은 step3_rag_cot.py 로 저장해줘
확인 포인트
- 과거/현재/미래/종합 섹션이 명확히 분리되는가
- 어투가 전문가답게 바뀌었는가
- 세 카드가 하나의 이야기로 연결되는가
- 여러 번 실행해도 매번 같은 형식으로 나오는가
Step 2와 Step 3의 차이를 만든 것은 무엇인가. 주입된 RAG 정보는 완전히 같다. 달라진 것은 프롬프트 설계뿐이다. 그렇다면 형식을 말로 지시하는 대신, '좋은 해석의 예시'를 직접 보여주면 어떻게 될까? 그것이 다음 단계의 Few-shot이다.
예시를 보여주며 스타일을 제어한다
원하는 출력의 예시를 직접 써서 프롬프트 맨 앞에 넣는다. 예시의 품질이 결과의 품질을 결정한다.
말로 설명하는 대신 예시로 보여준다
원하는 출력의 예시를 보여주면 모델은 그 패턴 — 형식, 어투, 길이 — 을 따라한다. 예시의 품질이 결과의 품질을 결정하므로, 좋은 예시를 작성하는 것 자체가 중요한 스킬이다.
먼저 직접 작성한다
AI에게 요청하기 전에, '이상적인 타로 해석 예시'를 손으로 먼저 작성한다. 아래 구성을 갖추면 된다.
- 관심사(고민) 한 줄
- 과거·현재·미래 카드 각각 2~3문장의 해석
- 종합 메시지 3~4문장
step3_rag_cot.py를 기반으로 Few-shot 예시를 추가한 step4_few_shot.py를 만들어줘. 프롬프트 맨 앞에 아래 예시를 추가해줘: [해석 예시] [여기에 직접 작성한 예시 붙여넣기] [예시 끝] 예시 다음에 '위 예시와 같은 형식과 어투로 아래 카드를 해석해주세요.'라는 지시를 추가해줘. 나머지 코드는 step3와 동일하게 유지해줘. 파일명은 step4_few_shot.py
확인 포인트
- 내가 쓴 예시의 어투가 결과에 반영되는가
- 문장 길이와 문체가 예시와 유사한가
- 예시 길이를 바꾸면 결과 길이도 따라 변하는가
실험해 볼 것 — 예시를 짧게 써 보고, 시적으로 써 보고, 직설적으로 써 보라. 결과가 예시를 얼마나 충실히 따라오는지 관찰하면, "모델을 제어하는 가장 직접적인 수단은 지시문이 아니라 예시"라는 감각이 생긴다. 이제 네 가지 기법이 모두 준비되었다. 마지막 단계에서 이들을 같은 조건에 놓고 동시에 비교한다.
4가지 기법을 한 화면에서 비교한다
같은 카드 3장을 4가지 기법에 동일하게 적용해 2×2 그리드로 나란히 본다. 이 단계가 실습의 핵심이다.
같은 입력, 네 개의 출력
비교가 공정하려면 조건이 같아야 한다. 카드 3장을 한 번만 뽑아 4가지 기법 모두에 동일하게 적용하고, 결과를 2×2 그리드로 동시에 띄운다.
step1~step4에서 만든 4가지 프롬프트 함수를 모아서 비교 앱 step5_compare.py를 만들어줘. 요구사항: - 카드 3장을 한 번만 뽑아서 4가지 기법 모두에 동일하게 적용해 - 버튼 1개로 4가지 기법을 순서대로 실행해 (gr.Progress로 진행 표시) - UI: 상단 고민 입력+HF 토큰+모델 선택 드롭다운+실행 버튼 / 중간 카드 이미지 3장 / 하단 2×2 그리드 - 각 결과는 gr.Markdown 렌더링, max-height: 500px 스크롤, 섹션 헤더 색상 강조 - 탭 2개: '🃏 기법 비교' 탭과 '📚 학습 가이드' 탭 - max_tokens는 2500 - 파일명은 step5_compare.py 모델 목록: Qwen/Qwen3-8B (기본), Qwen/Qwen3-4B-Instruct-2507, mistralai/Mistral-7B-Instruct-v0.3
최종 비교 포인트
- Zero-shot vs RAG — 정보의 품질이 어떻게 달라졌는가
- RAG vs RAG+CoT — 해석의 깊이가 어떻게 달라졌는가
- RAG+CoT vs Few-shot — 스타일이 결과에 어떤 영향을 주는가
- 가장 마음에 드는 기법은 무엇이고, 그 이유는 무엇인가
모델 선택 드롭다운이 있는 이유도 비교에 있다. 같은 프롬프트를 다른 모델(Qwen3-8B, Qwen3-4B, Mistral-7B)에 넣어 보면, 기법 간 격차가 모델에 따라 어떻게 달라지는지도 관찰할 수 있다. 작은 모델일수록 프롬프트 설계의 효과가 극적으로 나타나는 경우가 많다 — 모델의 크기로 밀어붙일 수 없는 만큼, 컨텍스트 설계가 성능을 좌우하기 때문이다.
비교표와 핵심 정리
네 기법이 각각 무엇을 더했는지 표 한 장으로 정리하고, 실무로 연결한다.
4가지 기법, 무엇이 다른가
| 항목 | Zero-shot | RAG | RAG+CoT | Few-shot |
|---|---|---|---|---|
| 외부 지식 | ❌ | ✅ | ✅ | ✅ |
| 단계적 추론 | ❌ | ❌ | ✅ | ❌ |
| 역할 부여 | 최소 | 최소 | ✅ | 최소 |
| 형식 제어 | ❌ | ❌ | 템플릿 | 예시 |
| 예시 제공 | ❌ | ❌ | ❌ | ✅ |
| 답변 품질 | 낮음 | 중간 | 높음 | 높음 |
하나. 같은 모델이라도 프롬프트 설계에 따라 결과가 크게 달라진다. 모델 교체보다 먼저 시도할 것은 컨텍스트 설계다.
둘. 네 기법은 각각 다른 문제를 푼다. RAG는 모르는 정보를 외부에서 찾아 알려주고, CoT는 단계별로 생각하게 하고, Role은 역할에 맞게 답하게 하고, Few-shot은 예시 스타일을 따라하게 한다.
셋. 이 네 기법은 실제 AI 서비스 개발에서 그대로 활용된다. 타로 앱에서 연습한 조합이 곧 실무의 프롬프트 설계다.
원본 실습 자료 RAG타로: 프롬프트 엔지니어링 비교 (3H~4H 실습), notion.site (RAG 타로 실습 페이지)
이 자료는 단일 HTML 파일로 배포되며, 프롬프트 블록의 '복사' 버튼으로 원문을 그대로 복사해 실습에 사용할 수 있다.