버전:
v1.0.0· 권장 Python:3.13
GitHub 저장소의 코드를 검색 가능한 지식으로 만들고, 검색된 코드만 근거로 답변하는 Django 챗봇 실습입니다. 복잡한 GitHub 수집·보안·Chroma 교체 로직은 완성된 상태로 제공되며, 실습에서는 채팅 메시지가 답변과 출처로 돌아오기까지의 여섯 함수를 완성합니다.
브라우저 메시지
→ Django POST API
→ 대화 서비스
→ Vector DB 검색
→ 검색 결과를 Context로 변환
→ 최근 대화 + Context + 현재 질문으로 Prompt 조립
→ Upstage LLM 호출
→ 검색 Metadata에서 Citation 생성
→ JSON 응답과 Evidence 표시
RAG(Retrieval-Augmented Generation)는 LLM이 답변하기 전에 관련 자료를 검색하고, 검색 결과를 질문과 함께 전달해 근거 있는 답변을 생성하게 하는 파이프라인입니다.
- Chunk: 긴 코드나 문서를 검색하기 좋은 크기로 나눈 조각
- Embedding: 코드와 질문의 의미를 숫자 벡터로 변환하는 과정
- Chroma: 벡터, 원문 Chunk, 파일 경로와 줄 번호를 함께 저장하는 Vector DB
- Retrieval: 질문과 의미가 가까운 코드 Chunk 검색
- Augmentation: 검색 결과를 LLM이 읽을 Context로 조립
- Generation: Context를 근거로 답변 생성
이 프로젝트의 데이터 흐름은 다음과 같습니다.
GitHub URL → 코드 수집 → Chunk → Embedding → Chroma
→ 검색 → Context → Prompt → LLM 답변 + Citation
RAG는 새로운 모델 하나가 아니라 검색, Context 구성, Prompt 구성, 생성, 출처 반환을 연결한 처리 구조입니다.
pirogramming-portfolio-rag-workshop/
├── config/ Django 프로젝트 설정
├── portfolio/
│ ├── management/commands/
│ │ ├── ask_llm.py RAG 없는 LLM 호출 비교
│ │ ├── workshop_check.py API Key와 실행 환경 점검
│ │ └── mobile_serve.py 선택 기능: Tailscale 연결
│ ├── services/
│ │ ├── conversation.py 대화 상태와 검색 연결
│ │ ├── rag.py Context, Prompt, Citation, 답변
│ │ ├── vector_store.py Chroma 저장과 검색
│ │ ├── code_documents.py 코드 Chunk와 줄 Metadata
│ │ ├── repository_url.py GitHub URL 검증
│ │ ├── source_policy.py 수집할 파일 선택
│ │ ├── github_client.py GitHub API 요청과 재시도
│ │ └── jd_analyzer.py JD 코드 근거 분석
│ ├── templates/portfolio/index.html 챗봇 화면
│ ├── static/portfolio/ CSS와 JavaScript
│ └── views.py HTTP 요청과 JSON 응답
├── fixtures/ GitHub 장애 시 샘플 데이터
├── tests/ 단계별 자동 테스트
├── .env.example 환경변수 예시
├── manage.py
└── pyproject.toml Python과 패키지 설정
Starter에는 함수 선언, 타입 힌트, import가 이미 있습니다. 각 대상 함수의 raise WorkshopStepIncomplete(...)를 완성 코드로 교체합니다.
| Step | 파일 | 함수 | 핵심 개념 |
|---|---|---|---|
| 1 | portfolio/views.py |
messages |
브라우저 POST → Form 검증 → 서비스 → JSON |
| 2 | portfolio/services/conversation.py |
_answer_code_question |
질문 → Top 6 검색 → RAG 답변 |
| 3 | portfolio/services/rag.py |
format_context |
검색 Chunk → LLM Context |
| 4 | portfolio/services/rag.py |
_answer_prompt |
최근 대화 + Context + 질문 |
| 5 | portfolio/services/rag.py |
_citations |
검색 Metadata 기반 출처와 중복 제거 |
| 6 | portfolio/services/rag.py |
answer_with_context |
근거 확인 → LLM 호출 → 답변·출처 반환 |
다음 로직은 완성된 코드로 제공됩니다.
- GitHub URL 검증:
parse_github_repository_url - 파일 정책과 예산:
select_source_candidates - 코드 Chunk와 줄 번호:
chunk_source_file,build_code_documents - Chroma 교체와 검색:
reset_and_index,search - JD 코드 근거 분석:
analyze_jd - GitHub 재시도, 비공개 저장소 확인, 원자적 index 교체, 화면 렌더링
- Python
3.11이상3.14미만 — Python3.13권장 - Git
- GitHub 계정과 Fine-grained personal access token
- Upstage API Key
- macOS, Linux 또는 Windows PowerShell
Python 3.14에서는 현재 고정된 tokenizers가 사용하는 PyO3 버전이 Python 3.13까지만 지원해 설치 과정에서 wheel build가 실패합니다. Rust를 다시 설치하기보다 Python 3.13 가상환경을 사용하세요.
앱이 분석 대상 저장소를 읽을 때 사용하는 인증 값입니다.
- GitHub Fine-grained token 생성 화면을 엽니다.
- 수업에 필요한 짧은 만료 기간을 설정합니다.
- 비공개 저장소를 사용할 경우
Only select repositories로 필요한 저장소만 선택합니다. - Repository permissions에서
Contents: Read-only를 선택합니다. - 생성 직후 값을 복사해
.env의GITHUB_TOKEN에만 넣습니다.
쓰기 권한, Issues, Pull requests, Actions 권한은 필요하지 않습니다.
Chat 모델과 Embedding 모델을 호출할 때 사용하는 인증 값입니다.
- Upstage Console API Keys에 로그인합니다.
Create new key를 눌러 Key를 발급합니다.- 발급 직후 한 번만 복사해
.env의UPSTAGE_API_KEY에 넣습니다.
이 실습은 한국어 코드 질문과 설명을 한 provider에서 처리하고, langchain-upstage로 Chat과 Embedding 연결을 단순하게 유지하기 위해 Upstage를 사용합니다. 계정 credit과 rate limit이 있으므로 수업 전 workshop_check로 실제 호출 가능 여부를 확인해야 합니다.
저장소를 내려받습니다.
git clone https://github.com/inoaole/pirogramming-portfolio-rag-workshop.git
cd pirogramming-portfolio-rag-workshoppython3.13 -m venv .venv
source .venv/bin/activate
python -m pip install -e '.[dev]'
cp .env.example .envpython3.13 명령이 없다면 설치된 Python 3.11~3.13의 명령을 사용합니다.
py -3.13 -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install -e ".[dev]"
Copy-Item .env.example .envPowerShell이 가상환경 실행을 막으면 사용자 계정 범위에서 한 번 실행합니다.
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned.env 파일에 본인이 발급한 값을 입력합니다.
GITHUB_TOKEN=본인의_fine_grained_token
USE_SAMPLE_GITHUB=false
UPSTAGE_API_KEY=본인의_upstage_api_key
UPSTAGE_CHAT_MODEL=solar-pro3
UPSTAGE_EMBEDDING_MODEL=solar-embedding-1-large
CHROMA_PATH=.workshop/chromaToken과 API Key를 README, 메신저, 브라우저 입력창, 화면 캡처 또는 Git commit에 올리지 않습니다. .env는 Git에서 제외되어 있습니다.
API 없이 로컬 설치부터 확인합니다.
python manage.py workshop_check --offline실제 Token과 Key까지 확인합니다.
python manage.py workshop_checkReady for workshop이 표시되면 준비가 끝났습니다.
각 Step에서 지정된 함수만 수정하고 해당 테스트를 통과시킨 뒤 다음 단계로 이동합니다. 아래 명령은 활성화된 가상환경의 Python을 사용하도록 python -m pytest 형태로 실행합니다.
- 위치:
portfolio/views.py의messages함수 전체 - 역할: 입력 검증, session 전달, 서비스 호출, JSON 응답
python -m pytest tests/test_step1_messages.py -q- 위치:
portfolio/services/conversation.py의ConversationService._answer_code_question메서드 전체 - 주의: 클래스 내부 메서드이므로
def앞에 4칸을 들여씁니다. - 역할: Top 6 검색,
answer_with_context호출,ConversationReply반환
python -m pytest tests/test_step2_conversation.py -q- 위치:
portfolio/services/rag.py의format_context함수 전체 - 역할: repository, path, lines, URL, content를
<portfolio_context>로 조립
python -m pytest tests/test_step3_context.py -q- 위치:
portfolio/services/rag.py의_answer_prompt함수 전체 - 역할: 최근 대화 6개, 검색 Context, 현재 질문을 일정한 순서로 결합
python -m pytest tests/test_step4_prompt.py -q- 위치:
portfolio/services/rag.py의_citations함수 전체 - 역할: 빈 URL 제외, 중복 제거, relevance 보존
python -m pytest tests/test_step5_citations.py -q- 위치:
portfolio/services/rag.py의answer_with_context함수 전체 - 역할: 검색 결과가 없으면 모델을 호출하지 않고, 있으면 Upstage 답변과 Citation을 반환
python -m pytest tests/test_step6_answer.py -q첫 번째 터미널에서 서버를 실행합니다.
python manage.py runserver 127.0.0.1:8000브라우저에서 http://127.0.0.1:8000을 엽니다.
https://github.com/owner/repository형식의 정확한 저장소 URL을 보냅니다.- 비공개 저장소라면 Upstage 전송 안내를 읽고 동의 또는 취소합니다.
- 인덱싱이 끝나면 코드 구조나 함수 호출 흐름을 질문합니다.
- Evidence에서 파일 경로, 줄 범위, relevance와 GitHub 링크를 확인합니다.
JD 적합도 분석기능은 완성된 확장 기능으로 실행해 코드 근거를 확인합니다.
여섯 Step을 모두 완료한 뒤 실행합니다.
python -m pytest \
tests/test_step1_messages.py \
tests/test_step2_conversation.py \
tests/test_step3_context.py \
tests/test_step4_prompt.py \
tests/test_step5_citations.py \
tests/test_step6_answer.py -q
ruff check .
python manage.py checkGit clone에서 작업했다면 다음도 확인합니다.
git diff --check
git status --short오류에 configured Python interpreter version (3.14) is newer than PyO3's maximum supported version (3.13)가 보이면 Python 3.14 가상환경입니다. .venv를 삭제하고 Python 3.13으로 다시 만듭니다.
오류에 표시된 Step 함수가 아직 비어 있다는 뜻입니다. 해당 함수의 body만 완성하고 그 Step 테스트를 다시 실행합니다. import, helper, test를 고쳐 우회하지 않습니다.
Fine-grained Token의 만료 여부, repository 선택, Contents: Read-only 권한을 확인합니다.
.env의 UPSTAGE_API_KEY, UPSTAGE_CHAT_MODEL, UPSTAGE_EMBEDDING_MODEL 값을 확인하고 python manage.py workshop_check를 다시 실행합니다.
기존 Django 서버를 실행한 터미널에서 Ctrl+C를 누릅니다.
macOS/Linux:
lsof -nP -iTCP:8000 -sTCP:LISTENWindows PowerShell:
Get-NetTCPConnection -LocalPort 8000 -State Listen -ErrorAction SilentlyContinue- GitHub Token과 Upstage API Key는
.env에만 저장하고 공유하거나 commit하지 않습니다. - 앱은 GitHub 저장소에 쓰지 않으며
Contents: Read-only권한만 사용합니다. - 비공개 저장소는 동의 후 선택된 코드 Chunk가 Upstage Embedding 요청으로 전송되고, 검색된 Chunk가 Chat 요청으로 전송됩니다.
- Chroma 원문과 벡터는 로컬
.workshop/chroma/에 저장됩니다. - 파일 형식, 크기, 전체 용량, Chunk 개수 제한 때문에 모든 파일이 인덱싱된다고 보장하지 않습니다.
- RAG 답변은 검색 결과를 요약한 것이므로 중요한 판단은 Evidence의 원본 파일과 줄 번호로 확인합니다.
- JD 결과는 공개 코드에서 확인되는 기술 근거 비율이며 경력, 협업 능력 또는 실제 채용 결과를 예측하지 않습니다.