폐쇄망/로컬 환경에서 사용하는 경량 RAG 서버입니다.
- 문서: 전처리 완료된
data/*.md입력 - 청킹:
##,###,####헤더 기반 + 문자 분할(기본), 토큰 분할(옵션) - 벡터스토어: Chroma (로컬 폴더)
- LLM:
openai/ollama/lmstudio선택(기본 예시:ollama+qwen3:4b) - 인터페이스: FastAPI + 브라우저(
http://127.0.0.1:8000) - 업로드 워크플로우: 사용자 요청(
pending) -> 관리자 승인/반려
trunk_rag는 "가벼운 RAG 런타임" 역할에 집중합니다.
- 외부 전처리 단계(별도 프로세스, 클라우드 LLM 포함 가능)
- 원본 소스를 정제해 RAG 정책에 맞는 Markdown으로 변환
- 메타데이터(
source,country,doc_type)를 채운 산출물 생성
trunk_rag단계(현재 + 다음 우선순위)
- 현재: 정제된 md를 인덱싱/검색/질의
- 현재: 데이터 등록 시 검증(사용 가능/불가 판정) 적용
- 현재: 분야별 컬렉션 + 단순 라우팅 적용
- 현재: 승인된 업로드는
chroma_db/managed_docs/의 active markdown 원본 기준으로 유지 - 현재: answer-level eval fixture +
/query품질 평가 하네스 추가 - 현재: Vector RAG answer-level baseline 1차 실측 완료(
pass_rate=0.3333,p95=14277.843ms) - 현재: 업로드 관리자 Slice 2 완료(
pending기본 필터, update 강조, active 문서 미리보기, reject reason code/decision_note) - 현재: graph snapshot backend의
graph-candidateanswer-level 비교는2/3 pass,avg_weighted_score=0.8444 - 현재 판단: GraphRAG는 MVP 통합 No-Go, 연구용 sidecar 트랙만 유지
- 다음 우선순위(P2/P3):
uk인덱스 부재와fr,getimeout 등 기본 경로 신뢰성 복구
비목표(현재 단계):
- 원본 수집/크롤링
- 대규모 자동 재작성 파이프라인
- 무거운 rerank/multi-vector 파이프라인 기본 탑재
app_api.py: FastAPI 앱 엔트리포인트/조립 계층api/routes_*.py: API/UI 라우트 모듈services/*.py: 질의/인덱싱/업로드 서비스 모듈core/*.py: 설정/에러/HTTP 유틸build_index.py: 초기 인덱스 생성 스크립트common.py: 공통 유틸리티web/index.html: 간단 웹 UIweb/intro.html: 인트로/상태 확인 페이지web/admin.html: 관리자 상태 페이지(MVP)web/js/*.js: 프론트엔드 로직 모듈web/styles.css: 공통 스타일scripts/validate_rag_doc.py: 등록 전 문서 검증 스크립트scripts/benchmark_multi_collection.py: 단일/다중 컬렉션 검색 비교 벤치scripts/benchmark_token_chunking.py: char/token 청킹 비교 벤치 스크립트scripts/benchmark_query_e2e.py:/queryE2E p95 벤치 스크립트scripts/benchmark_graphrag_sidecar.py: GraphRAG sidecar retrieval PoC/실측 스크립트scripts/eval_query_quality.py: answer-level/query품질 평가 스크립트scripts/runtime_preflight.py: P1 벤치 전 런타임 준비 상태 점검run_doc_rag.bat: 터미널 명령 없이 서버+브라우저 실행stop_doc_rag.bat: 실행 중인 로컬 서버 종료desktop/electron/*: 기존 웹 UI를 감싸는 실험용 Electron 데스크톱 래퍼 PoCAGENTS.md: 에이전트용 상시 작업 정책WORKFLOW.md: 사람/에이전트 공통 작업 순서requirements.txt: 런타임 의존성requirements-dev.txt: 테스트/브라우저 의존성.env.example: 환경변수 템플릿docs/PREPROCESSING_RULES.md: 전처리 규칙 초안docs/PREPROCESSING_PROMPT_TEMPLATE.md: 전처리 프롬프트 템플릿docs/PREPROCESSING_METADATA_SCHEMA.json: 전처리 메타데이터 스키마docs/UPLOAD_ADMIN_WORKFLOW.md: 업로드/갱신 관리자 워크플로우 설계 기준docs/GRAPH_RAG_QUESTION_SET.md: GraphRAG 판단용 관계형 질문셋evals/answer_level_eval_fixtures.jsonl: answer-level 평가 fixturedocs/GRAPH_RAG_SIDECAR_CONTRACT.md: GraphRAG sidecar 계약과 최소 적재 파이프라인docs/reports/GRAPH_RAG_ACTUAL_POC_REPORT_2026-03-17.md: GraphRAG retrieval PoC 1차 실측 결과docs/reports/GRAPH_RAG_VECTOR_GAP_REPORT_2026-03-17.md: 현재 Vector RAG 실패 사례와 Graph 후보 범위docs/reports/QUERY_ANSWER_EVAL_REPORT_2026-03-18_VECTOR_BASELINE.md: Vector RAG 1차 answer-level baseline 실측 결과docs/reports/QUERY_ANSWER_EVAL_REPORT_2026-03-18_GRAPH_SNAPSHOT.md: graph snapshot backend answer-level 비교 결과docs/reports/GRAPH_RAG_GO_NO_GO_REVIEW_2026-03-18.md: GraphRAG Go/No-Go 판단 문서docs/VECTORSTORE_POLICY.md: 벡터스토어 운영/용량 정책docs/COLLECTION_ROUTING_POLICY.md: 분야별 컬렉션/라우팅 정책docs/FUTURE_EXTERNAL_CONSTRAINTS.md: 외부 제한사항 중 추후 적용 항목docs/reports/DESKTOP_WRAPPER_POC_REPORT_2026-03-17.md: 데스크톱 래핑 PoC 결과 및 MVP 반영 판단docs/reports/DESKTOP_PACKAGING_HARDENING_REVIEW_2026-03-17.md: 데스크톱 패키징/배포 하드닝 재검토 결과
- Python 가상환경 생성(권장):
cd <repo>
python -m venv .venv- 런타임 패키지 설치:
cd <repo>
.venv\Scripts\python.exe -m pip install -r requirements.txt- 완전 오프라인 환경에서는 임베딩 모델
BAAI/bge-m3를 사전에 로컬 캐시에 준비하거나DOC_RAG_EMBEDDING_MODEL로 로컬 경로를 지정해야 합니다.
- 환경변수 파일 준비(권장):
cd <repo>
copy .env.example .env.env.example기본값은 로컬 우선 설정(ollama,qwen3:4b)입니다.
- Windows 빠른 실행(권장):
cd <repo>
.\run_doc_rag.bat.venv\Scripts\python.exe가 있으면 우선 사용하고, 없으면 시스템python을 찾습니다./health가 준비될 때까지 최대 45초 대기한 뒤http://127.0.0.1:8000/intro를 엽니다.
- 첫 실행이거나 상태 메시지에
vectors=0이 보이면 먼저 인덱싱:- 브라우저 왼쪽 메뉴에서
Reindex를 실행하거나
- 브라우저 왼쪽 메뉴에서
cd <repo>
.venv\Scripts\python.exe build_index.py --reset- 수동 실행이 필요하면:
cd <repo>
.venv\Scripts\python.exe app_api.py- 브라우저에서
http://127.0.0.1:8000/intro가 열리고,사용자 모드 시작버튼으로/app진입.- 관리자 모드는 인증 코드 입력 후
/admin진입
- 관리자 모드는 인증 코드 입력 후
- Windows 배치 실행 종료:
cd <repo>
.\stop_doc_rag.bat수동 실행 시에는 실행 중인 터미널에서 Ctrl+C로 종료할 수 있습니다.
기본 운영 경로는 계속 브라우저 UI이지만, desktop/electron에 최소 실행 가능한 Electron PoC를 추가했습니다.
cd <repo>\desktop\electron
npm install
npm run check
npm run preflight
npm run smoke
npm startnpm run preflight는 repo 경로, Python 런타임,app_apiimport, 기존/health, 기본 LLM 런타임 도달 여부를 먼저 점검합니다.npm run smoke는.venv의 Python 또는 시스템 Python으로app_api.py를 띄운 뒤/healthreadiness를 확인합니다.npm start는 같은 런타임을 Electron 창에 연결해/intro를 엽니다.- Electron 앱 시작 시에도 같은 preflight를 먼저 실행하고, blocking 실패가 있으면 창에서 바로 이유를 보여 줍니다.
- 현재 PoC는 설치형 제품이 아니라 "기존 웹 UI를 데스크톱 셸로 감쌀 수 있는지"를 검증하는 수준입니다.
- 결론과 리스크는
docs/reports/DESKTOP_WRAPPER_POC_REPORT_2026-03-17.md를 기준으로 봅니다. - 패키징/배포 하드닝 재검토 결과는
docs/reports/DESKTOP_PACKAGING_HARDENING_REVIEW_2026-03-17.md를 기준으로 보며, 현재 판단은 "보류 유지"입니다.
등록된 문서 기준으로 /query 응답의 완성도를 보려면 answer-level 평가 하네스를 사용합니다.
.venv\Scripts\python.exe scripts\eval_query_quality.py `
--base-url http://127.0.0.1:8000 `
--llm-provider ollama `
--llm-model qwen3:4b `
--llm-base-url http://localhost:11434 `
--output-json docs\reports\query_answer_eval_2026-03-17.json `
--output-report docs\reports\QUERY_ANSWER_EVAL_REPORT_2026-03-17.md- 기본 fixture는
evals/answer_level_eval_fixtures.jsonl을 사용합니다. - 현재 fixture는
ops-baseline과graph-candidate의 대표 질문 일부를 포함합니다. - 평가 항목은
must_include,must_include_any,must_not_include, 최소 답변 길이, 실제 route header를 기반으로 점수화됩니다. - 현재
/query는 최대 2개 컬렉션까지만 직접 선택 가능하므로, 3개 이상 컬렉션이 필요한 graph 질문은 vector baseline 평가 시collection=all로 fallback 합니다. - 이 스크립트는 GraphRAG 자체를 평가하는 것이 아니라, 현재 Vector RAG 기본 경로의 answer-level 기준선을 만드는 용도입니다.
2026-03-18기준 최신 baseline은docs/reports/QUERY_ANSWER_EVAL_REPORT_2026-03-18_VECTOR_BASELINE.md이며, 6개 fixture 중 2개만 통과했습니다.- 같은 실측에서
GQ-03은uk컬렉션 인덱스 부재로VECTORSTORE_EMPTY,GQ-05는fr,ge비교 질문에서LLM_TIMEOUT이 발생했습니다. - 같은 스크립트는
--backend graph_snapshot으로 graph snapshot 비교에도 재사용할 수 있습니다. docs/reports/QUERY_ANSWER_EVAL_REPORT_2026-03-18_GRAPH_SNAPSHOT.md기준graph-candidate3개 케이스는2/3 pass였지만,docs/reports/GRAPH_RAG_GO_NO_GO_REVIEW_2026-03-18.md기준 MVP 통합은 아직 No-Go입니다.- 공식 기본 임베딩
BAAI/bge-m3로컬 캐시가 없는 환경에서는DOC_RAG_EMBEDDING_MODEL에 로컬 경로를 주고,minishlab/potion-base-4M계열은DOC_RAG_EMBEDDING_DEVICE=cpu가 필요할 수 있습니다.
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: 관리자 반려- 운영 기준은
docs/UPLOAD_ADMIN_WORKFLOW.md를 따른다. GET /rag-docs는 repo의 seed 문서와 승인된 managed active 문서를 함께 반환한다.POST /upload-requests는 선택적으로request_type,doc_key,change_summary를 받을 수 있다.POST /upload-requests/{id}/reject는reason_code,decision_note를 함께 받을 수 있다.DOC_RAG_AUTO_APPROVE는create요청에만 적용되고update요청은 항상 관리자 승인 경로를 사용한다.- GraphRAG는 아직 기본 경로가 아니며, 현재는 graph snapshot 기반 retrieval PoC와 1차 측정까지만 반영된 상태다.
POST /reindex 응답의 validation에는 기계 판독용 필드와 함께
summary_text(예: total=5, usable=5, rejected=0, warnings=0, usable_ratio=100.00%)가 포함됩니다.
GET /health 응답에는 현재 적용 중인 chunking_mode(char 또는 token)와
embedding_model, query_timeout_seconds, max_context_chars, default_llm_provider,
default_llm_model, default_llm_base_url가 포함됩니다.
브라우저 기본 모드는 이 값을 받아 권장 LLM 설정을 자동 적용하고,
고급 설정 펼치기를 누른 경우에만 provider/model/base URL/API key를 직접 수정합니다.
POST /reindex 응답에는 실제 인덱싱에 사용된 chunking 설정이 포함됩니다.
POST /query에서 collection/collections를 명시하지 않으면 키워드 기반 자동 라우팅이 동작하고,
복수 국가 키워드가 동시에 감지되면 최대 2개 컬렉션까지 함께 조회합니다.
예시:
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\",\"request_type\":\"create\",\"doc_key\":\"new_doc\",\"change_summary\":\"초안 등록\",\"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헤더:- 실제 질의에 사용된 컬렉션 이름을 반환
-
X-RAG-Collections헤더:- 실제 질의에 사용된 전체 컬렉션 목록을 반환
- 자동 다중 라우팅이면 최대 2개 컬렉션이 쉼표로 연결된다
현재 정책:
trunk_rag는 전처리된 md를 입력으로 사용한다.- 전처리 가이드/규칙은
docs/PREPROCESSING_RULES.md를 기준으로 한다. - 외부 전처리 프롬프트 템플릿은
docs/PREPROCESSING_PROMPT_TEMPLATE.md를 사용한다. - 메타데이터 형식은
docs/PREPROCESSING_METADATA_SCHEMA.json을 따른다.
현재 적용 정책:
- 문서 등록 또는 인덱싱 전 검증을 수행하고
usable=true/false판정을 제공한다. - 불가(
usable=false) 문서는 벡터스토어에 반영하지 않는다.
참고:
- 본 정책의 상세 운영 기준은
docs/FUTURE_EXTERNAL_CONSTRAINTS.md에 정리한다.
.env.example를 복사해 .env 생성 후 사용.
-
기본 예시는
LLM_PROVIDER=ollama,LLM_MODEL=qwen3:4b -
로컬 기본 경로에서는
OLLAMA_BASE_URL=http://localhost:11434 -
오프라인 운영 시에는
DOC_RAG_EMBEDDING_MODEL로 지정한 경로 또는BAAI/bge-m3로컬 캐시가 필요 -
Ollama 기본 경로를 쓰려면 대상 모델이 로컬에 pull/run 된 상태여야 함
-
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) -
임베딩 모델(선택):
DOC_RAG_EMBEDDING_MODEL(기본BAAI/bge-m3, 로컬 경로 가능) -
임베딩 디바이스(선택):
DOC_RAG_EMBEDDING_DEVICE(예: Apple Silicon 로컬 모델은cpu권장)
운영 기본값 결정 메모(2026-03-15):
- 기본 청킹 모드는 계속
char를 사용합니다. token_800_120은 로컬 벤치에서 소폭 더 빨랐지만, 샘플 질의 품질 차이가 없어 기본값을 바꾸지 않았습니다.- 교차 국가 비교 질의는
all고정보다 자동 다중 라우팅(최대 2개 컬렉션)을 기본 경로로 둡니다. - 관련 근거는
docs/reports/QUERY_E2E_CHAR_VS_TOKEN_REPORT_2026-03-14.md,docs/reports/QUERY_QUALITY_ROUTE_REPORT_2026-03-15.md에 정리했습니다.
- 기본 질의 모드에서는
/health의 런타임 기본 LLM 설정을 자동 사용합니다. 고급 설정 펼치기를 눌러야 provider/model/base URL/API key를 직접 수정할 수 있습니다.vectors=0이면 질문 전Reindex를 먼저 실행하라는 안내가 표시됩니다.- 업로드 요청에서
Source Name은 비워둘 수 있고,country/doc_type은 컬렉션 기준 기본값을 따를 수 있습니다.
개발용 테스트 의존성 설치:
.venv\Scripts\python.exe -m pip install -r requirements-dev.txt
.venv\Scripts\python.exe -m playwright install chromiumElectron PoC 검증:
cd <repo>\desktop\electron
npm run check
npm run preflight
npm run smoke실행:
.venv\Scripts\python.exe -m pytest -q개별 실행:
.venv\Scripts\python.exe -m pytest -q tests/api
.venv\Scripts\python.exe -m pytest -q tests/test_chunking_modes.py
.venv\Scripts\python.exe -m 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\runtime_preflight.py --base-url http://127.0.0.1:8010blocked가 나오면DOC_RAG_EMBEDDING_MODEL,OLLAMA_BASE_URL,vectors=0, 포트 충돌을 먼저 정리합니다.- 다른 프로젝트가
8000포트를 쓰고 있으면 이 프로젝트 서버를 다른 포트로 띄우고 같은--base-url를 넘깁니다.
.venv\Scripts\python.exe scripts\benchmark_query_e2e.py `
--base-url http://127.0.0.1:8010 `
--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가 포함됩니다. charvstoken_800_120재측정 결과는docs/reports/QUERY_E2E_CHAR_VS_TOKEN_REPORT_2026-03-14.md에 정리돼 있습니다.- 샘플 질의 품질과 자동 다중 라우팅 결과는
docs/reports/QUERY_QUALITY_ROUTE_REPORT_2026-03-15.md에 정리돼 있습니다. - 느린 로컬 CPU 환경에서는 아래 런타임 설정을 권장:
DOC_RAG_QUERY_TIMEOUT_SECONDS=90DOC_RAG_OLLAMA_NUM_PREDICT=32DOC_RAG_MAX_CONTEXT_CHARS=300
데이터가 증가하면 속도/품질 저하 우려가 있습니다.
- 속도 리스크: 벡터 수 증가에 따른 검색 지연 증가
- 품질 리스크: 유사하지만 덜 관련된 청크가 상위로 노출(노이즈 증가)
정책:
- 무제한 적재 대신 컬렉션 용량 가이드를 둔다.
- 컬렉션당 cap:
30,000 ~ 50,000 vectors - cap은 토큰이 아니라 벡터(청크) 수 기준이다.
- 분야별 컬렉션으로 분할하고 단순 라우팅으로 조회 범위를 제한한다.
- 상세 수치와 대응 단계는
docs/VECTORSTORE_POLICY.md를 따른다. - 라우팅 방식 상세는
docs/COLLECTION_ROUTING_POLICY.md를 따른다.