폐쇄망/로컬 환경에서 사용하는 경량 RAG 서버입니다.
- 문서: 전처리 완료된
data/*.md입력 - 청킹:
##,###,####헤더 기반 + 문자 분할(기본), 토큰 분할(옵션) - 벡터스토어: Chroma (로컬 폴더)
- LLM:
openai/ollama/lmstudio선택 - 인터페이스: FastAPI + 브라우저(
http://127.0.0.1:8000) - 업로드 워크플로우: 사용자 요청(
pending) -> 관리자 승인/반려
trunk_rag는 "가벼운 RAG 런타임" 역할에 집중합니다.
- 외부 전처리 단계(별도 프로세스, 클라우드 LLM 포함 가능)
- 원본 소스를 정제해 RAG 정책에 맞는 Markdown으로 변환
- 메타데이터(
source,country,doc_type)를 채운 산출물 생성
trunk_rag단계(현재 + 다음 단계)
- 현재: 정제된 md를 인덱싱/검색/질의
- 다음 단계(P1): 데이터 등록 시 검증(사용 가능/불가 판정) 기능 추가
- 다음 단계(P1): 분야별 컬렉션 + 단순 라우팅 적용
비목표(현재 단계):
- 원본 수집/크롤링
- 대규모 자동 재작성 파이프라인
- 무거운 rerank/multi-vector 파이프라인 기본 탑재
app_api.py: 메인 로컬 서버build_index.py: 초기 인덱스 생성 스크립트common.py: 공통 유틸리티web/index.html: 간단 웹 UIweb/intro.html: 인트로/상태 확인 페이지web/admin.html: 관리자 상태 페이지(MVP)scripts/validate_rag_doc.py: 등록 전 문서 검증 스크립트scripts/benchmark_token_chunking.py: char/token 청킹 비교 벤치 스크립트scripts/benchmark_query_e2e.py:/queryE2E p95 벤치 스크립트run_doc_rag.bat: 터미널 명령 없이 서버+브라우저 실행stop_doc_rag.bat: 실행 중인 로컬 서버 종료.env.example: 환경변수 템플릿docs/PREPROCESSING_RULES.md: 전처리 규칙 초안docs/PREPROCESSING_PROMPT_TEMPLATE.md: 전처리 프롬프트 템플릿docs/PREPROCESSING_METADATA_SCHEMA.json: 전처리 메타데이터 스키마docs/VECTORSTORE_POLICY.md: 벡터스토어 운영/용량 정책docs/COLLECTION_ROUTING_POLICY.md: 분야별 컬렉션/라우팅 정책docs/FUTURE_EXTERNAL_CONSTRAINTS.md: 외부 제한사항 중 추후 적용 항목
- 최초 1회 인덱싱:
cd C:\Users\sunji\workspace\doc_rag
C:\Users\sunji\llm_5th\001_chatbot\.venv\Scripts\python.exe build_index.py --reset- 이후 실행:
cd C:\Users\sunji\workspace\doc_rag
.\run_doc_rag.bat- 브라우저에서
http://127.0.0.1:8000/intro가 열리고,사용자 모드 시작버튼으로/app진입.- 관리자 모드는 인증 코드 입력 후
/admin진입
- 관리자 모드는 인증 코드 입력 후
- 종료:
cd C:\Users\sunji\workspace\doc_rag
.\stop_doc_rag.bat수동 실행이 필요하면 기존처럼 app_api.py 직접 실행도 가능.
GET /health: 서버/벡터 상태 확인GET /collections: 컬렉션별 벡터 수/cap 사용률 조회POST /reindex: 문서 재인덱싱POST /query: 질의(기본 단일 컬렉션, 필요 시 최대 2개 컬렉션 선택)GET /rag-docs: RAG 대상 문서 목록GET /rag-docs/{doc_name}: 문서 원문(md) 조회POST /admin/auth: 관리자 인증 코드 확인GET /upload-requests: 업로드 요청 목록/상태 조회POST /upload-requests: 일반 사용자 업로드 요청 생성POST /upload-requests/{id}/approve: 관리자 승인POST /upload-requests/{id}/reject: 관리자 반려
POST /reindex 응답의 validation에는 기계 판독용 필드와 함께
summary_text(예: total=5, usable=5, rejected=0, warnings=0, usable_ratio=100.00%)가 포함됩니다.
GET /health 응답에는 현재 적용 중인 chunking_mode(char 또는 token)와
query_timeout_seconds, max_context_chars가 포함됩니다.
POST /reindex 응답에는 실제 인덱싱에 사용된 chunking 설정이 포함됩니다.
예시:
curl http://127.0.0.1:8000/health
curl -X POST http://127.0.0.1:8000/query `
-H "Content-Type: application/json" `
-d "{\"query\":\"각 국가별 대표적인 과학적 성과\",\"collection\":\"all\",\"llm_provider\":\"ollama\",\"llm_model\":\"qwen3:4b\",\"llm_base_url\":\"http://localhost:11434\"}"- 성공 응답은 기존과 동일:
{
"answer": "...",
"provider": "ollama",
"model": "qwen3:4b"
}- 실패 응답은
flat + detail호환 포맷:
{
"code": "LLM_TIMEOUT",
"message": "LLM 응답 시간이 제한(15초)을 초과했습니다.",
"hint": "모델 상태를 확인하거나 더 짧은 질문으로 다시 시도하세요.",
"request_id": "uuid-or-client-id",
"detail": "LLM 응답 시간이 제한(15초)을 초과했습니다."
}- 타임아웃은 기본
15초이며DOC_RAG_QUERY_TIMEOUT_SECONDS로 조정할 수 있습니다.
업로드 요청 생성 예시:
curl -X POST http://127.0.0.1:8000/upload-requests `
-H "Content-Type: application/json" `
-d "{\"source_name\":\"new_doc.md\",\"collection\":\"fr\",\"country\":\"france\",\"doc_type\":\"country\",\"content\":\"## 제목\\n본문\"}"-
실패 코드 매핑:
INVALID_REQUEST->422VECTORSTORE_EMPTY->400INVALID_PROVIDER->400LLM_CONNECTION_FAILED->502LLM_TIMEOUT->504INTERNAL_ERROR->500
-
X-Request-ID헤더:/query의 성공/실패 응답 모두 포함- 요청에
X-Request-ID를 보내면 같은 값 재사용 - 없으면 서버가 UUID 생성
-
X-RAG-Collection헤더:- 실제 질의에 사용된 컬렉션 이름을 반환
현재 정책:
trunk_rag는 전처리된 md를 입력으로 사용한다.- 전처리 가이드/규칙은
docs/PREPROCESSING_RULES.md를 기준으로 한다. - 외부 전처리 프롬프트 템플릿은
docs/PREPROCESSING_PROMPT_TEMPLATE.md를 사용한다. - 메타데이터 형식은
docs/PREPROCESSING_METADATA_SCHEMA.json을 따른다.
다음 단계(P1) 정책:
- 문서 등록 또는 인덱싱 전 검증을 수행하고
usable=true/false판정을 제공한다. - 불가(
usable=false) 문서는 벡터스토어에 반영하지 않는다.
참고:
- 본 정책의 상세 운영 기준은
docs/FUTURE_EXTERNAL_CONSTRAINTS.md에 정리한다.
.env.example를 복사해 .env 생성 후 사용.
- OpenAI 사용 시:
OPENAI_API_KEY - Ollama 사용 시:
OLLAMA_BASE_URL - Ollama 응답 길이 제한(선택):
DOC_RAG_OLLAMA_NUM_PREDICT(예:8, 미설정 시 모델 기본값) - LM Studio 사용 시:
LMSTUDIO_BASE_URL,LMSTUDIO_API_KEY - 관리자 모드 인증 코드(선택):
DOC_RAG_ADMIN_CODE(기본값:admin1234) - 개인 운영 자동 승인(선택):
DOC_RAG_AUTO_APPROVE(1/true/on이면 요청 생성 즉시 승인/인덱싱) - 질의 타임아웃(선택):
DOC_RAG_QUERY_TIMEOUT_SECONDS(기본15, 단위 초) - 컨텍스트 길이 제한(선택):
DOC_RAG_MAX_CONTEXT_CHARS(미설정 시 제한 없음) - 청킹 모드(선택):
DOC_RAG_CHUNKING_MODE(char기본,token옵션) - 토큰 인코딩(선택):
DOC_RAG_CHUNK_TOKEN_ENCODING(기본cl100k_base)
개발용 테스트 의존성 설치:
python -m pip install -r requirements-dev.txt
python -m playwright install chromium실행:
pytest -q개별 실행:
pytest -q tests/api
pytest -q tests/e2e/test_web_flow_playwright.py -m e2e다중 컬렉션 PoC 벤치(검색 단계):
.venv\Scripts\python.exe scripts\benchmark_multi_collection.py --reindex --rounds 5 --output docs\reports\multi_collection_benchmark_2026-02-26.json- 결과 메모:
docs/reports/MULTI_COLLECTION_POC_REPORT_2026-02-26.md
토큰 청킹 PoC 벤치(분할 단계):
.venv\Scripts\python.exe scripts\benchmark_token_chunking.py --rounds 5 --output docs\reports\token_chunking_benchmark_2026-02-27.json- 결과 메모:
docs/reports/TOKEN_CHUNKING_POC_REPORT_2026-02-27.md
/query E2E 벤치(LLM 포함, API 기준):
.venv\Scripts\python.exe scripts\benchmark_query_e2e.py `
--base-url http://127.0.0.1:8000 `
--llm-provider ollama `
--llm-model phi3:mini `
--llm-base-url http://localhost:11434 `
--rounds 2 `
--warmup 1 `
--query-timeout-seconds 120 `
--output docs\reports\query_e2e_benchmark_2026-02-27.json- 기본 시나리오:
single_all,single_fr,dual_fr_ge - 출력에는 시나리오별
latency_success_p95_ms와status_counts가 포함됩니다. - 느린 로컬 CPU 환경에서는 아래 런타임 설정을 권장:
DOC_RAG_QUERY_TIMEOUT_SECONDS=90DOC_RAG_OLLAMA_NUM_PREDICT=8DOC_RAG_MAX_CONTEXT_CHARS=300
데이터가 증가하면 속도/품질 저하 우려가 있습니다.
- 속도 리스크: 벡터 수 증가에 따른 검색 지연 증가
- 품질 리스크: 유사하지만 덜 관련된 청크가 상위로 노출(노이즈 증가)
정책:
- 무제한 적재 대신 컬렉션 용량 가이드를 둔다.
- 컬렉션당 cap:
30,000 ~ 50,000 vectors - cap은 토큰이 아니라 벡터(청크) 수 기준이다.
- 분야별 컬렉션으로 분할하고 단순 라우팅으로 조회 범위를 제한한다.
- 상세 수치와 대응 단계는
docs/VECTORSTORE_POLICY.md를 따른다. - 라우팅 방식 상세는
docs/COLLECTION_ROUTING_POLICY.md를 따른다.