AI가 스스로 배우고 자신을 개선한다 — self_apply.py 구축 삽질기

growth_log에 쌓인 인사이트를 LLM이 분류하고 실제 시스템에 자동 적용하는 파이프라인. 만들면서 겪은 삽질들.

AI가 스스로 배우고 자신을 개선한다 — self_apply.py 구축 삽질기

아이디어

매일 JARVIS 시스템을 개선합니다. 그 과정에서 배운 것들을 growth_log.md에 씁니다.

# growth_log.md

## 2026-05-18
- devstral:24b 봇회의 타임아웃 문제 → gemma3:12b로 교체해야 함
- JSON 파싱 실패 시 재시도 로직 없음 → 추가 필요
- Ollama 모델 존재 확인 안 하고 pull 시도 → hub 확인 먼저 해야 함

이게 쌓이면 나중에 안 봅니다. 그냥 있습니다.

“이걸 AI가 읽고 자동으로 적용하면 어떨까?“


self_apply.py 동작 방식

매일 06:30 자동 실행:

1. growth_log.md 읽기 (최근 항목)
2. LLM에게 분류 요청
   → 카테고리: model_change / code_fix / config_update / skip
3. 카테고리별 처리
   - model_change: Ollama hub에서 모델 존재 확인 → pull 시도
   - code_fix: 해당 파일 수정 내용 생성 → 적용
   - config_update: 설정 파일 갱신
4. 결과 Telegram 보고

핵심 코드 (핵심 부분만)

VALID_TYPES = ["model_change", "code_fix", "config_update", "skip"]

def _categorize_insight(insight_text: str) -> dict:
    """LLM에게 인사이트 분류 요청. JSON 파싱 실패 시 재시도."""
    
    prompt = f"""
다음 인사이트를 분류하세요.

인사이트: {insight_text}

반드시 아래 JSON 형식으로만 응답하세요 (다른 텍스트 없이):
{{"type": "model_change|code_fix|config_update|skip", "action": "구체적 실행 내용"}}
"""
    
    for attempt in range(3):  # 최대 2회 재시도
        response = ask_ollama(prompt)
        try:
            # 마크다운 코드블록 제거
            cleaned = re.sub(r'```json?\n?|```', '', response).strip()
            result = json.loads(cleaned)
            
            if result.get("type") in VALID_TYPES:
                return result
                
        except (json.JSONDecodeError, KeyError):
            pass
        
        # 재시도 프롬프트 강화
        prompt = prompt + "\n\n반드시 순수 JSON만. 마크다운 없이."
    
    return {"type": "skip", "action": "파싱 실패"}

모델 존재 확인

Ollama 모델을 pull하기 전에 존재하는지 확인합니다.

def _hub_model_exists(model_name: str) -> bool:
    """ollama.com에서 모델 존재 여부 확인."""
    # model_name 예: "gemma3:12b"
    name_part = model_name.split(":")[0]
    url = f"https://ollama.com/library/{name_part}"
    
    try:
        response = requests.head(url, timeout=10)
        return response.status_code == 200
    except Exception:
        return False

처음엔 이 확인 없이 바로 pull을 시도했습니다. 존재하지 않는 모델명이 growth_log에 오타로 들어가면 pull이 한참 기다리다 실패했습니다.


겪었던 삽질들

삽질 1: JSON 파싱 실패율 30%

LLM(특히 소형 모델)이 JSON을 정확히 출력하는 비율이 낮았습니다.

출력 예:

# 이렇게 나옴
다음과 같이 분류됩니다:

```json
{
  "type": "model_change",
  "action": "devstral 대신 gemma3 사용"
}

코드블록으로 감싸거나, 앞에 설명 텍스트 붙이거나, 키 이름이 달라지거나.

해결: 정규식으로 코드블록 제거 + 2회 재시도 + 재시도 시 프롬프트 강화.

### 삽질 2: 타임아웃 60초

처음 debate 타임아웃이 60초였습니다. 14B 모델이 복잡한 분류 작업을 하면 60초 안에 못 끝냈습니다.

150초로 늘렸습니다.

### 삽질 3: code_fix 자동 적용의 위험성

LLM이 "이 파일 이렇게 수정하세요"라고 하면 그대로 적용했습니다.

문제: LLM이 잘못된 수정안을 제안하면 그대로 들어갑니다. 한 번은 import 구문을 잘못 수정해서 봇이 다운됐습니다.

해결: `code_fix` 타입은 자동 적용 중단. Telegram으로 수정 제안만 보내고 사람이 확인 후 적용.

```python
if insight["type"] == "code_fix":
    # 자동 적용 안 함
    send_telegram(f"코드 수정 제안:\n{insight['action']}\n\n직접 확인 후 적용 요망")
    continue

삽질 4: devstral:24b → gemma3:12b 교체

자동화 분류 작업에 큰 모델이 필요할 것 같아서 devstral:24b를 썼습니다.

현실: 단순 분류에 24B 파라미터는 과함. 로딩 시간만 길어지고 결과는 비슷.

12B로 줄이니까 2배 빠르고 타임아웃도 없어졌습니다.


현재 상태

자동으로 처리하는 것:

  • model_change: Ollama 모델 교체 제안 → 사람이 확인 후 실행
  • config_update: 설정값 변경 → 검토 후 적용
  • skip: 그냥 넘김

자동 코드 수정은 중단했습니다. 제안만 받습니다.


결론

“AI가 스스로 개선한다”는 아이디어는 좋지만 완전 자동화는 위험합니다. 특히 코드 수정은.

현재는 “AI가 분석하고, 사람이 적용”하는 반자동 방식으로 씁니다. 이게 더 안전합니다.

#Python#자동화#LLM#자가개선#JARVIS