docs: inventory llm model call paths

This commit is contained in:
happybell80 2026-03-16 00:58:40 +09:00
parent 37b79ddbb8
commit 32537766fc

View File

@ -177,6 +177,114 @@ tags: [research, llm, ssot, workspace-config, hardcoding, robeing]
- `provider` + `model`을 명시적으로 받고 factory가 둘을 함께 검증
- 현재 로빙처럼 서비스 코드 곳곳에서 Gemini SDK 직접 호출, OpenAI handler 직접 생성, fallback 배열 직접 선언이 섞여 있는 구조는 외부 사례의 "요청 입력은 유연하게, 내부 선택은 단일화" 패턴과 다릅니다.
## 현재 코드 인벤토리
### 1. 기본 모델 원천과 기본 handler 생성
- [rb8001/app/core/config.py](../../../../rb8001/app/core/config.py)
- `DEFAULT_LLM_MODEL` 기본값 문자열이 코드에 남아 있습니다.
- 현재 설정 진입점으로는 맞지만, 최종 목표는 `workspace-config/runtime.env` 중심 해석입니다.
- [rb8001/app/services/llm/llm_service.py](../../../../rb8001/app/services/llm/llm_service.py)
- 이미 `settings.DEFAULT_LLM_MODEL`로 기본 handler를 생성합니다.
- 새 추상화 계층을 만들기보다 이 파일을 단일 진입점으로 정리하는 편이 최소 변경입니다.
### 2. SSOT를 깨는 직접 우회 경로
- [rb8001/app/services/llm/gemini_handler.py](../../../../rb8001/app/services/llm/gemini_handler.py)
- `os.getenv("GEMINI_MODEL", model or settings.DEFAULT_LLM_MODEL)` 우회가 있습니다.
- CLI 경로도 `GEMINI_MODEL`을 다시 읽습니다.
- [rb8001/app/router/llm_endpoint.py](../../../../rb8001/app/router/llm_endpoint.py)
- 스트리밍 엔드포인트가 `GeminiHandler(model=request.model)`를 직접 생성합니다.
- [rb8001/app/services/coldmail_llm_classifier.py](../../../../rb8001/app/services/coldmail_llm_classifier.py)
- `google.generativeai`를 직접 import하고 `genai.GenerativeModel(GEMINI_MODEL)`을 직접 생성합니다.
- [rb8001/app/services/ir_analyzer.py](../../../../rb8001/app/services/ir_analyzer.py)
- `fallback_models = ["gemini-2.5-flash", "gemini-2.0-flash", "gemini-2.0-flash-lite"]`가 코드에 하드코딩되어 있습니다.
- Gemini File Search API 키도 함수 내부에서 직접 읽습니다.
### 3. 이미 상대적으로 정리된 경로
- [rb8001/app/services/gemini_file_search_client.py](../../../../rb8001/app/services/gemini_file_search_client.py)
- 모델 인자를 받되 기본값은 `settings.DEFAULT_LLM_MODEL`을 사용합니다.
- [rb8001/app/services/skills/naverworks_briefing.py](../../../../rb8001/app/services/skills/naverworks_briefing.py)
- `settings.DEFAULT_LLM_MODEL`을 사용하는 경로가 이미 있습니다.
- [rb8001/app/services/workflows/headlines_workflow.py](../../../../rb8001/app/services/workflows/headlines_workflow.py)
- 기본 모델은 `settings.DEFAULT_LLM_MODEL`을 쓰지만, `or GeminiHandler(default_model)` 직접 생성이 남아 있습니다.
### 4. provider 추상화는 이미 일부 존재한다
- [rb8001/app/services/llm/openai_handler.py](../../../../rb8001/app/services/llm/openai_handler.py)
- OpenAI handler는 이미 구현돼 있습니다.
- [rb8001/app/services/llm/models.py](../../../../rb8001/app/services/llm/models.py)
- `LLMRequest.model` 필드가 이미 존재합니다.
- 즉 "모델 override를 받을 구조"는 이미 있고, 부족한 것은 handler 선택을 한 곳으로 모으는 일입니다.
### 5. skill-slack 쪽 하드코딩 호출
- [skill-slack/app/services/digest.py](../../../../skill-slack/app/services/digest.py)
- `model: "gemini-2.5-flash"` 하드코딩
- [skill-slack/app/services/action_extractor.py](../../../../skill-slack/app/services/action_extractor.py)
- `model: "gemini-2.5-flash"` 하드코딩
- [skill-slack/app/services/summarizer.py](../../../../skill-slack/app/services/summarizer.py)
- `skill_level`에 따라 `gemini-2.5-flash` / `gemini-2.5-pro`를 직접 선택합니다.
- [skill-slack/app/core/config.py](../../../../skill-slack/app/core/config.py)
- 현재 LLM 기본 모델 설정 자체가 없습니다.
## 최소 변경 원칙
### 1. 새 추상화 계층을 더 만들지 않는다
- 기존 [rb8001/app/services/llm/llm_service.py](../../../../rb8001/app/services/llm/llm_service.py)를 단일 진입점으로 강화하는 편이 맞습니다.
- 새 `manager`, 새 `registry`, 새 `gateway wrapper`를 추가하는 것은 현재 문제를 닫는 데 필수가 아닙니다.
### 2. 우선순위는 추가보다 제거다
- 1순위 제거 대상은 아래입니다.
- `GeminiHandler(...)` 직접 생성
- `genai.GenerativeModel(...)` 직접 생성
- 파일별 fallback 배열
- `GEMINI_MODEL` 별도 env 우회
- 즉 핵심은 새 기능 추가가 아니라 기존 우회 경로 삭제입니다.
### 3. 기존 요청 스키마를 재사용한다
- [rb8001/app/services/llm/models.py](../../../../rb8001/app/services/llm/models.py)의 `LLMRequest.model`을 그대로 활용하는 편이 맞습니다.
- API 입력 모델 override를 위해 새 request schema를 추가하지 않아도 됩니다.
### 4. 과도기 허용 범위를 더 넓히지 않는다
- 기본값 변경은 `workspace-config/runtime.env`와 과도기 `rb8001/.env`까지만 허용합니다.
- 요청 단위 override는 API 입력 `model`만 허용합니다.
- 그 외 서비스별 별도 `.env`, 별도 `GEMINI_MODEL`, 파일별 fallback 리스트는 더 늘리지 않습니다.
## 정확히 바꿔야 할 지점
### 1. 바로 정리할 파일
- [rb8001/app/services/llm/gemini_handler.py](../../../../rb8001/app/services/llm/gemini_handler.py)
- `GEMINI_MODEL` env 우회 제거
- [rb8001/app/services/llm/llm_service.py](../../../../rb8001/app/services/llm/llm_service.py)
- 동적 handler 생성과 fallback 정책을 중앙화
- [rb8001/app/router/llm_endpoint.py](../../../../rb8001/app/router/llm_endpoint.py)
- router의 직접 `GeminiHandler` 생성을 `LLMService` 경유로 변경
- [rb8001/app/services/ir_analyzer.py](../../../../rb8001/app/services/ir_analyzer.py)
- 파일 내부 fallback 배열 제거 또는 중앙 정책으로 이동
- [rb8001/app/services/coldmail_llm_classifier.py](../../../../rb8001/app/services/coldmail_llm_classifier.py)
- 직접 Gemini SDK 호출 제거 또는 공용 LLM 경유로 정리
- [skill-slack/app/services/digest.py](../../../../skill-slack/app/services/digest.py)
- [skill-slack/app/services/action_extractor.py](../../../../skill-slack/app/services/action_extractor.py)
- [skill-slack/app/services/summarizer.py](../../../../skill-slack/app/services/summarizer.py)
- 하드코딩 모델 문자열을 설정값 또는 API 입력값으로 승격
### 2. 굳이 지금 추가하지 않아도 되는 것
- 새 provider enum 파일
- 새 config loader 계층
- 새 fallback registry 파일
- 새 gateway 패키지
- 새 request model 타입 분기
위 항목들은 현재 문제를 닫는 데 필수가 아닙니다. 먼저 기존 구조를 줄이는 것이 우선입니다.
## Interpretation
### 1. workspace-config는 값 저장 폴더가 아니라 런타임 계약입니다