feat(rewrite): enhance model rewrite logic with cycle detection and chain evaluation
This commit is contained in:
parent
2bac7ad6a4
commit
7cef8635bd
9 changed files with 531 additions and 79 deletions
|
|
@ -23,9 +23,10 @@
|
|||
`/v1/**`는 기존 사용자 API 키 인증을 유지하며 관리자 인증과 분리된다.
|
||||
|
||||
추가 동작:
|
||||
- `/v1/chat/completions` 는 요청 모델명을 먼저 전역 rewrite 규칙으로 해석한 뒤, 최종 모델을 서빙하는 허용 가능한 활성 백엔드만 후보로 사용한다
|
||||
- `force=true` rewrite 는 항상 적용된다
|
||||
- `force=false` rewrite 는 원본 모델을 서빙하는 허용 가능한 활성 백엔드가 없을 때만 fallback 으로 적용된다
|
||||
- `/v1/chat/completions` 는 요청 모델명을 먼저 전역 rewrite 체인으로 해석한 뒤, 최종 모델을 서빙하는 허용 가능한 활성 백엔드만 후보로 사용한다
|
||||
- `force=true` rewrite 는 항상 적용되고 target 모델의 다음 규칙까지 계속 평가한다
|
||||
- `force=false` rewrite 는 현재 모델을 서빙하는 허용 가능한 활성 백엔드가 없을 때만 fallback 으로 적용되고 target 모델의 다음 규칙까지 계속 평가한다
|
||||
- `/v1/models` 는 native backend 모델뿐 아니라 현재 사용자 권한에서 최종 후보가 있는 rewrite source alias도 함께 반환한다
|
||||
- 최종 후보가 없으면 모델 미지원 오류를 반환하고 `request_model`, `routed_model` 을 함께 내려준다
|
||||
|
||||
## Admin API
|
||||
|
|
@ -80,6 +81,8 @@
|
|||
| PUT | `/admin/model-rewrites/:id` | 전역 모델 rewrite 규칙 수정 |
|
||||
| DELETE | `/admin/model-rewrites/:id` | 전역 모델 rewrite 규칙 삭제 |
|
||||
|
||||
활성 rewrite 그래프에 cycle을 만드는 생성/수정 요청은 `409 { error, cycle }` 로 거부된다. 비활성 규칙끼리의 cycle은 저장할 수 있지만 활성화 시점에는 같은 검사를 통과해야 한다.
|
||||
|
||||
`GET /admin/backends/:id/models` 응답에는 아래가 함께 포함된다.
|
||||
- `backend`: 백엔드 기본 정보 + 캐시 요약
|
||||
- `cache`: 메모리 캐시 상태 (`ready`, `uninitialized`, `error`, `inactive`)
|
||||
|
|
|
|||
|
|
@ -78,7 +78,8 @@ SPA는 `/dashboard`를 라우터 base로 사용하고, 관리자 API는 계속 `
|
|||
- `Backends` 화면은 백엔드별 모델 캐시 상태, 모델 수, 마지막 sync 상태를 표시한다
|
||||
- `Backends` 화면에서 활성 백엔드는 수동 refresh 와 캐시된 모델 목록 확인이 가능하다
|
||||
- 비활성 백엔드는 모델 조회를 시도하지 않으며 UI에서도 `Skipped` 상태로 표시된다
|
||||
- `Models` 화면은 전체 메모리 모델 카탈로그와 전역 모델 rewrite 규칙을 관리한다
|
||||
- `Models` 화면은 전체 메모리 모델 카탈로그와 전역 모델 rewrite 체인을 관리한다
|
||||
- rewrite 규칙은 2가지 모드를 가진다
|
||||
- `Force`: 원본 모델 사용 가능 여부와 관계없이 항상 target model 로 rewrite
|
||||
- `Fallback`: 원본 모델을 서빙하는 허용 가능한 활성 백엔드가 없을 때만 target model 로 rewrite
|
||||
- `Force`: 현재 모델 사용 가능 여부와 관계없이 항상 target model 로 이동하고 다음 규칙을 계속 평가
|
||||
- `Fallback`: 현재 모델을 서빙하는 허용 가능한 활성 백엔드가 없을 때만 target model 로 이동하고 다음 규칙을 계속 평가
|
||||
- 활성 rewrite cycle은 저장 시점에 거부되며, `/v1/models` 는 실제 요청 가능한 rewrite alias를 함께 반환한다
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
1. 사용자 API 키 인증
|
||||
2. 사용자가 접근 가능한 backend id 목록 로드
|
||||
3. 접근 가능한 활성 백엔드 중 아직 메모리 카탈로그가 초기화되지 않은 백엔드만 `/v1/models` 로 lazy fetch
|
||||
4. 요청 `model` 에 대해 전역 `model_rewrites` 규칙 평가
|
||||
4. 요청 `model` 에 대해 전역 `model_rewrites` 체인을 끝까지 평가
|
||||
5. 최종 모델을 서빙하는 허용 가능한 활성 백엔드만 후보로 선택
|
||||
6. 후보 중 1개를 랜덤 선택 후 업스트림으로 포워딩
|
||||
|
||||
|
|
@ -17,7 +17,8 @@
|
|||
|
||||
1. 사용자 API 키 인증
|
||||
2. 접근 가능한 활성 백엔드의 메모리 카탈로그를 확인
|
||||
3. 모델 ID 합집합을 반환
|
||||
3. native backend 모델과 rewrite `source_model` alias를 같은 체인 해석기로 평가
|
||||
4. 최종 모델 후보가 있는 requestable 모델 ID 합집합을 반환
|
||||
|
||||
## Caching Rules
|
||||
|
||||
|
|
@ -37,13 +38,22 @@
|
|||
|
||||
| Mode | Condition | Result |
|
||||
|------|-----------|--------|
|
||||
| `force=true` | 항상 | `source_model` 을 즉시 `target_model` 로 치환 |
|
||||
| `force=false` | 원본 모델 후보가 없을 때만 | `target_model` 을 fallback 으로 사용 |
|
||||
| `force=true` | 항상 | `source_model` 을 `target_model` 로 치환하고 다음 규칙을 계속 평가 |
|
||||
| `force=false` | 현재 모델 후보가 없을 때만 | `target_model` 을 fallback 으로 사용하고 다음 규칙을 계속 평가 |
|
||||
|
||||
해석 기준:
|
||||
- “원본 모델 후보가 있다”는 것은 사용자가 접근 가능하고 활성 상태이며, 메모리 카탈로그상 해당 모델을 서빙하는 백엔드가 하나 이상 있다는 뜻이다
|
||||
- 원본 모델 후보가 있으면 fallback 규칙은 무시된다
|
||||
- “현재 모델 후보가 있다”는 것은 사용자가 접근 가능하고 활성 상태이며, 메모리 카탈로그상 해당 모델을 서빙하는 백엔드가 하나 이상 있다는 뜻이다
|
||||
- 현재 모델 후보가 있으면 fallback 규칙은 무시되고 체인 평가가 멈춘다
|
||||
- force 규칙은 현재 모델 후보 존재 여부와 관계없이 target으로 이동한다
|
||||
- 최종 모델 후보가 없으면 라우터는 포워딩하지 않고 모델 미지원 오류를 반환한다
|
||||
- 활성 rewrite 그래프에 cycle이 생기는 관리자 생성/수정은 거부된다
|
||||
- 직접 DB 조작 등으로 runtime cycle이 발견되면 라우터는 설정 오류를 반환한다
|
||||
- 체인 평가는 요청별 allowed backend set과 candidate memo를 사용해 반복 DB 조회를 피한다
|
||||
|
||||
예시:
|
||||
`AutoModelTranslate -(Force)-> Qwen3.5 -(Force)-> Qwen/Qwen3.5-397B-A17B-FP8 -(Fallback)-> Gemma4 -(Force)-> cyankiwi/gemma-4-26B-A4B-it-AWQ-4bit`
|
||||
|
||||
위 예시에서 `Qwen/Qwen3.5-397B-A17B-FP8` 후보가 있으면 fallback이 적용되지 않고 그 모델로 라우팅된다. 후보가 없으면 `Gemma4`로 이동한 뒤 force 규칙을 이어서 적용한다.
|
||||
|
||||
## Admin Surface
|
||||
|
||||
|
|
|
|||
|
|
@ -62,11 +62,12 @@ server/src/
|
|||
|
||||
## Model Routing
|
||||
|
||||
- 요청 모델명은 먼저 전역 `model_rewrites` 규칙을 확인한다
|
||||
- `force=1` 규칙은 항상 `source_model -> target_model` 로 변환한다
|
||||
- `force=0` 규칙은 원본 모델을 서빙하는 허용 가능한 활성 백엔드가 없을 때만 fallback 으로 적용한다
|
||||
- 요청 모델명은 먼저 전역 `model_rewrites` 체인을 확인한다
|
||||
- `force=1` 규칙은 항상 `source_model -> target_model` 로 변환하고 다음 규칙을 계속 확인한다
|
||||
- `force=0` 규칙은 현재 모델을 서빙하는 허용 가능한 활성 백엔드가 없을 때만 fallback 으로 적용하고 다음 규칙을 계속 확인한다
|
||||
- 활성 rewrite cycle은 관리자 생성/수정 시 거부하고, runtime에서도 방어한다
|
||||
- 최종 모델을 서빙하는 허용 가능한 활성 백엔드가 없으면 `/v1/chat/completions` 는 모델 미지원 오류를 반환한다
|
||||
- `/v1/models` 는 허용 가능한 활성 백엔드들의 캐시된 모델 목록 합집합을 반환한다
|
||||
- `/v1/models` 는 허용 가능한 활성 백엔드들의 native 모델과 실제 요청 가능한 rewrite alias 합집합을 반환한다
|
||||
|
||||
참고:
|
||||
- 세부 라우팅 규칙과 캐시 트리거는 [docs/model-routing.md](./model-routing.md) 참고
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue