docs: LLM 모델 SSOT 전환 계획 및 workspace-config 리서치 갱신
Made-with: Cursor
This commit is contained in:
parent
53da59d673
commit
1b3a0a5632
@ -24,8 +24,16 @@
|
||||
|
||||
- `rb8001`의 모델 기본값/직접 handler 생성/직접 Gemini SDK 호출/fallback 배열 정리
|
||||
- `skill-slack`의 하드코딩 모델 문자열 정리
|
||||
- 전수 확인으로 드러난 `rb8001`의 추가 직접 생성 경로 정리
|
||||
- `skill-news`의 독자 `GEMINI_MODEL` SSOT와 직접 Gemini SDK 호출 정리
|
||||
- 모델 변경 검증 체크리스트 고정
|
||||
|
||||
### 포함 근거
|
||||
|
||||
- 리서치 기준 `skill-news`는 단순 모델 문자열 1~2개가 아니라, `README`, `.env.example`, `docker-compose.yml`, 서비스 코드, API 모듈 import 시점 초기화가 함께 `.env`의 `GEMINI_MODEL`을 독자 SSOT로 강화하고 있습니다.
|
||||
- 따라서 `skill-news`를 범위 밖으로 두면 로빙 전체 관점에서 "주 모델 변경이 SSOT 1회 수정으로 닫힌다"는 목표를 충족할 수 없습니다.
|
||||
- 특히 `skill-news/app/api/news_endpoints.py`의 `news_summarizer = NewsSummarizer()`는 프로세스 시작 시점에 현재 모델 계약을 고정하므로, 단순 문서 수정이나 compose 수정만으로는 충분하지 않습니다.
|
||||
|
||||
### 제외
|
||||
|
||||
- 새 provider registry 파일 추가
|
||||
@ -53,6 +61,10 @@
|
||||
- 직접 `genai.GenerativeModel(...)` 생성 제거
|
||||
- [rb8001/app/services/ir_analyzer.py](../../../../rb8001/app/services/ir_analyzer.py)
|
||||
- 파일 내부 fallback 배열 제거 또는 중앙 정책으로 이동
|
||||
- [rb8001/app/services/diary/generator.py](../../../../rb8001/app/services/diary/generator.py)
|
||||
- 직접 `GeminiHandler()` 생성 제거 검토
|
||||
- [rb8001/app/services/workflows/headlines_workflow.py](../../../../rb8001/app/services/workflows/headlines_workflow.py)
|
||||
- `or GeminiHandler(default_model)` 우회 제거
|
||||
|
||||
### 3. 스킬 계층 정리
|
||||
|
||||
@ -63,6 +75,38 @@
|
||||
- [skill-slack/app/core/config.py](../../../../skill-slack/app/core/config.py)
|
||||
- 필요 최소한의 기본 모델 설정만 추가 검토합니다.
|
||||
|
||||
### 4. skill-news 정리
|
||||
|
||||
- [skill-news/app/services/news_summarizer.py](../../../../skill-news/app/services/news_summarizer.py)
|
||||
- [skill-news/app/services/companyx_news_summarizer.py](../../../../skill-news/app/services/companyx_news_summarizer.py)
|
||||
- [skill-news/app/services/sea_news_filter.py](../../../../skill-news/app/services/sea_news_filter.py)
|
||||
- 직접 `genai.GenerativeModel(...)` 생성과 `GEMINI_MODEL` 독자 SSOT를 정리합니다.
|
||||
- [skill-news/app/api/news_endpoints.py](../../../../skill-news/app/api/news_endpoints.py)
|
||||
- import 시점 `NewsSummarizer()` 생성이 어떤 설정 계약을 고정하는지 정리합니다.
|
||||
- [skill-news/docker-compose.yml](../../../../skill-news/docker-compose.yml)
|
||||
- 모델 주입을 `workspace-config/runtime.env` 기준으로 재해석할지 확정합니다.
|
||||
- [skill-news/README.md](../../../../skill-news/README.md)
|
||||
- [skill-news/.env.example](../../../../skill-news/.env.example)
|
||||
- 문서 SSOT 표현을 코드/운영 계약과 맞춥니다.
|
||||
|
||||
## 수정 규모 기준
|
||||
|
||||
### 1. 최소 직접 수정 범위
|
||||
|
||||
- `rb8001` 9개 내외
|
||||
- `skill-slack` 4개 내외
|
||||
- `skill-news` 6개 내외
|
||||
- 서비스 코드 4개
|
||||
- compose 1개
|
||||
- 문서/예시 2개 중 계약상 필수 범위 포함
|
||||
- 문서/테스트 제외 최소 직접 수정 예상은 `19개 내외`로 봅니다.
|
||||
|
||||
### 2. 완전 종결 범위
|
||||
|
||||
- 위 최소 범위 외에도 compose의 `.env` 오버라이드, `workspace-config` 주입 순서, 서비스별 예외를 더 확인해야 합니다.
|
||||
- `skill-news`는 독자 제품 SSOT처럼 운영돼 온 흔적이 있어, 계획 실행 중 예외 선언으로 분리할지 통합 전환할지 정책 판단이 추가로 필요할 수 있습니다.
|
||||
- 따라서 이 계획은 `핵심 SSOT 경로 복구 계획`이고, `로빙 전체 workspace-config 완전 종결 계획`과는 범위를 구분합니다.
|
||||
|
||||
## 정책 판단
|
||||
|
||||
### 1. 유지 가능한 정책
|
||||
@ -77,6 +121,8 @@
|
||||
- router/service의 직접 handler 생성
|
||||
- 서비스 파일 안의 직접 Gemini/OpenAI SDK 생성
|
||||
- `skill-slack`의 고정 모델 문자열
|
||||
- `skill-news`의 `.env` 기반 독자 모델 SSOT 표현
|
||||
- import 시점 초기화가 특정 모델 계약을 고정하는 구조
|
||||
|
||||
### 3. 추가하지 않을 것
|
||||
|
||||
@ -104,25 +150,31 @@
|
||||
- `genai.GenerativeModel(...)` 직접 생성이 공용 경로 밖에서 사라집니다.
|
||||
- `ir_analyzer.py`의 파일 내부 fallback 배열이 제거되거나 중앙 정책으로 이동합니다.
|
||||
- `skill-slack`의 하드코딩 모델 문자열이 제거됩니다.
|
||||
- `diary/generator.py`, `headlines_workflow.py`의 직접 `GeminiHandler` 생성이 제거됩니다.
|
||||
- `skill-news`의 직접 Gemini SDK 생성과 `GEMINI_MODEL` 독자 SSOT가 정리됩니다.
|
||||
- `skill-news/app/api/news_endpoints.py`의 import 시점 초기화가 새 계약과 모순되지 않게 정리됩니다.
|
||||
|
||||
## 적용 순서
|
||||
|
||||
1. `rb8001` 공용 경로 정리
|
||||
- `config.py`, `llm_service.py`, `gemini_handler.py`
|
||||
2. `rb8001` 우회 경로 제거
|
||||
- `llm_endpoint.py`, `coldmail_llm_classifier.py`, `ir_analyzer.py`
|
||||
- `llm_endpoint.py`, `coldmail_llm_classifier.py`, `ir_analyzer.py`, `diary/generator.py`, `workflows/headlines_workflow.py`
|
||||
3. `skill-slack` 모델 선택 정리
|
||||
- `digest.py`, `action_extractor.py`, `summarizer.py`, 필요 시 `app/core/config.py`
|
||||
4. 기본값 변경 검증
|
||||
4. `skill-news` 모델 경로 정리
|
||||
- `news_summarizer.py`, `companyx_news_summarizer.py`, `sea_news_filter.py`, `docker-compose.yml`, `README.md`, `.env.example`
|
||||
5. 기본값 변경 검증
|
||||
- `workspace-config/runtime.env`
|
||||
- 과도기 `rb8001/.env`
|
||||
- API 입력 `model` override
|
||||
5. worklog 작성 후 닫힘 선언
|
||||
6. worklog 작성 후 닫힘 선언
|
||||
|
||||
## 레포별 경계
|
||||
|
||||
- 1차 대상 레포: `robeing/rb8001`
|
||||
- 2차 대상 레포: `robeing/skill-slack`
|
||||
- 3차 대상 레포: `robeing/skill-news`
|
||||
- 문서/검증 기록 레포: `robeing/DOCS`
|
||||
- 한 번에 여러 레포를 한 커밋으로 묶지 않습니다.
|
||||
|
||||
@ -130,6 +182,7 @@
|
||||
|
||||
- `rb8001` 변경은 `rb8001` 레포 안에서만 롤백 판단합니다.
|
||||
- `skill-slack` 변경은 `skill-slack` 레포 안에서만 롤백 판단합니다.
|
||||
- `skill-news` 변경은 `skill-news` 레포 안에서만 롤백 판단합니다.
|
||||
- 문서 변경은 `DOCS` 레포 안에서만 롤백 판단합니다.
|
||||
- 과도기에는 `workspace-config/runtime.env`와 `rb8001/.env`를 이전 값으로 되돌리는 것이 가장 작은 운영 롤백 단위입니다.
|
||||
|
||||
@ -139,4 +192,5 @@
|
||||
2. 과도기에도 `workspace-config/runtime.env`와 `rb8001/.env`까지만 수정하면 됩니다.
|
||||
3. API 입력 모델명으로 요청 단위 override가 가능합니다.
|
||||
4. 리서치 문서에 적힌 직접 우회 경로가 실제 코드에서 제거됩니다.
|
||||
5. 닫힘 선언은 `worklog`에서만 합니다.
|
||||
5. `skill-news`까지 포함해 독자 모델 SSOT 표현이 정리됩니다.
|
||||
6. 닫힘 선언은 `worklog`에서만 합니다.
|
||||
|
||||
@ -229,6 +229,47 @@ tags: [research, llm, ssot, workspace-config, hardcoding, robeing]
|
||||
- [skill-slack/app/core/config.py](../../../../skill-slack/app/core/config.py)
|
||||
- 현재 LLM 기본 모델 설정 자체가 없습니다.
|
||||
|
||||
### 6. 전수 확인으로 추가 확인된 누락 범위
|
||||
|
||||
- [rb8001/app/services/diary/generator.py](../../../../rb8001/app/services/diary/generator.py)
|
||||
- `GeminiHandler()`를 직접 생성합니다.
|
||||
- 기본 모델은 간접적으로 따라가더라도, 호출 진입점이 `LLMService` 단일 경로로 닫히지 않았습니다.
|
||||
- [rb8001/app/services/workflows/headlines_workflow.py](../../../../rb8001/app/services/workflows/headlines_workflow.py)
|
||||
- `llm_service.handlers.get(default_model) or GeminiHandler(default_model)` 경로가 남아 있습니다.
|
||||
- 기본값은 `settings.DEFAULT_LLM_MODEL`을 보더라도 handler 직접 생성 우회가 살아 있습니다.
|
||||
- [skill-news/app/services/news_summarizer.py](../../../../skill-news/app/services/news_summarizer.py)
|
||||
- `os.getenv("GEMINI_MODEL", "gemini-2.5-flash-lite")` 기본값 문자열과 직접 `genai.GenerativeModel(...)` 생성이 남아 있습니다.
|
||||
- [skill-news/app/services/companyx_news_summarizer.py](../../../../skill-news/app/services/companyx_news_summarizer.py)
|
||||
- `os.getenv("GEMINI_MODEL", "gemini-2.5-flash-lite")` 기본값 문자열과 직접 `genai.GenerativeModel(...)` 생성이 남아 있습니다.
|
||||
- [skill-news/app/services/sea_news_filter.py](../../../../skill-news/app/services/sea_news_filter.py)
|
||||
- `GEMINI_MODEL`을 독자 SSOT처럼 요구하고 직접 `genai.GenerativeModel(...)`를 생성합니다.
|
||||
- [skill-news/app/api/news_endpoints.py](../../../../skill-news/app/api/news_endpoints.py)
|
||||
- 모듈 import 시점에 `news_summarizer = NewsSummarizer()`가 즉시 생성됩니다.
|
||||
- 즉 `skill-news`는 단순 설정 조회가 아니라, 프로세스 시작 시점부터 `.env`의 `GEMINI_MODEL` 계약을 전제로 동작합니다.
|
||||
- [skill-news/docker-compose.yml](../../../../skill-news/docker-compose.yml)
|
||||
- 현재 `workspace-config/runtime.env`를 읽지 않고 `${GEMINI_MODEL}`을 직접 전달합니다.
|
||||
- [skill-news/README.md](../../../../skill-news/README.md)
|
||||
- 모델명 SSOT를 `.env`의 `GEMINI_MODEL`로 선언하고 있어, 현재 로빙 전체 목표 SSOT와 충돌합니다.
|
||||
- [skill-news/.env.example](../../../../skill-news/.env.example)
|
||||
- `GEMINI_MODEL` 예시값을 별도 SSOT처럼 유지합니다.
|
||||
|
||||
### 7. compose / env_file 계층 확인 결과
|
||||
|
||||
- [rb8001/docker-compose.yml](../../../../rb8001/docker-compose.yml)
|
||||
- `env_file`에 `.env`, `/home/admin/workspace-config/runtime.env`, `/home/admin/workspace-config/secrets.env`를 함께 읽습니다.
|
||||
- 즉 구조는 workspace-config를 쓰지만, 서비스별 `.env` 오버라이드가 아직 실제 경로에 남아 있습니다.
|
||||
- [skill-slack/docker-compose.yml](../../../../skill-slack/docker-compose.yml)
|
||||
- `env_file`에 `.env`, `/home/admin/workspace-config/runtime.env`, `/home/admin/workspace-config/secrets.env`를 함께 읽습니다.
|
||||
- [skill-rag-file/docker-compose.yml](../../../../skill-rag-file/docker-compose.yml)
|
||||
- `env_file` 3중 구조와 별도 `./.env:/app/.env:ro` 마운트가 함께 있습니다.
|
||||
- 로빙 전체 SSOT 문제를 닫을 때 `.env` 오버라이드가 실제 런타임 우선순위를 어떻게 바꾸는지 별도 점검이 필요합니다.
|
||||
- [skill-calendar/docker-compose.yml](../../../../skill-calendar/docker-compose.yml)
|
||||
- [skill-email/docker-compose.yml](../../../../skill-email/docker-compose.yml)
|
||||
- [robeing-monitor/docker-compose.yml](../../../../robeing-monitor/docker-compose.yml)
|
||||
- [robeing-gateway/docker-compose.yml](../../../../robeing-gateway/docker-compose.yml)
|
||||
- 공통으로 `workspace-config`와 서비스별 `.env`를 함께 읽는 구조가 남아 있습니다.
|
||||
- 따라서 `LLM 모델 SSOT`를 넘어 `서비스별 .env 오버라이드` 문제까지 완전 종결하려면 후속 점검 범위가 더 큽니다.
|
||||
|
||||
## 확인 사실 요약표
|
||||
|
||||
| 항목 | 확인 사실 | 해석 |
|
||||
@ -242,6 +283,10 @@ tags: [research, llm, ssot, workspace-config, hardcoding, robeing]
|
||||
| API 입력 model | `rb8001/app/services/llm/models.py`의 `LLMRequest.model` 존재 | override 구조는 이미 있음 |
|
||||
| OpenAI handler | `rb8001/app/services/llm/openai_handler.py` 존재 | provider 추상화 일부 존재 |
|
||||
| skill-slack 모델 선택 | `digest.py`, `action_extractor.py`, `summarizer.py`에 모델 문자열 존재 | 설정화 또는 정책화 필요 |
|
||||
| rb8001 추가 직접 생성 | `diary/generator.py`, `workflows/headlines_workflow.py`에 `GeminiHandler` 직접 생성 잔존 | 계획 누락 |
|
||||
| skill-news 독자 SSOT | `skill-news`가 `.env`의 `GEMINI_MODEL`을 자체 SSOT로 유지 | 로빙 전체 SSOT와 충돌 |
|
||||
| skill-news 초기화 시점 | `news_endpoints.py`가 import 시점에 `NewsSummarizer()` 생성 | 런타임 계약이 프로세스 시작 시점에 고정 |
|
||||
| compose env 계층 | 여러 서비스가 `workspace-config`와 `.env`를 함께 읽음 | 구조는 있으나 오버라이드 잔존 |
|
||||
|
||||
## 최소 변경 원칙
|
||||
|
||||
@ -288,6 +333,49 @@ tags: [research, llm, ssot, workspace-config, hardcoding, robeing]
|
||||
- [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 입력값으로 승격
|
||||
- [rb8001/app/services/diary/generator.py](../../../../rb8001/app/services/diary/generator.py)
|
||||
- 직접 `GeminiHandler()` 생성 제거 검토
|
||||
- [rb8001/app/services/workflows/headlines_workflow.py](../../../../rb8001/app/services/workflows/headlines_workflow.py)
|
||||
- `or GeminiHandler(default_model)` 우회 제거
|
||||
- [skill-news/app/services/news_summarizer.py](../../../../skill-news/app/services/news_summarizer.py)
|
||||
- [skill-news/app/services/companyx_news_summarizer.py](../../../../skill-news/app/services/companyx_news_summarizer.py)
|
||||
- [skill-news/app/services/sea_news_filter.py](../../../../skill-news/app/services/sea_news_filter.py)
|
||||
- `GEMINI_MODEL` 독자 SSOT와 직접 Gemini SDK 생성을 정리
|
||||
- [skill-news/app/api/news_endpoints.py](../../../../skill-news/app/api/news_endpoints.py)
|
||||
- import 시점 인스턴스 생성이 어떤 설정 계약을 고정하는지 함께 정리
|
||||
- [skill-news/docker-compose.yml](../../../../skill-news/docker-compose.yml)
|
||||
- `workspace-config/runtime.env` 기준 모델 주입으로 맞출지 검토
|
||||
- [skill-slack/app/core/config.py](../../../../skill-slack/app/core/config.py)
|
||||
- LLM 기본 모델 설정 경로를 둘지 여부 확정 필요
|
||||
|
||||
### 1-1. 현재 전수 확인 기준 최소 직접 수정 규모
|
||||
|
||||
- `rb8001` 9개 내외
|
||||
- `app/core/config.py`
|
||||
- `app/services/llm/llm_service.py`
|
||||
- `app/services/llm/gemini_handler.py`
|
||||
- `app/router/llm_endpoint.py`
|
||||
- `app/services/coldmail_llm_classifier.py`
|
||||
- `app/services/ir_analyzer.py`
|
||||
- `app/services/diary/generator.py`
|
||||
- `app/services/workflows/headlines_workflow.py`
|
||||
- 필요 시 `app/services/llm/models.py`
|
||||
- `skill-slack` 4개 내외
|
||||
- `app/services/digest.py`
|
||||
- `app/services/action_extractor.py`
|
||||
- `app/services/summarizer.py`
|
||||
- `app/core/config.py`
|
||||
- `skill-news` 6개 내외
|
||||
- `skill-news`는 서비스 코드 4개 + compose 1개 + 문서/예시 2개까지 걸쳐 있어, 코드 수정만으로 끝나지 않고 계약 문서도 같이 바뀌어야 합니다.
|
||||
- `app/services/news_summarizer.py`
|
||||
- `app/services/companyx_news_summarizer.py`
|
||||
- `app/services/sea_news_filter.py`
|
||||
- `app/api/news_endpoints.py`
|
||||
- `docker-compose.yml`
|
||||
- `README.md`
|
||||
- `.env.example`
|
||||
- 따라서 2026-03-16 전수 확인 기준으로, 문서/테스트 제외 최소 직접 수정 예상은 `19개 내외`로 보는 편이 맞습니다.
|
||||
- 특히 `skill-news`는 `.env` 기반 독자 SSOT를 README와 compose, 서비스 초기화 코드가 함께 강화하고 있으므로, 단순 코드 치환보다 "계약 전환"으로 다루는 편이 맞습니다.
|
||||
|
||||
### 2. 굳이 지금 추가하지 않아도 되는 것
|
||||
|
||||
@ -310,6 +398,8 @@ tags: [research, llm, ssot, workspace-config, hardcoding, robeing]
|
||||
### 2. 로빙의 현재 모델 구조 문제도 같은 유형입니다
|
||||
|
||||
- `DEFAULT_LLM_MODEL`은 선언돼 있지만, 실제 경로는 `GeminiHandler` 직접 생성, Gemini SDK 직접 호출, `gemini-*` fallback 리스트, 서비스별 개별 모델 하드코딩이 섞여 있습니다.
|
||||
- `skill-news`는 이 문제의 바깥 예외가 아니라, 별도 제품 SSOT를 이미 갖고 있는 하위 서비스입니다.
|
||||
- 그래서 로빙 전체 모델 SSOT를 하나로 묶으려면 `skill-news`를 예외로 선언하거나, 아니면 README/compose/service 초기화까지 함께 계약 전환해야 합니다.
|
||||
- 그래서 `주 모델 변경`이 `SSOT 1개 값 변경`으로 닫히지 않고, 여러 서비스의 코드 경로를 다시 건드려야 하는 구조가 됩니다.
|
||||
- 즉 지금의 직접 원인은 `gpt-5-mini` 전환 작업이고, 근본 원인은 `모델 호출 계약의 SSOT`와 `실제 호출 구현`이 분리되지 않은 점입니다.
|
||||
- 이 해석은 서버와 로컬 모두 동일합니다. 서버별 모델 차이가 필요해도 그것은 코드 차이가 아니라 `runtime.env` 값 차이로만 표현돼야 합니다.
|
||||
@ -322,6 +412,7 @@ tags: [research, llm, ssot, workspace-config, hardcoding, robeing]
|
||||
- 이 기준이 닫혀야 `DEFAULT_LLM_MODEL` 같은 값이 실제 SSOT가 됩니다.
|
||||
- 닫혀야 할 최종 경로는 `runtime.env -> settings.DEFAULT_LLM_MODEL -> 단일 LLM factory/service -> handler`입니다.
|
||||
- `GEMINI_MODEL`, 코드 기본값 문자열, 요청별 모델 직접 주입, 서비스별 fallback 배열은 모두 이 경로의 우회로로 봐야 합니다.
|
||||
- `skill-news`처럼 README와 `.env.example`, compose, import 시점 초기화 코드가 함께 특정 키를 독자 SSOT로 강화하는 경우도 같은 우회로로 봐야 합니다.
|
||||
- 사용자 작업 기준으로는 목표 수정 지점과 과도기 최소 수정 지점을 함께 고정해야 합니다.
|
||||
- 목표 수정 지점: `workspace-config/runtime.env`
|
||||
- 과도기 최소 수정 지점: `workspace-config/runtime.env`와 `rb8001/.env`
|
||||
@ -334,6 +425,7 @@ tags: [research, llm, ssot, workspace-config, hardcoding, robeing]
|
||||
- 서비스별 `.env`와 코드 fallback 중 무엇이 아직 실제 런타임 경로에 남아 있는지 전체 인벤토리
|
||||
- 로컬 기준 공용 파일만 읽도록 바꿀 때, 프로젝트별 예외가 필요한 서비스가 있는지 여부
|
||||
- 서버 기준 공용 파일만 읽도록 바꿀 때, 운영상 예외가 필요한 서비스가 있는지 여부
|
||||
- `skill-news`를 로빙 전체 모델 SSOT 전환 범위에 포함할지, 아니면 별도 제품 SSOT 예외로 둘지 최종 정책 확정
|
||||
|
||||
## workspace-config 로컬 이식 기준
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user