파인튜닝 관련 문의 좀 드립니다.

안녕하세요.

저는 커서를 이용해서 개발을 하고 있는 개발자 입니다.

회사에서는 자유롭게 커서를 사용할수 있지만, 한번씩 프로젝트를 나가게 되면 대부분 외부 AI와의 접속을 허용하지 않아서 local llm을 이용해서 프로젝트를 분석해보려고 local llm +RAG 시스템을 개발하게 되었는데, 아무래도 좀 부족한 부분들이 생기고 기존 AI에 익숙하다보니 커서와 같이 워크스페이스를 뛰어나게 분석하는데는 무리가 있나 봅니다.

그래서 unsloth를 이용해서 파인튜닝도 해봤는데, 튜닝후에는 local llm(qwen2.5:7b-instruct 기반) 이 잘 분석하는거 같더니 또 딴소리를 하기도 하더군요..ㅡㅡ

RAG는 Q&A에 가까워서 AS-IS 시스템을 분석하는데 한계가 있더군요..

혹시라도 local llm + RAG를 이용해서 (다른 방법이라도) AS-IS 시스템을 제대로 분석할만한 방법이 있을까요?

두서없이 주절거리다 보니.. 질문이 제대로 된건지도 잘 모르겠네요..ㅡㅡ

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

안녕하세요! 그런 상황에서 어려움을 겪으셨다니 이해가 됩니다. 파인튜닝을 시도해보셨다는데, 결과가 만족스럽지 않으셨군요. 특히, local LLM과 RAG 시스템을 사용하여 AS-IS 시스템을 분석하는 데 어려움이 있다는 점을 말씀하셨네요.

Local LLM과 RAG 시스템의 결합은 상당히 흥미로운 접근이지만, AS-IS 시스템 분석에 있어서의 특별한 한계에 봉착한 것 같습니다. 몇 가지 도움될 수 있는 방법을 고려해 볼 수 있습니다:

  1. 파인튜닝의 개선:

    • 파인튜닝은 모델이 특정한 도메인에 잘 적응하도록 하는 작업입니다. 이를 위해서는 더 많은 도메인별 데이터가 필요할 수 있습니다.
    • 데이터 준비 과정에서 데이터의 질이 충분히 높은지, 라벨링이 잘 되었는지도 확인해 보세요.
  2. Feature Extraction 및 Embedding:

    • 분석하고자 하는 시스템의 주요 기능들을 추출하여, 이를 Embedding으로 변환하면 더 나은 결과를 얻을 수 있습니다.
    • PyTorch를 사용하여 Embedding Layer로 기능 벡터를 만들고 추론에 활용할 수 있습니다.
  3. 모델의 Fine-Tuning과 옵티마이제이션:

    • 학습률(lr) 조정이나 옵티마이저 변경을 통해 모델의 성능을 개선해 보세요.
    • 예를 들어, Adam 옵티마이저를 사용해볼 수 있습니다.
  4. 다른 AI 및 분석 테크닉 병행 사용:

    • RAG가 Q&A 시스템에 가까우므로, 다른 심층분석 기법인 Transformer 기반의 접근을 추가로 활용하는 것도 좋습니다.

다음은 간단한 파인튜닝 예제 코드입니다. 가정된 LLM 모델에 대한 PyTorch를 이용한 기본적인 접근 방식입니다:

import torch
from transformers import AdamW, get_linear_schedule_with_warmup
from transformers import GPT2Tokenizer, GPT2LMHeadModel

# 모델과 토크나이저를 로드합니다.
tokenizer = GPT2Tokenizer.from_pretrained('gpt2')
model = GPT2LMHeadModel.from_pretrained('gpt2')

# 데이터 전처리
text = "여러분은 PyTorch로 파인튜닝을 하고 있습니다."
inputs = tokenizer(text, return_tensors='pt')

# 옵티마이저와 학습률 스케줄러 설정
optimizer = AdamW(model.parameters(), lr=5e-5)
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=0, num_training_steps=100)

# 모델 훈련 루프
model.train()
epochs = 3
for epoch in range(epochs):
    outputs = model(**inputs, labels=inputs["input_ids"])
    loss = outputs.loss
    loss.backward()
    
    optimizer.step()
    scheduler.step()
    optimizer.zero_grad()
    
    print(f'Epoch {epoch+1}, Loss: {loss.item()}')

파인튜닝을 어떻게 하는지에 대한 더 자세한 자료는 PyTorch 튜토리얼 페이지에서 확인하실 수 있습니다. 이곳에서 다양한 튜토리얼과 예제를 보실 수 있습니다.

도움이 되셨기를 바라며, 추가적인 질문이 있으면 언제든지 말씀해 주세요. 제 답변이 모든 상황에 완벽히 맞지는 않을 수 있으니, 직접 적용하며 테스트도 해보시면 좋겠습니다.


  • 답변이 어떠셨나요? 괜찮았다고 생각하신다면 아래 :+1:를 한 번 눌러주시길 부탁드려요!
1개의 좋아요
  • 아래 답변은 Anthropic의 Claude 모델로 자동 생성한 것으로, 정확하지 않을 수 있습니다.
  • 잘못된 답변을 보셨다면 댓글로 첨삭 지도 부탁드립니다. :sweat_smile:

안녕하세요! :blush:

외부 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 구성 등)을 알려주시면 더 맞춤형 조언을 드릴 수 있습니다! 화이팅입니다! :flexed_biceps:


  • 답변이 어떠셨나요? 괜찮았다고 생각하신다면 아래 :+1:를 한 번 눌러주시길 부탁드려요!
1개의 좋아요
  • 아래 답변은 OpenAI의 GPT-4o 모델로 자동 생성한 것으로, 정확하지 않을 수 있습니다.
  • 잘못된 답변을 보셨다면 댓글로 첨삭 지도 부탁드립니다. :sweat_smile:

안녕하세요! 파인튜닝과 관련된 문제로 고민이 많으시군요. 프로젝트 환경에서 외부 AI와의 접속이 제한되어 있어 local LLM과 RAG 시스템을 활용하여 AS-IS 시스템을 분석하려고 하셨지만, 기대한 만큼의 성능을 얻지 못하신 것 같습니다. 특히, 파인튜닝을 통해 성능을 개선하려고 했지만 여전히 만족스럽지 않은 결과를 얻으신 것 같네요.

파인튜닝과 RAG 시스템을 활용하여 AS-IS 시스템을 분석하는 데 있어서 몇 가지 고려할 점과 개선 방법을 제안드리겠습니다.

  1. 데이터 품질 및 양: 파인튜닝의 성능은 주로 사용된 데이터의 품질과 양에 크게 의존합니다. 데이터가 충분히 다양하고, 분석하려는 시스템의 특성을 잘 반영하고 있는지 확인해보세요. 데이터가 부족하거나 편향되어 있다면, 추가적인 데이터를 수집하거나 데이터 증강 기법을 활용해보는 것도 좋습니다.

  2. 모델 아키텍처: 사용하신 모델이 특정 작업에 적합한지 검토해보세요. Qwen2.5:7b-instruct 기반의 모델이 특정 도메인이나 작업에 최적화되어 있지 않을 수 있습니다. 다른 모델 아키텍처나 파라미터를 실험해보는 것도 방법입니다.

  3. RAG 시스템의 활용: RAG 시스템은 주로 Q&A 형식의 작업에 적합합니다. AS-IS 시스템 분석과 같은 복잡한 작업에는 추가적인 전처리나 후처리 단계가 필요할 수 있습니다. 예를 들어, 시스템의 구조적 정보를 추출하고 이를 기반으로 분석을 수행하는 방법을 고려해보세요.

  4. 모델 평가 및 개선: 모델의 성능을 평가하고, 개선할 수 있는 부분을 식별하는 것이 중요합니다. 모델의 예측 결과를 분석하여 어떤 부분에서 오류가 발생하는지 파악하고, 이를 개선하기 위한 전략을 수립하세요.

다음은 PyTorch를 사용하여 파인튜닝을 수행하는 기본적인 예제 코드입니다. 이 코드를 기반으로 다양한 실험을 진행해보세요.

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, Trainer, TrainingArguments

# 모델과 토크나이저 로드
model_name = "qwen2.5:7b-instruct"
model = AutoModelForCausalLM.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# 데이터셋 준비
train_texts = ["example text 1", "example text 2"]  # 여기에 실제 데이터를 넣으세요.
train_encodings = tokenizer(train_texts, truncation=True, padding=True, return_tensors="pt")

# 데이터셋 클래스 정의
class CustomDataset(torch.utils.data.Dataset):
    def __init__(self, encodings):
        self.encodings = encodings

    def __getitem__(self, idx):
        return {key: tensor[idx] for key, tensor in self.encodings.items()}

    def __len__(self):
        return len(self.encodings.input_ids)

train_dataset = CustomDataset(train_encodings)

# 트레이너 설정
training_args = TrainingArguments(
    output_dir="./results",
    num_train_epochs=3,
    per_device_train_batch_size=2,
    save_steps=10_000,
    save_total_limit=2,
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset,
)

# 파인튜닝 수행
trainer.train()

이 코드에서는 transformers 라이브러리를 사용하여 모델을 파인튜닝하는 방법을 보여줍니다. 데이터셋을 준비하고, 트레이너를 설정한 후, trainer.train()을 호출하여 파인튜닝을 수행합니다.

더 많은 정보를 얻고 싶으시다면, PyTorch의 공식 튜토리얼을 참고해보세요. PyTorch 튜토리얼에서는 다양한 예제와 설명을 제공하고 있습니다. 한국어로 된 튜토리얼은 여기에서 확인하실 수 있습니다.

혹시라도 제 답변이 부족하거나 잘못된 부분이 있다면 언제든지 추가 질문을 남겨주세요. 도움이 되셨길 바랍니다!


  • 이 답변이 도움이 되셨나요? 괜찮았다고 생각하신다면 아래 :heart:를 한 번 눌러주시길 부탁드려요!