- 아래 답변은 Anthropic의 Claude 모델로 자동 생성한 것으로, 정확하지 않을 수 있습니다.
- 잘못된 답변을 보셨다면 댓글로 첨삭 지도 부탁드립니다.

안녕하세요! 
외부 AI 접속이 제한된 환경에서 Local LLM + RAG로 코드베이스를 분석하려는 시도를 하고 계시는군요. Cursor처럼 워크스페이스를 잘 분석하고 싶은데, 파인튜닝 후에도 일관성 없는 답변이 나오고, RAG만으로는 AS-IS 시스템 분석에 한계가 있다는 고민이시네요. 충분히 공감됩니다!
문제 분석 및 해결 방안
Local LLM으로 코드베이스를 분석할 때 몇 가지 개선 방법을 제안드립니다:
1. RAG 개선: 코드 특화 청킹 및 임베딩
일반적인 텍스트 청킹 대신 코드 구조를 인식하는 청킹이 필요합니다:
import os
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
# 코드 특화 청킹 - 함수/클래스 단위로 분리
class CodeAwareTextSplitter:
def __init__(self, chunk_size=1500, chunk_overlap=200):
self.splitter = RecursiveCharacterTextSplitter(
separators=[
"\nclass ", "\ndef ", "\n\ndef ", # Python
"\npublic class ", "\nprivate ", "\nprotected ", # Java
"\nfunction ", "\nconst ", "\nexport ", # JavaScript
"\n\n", "\n", " "
],
chunk_size=chunk_size,
chunk_overlap=chunk_overlap
)
def split_with_metadata(self, code: str, file_path: str):
"""파일 경로와 함께 메타데이터 포함"""
chunks = self.splitter.split_text(code)
return [
{
"content": chunk,
"metadata": {
"file_path": file_path,
"file_type": os.path.splitext(file_path)[1]
}
}
for chunk in chunks
]
# 코드 특화 임베딩 모델 사용
embeddings = HuggingFaceEmbeddings(
model_name="microsoft/codebert-base", # 코드 특화 임베딩
# 또는 "BAAI/bge-base-en-v1.5" 도 좋은 선택
)
2. 코드 구조 그래프 생성 (AST 활용)
RAG만으로는 코드 간의 관계를 파악하기 어렵습니다. AST를 활용해 구조를 추출하세요:
import ast
import json
class CodeStructureExtractor:
"""Python 코드의 구조를 추출하여 LLM에게 컨텍스트 제공"""
def extract_structure(self, code: str, file_path: str) -> dict:
try:
tree = ast.parse(code)
structure = {
"file": file_path,
"classes": [],
"functions": [],
"imports": []
}
for node in ast.walk(tree):
if isinstance(node, ast.ClassDef):
methods = [n.name for n in node.body if isinstance(n, ast.FunctionDef)]
structure["classes"].append({
"name": node.name,
"methods": methods,
"line": node.lineno
})
elif isinstance(node, ast.FunctionDef) and not self._is_method(node, tree):
structure["functions"].append({
"name": node.name,
"args": [arg.arg for arg in node.args.args],
"line": node.lineno
})
elif isinstance(node, (ast.Import, ast.ImportFrom)):
structure["imports"].append(ast.unparse(node))
return structure
except SyntaxError:
return {"file": file_path, "error": "Parse failed"}
def _is_method(self, node, tree):
for parent in ast.walk(tree):
if isinstance(parent, ast.ClassDef) and node in parent.body:
return True
return False
# 전체 프로젝트 구조 요약 생성
def generate_project_summary(project_path: str) -> str:
extractor = CodeStructureExtractor()
all_structures = []
for root, dirs, files in os.walk(project_path):
dirs[:] = [d for d in dirs if d not in ['node_modules', '.git', '__pycache__', 'venv']]
for file in files:
if file.endswith('.py'):
file_path = os.path.join(root, file)
with open(file_path, 'r', encoding='utf-8') as f:
code = f.read()
structure = extractor.extract_structure(code, file_path)
all_structures.append(structure)
return json.dumps(all_structures, indent=2, ensure_ascii=False)
3. Multi-Step 분석 파이프라인
한 번의 질문으로 분석하지 말고, 단계별로 분석하세요:
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
class CodeAnalysisPipeline:
def __init__(self, model_name="Qwen/Qwen2.5-7B-Instruct"):
self.tokenizer = AutoTokenizer.from_pretrained(model_name)
self.model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.float16,
device_map="auto"
)
def analyze_system(self, project_summary: str, user_question: str):
"""3단계 분석 파이프라인"""
# Step 1: 프로젝트 구조 이해
step1_prompt = f"""당신은 코드 분석 전문가입니다.
다음 프로젝트 구조를 분석하고 핵심 컴포넌트를 파악하세요:
{project_summary[:4000]}
핵심 컴포넌트와 역할을 간단히 정리하세요:"""
structure_analysis = self._generate(step1_prompt)
# Step 2: 관련 코드 식별
step2_prompt = f"""프로젝트 분석 결과:
{structure_analysis}
사용자 질문: {user_question}
이 질문에 답하기 위해 어떤 파일/클래스/함수를 확인해야 하는지 나열하세요:"""
relevant_parts = self._generate(step2_prompt)
# Step 3: 최종 답변 (여기서 RAG로 관련 코드 검색 후 포함)
step3_prompt = f"""분석 컨텍스트:
{structure_analysis}
관련 코드 영역:
{relevant_parts}
사용자 질문: {user_question}
위 정보를 바탕으로 상세하게 답변하세요:"""
return self._generate(step3_prompt)
def _generate(self, prompt: str, max_new_tokens=1024):
messages = [{"role": "user", "content": prompt}]
text = self.tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True
)
inputs = self.tokenizer(text, return_tensors="pt").to(self.model.device)
outputs = self.model.generate(
**inputs,
max_new_tokens=max_new_tokens,
temperature=0.3, # 낮은 temperature로 일관성 향상
do_sample=True,
top_p=0.9
)
return self.tokenizer.decode(outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=True)
4. 파인튜닝 데이터 품질 개선
Unsloth로 파인튜닝 시 데이터 형식이 중요합니다:
# 좋은 파인튜닝 데이터 예시
training_data = [
{
"instruction": "다음 Python 클래스의 역할과 주요 메서드를 분석하세요.",
"input": """class UserService:
def __init__(self, db_connection):
self.db = db_connection
def get_user(self, user_id):
return self.db.query(User).filter_by(id=user_id).first()
def create_user(self, name, email):
user = User(name=name, email=email)
self.db.add(user)
self.db.commit()
return user""",
"output": """## UserService 클래스 분석
**역할**: 사용자 관련 데이터베이스 작업을 처리하는 서비스 레이어
**주요 메서드**:
1. `__init__(db_connection)`: DB 연결 객체를 주입받아 초기화
2. `get_user(user_id)`: ID로 사용자 조회 (단일 결과 반환)
3. `create_user(name, email)`: 새 사용자 생성 및 DB 저장
**패턴**: Repository/Service 패턴 사용, 의존성 주입(DI) 적용"""
}
]
5. 추가 팁
- Temperature 낮추기: 0.1~0.3으로 설정하면 "딴소리" 감소
- System Prompt 강화: 역할과 제약조건을 명확히 지정
- 더 큰 모델 고려: 가능하다면
qwen2.5:14b 또는 qwen2.5-coder 시리즈 사용
참고 자료
제 답변이 완벽하지 않을 수 있으니, 추가로 궁금한 점이나 구체적인 상황(예: 분석하려는 프로젝트 언어, 현재 RAG 구성 등)을 알려주시면 더 맞춤형 조언을 드릴 수 있습니다! 화이팅입니다! 
- 답변이 어떠셨나요? 괜찮았다고 생각하신다면 아래
를 한 번 눌러주시길 부탁드려요!