Skip to content

Feature/rag/#37#46

Merged
Yoo-SH merged 4 commits into
mainfrom
feature/rag/#37
Dec 15, 2025
Merged

Feature/rag/#37#46
Yoo-SH merged 4 commits into
mainfrom
feature/rag/#37

Conversation

@Yoo-SH

@Yoo-SH Yoo-SH commented Dec 15, 2025

Copy link
Copy Markdown
Member

📋 요약

RAG 시스템을 FastAPI로 분리하고, 로컬 개발 환경을 개선하며, 파일명 기반 검색 기능을 강화했습니다.

✨ 주요 변경사항

1. RAG 서비스 분리 및 리팩토링

  • FastAPI 기반 RAG 서비스 분리
  • LangChain 통합
  • Elasticsearch를 활용한 키워드 + 벡터 하이브리드 검색
  • 검색 가중치: 키워드 30% / 벡터 70%

2. 로컬 개발 환경 구축

  • Elasticsearch HTTP 모드 설정 (SSL 비활성화)
  • 임베딩 모델 통합 (bge-m3:latest, 1024차원)
  • 개발용 설정 파일 정리

3. MCP 서버 통합

  • Claude Code와 MCP 서버 연동
  • find_knowledge 및 get_content 도구 제공
  • HTTP 모드 설정 (localhost:3000)

4. 문서화 개선

  • QUICKSTART.md: 5분 빠른 시작 가이드
  • CLAUDE.md: Claude Code를 위한 프로젝트 가이드
  • .env.example: 환경 변수 템플릿
  • README.md: QUICKSTART 링크 추가

5. 검색 기능 강화

  • 파일명 기반 검색 추가 (metadata.originalFilename)
  • 검색 필드 가중치 최적화:
    • 파일명: 3.0배 (최우선)
    • 본문: 2.0배
    • 제목: 1.5배

6. 의존성 정리

  • Unstructured API 제거 (미사용)
  • docker-compose.yml 정리

🔧 기술 스택

  • Backend: Spring Boot 3.3.11 + Java 21
  • RAG Service: FastAPI + LangChain
  • Search: Elasticsearch (BM25 + Vector)
  • Embedding: Ollama bge-m3:latest (1024-dim)
  • MCP: Node.js MCP Adapter

📊 검색 개선 효과

Before:

  • 검색 필드: content, title (2개)
  • 파일명 매칭 시 낮은 순위

After:

  • 검색 필드: originalFilename, content, title (3개)
  • 파일명 정확 매칭 시 최우선 순위 (3배 가중치)

예시:

검색: "Spring Security Guide"
- Spring_Security_Guide.pdf → 1위 (파일명 매칭)
- API_Documentation.pdf → 2위 (내용 매칭)

🧪 테스트

  • 로컬 환경에서 Elasticsearch 연결 확인
  • MCP 서버 연동 테스트
  • 파일명 기반 검색 테스트
  • 하이브리드 검색 정확도 확인
  • 문서화 검증

📝 관련 이슈

🚀 배포 후 작업

  • 기존 문서 재인덱싱 (파일명 검색 적용)
  • 프로덕션 환경 Elasticsearch 설정 검토
  • 사용자 피드백 수집

리뷰 포인트:

  1. RAG 서비스 분리 아키텍처
  2. 파일명 기반 검색 가중치 적절성
  3. 문서화 완성도
  4. 로컬 개발 환경 설정 방식

- rag pipeline fastapi에서 처리
- langchain과 결합
- elasticsearch 데이터 저장 for(keyword, vector)
- 백엔드에서는 rag 검색만 진행
- 키워드(파일원본,제목,본문)검색+백터검색 3/7
- unstructed io 관련설정 제거

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a FastAPI-based RAG (Retrieval-Augmented Generation) service separation, migrating document processing from the Java Spring Boot core service to a dedicated Python microservice. The implementation includes hybrid search (BM25 + vector similarity), filename-based search enhancement, and improved local development setup.

Key Changes:

  • Separates RAG pipeline into standalone FastAPI service with LangChain and Ollama integration
  • Adds filename-based search field with 3x weighting for improved document retrieval
  • Implements paragraph-based chunking and PyMuPDF document parsing
  • Configures local development environment with HTTP-mode Elasticsearch

Reviewed changes

Copilot reviewed 37 out of 61 changed files in this pull request and generated 18 comments.

Show a summary per file
File Description
rag/requirements.txt Python dependencies for FastAPI RAG service
rag/app/services/*.py Core RAG services: parsing, chunking, embedding, indexing, and search
rag/app/api/v1/*.py FastAPI endpoints for document processing, search, and content retrieval
rag/app/config/settings.py Pydantic-based configuration management
rag/Dockerfile Container definition for RAG service
docker-compose.yml Replaces unstructured-api with FastAPI RAG service
core/src/main/java/com/opencontext/service/SearchService.java Adds filename field to search query with 3x boost
core/src/main/java/com/opencontext/service/IndexingService.java Stores originalFilename in metadata for search
core/src/main/java/com/opencontext/controller/SourceController.java Integrates with RAG service via REST API
core/src/main/resources/application*.yml Configuration updates for RAG service integration
core/src/main/java/com/opencontext/config/SecurityConfig.java Temporarily disables API authentication

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread rag/app/main.py
Comment on lines +30 to +36
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # In production, restrict to specific origins
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

Copilot AI Dec 15, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CORS middleware is configured to allow all origins with 'allow_origins=["*"]'. While the comment acknowledges this should be restricted in production, having permissive CORS in code increases the risk it will be deployed to production. Consider using environment-based configuration to enforce proper CORS settings.

Copilot uses AI. Check for mistakes.
Comment thread rag/app/api/v1/process.py

Pipeline:
1. Download file from presigned URL
2. Parse document (Unstructured.io)

Copilot AI Dec 15, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states 'Parse document (Unstructured.io)' but the code is actually using PyMuPDF for parsing. This is misleading and should be updated to reflect the actual implementation.

Suggested change
2. Parse document (Unstructured.io)
2. Parse document (PyMuPDF)

Copilot uses AI. Check for mistakes.
Comment thread rag/app/models/chunks.py
Comment on lines +23 to +25
title: str = Field(
...,
description="Section heading or title (from H1 header)"

Copilot AI Dec 15, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The field description states 'Section heading or title (from H1 header)' but the actual implementation extracts the title from the first line or first 50 characters of a paragraph, not from H1 headers. This misleading documentation should be updated to match the actual behavior.

Copilot uses AI. Check for mistakes.
Comment thread rag/app/models/chunks.py
Comment on lines +32 to +35
elementType: str = Field(
default="TitleBasedChunk",
description="Type of chunk (TitleBasedChunk for H1-split chunks)"
)

Copilot AI Dec 15, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The field description states 'Type of chunk (TitleBasedChunk for H1-split chunks)' with a default value of 'TitleBasedChunk', but the actual implementation uses 'ParagraphChunk' as the element type (line 88 in chunking.py). This inconsistency between the model default and actual usage should be corrected.

Copilot uses AI. Check for mistakes.
profiles:
active: dev

# Database Configuration (Development)

Copilot AI Dec 15, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment incorrectly describes the configuration as 'Docker' when it's actually for local development based on the values (localhost URLs). The profile is also set to 'dev' on line 6. Update the comment to accurately reflect this is a development configuration.

Copilot uses AI. Check for mistakes.
Comment thread rag/app/main.py
import logging

from app.config.settings import settings
from app.utils.exceptions import RagServiceException, rag_exception_handler

Copilot AI Dec 15, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'rag_exception_handler' is not used.

Copilot uses AI. Check for mistakes.
Comment thread rag/app/api/v1/process.py
Internal API called by core/ service after file upload.
"""
import logging
from fastapi import APIRouter, HTTPException

Copilot AI Dec 15, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'HTTPException' is not used.

Suggested change
from fastapi import APIRouter, HTTPException
from fastapi import APIRouter

Copilot uses AI. Check for mistakes.
Comment thread rag/app/api/v1/process.py
from app.models.responses import ProcessResponse
from app.services.parsing import DocumentParsingService
from app.services.chunking import ChunkingService
from app.services.embedding import EmbeddingService

Copilot AI Dec 15, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'EmbeddingService' is not used.

Suggested change
from app.services.embedding import EmbeddingService

Copilot uses AI. Check for mistakes.
Comment thread rag/app/api/v1/process.py
from app.services.parsing import DocumentParsingService
from app.services.chunking import ChunkingService
from app.services.embedding import EmbeddingService
from app.services.indexing import IndexingService

Copilot AI Dec 15, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'IndexingService' is not used.

Suggested change
from app.services.indexing import IndexingService

Copilot uses AI. Check for mistakes.
Provides accurate token counting for content retrieval with truncation support.
"""
import tiktoken
from typing import Optional

Copilot AI Dec 15, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'Optional' is not used.

Copilot uses AI. Check for mistakes.
@kAYI0019

Copy link
Copy Markdown
Member

RAG 리팩토링, 검색 정확도 개선, 문서화까지 고생하셨습니다!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BACKEND] RAG서버를 SPIRNG에서 분리하기

3 participants