목적(purpose) 레지스트리 — 단일 LLM 창구 계약
소비 포탈은 목적(purpose)만 알고, 모델·키·쿼터·비용·감사는 ModelGateway가 소유한다. 새 포탈이나 새 기능(번역·정합성 분석 등)은 purpose 항목을 추가하는 것으로 얹힌다.
1. 라우팅 규칙
요청 본문 model | 게이트웨이 동작 |
|---|---|
값 있음(예: deepseek-flash) | 그 모델로 보낸다. allowedModels 밖이면 400 |
"auto" 또는 미지정 | x-purpose → purposeModels 매핑 → 없으면 defaultModel |
purposeModels는MODEL_GATEWAY_PURPOSE_MODELS(env,purpose=model쉼표 구분) 또는 관리 API로 설정하고, PortalConsole → 모델 게이트웨이 → 실행 설정의 purpose 매핑(모델 드롭다운)에서 관리한다."auto"는 빈 모델을 거부하는 소비자(예: vendored 포털 AI 계약)를 위한 예약값이다. 소비자가 모델을 비울 수 있으면 생략해도 같은 뜻이다.- 귀속 헤더
x-portal-id·x-purpose·x-actor는 감사·쿼터·비용의 축이다 — 포털 호출은 항상 붙인다. 배치·크론은 자기x-portal-id(예:process-center-batch)와x-actor(<작업>@<호스트>)를 쓴다.
2. 어휘
| 구분 | purpose | 출력 | 비고 |
|---|---|---|---|
| 공통 | rag.embedding | 벡터 | 임베딩(모델 선택이 곧 목적) |
| 공통 | rag.answer | text | 근거 기반 답변(RAGService가 검색, LLM은 게이트웨이) |
| 공통 | content.translate | text | 다국어 자동 생성(포탈별 타깃 필드에 기록) |
| 포탈 | process.version-summary | json | 게시본 변경 요약(ProcessCenter) |
| 포탈 | process.consistency | json | 의미 정합성 분석(ProcessCenter, 규칙 기반 designQuality와 별개 계층) |
- 포탈 전용 목적은
<portal>.<기능>규칙을 쓴다(rag.*·content.*는 공통). - 문자열은 과금·쿼터·감사의 키이므로 한 번 정하면 이름을 바꾸지 않는다(바꾸면 과거 집계가 끊긴다).
- 이 목록은 PortalConsole 화면의 "자주 쓰는 목적" 제안과 같아야 한다(
ModelGatewayDesk.tsx의KNOWN_PURPOSES).
3. 소비자 계약(포탈 구현)
x-purpose에 위 어휘를 넣고, 모델은"auto"(또는 생략)로 둔다 — 모델 고정은 예외 상황에서만.- 출력 형태(text/json)와 프롬프트는 소비자(포탈) 소유다. 게이트웨이는 본문을 그대로 전달한다.
- 실패는 예외로 올리되, 사용자 흐름을 막지 않는 경로(색인·알림)는 비차단으로 처리한다.
- 값이 필요하면 자기 사용량을 조회한다:
GET /v1/usage?portalId=<자기>&purpose=<목적>&days=7→totals.costUsd(USD).
4. 비용(USD)과 시간대
- 감사 레코드에
costUsd(USD) ·cacheReadTokens를 남긴다(src/pricing.ts). - 단가표는 실행 설정(DB)이 정본이다 — 콘솔(모델 게이트웨이 → 실행 설정 → 단가표)에서 모델별 단가·피크 규칙·공휴일을 고치면 재배포 없이 다음 요청부터 적용된다. 기본 시드는 코드(DeepSeek 공식 단가) + env(
MODEL_GATEWAY_PRICING_HOLIDAYS)이고, 저장된 override가 지정한 칸만 덮는다. - 피크/오프피크를 반영한다 — 오프피크가 피크의 절반, 피크는
01:00–04:00·06:00–10:00UTC 월–금. 공휴일 캘린더는ModelPrice.source(요금제 키)로 공유되므로 한 요금제의 공휴일이 다른 공급자 판정에 섞이지 않는다. - 캐시 히트 입력은 캐시 단가로 계산한다. 단가표에 없는 모델은
costUsd를 만들지 않는다(null).
5. 새 소비 포탈 온보딩 체크리스트
- [ ] PortalConsole에 포탈 등록(접근권한·위임 audience/scope에
rag-center·rag:read|rag:admin포함) - [ ] 게이트웨이
x-portal-id(자기 ID) +x-purpose(2장 어휘) 사용 - [ ] 필요한 목적의 모델 매핑을 콘솔 화면에서 지정(없으면
defaultModel로 간다) - [ ] 자기 데이터를 RagService에 발행(uuid5 식별자 정합 — ProcessCenter
server/rag/ragIdentity.ts선례) - [ ] 사용량·비용은 자기
x-portal-id로 조회(대시보드는 PortalConsole)
6. 남은 결정(미구현)
- 어휘를 공유 패키지(
@hohyun94/portal-ai또는portal-foundation)로 올릴지 — 지금은 문서·화면 목록이 정본이다. - 목적별 파라미터(온도·최대 토큰·타임아웃)를 게이트웨이 설정으로 흡수할지 — 지금은 소비자가 본문으로 보낸다.
단가표를 실행 설정(DB)으로 승격— 완료(2026-09-26):modelPricing실행 설정(DB) + 콘솔 "단가표" 화면. 기본 시드는 코드(DeepSeek 공식 단가) + env 공휴일이고 저장된 override가 그 위를 덮으므로, 단가·공휴일 갱신에 재배포가 필요 없다.- 다음 후보: 단가 자동 수집 — 공급자 API가 단가를 주지 않으므로(DeepSeek
/v1/models는 모델 ID만) 완전 자동은 외부 페이지 스크래핑이 되어야 하고, 파싱 취약성·외부 의존을 감수할 만하지 않다. 대신 빠진 단가를 찾아 채우는 흐름을 택했다: 사용량의모델별에서 단가 미입력 배지 + "단가 행 추가"(게이트웨이의 실효 단가로 프리필, PortalConsole). 연결 테스트가/models에서 모델 ID를 가져오므로(콘솔 "발견 모델 반영") 모델 목록은 이미 자동에 가깝다.