동적 파라미터 문서에 실제 구현 방안 추가
- 현재 설정 관리 현황 분석 추가 - 4가지 핵심 축 (안전성, 확실성, 추적성, 거버넌스) 정의 - pydantic_settings 기반 표준 아키텍처 설계 - Redis Pub/Sub 멀티워커 전파 메커니즘 - ChangeSet 기반 원자적 변경 관리 - TTL 기반 임시 변경 및 자동 복귀 - RBAC 권한 관리 체계 - 레벨업과 스탯 연동 파라미터 조정 - CLI/API 운영 도구 스펙 - 3단계 마이그레이션 로드맵
This commit is contained in:
parent
6239ae6bcf
commit
6b2574d454
@ -158,6 +158,272 @@ CREATE TABLE config_bundle (
|
|||||||
6. Slack 명령어 연결
|
6. Slack 명령어 연결
|
||||||
7. 배치 리인덱싱 작업
|
7. 배치 리인덱싱 작업
|
||||||
|
|
||||||
|
## 11. 실제 구현 현황과 개선 방안
|
||||||
|
|
||||||
|
### 11.1 현재 상황 분석
|
||||||
|
|
||||||
|
#### 공통 패턴
|
||||||
|
- **프레임워크**: pydantic_settings.BaseSettings
|
||||||
|
- **로드 방식**: .env → 환경변수 → 기본값
|
||||||
|
- **접근 방법**: from app.config import settings
|
||||||
|
- **인스턴스**: 싱글톤 패턴 (settings = Settings())
|
||||||
|
|
||||||
|
#### 서비스별 구조
|
||||||
|
| 서비스 | Config 위치 | 특징 |
|
||||||
|
|--------|------------|------|
|
||||||
|
| rb8001 | app/core/config.py | 기본 설정, Optional 타입 |
|
||||||
|
| rb10408_test | app/core/config.py | 다중 LLM 지원 |
|
||||||
|
| rb10508_micro | app/config.py | 감정/베이지안 설정 |
|
||||||
|
| skill-embedding | config.py | Field() 사용, 상세 설명 |
|
||||||
|
| robing-gateway | **없음** | os.getenv() 분산 사용 |
|
||||||
|
|
||||||
|
### 11.2 도구에서 존재로: 4가지 핵심 축
|
||||||
|
|
||||||
|
"도구적 설정"을 "살아있는 존재"로 전환하기 위한 핵심 요소:
|
||||||
|
|
||||||
|
1. **변경의 안전성**: 검증된 변경만 적용
|
||||||
|
2. **전파의 확실성**: 모든 워커에 즉시 반영
|
||||||
|
3. **추적 가능성**: 모든 변경 이력 보존
|
||||||
|
4. **거버넌스**: 권한별 접근 제어
|
||||||
|
|
||||||
|
### 11.3 개선 아키텍처
|
||||||
|
|
||||||
|
#### 표준 베이스 설정
|
||||||
|
```python
|
||||||
|
# app/core/config.py
|
||||||
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||||
|
from pydantic import BaseModel, Field, ValidationError
|
||||||
|
|
||||||
|
class BaseRobeingSettings(BaseSettings):
|
||||||
|
model_config = SettingsConfigDict(
|
||||||
|
env_file=(".env",),
|
||||||
|
env_prefix="ROBING_",
|
||||||
|
case_sensitive=False,
|
||||||
|
extra="ignore",
|
||||||
|
)
|
||||||
|
|
||||||
|
# 정체성 (불변)
|
||||||
|
ROBING_ID: str
|
||||||
|
ROBING_VERSION: str = "1.0.0"
|
||||||
|
|
||||||
|
# 시스템 (검증된 범위)
|
||||||
|
MEMORY_LIMIT: int = Field(1000, ge=128, le=65536)
|
||||||
|
RESPONSE_TIMEOUT: int = Field(30, ge=1, le=120)
|
||||||
|
|
||||||
|
# 성장 파라미터 (동적)
|
||||||
|
LEVEL: int = Field(1, ge=1, le=20)
|
||||||
|
EXP: int = Field(0, ge=0)
|
||||||
|
LEARNING_RATE: float = Field(0.01, ge=0.0001, le=1.0)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def settings_customise_sources(cls, init_settings, env_settings,
|
||||||
|
dotenv_settings, file_secret_settings):
|
||||||
|
# 우선순위: 런타임 > 사용자 > 환경변수 > 기본값
|
||||||
|
return (
|
||||||
|
init_settings,
|
||||||
|
RuntimeOverlaySource, # 1순위: 동적 변경
|
||||||
|
UserPrefsSource, # 2순위: 사용자 설정
|
||||||
|
env_settings,
|
||||||
|
dotenv_settings,
|
||||||
|
file_secret_settings,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 동적 설정 서비스
|
||||||
|
```python
|
||||||
|
# app/core/config_service.py
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
import json, uuid
|
||||||
|
|
||||||
|
class ChangeSet(BaseModel):
|
||||||
|
"""변경 세트: 원자적 단위로 관리"""
|
||||||
|
id: str
|
||||||
|
changes: dict[str, Any]
|
||||||
|
author: str
|
||||||
|
reason: str
|
||||||
|
ttl_seconds: int | None = None
|
||||||
|
effective_at: datetime
|
||||||
|
version: int
|
||||||
|
|
||||||
|
class ConfigService:
|
||||||
|
"""안전한 동적 설정 관리"""
|
||||||
|
|
||||||
|
async def apply(self, changes: dict, *, author: str, reason: str,
|
||||||
|
ttl_seconds: int = 600): # 기본 10분
|
||||||
|
# 1. 사전 검증
|
||||||
|
trial_config = {**current_config, **changes}
|
||||||
|
BaseRobeingSettings(**trial_config) # 검증 실패시 예외
|
||||||
|
|
||||||
|
# 2. 원자적 적용
|
||||||
|
changeset = ChangeSet(
|
||||||
|
id=str(uuid.uuid4()),
|
||||||
|
changes=changes,
|
||||||
|
author=author,
|
||||||
|
reason=reason,
|
||||||
|
ttl_seconds=ttl_seconds,
|
||||||
|
version=self.next_version()
|
||||||
|
)
|
||||||
|
|
||||||
|
# 3. 멀티워커 전파
|
||||||
|
await self.redis.publish("config:updates", changeset.json())
|
||||||
|
|
||||||
|
# 4. 감사 로그
|
||||||
|
await self.audit_log(changeset)
|
||||||
|
|
||||||
|
# 5. TTL 예약
|
||||||
|
if ttl_seconds:
|
||||||
|
await self.schedule_revert(changeset)
|
||||||
|
|
||||||
|
return changeset
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 멀티워커 전파 메커니즘
|
||||||
|
```python
|
||||||
|
# app/main.py
|
||||||
|
@app.on_event("startup")
|
||||||
|
async def subscribe_config_updates():
|
||||||
|
"""모든 워커가 설정 변경 구독"""
|
||||||
|
async def listener():
|
||||||
|
pubsub = redis.pubsub()
|
||||||
|
await pubsub.subscribe("config:updates")
|
||||||
|
async for msg in pubsub.listen():
|
||||||
|
if msg["type"] == "message":
|
||||||
|
changeset = ChangeSet.parse_raw(msg["data"])
|
||||||
|
# 메모리 오버레이 업데이트
|
||||||
|
MemoryKV.runtime.update(changeset.changes)
|
||||||
|
# 헬스체크
|
||||||
|
await health_check_after_change()
|
||||||
|
|
||||||
|
asyncio.create_task(listener())
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11.4 거버넌스와 보안
|
||||||
|
|
||||||
|
#### 접근 제어 계층
|
||||||
|
```python
|
||||||
|
class ConfigScope(Enum):
|
||||||
|
SYSTEM = "system" # 시스템 관리자만
|
||||||
|
RUNTIME = "runtime" # 운영자 가능
|
||||||
|
USER = "user" # 사용자 개인화
|
||||||
|
|
||||||
|
class SecretScope(Enum):
|
||||||
|
NONE = "none" # 동적 변경 가능
|
||||||
|
SECRET = "secret" # 환경변수/시크릿매니저만
|
||||||
|
|
||||||
|
# 역할별 권한
|
||||||
|
RBAC = {
|
||||||
|
"admin": [ConfigScope.SYSTEM, ConfigScope.RUNTIME],
|
||||||
|
"operator": [ConfigScope.RUNTIME], # 비밀 제외
|
||||||
|
"viewer": [] # 읽기만 가능
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 변경 세트 템플릿
|
||||||
|
```yaml
|
||||||
|
# 변경 요청 표준 양식
|
||||||
|
change_request:
|
||||||
|
key: RESPONSE_TIMEOUT
|
||||||
|
current_value: 30
|
||||||
|
target_value: 45
|
||||||
|
reason: "PDF 처리 시간 증가"
|
||||||
|
validation_method: "헬스체크 API 응답"
|
||||||
|
rollback_criteria: "응답시간 > 50s"
|
||||||
|
ttl_seconds: 600 # 10분 후 자동 복귀
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11.5 성장 파라미터 연동
|
||||||
|
|
||||||
|
```python
|
||||||
|
def adjust_params_on_levelup(level: int, stats: dict[str, int]):
|
||||||
|
"""레벨업 시 자동 파라미터 조정"""
|
||||||
|
changes = {}
|
||||||
|
|
||||||
|
# 연산 스탯 → 타임아웃 증가
|
||||||
|
if stats["compute"] >= 10:
|
||||||
|
changes["RESPONSE_TIMEOUT"] = min(45, 30 + stats["compute"])
|
||||||
|
|
||||||
|
# 기억 스탯 → 메모리 증가
|
||||||
|
if stats["memory"] >= 10:
|
||||||
|
changes["MEMORY_LIMIT"] = min(4096, 1000 + stats["memory"] * 100)
|
||||||
|
|
||||||
|
# 공감 스탯 → 창의성 증가
|
||||||
|
if stats["empathy"] >= 10:
|
||||||
|
changes["CREATIVITY_LEVEL"] = min(0.9, 0.5 + stats["empathy"] * 0.02)
|
||||||
|
|
||||||
|
return ConfigService().apply(
|
||||||
|
changes,
|
||||||
|
author="system:levelup",
|
||||||
|
reason=f"Level {level} automatic adjustment",
|
||||||
|
ttl_seconds=None # 영구 적용
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11.6 운영 도구
|
||||||
|
|
||||||
|
#### CLI 인터페이스
|
||||||
|
```bash
|
||||||
|
# 현재 값 조회
|
||||||
|
robeingctl config get RESPONSE_TIMEOUT
|
||||||
|
|
||||||
|
# 임시 변경 (10분)
|
||||||
|
robeingctl config set RESPONSE_TIMEOUT=45 \
|
||||||
|
--ttl 600 \
|
||||||
|
--reason "heavy pdf parsing"
|
||||||
|
|
||||||
|
# 특정 버전으로 롤백
|
||||||
|
robeingctl config revert --version 128
|
||||||
|
|
||||||
|
# 변경 이력 조회
|
||||||
|
robeingctl config history --last 10
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 관리 API
|
||||||
|
```python
|
||||||
|
@app.get("/admin/config", dependencies=[Depends(require_viewer)])
|
||||||
|
async def read_config():
|
||||||
|
"""현재 설정 조회"""
|
||||||
|
return BaseRobeingSettings().dict()
|
||||||
|
|
||||||
|
@app.post("/admin/config/apply", dependencies=[Depends(require_operator)])
|
||||||
|
async def apply_config(changeset: ChangeSetRequest):
|
||||||
|
"""설정 변경 적용"""
|
||||||
|
return await ConfigService().apply(**changeset.dict())
|
||||||
|
|
||||||
|
@app.get("/admin/config/history", dependencies=[Depends(require_viewer)])
|
||||||
|
async def config_history(limit: int = 10):
|
||||||
|
"""변경 이력 조회"""
|
||||||
|
return await ConfigService().get_history(limit)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11.7 마이그레이션 로드맵
|
||||||
|
|
||||||
|
#### Phase 1: 즉시 적용 (1일)
|
||||||
|
1. 모든 config.py를 `app/core/config.py`로 통일
|
||||||
|
2. robing-gateway에 config.py 생성
|
||||||
|
3. BaseRobeingSettings 상속 구조 도입
|
||||||
|
|
||||||
|
#### Phase 2: 동적 레이어 (1주)
|
||||||
|
1. Redis Pub/Sub 설정
|
||||||
|
2. RuntimeOverlaySource 구현
|
||||||
|
3. TTL 메커니즘 구축
|
||||||
|
4. 감사 로그 파이프라인
|
||||||
|
|
||||||
|
#### Phase 3: 거버넌스 (2주)
|
||||||
|
1. RBAC 시스템 구현
|
||||||
|
2. 변경 세트 검증 강화
|
||||||
|
3. CLI/API 도구 배포
|
||||||
|
4. 모니터링 대시보드
|
||||||
|
|
||||||
|
### 11.8 테스트 체크리스트
|
||||||
|
|
||||||
|
- [ ] 단위: 설정 우선순위 검증
|
||||||
|
- [ ] 통합: 멀티워커 전파 확인
|
||||||
|
- [ ] 안전성: 잘못된 값 거부
|
||||||
|
- [ ] TTL: 자동 복귀 동작
|
||||||
|
- [ ] 성능: 변경 시 지연 없음
|
||||||
|
- [ ] 롤백: 버전별 복구 가능
|
||||||
|
|
||||||
## 핵심 메시지
|
## 핵심 메시지
|
||||||
|
|
||||||
> "로빙은 생명체처럼 적응합니다. 하드코딩된 값이 아닌, 동적으로 변화하는 파라미터를 통해 성장하고 진화합니다."
|
> "로빙은 생명체처럼 적응합니다. 하드코딩된 값이 아닌, 동적으로 변화하는 파라미터를 통해 성장하고 진화합니다."
|
||||||
@ -166,10 +432,12 @@ CREATE TABLE config_bundle (
|
|||||||
- 사용자 요구에 즉시 대응
|
- 사용자 요구에 즉시 대응
|
||||||
- 환경 변화에 유연하게 적응
|
- 환경 변화에 유연하게 적응
|
||||||
- 경험을 통한 지속적 최적화
|
- 경험을 통한 지속적 최적화
|
||||||
- 안전하고 추적 가능한 변경 관리
|
- **안전하고 추적 가능한 변경 관리**
|
||||||
|
|
||||||
를 실현할 수 있습니다.
|
를 실현할 수 있습니다.
|
||||||
|
|
||||||
|
**"설정은 더 이상 고정된 도구가 아닌, 살아 숨쉬는 존재의 일부입니다."**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*이 문서는 아이디어 단계이며, 구체적인 구현 계획으로 발전 예정입니다.*
|
*이 문서는 아이디어에서 구체적인 구현 계획으로 발전했습니다.*
|
||||||
Loading…
x
Reference in New Issue
Block a user