LangChain 공식 문서를 기반으로 하는 지능형 RAG (Retrieval-Augmented Generation) 챗봇 시스템입니다.
┌─────────────────────────────────────────────────────────────┐
│ Streamlit UI (demo.py) │
│ 웹 인터페이스 및 시각화 │
└────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Main Integration (main.py) │
│ 모든 컴포넌트 통합 및 오케스트레이션 │
└────────────────────────┬────────────────────────────────────┘
│
┌───────────────────┼───────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ LLM Manager │ │ Retriever │ │Conversation │
│ (llm.py) │ │(retriever.py)│ │ Manager │
└─────────────┘ └─────────────┘ │(conversation│
│ .py) │
└─────────────┘
┌───────────────────┼───────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Vector DB │ │Data Collector│ │Text-to-SQL │
│(vector_db.py│ │(data_collector│ │ RAG │
└─────────────┘ │ .py) │ │(text_to_sql│
└──────────────┘ │ .py) │
└─────────────┘
┌───────────────────┼───────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Evaluator │ │ Prompts │ │ Config │
│(evaluator.py│ │(prompts.py) │ │ Manager │
└─────────────┘ └─────────────┘ │(config.py) │
└─────────────┘
┌─────────────────────────────────────────────────────────────┐
│ ▼ │
│ Databases & Storage │
│ ▼ │
│ ┌──────────────────┴──────────────────┐ │
│ ▼ ▼ │
│ ChromaDB SQLite │
│ (Vector Storage) (Metadata & Logs) │
│ │
└─────────────────────────────────────────────────────────────┘
python -m venv venv
source venv/bin/activate # macOS/Linux
# venv\Scripts\activate # Windows
pip install -r requirements.txt
cp .env.example .env
# .env 파일을 열어 API 키 설정
필수 환경변수:
팀작업은 SOLAR_API_KEY
UPSTAGE_API_KEY=your_upstage_api_key_here
DATABASE_URL=sqlite:///./data/langchain.db
CHROMA_PERSIST_DIRECTORY=./data/chroma_db
python scripts/init_db.py
python main.py
# 또는
streamlit run demo.py
# 대화 모드
python main.py --mode chat
# 단일 질문
python main.py --mode chat --question "LangChain이 무엇인가요?"
# 데이터 수집
python main.py --mode collect --urls https://python.langchain.com/docs/get_started
# 시스템 평가
python main.py --mode evaluate
# SQL 쿼리
python main.py --mode chat --sql --question "최근 문서 5개를 보여주세요"
from main import LangChainRAGChatbot
# 챗봇 초기화
chatbot = LangChainRAGChatbot()
# 대화 시작
conversation_id = chatbot.create_new_conversation()
# 질문하기
response = chatbot.chat(
question="LangChain의 주요 컴포넌트는 무엇인가요?",
conversation_id=conversation_id
)
print(response['answer'])
./data/langchain.dbdocuments ─┬─< code_examples (doc_id)
├─< api_references (doc_id)
└─< messages (via conversation)
conversations ─┬─< messages (conversation_id)
└─< conversation_history (session_id)
evaluations (독립 테이블 - 평가 데이터)
CREATE TABLE documents (
id INTEGER PRIMARY KEY AUTOINCREMENT,
doc_id VARCHAR(255) UNIQUE NOT NULL, -- 문서 고유 ID
title VARCHAR(500), -- 문서 제목
url TEXT, -- 원본 URL
category VARCHAR(100), -- 카테고리 (general, modules, agents 등)
module_name VARCHAR(200), -- 모듈 이름
content TEXT NOT NULL, -- 문서 내용 (전체 텍스트)
summary TEXT, -- 문서 요약
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 인덱스
CREATE INDEX idx_documents_category ON documents(category);
CREATE INDEX idx_documents_created_at ON documents(created_at);
현재 데이터: 63개 레코드 (LangChain 공식 문서)
CREATE TABLE code_examples (
id INTEGER PRIMARY KEY AUTOINCREMENT,
doc_id VARCHAR(255), -- 관련 문서 ID
language VARCHAR(50), -- 프로그래밍 언어 (python, javascript 등)
code TEXT NOT NULL, -- 코드 내용
description TEXT, -- 코드 설명
imports TEXT, -- import 구문
FOREIGN KEY (doc_id) REFERENCES documents(doc_id)
);
현재 데이터: 0개 레코드 (추가 예정)
CREATE TABLE api_references (
id INTEGER PRIMARY KEY AUTOINCREMENT,
class_name VARCHAR(200), -- 클래스 이름
method_name VARCHAR(200), -- 메서드 이름
parameters TEXT, -- 파라미터 (JSON 형식)
return_type VARCHAR(100), -- 반환 타입
description TEXT, -- 설명
doc_id VARCHAR(255), -- 관련 문서 ID
FOREIGN KEY (doc_id) REFERENCES documents(doc_id)
);
현재 데이터: 0개 레코드 (추가 예정)
CREATE TABLE conversations (
id TEXT PRIMARY KEY, -- 대화 세션 ID
title TEXT, -- 대화 제목
summary TEXT, -- 대화 요약
metadata TEXT, -- 메타데이터 (JSON)
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
현재 데이터: 0개 레코드
CREATE TABLE messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
conversation_id TEXT NOT NULL, -- 대화 세션 ID
role TEXT NOT NULL, -- 역할 (user, assistant, system)
content TEXT NOT NULL, -- 메시지 내용
metadata TEXT, -- 메타데이터 (JSON)
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (conversation_id) REFERENCES conversations(id)
);
-- 인덱스
CREATE INDEX idx_messages_conversation ON messages(conversation_id);
CREATE INDEX idx_messages_created_at ON messages(created_at);
현재 데이터: 0개 레코드
CREATE TABLE conversation_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id VARCHAR(255), -- 세션 ID
role VARCHAR(50), -- 역할 (user, assistant)
content TEXT, -- 대화 내용
metadata TEXT, -- 메타데이터 (JSON)
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 인덱스
CREATE INDEX idx_session_id ON conversation_history(session_id);
현재 데이터: 대화 진행 시 자동 저장
CREATE TABLE evaluations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
question TEXT NOT NULL, -- 질문
generated_answer TEXT, -- 생성된 답변
reference_answer TEXT, -- 참조 답변
relevance_score REAL, -- 관련성 점수 (0-1)
accuracy_score REAL, -- 정확도 점수 (0-1)
completeness_score REAL, -- 완전성 점수 (0-1)
response_time REAL, -- 응답 시간 (초)
retrieval_precision REAL, -- 검색 정밀도
retrieval_recall REAL, -- 검색 재현율
overall_score REAL, -- 종합 점수
metadata TEXT, -- 메타데이터 (JSON)
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
현재 데이터: 평가 실행 시 저장
-- 최근 추가된 문서 5개 조회
SELECT title, category, created_at
FROM documents
ORDER BY created_at DESC
LIMIT 5;
-- 특정 카테고리의 문서 개수
SELECT category, COUNT(*) as count
FROM documents
GROUP BY category
ORDER BY count DESC;
-- Agent 관련 문서 검색
SELECT doc_id, title, url
FROM documents
WHERE content LIKE '%Agent%'
AND category IN ('modules', 'agents');
-- 특정 세션의 대화 이력
SELECT role, content, timestamp
FROM conversation_history
WHERE session_id = ?
ORDER BY timestamp ASC;
-- 최근 대화 세션 목록
SELECT id, title, created_at
FROM conversations
ORDER BY created_at DESC
LIMIT 10;
-- 평균 성능 지표
SELECT
AVG(relevance_score) as avg_relevance,
AVG(accuracy_score) as avg_accuracy,
AVG(response_time) as avg_response_time
FROM evaluations
WHERE created_at >= datetime('now', '-7 days');
-- 성능이 우수한 질문/답변 쌍
SELECT question, generated_answer, overall_score
FROM evaluations
WHERE overall_score >= 0.8
ORDER BY overall_score DESC
LIMIT 10;
자연어 질문을 SQL로 자동 변환:
from text_to_sql import TextToSQLRAG
sql_rag = TextToSQLRAG()
# 자연어 → SQL
question = "최근 일주일 동안 추가된 문서는 몇 개야?"
sql_query = sql_rag.generate_sql(question)
# 생성된 SQL: SELECT COUNT(*) FROM documents WHERE created_at >= datetime('now', '-7 days')
# SQL 실행
result = sql_rag.execute_sql(sql_query)
print(f"결과: {result.results}")
CREATE TABLE code_examples (
id INTEGER PRIMARY KEY AUTOINCREMENT,
doc_id TEXT NOT NULL, -- documents 테이블 참조
title TEXT, -- 코드 예제 제목
code TEXT NOT NULL, -- 코드 내용
language TEXT DEFAULT 'python', -- 프로그래밍 언어
description TEXT, -- 설명
output TEXT, -- 예상 출력
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (doc_id) REFERENCES documents (doc_id)
);
-- 인덱스
CREATE INDEX idx_code_examples_doc_id ON code_examples(doc_id);
CREATE INDEX idx_code_examples_language ON code_examples(language);
#### 3. api_references 테이블
```sql
CREATE TABLE api_references (
id INTEGER PRIMARY KEY AUTOINCREMENT,
doc_id TEXT NOT NULL, -- documents 테이블 참조
class_name TEXT, -- 클래스 이름
method_name TEXT, -- 메서드 이름
parameters TEXT, -- 파라미터 정보 (JSON)
returns TEXT, -- 반환 값
description TEXT, -- 설명
example_usage TEXT, -- 사용 예제
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (doc_id) REFERENCES documents (doc_id)
);
-- 인덱스
CREATE INDEX idx_api_references_class ON api_references(class_name);
CREATE INDEX idx_api_references_method ON api_references(method_name);
CREATE TABLE conversations (
id TEXT PRIMARY KEY, -- 대화 세션 ID
title TEXT, -- 대화 제목
summary TEXT, -- 대화 요약
metadata TEXT, -- JSON 형식 메타데이터
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
conversation_id TEXT NOT NULL, -- conversations 테이블 참조
role TEXT NOT NULL, -- 'user' 또는 'assistant'
content TEXT NOT NULL, -- 메시지 내용
metadata TEXT, -- JSON 형식 메타데이터
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (conversation_id) REFERENCES conversations (id)
);
-- 인덱스
CREATE INDEX idx_messages_conversation ON messages(conversation_id);
CREATE INDEX idx_messages_created_at ON messages(created_at);
CREATE TABLE evaluations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
question TEXT NOT NULL, -- 평가용 질문
generated_answer TEXT, -- 생성된 답변
reference_answer TEXT, -- 참조 답변
relevance_score REAL, -- 관련성 점수 (0-1)
accuracy_score REAL, -- 정확도 점수 (0-1)
completeness_score REAL, -- 완전성 점수 (0-1)
response_time REAL, -- 응답 시간 (초)
retrieval_precision REAL, -- 검색 정밀도
retrieval_recall REAL, -- 검색 재현율
overall_score REAL, -- 종합 점수 (0-1)
metadata TEXT, -- JSON 형식 메타데이터
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 인덱스
CREATE INDEX idx_evaluations_overall_score ON evaluations(overall_score);
CREATE INDEX idx_evaluations_created_at ON evaluations(created_at);
{
"ids": ["doc_001_chunk_0", "doc_001_chunk_1", ...],
"embeddings": [[0.1, 0.2, ...], [0.3, 0.4, ...], ...],
"metadatas": [
{
"doc_id": "doc_001",
"title": "Introduction to LangChain",
"url": "https://...",
"category": "tutorials",
"chunk_index": 0,
"created_at": "2024-01-01T00:00:00"
},
...
],
"documents": ["LangChain is a framework...", "It provides...", ...]
}
llm.py - LLM 및 임베딩 관리
vector_database.py - 벡터 데이터베이스 관리
prompts.py - 프롬프트 템플릿 관리
data_collector.py - 데이터 수집 및 처리
retriever.py - 검색 시스템
conversation.py - 대화 관리
text_to_sql.py - Text-to-SQL RAG
evaluator.py - 성능 평가
demo.py - Streamlit UI
main.py - 통합 모듈
utils.py - 유틸리티 함수
config.py - 설정 관리
requirements.txt - 의존성 목록
chatbot = LangChainRAGChatbot(config={
'model_name': 'solar-1-mini-chat',
'temperature': 0.7,
'search_mode': 'hybrid',
'top_k': 5
})
response = chatbot.chat(
question="질문 내용",
conversation_id="conv_123", # 선택사항
use_sql=False, # SQL 모드
evaluate=False # 평가 모드
)
# 반환: {'answer': str, 'sources': list, 'error': str}
results = chatbot.collect_documents(
urls=["https://example.com/docs"]
)
# 반환: {'total_documents': int, 'successful_urls': list, 'failed_urls': list}
stats = chatbot.evaluate_system(
test_cases=[
{'question': '...', 'reference_answer': '...'}
]
)
# 반환: {'avg_overall_score': float, 'avg_response_time': float, ...}
python -m pytest tests/ -v
# LLM 모듈 테스트
python llm.py
# 벡터 DB 테스트
python vector_database.py
# Retriever 테스트
python retriever.py
# 평가 시스템 테스트
python evaluator.py
python scripts/test_integration.py
main: 안정화된 버전develop: 개발 버전feature/*: 기능 개발 브랜치hotfix/*: 긴급 수정 브랜치feat: 새로운 기능 추가
fix: 버그 수정
docs: 문서 수정
style: 코드 포맷팅
refactor: 코드 리팩토링
test: 테스트 추가
chore: 빌드 업무 수정
LangChain 문서의 특성을 고려한 지능형 텍스트 분할 시스템을 구현했습니다. 코드 블록, 함수 시그니처, Markdown 구조를 보존하면서 효과적으로 문서를 청킹합니다.
advanced_text_splitter.py: 구조 기반 텍스트 분할기StructuredTextSplitter: Markdown/코드 구조 인식 분할HTMLStructuredSplitter: HTML 문서 전용 분할data_collector.py: 향상된 크롤러 및 청킹 통합from advanced_text_splitter import StructuredTextSplitter
from langchain.schema import Document
# 구조 기반 분할기 생성
splitter = StructuredTextSplitter(
chunk_size=1500,
chunk_overlap=200,
preserve_code_blocks=True,
preserve_functions=True,
preserve_markdown_structure=True
)
# 문서 분할
doc = Document(page_content=markdown_text, metadata={})
chunks = splitter.split_documents([doc])
# 각 청크는 메타데이터에 구조 정보 포함
for chunk in chunks:
print(f"타입: {chunk.metadata.get('chunk_type')}")
print(f"섹션: {chunk.metadata.get('section_title')}")
print(f"함수들: {chunk.metadata.get('functions', [])}")
code_block_max_size보다 크면 함수/클래스 단위로 분할section_title, section_level청크별 메타데이터:
chunk_type: "code", "text", "header", "section"language: 코드 블록의 프로그래밍 언어functions: 포함된 함수 이름 리스트classes: 포함된 클래스 이름 리스트has_code: 코드 포함 여부| 항목 | 일반 분할기 | 구조 기반 분할기 |
|---|---|---|
| 코드 블록 보존 | ❌ 분할될 수 있음 | ✅ 완전 보존 |
| 함수 정의 유지 | ❌ 중간에 잘림 | ✅ 함수 단위 유지 |
| 검색 정확도 | 보통 | 높음 |
| 컨텍스트 품질 | 단순 텍스트 | 구조적 컨텍스트 |
API 키 관리
데이터 보호
접근 제어
feature/issue-번호)