# 로컬 LLM 전문화 파이프라인 — OPUS-v2 실행계획

> **v1 후속.** v1(`ReferenceSources/.../plans/online-lora-학습-파이프라인-실행계획-byOPUS.md`)의
> "small dense + system 충분" 가정을 production 데이터로 폐기.
> **Verifier를 최선두로, 35B production을 기본으로, LoRA를 가속 트랙으로.**

---

## v1 → v2 핵심 변경

| 항목 | v1 | v2 |
|---|---|---|
| Production 모델 | 소형 dense (Qwen3-8B) | **A: Qwen3.6-35B-A3B-FP8** (기본 체력 floor) |
| **Verifier 위치** | Phase 2 (중기, 보조) | **Phase B — 최선두**, 며칠 내 MVP |
| LoRA 위치 | Phase 3~4 (조건부) | **Phase C — 적극 가속** (2~4주, 행동 *학습*) |
| "small + system 충분" 가설 | 가능 | **폐기** — production messy 환경에서 8B는 L2~L4 RAG 실패 |
| Production · LoRA 베이스 동일성 | 동일 가정 | **분리 가능성 명시** |
| 역할 분리(클라우드 프런티어) | 미고려 | **Phase D — 의제화** (안전 critical 옵션) |

---

## 핵심 진단 — 사용자 발견의 반영

### "RAG는 사이즈 무관"이 틀렸다 (4층 분해)

| 층 | 능력 | 사이즈 의존? | 8B (production 실측) |
|---|---|---|---|
| **L1** 순수 lookup | "X 가져와" → DB 반환 | ❌ 무관 | ✅ (코드 레벨) |
| **L2** 언제 검색할지 판단 | 모호 → *먼저* find_tags 호출, 추측 금지 | ✅ 의존 | ❌ `raw_material_input` 합성 |
| **L3** 무엇을·어떤 형식으로 | `area="P6-1"` 형식 준수, base_tag 구조 인식 | ✅ 의존 | ❌ `area="6-1"` 잘못 |
| **L4** 결과를 *충실히* 사용 | 빈 결과면 자기 인자 의심, 무필터 결과 둔갑 금지 | ✅ 의존 | ❌ 전체 area를 "6-1차"로 포장 |

→ **L2~L4가 무너지면 RAG 환경을 아무리 잘 깔아도 "사실 조회조차 못함" = 기본 체력 부족.**
이건 통제된 Phase 0 eval에선 안 잡힘(스캐폴드 100%, abstain 100%였음). production messy 환경에서야 드러남.
**작은 모델은 production operator brain으로 부적합** — 사용자 직관 데이터 확인.

### "부분 진실 fabrication"이 가장 위험
A35B도 가끔 헛소리하는데, 가장 위험한 패턴은:
- 실제 태그(p-6102) + 지어낸 상태(R-FAULT)
- 실제 데이터(전체 area 결과) + 잘못된 필터 포장("6-1차 결과")
- 실제 도구(trace_connections) + 지어낸 인자(raw_material_input)

표면이 그럴듯해 운전원이 알아채기 어려움 → **결정적 코드 검증(Verifier)이 유일한 신뢰 가능 차단선.**

---

## Phase B — Verifier MVP ★ 최선두 (3~5일)

> **모델 사이즈와 무관하게 *결정적으로* fabrication을 차단.** 35B(A) production에서도 잔여 헛소리를 잡고,
> LoRA(C) 학습의 *실패 케이스 입력*까지 자동 수집하는 핵심 인프라.

### B.1 위치 — MCP 서버 미들웨어

```
운전원 요청
  ↓
[opencode 채팅] → [vLLM] → 모델 응답·툴호출
                              ↓
                    ━━━━ Verifier 미들웨어 ━━━━
                    ① 결정적 룰 (코드, 모델 호출 0)
                    ② 룰 통과 → 응답 그대로
                       룰 실패 → reject + error+hint를 모델에 반환 → 재시도
                    ━━━━━━━━━━━━━━━━━━━━━━━
                              ↓
                       [opencode UI]
```

`mcp-server/server.py`의 도구 함수 입구에 데코레이터/래퍼로 → 잘못된 인자 호출 즉시 차단.
모델 응답 검증은 `OllamaController.cs`의 응답 후처리에서 (또는 opencode → MCP proxy 단)에서 수행.

### B.2 MVP 룰 카탈로그 (이번 phase에서 구현)

| # | 룰 | 어디서 적용 | 실패 시 |
|---|---|---|---|
| **R1** | `tag-existence` — 응답·툴호출 인자에 등장한 `[a-z]+-\d+[a-z]?` 패턴 base_tag가 `tag_metadata.base_tag` ∪ `pid_equipment.tag_no` 에 존재? | 모든 툴 인자 + 최종 응답 텍스트 | reject + `{"error":"unknown tag X","suggested":[find_tags top3]}` 모델에 반환 → 재시도 |
| **R2** | `area-format` — `area=` 인자가 `^P\d+(-\d+)?$` 매치? | `find_tags`/`active_alarms`/`query_events`/`summarize_events`/`generate_status_report` | reject + `"use P6 or P6-1 format"` |
| **R3** | `pump-state-enum` — `livevalue` / `corroborated_status` 가 화이트리스트 안? (CONFIRMED_RUNNING / SUSPICIOUS_RUNNING / STALE / INDETERMINATE_RUNNING / STOPPED / TRIPPED; pump state: L-RUN/R-RUN/L-STOP/R-STOP/L-TRIP/R-TRIP) | 최종 응답 텍스트 스캔 | reject (R-FAULT 같은 변종 차단) |
| **R4** | `trace-start-tag` — `trace_connections(start_tag=X)` 의 X가 `pid_equipment` 에 존재? | 도구 입구 | reject + `find_tags(query=user_query)` 결과를 hint로 |
| **R5** | `filter-applied-claim` — 응답이 "X차 결과" 같은 필터된 답이라 주장하면, 실제 도구 호출이 그 sub_area로 필터됐는지 검증 | 응답 후처리 (LLM-judge 가능) | reject + "필터 미적용 결과로 답하지 말 것" |

### B.3 구현 우선순위 (B 단독으로 production 즉시 안전)
1. **R1, R2, R4** 먼저 (3가지 모두 코드 정규식·DB 조회로 결정적, 즉효) — 1~2일
2. **R3** (enum 화이트리스트) — 0.5일
3. **R5** (LLM-judge 보조) — 1~2일, 강도 높음

### B.4 Verifier 출력 = LoRA 입력 (피드백 루프)
실패한 (모델 호출, hint, 재시도 후 통과한 호출) 트리플을 **`mcp-server/verifier/logs/*.jsonl`** 에 자동 축적
→ Phase C1(데이터 큐레이션)의 주 데이터셋. 즉 *시스템이 학습 신호를 자기 생성*.

### B.5 Verifier 게이트 (B 완료 기준)
- [ ] R1~R4 구현 + py_compile + 단위 테스트
- [ ] opencode 채팅에서 "원료 투입 경로" 질문 → invention 발생 시 Verifier가 차단·재시도·올바른 호출 도달
- [ ] Verifier 로그 jsonl 자동 적재 확인
- [ ] eval 하네스에 Verifier-on/off A/B 옵션 추가 (효과 측정)

---

## Phase A — Qwen3.6-35B-A3B production 전환 (병행, 1일)

### 무엇
- 기존 `scripts/run-qwen3.6-35b-a3b.sh` 그대로 활용 (instanttensor/MTP 등 3.6 전용 플래그 유효).
- `opencode.json` 기본 model을 실제 서빙 중인 vllm-36b/Qwen3.6-35B-A3B-FP8 으로 정합화.
- `plant_context.md` 를 opencode system prompt에 자동 주입(또는 opencode-side 설정).
- 8B는 eval/실험용으로 보존 (Verifier·LoRA 베이스 후보 평가용).

### 게이트
- [ ] opencode에서 "6-1차 운전 상황", "6-1차 원료 투입 경로" 질문 → A35B + Verifier 조합에서 invention 0 또는 자기교정.

---

## Phase C — LoRA 가속 (2~4주)

> Verifier(B)가 잡아내는 *실패 패턴*을 학습 데이터로 사용해, **행동 자체를 모델 weights에 박음.**
> 무한 prompt 강화 = 끝없음. 학습 = 행동을 한 번에 옮김. byOPUS의 원래 의도.

### C1 데이터 큐레이션 (1주)
- **Verifier 로그(B.4)에서 자동 추출**:
  - 잘못된 인자/추측 호출 → Verifier hint → 올바른 호출 행동 쌍
  - "find_tags 먼저 호출, area는 P6-1 형식, 빈 결과면 자기 의심" 행동 시퀀스
- 운전원 검수 (사람 in the loop) — 50~200건 정선

### C2 SFT-LoRA (1주)
- **베이스**: bf16 dense (Qwen2.5-7B-Instruct or Qwen3-8B bf16 또는 27B dense — 별도 평가).
  ⚠️ A(production)는 35B-A3B MoE인데, LoRA 학습은 dense에서 — **production과 학습 베이스 분리** 인정.
  → 학습된 dense 어댑터를 production에 적용하려면 (a) dense 베이스를 *별도 라인*으로 production 추가, (b) LoRA-distill로 35B에 행동 이전 — *어느 쪽이 비용효율적인지는 C 완료 시점에 결정*.
- 타겟 모듈: attention-only(q/k/v/o) 1차, MoE expert 회피.
- `r=32~64`, rslora, grad-ckpt unsloth.

### C3 DPO/GRPO (1~2주)
- **보상 = Verifier 판정 + 운전원 👍/👎** → 선호쌍 → DPO.
- 학습 목표: **calibration** ("내가 모를 때 답하지 않기")를 weights 자체에 박음.
- 자기학습 collapse 위험 회피 (사람·Verifier 신호 기반).

### C 게이트
- Phase 0 평가셋 + 새로 추가된 "invention" 카테고리에서 회귀 0 + invention rate 0 → 배포.

---

## Phase D — 역할 분리 의제 (병행 논의, 결정 보류)

운전 위기/안전 critical 응답에 한해 운전원이 **"강화모드"** 토글 → 프런티어 클라우드(Claude/GPT-4) 호출.

- 비용 < fabrication 의 잠재 사고 비용 (안전 산업)
- 일반 응답은 로컬(A+B+C), 강화모드만 클라우드 → 비용 통제 가능
- 데이터 외부 전송 정책은 별도 검토 필요
- 결정: Phase A·B 안정화 후 2시간짜리 의사결정 회의로 채택여부 확정

---

## 의사결정 게이트 (간소)

```
Phase -1 (seed 정리)        ✅ 완료
Phase 0  (평가셋·모델사다리)  ✅ 완료 → 8B 부족 결론
        ↓
Phase B  (Verifier MVP, 3~5d)   ← 최우선
        ↓
Phase A  (35B production 전환, 1d, B와 병행 가능)
        ↓
Phase C  (LoRA 가속, 2~4w) — Verifier 로그를 학습 입력으로
        ↓
Phase D  (역할 분리 결정, 2h) — A·B 안정화 후
```

각 phase는 이전 게이트 통과 시에만 다음으로. Verifier(B)는 모든 후속 phase의 **공통 인프라**.

---

## 타임라인 (개정)

| Phase | 작업 | 소요 | 비고 |
|---|---|---|---|
| -1 | seed 정리 | ✅ 완료 | knowledge/ 구축됨 |
| 0  | 평가셋·러너·모델 사다리 | ✅ 완료 | 8B = production 부적합 확정 |
| **B** | Verifier MVP (R1~R4) | **3~5d** | 미들웨어 + 룰 코드 + 로그 적재 |
| A  | 35B-A3B production 전환 + opencode 정합 | 1d | B와 병행 |
| C1 | 데이터 큐레이션 (Verifier 로그 + 검수) | 1w | |
| C2 | SFT-LoRA (bf16 dense 베이스) | 1w | production·학습 베이스 분리 |
| C3 | DPO (calibration) | 1~2w | Verifier·👍/👎 보상 |
| D  | 역할분리 의사결정 회의 | 2h | A·B 안정화 후 |

---

## 운영 모니터링 (B 추가 지표)

| 항목 | 의미 |
|---|---|
| **Verifier reject 비율** (룰별 / 카테고리별) | invention 압력 지표. 낮아질수록 모델·시스템 건강 |
| **재시도 후 통과율** | 자기교정 효과. 100% 가까울수록 hint 품질 좋음 |
| **fabrication slip-through** (수동 감사) | Verifier가 못 잡은 부분 진실 fabrication. 룰 추가 신호 |
| Verifier 로그 적재 속도 | LoRA 데이터 공급 속도 |
| (D 채택 시) 강화모드 호출 비율·비용 | 클라우드 의존도 추적 |

---

## v1 자기비판 (명시)

1. **"RAG는 사이즈 무관"** → **틀림.** L1(lookup)만 무관. L2~L4(언제·뭘·충실히 사용)는 사이즈 의존. 사용자가 production 데이터로 정정.
2. **"Phase 1 무학습 레버만으로 80% 해결"** → **틀림.** 통제 eval에선 맞았으나 production messy 환경에선 ~50%. 통제·production 갭 과소평가.
3. **"small dense + 좋은 시스템 = 충분"** → **틀림.** 8B는 L2~L4 부족. production operator brain으로 부적합.
4. **"Verifier는 Phase 2 (중기 보조)"** → **틀림.** Verifier가 즉시 최대 leverage. v2에서 *최선두*로 정정.
5. **"production·학습 베이스 동일 모델"** → **재고.** A=35B-MoE, LoRA 학습=dense → 분리 가능성 인정.
6. **"역할 분리 미고려"** → **수정.** Phase D 의제화.

---

## 다음 한 수

**Phase B(Verifier MVP) 착수.** R1~R4 구현 작업지시서를 다른 LLM에 위임 가능한 형식으로 작성 →
완성되면 즉시 opencode에서 invention 재현 시도 → Verifier 차단 확인 → A35B로 production 전환.
