diff --git a/agent-roadmap/phase/operational-observability-provider-management/PHASE.md b/agent-roadmap/phase/operational-observability-provider-management/PHASE.md index 47d9b45..de4851a 100644 --- a/agent-roadmap/phase/operational-observability-provider-management/PHASE.md +++ b/agent-roadmap/phase/operational-observability-provider-management/PHASE.md @@ -20,9 +20,9 @@ provider 확장 Phase에서 검증한 Ollama, vLLM, SGLang, Lemonade 같은 추 - 경로: `agent-roadmap/phase/operational-observability-provider-management/milestones/usage-token-log-ops-mvp.md` - 요약: 사용자 관리, token 관리, API/CLI/local inference 사용량 집계, 로그 관리의 1차 운영 경계를 스케치한다. -- [스케치] Provider Catalog와 로컬 디바이스 상태 관리 +- [스케치] Model Alias Provider Pool과 Provider Catalog - 경로: `agent-roadmap/phase/operational-observability-provider-management/milestones/provider-catalog-device-status.md` - - 요약: API, CLI, local inference provider를 같은 운영 catalog에서 보고 vLLM, vLLM-MLX, Lemonade, SGLang 같은 로컬 디바이스 provider 상태를 추적하는 경계를 스케치한다. + - 요약: `qwen3.6:35b` 같은 논리 model alias 아래에 vLLM, Lemonade, Ollama, SGLang 같은 provider 후보를 묶고, Edge가 provider pool의 상태와 capacity를 기준으로 선택/큐잉하는 운영 catalog 경계를 스케치한다. - [스케치] Provider-Device-Model Qualification 리포트와 Lifecycle 관리 - 경로: `agent-roadmap/phase/operational-observability-provider-management/milestones/provider-device-model-qualification-report.md` diff --git a/agent-roadmap/phase/operational-observability-provider-management/milestones/provider-catalog-device-status.md b/agent-roadmap/phase/operational-observability-provider-management/milestones/provider-catalog-device-status.md index 232407c..a06870f 100644 --- a/agent-roadmap/phase/operational-observability-provider-management/milestones/provider-catalog-device-status.md +++ b/agent-roadmap/phase/operational-observability-provider-management/milestones/provider-catalog-device-status.md @@ -1,4 +1,4 @@ -# Milestone: Provider Catalog와 로컬 디바이스 상태 관리 +# Milestone: Model Alias Provider Pool과 Provider Catalog ## 위치 @@ -7,8 +7,9 @@ ## 목표 -API provider, CLI provider, local inference provider를 운영자가 같은 catalog에서 볼 수 있는 MVP 경계를 스케치한다. -vLLM, vLLM-MLX, Lemonade, SGLang 같은 로컬 디바이스 provider는 adapter 구현 자체가 아니라 상태, lifecycle capability, 가용성, 운영 표시 기준을 우선 정리한다. +`qwen3.6:35b` 같은 논리 model alias를 중심으로 여러 추론 엔진 provider 후보를 하나의 provider pool로 묶는 MVP 경계를 스케치한다. +vLLM, vLLM-MLX, Lemonade, Ollama, SGLang 같은 로컬 디바이스 provider는 같은 alias를 제공할 수 있는 candidate로 다루고, Edge가 provider별 실제 target, health, capacity, in-flight 상태를 기준으로 선택/큐잉하는 책임 경계를 우선 정리한다. +API provider, CLI provider, local inference provider catalog는 이 alias pool을 운영자가 관찰하고 조정하기 위한 표시/상태 모델로 연결한다. provider/device/model별 qualification report와 benchmark/품질 비교는 이 Milestone의 직접 구현 범위가 아니라 후속 심화 Milestone으로 분리한다. ## 상태 @@ -17,26 +18,31 @@ provider/device/model별 qualification report와 benchmark/품질 비교는 이 ## 승격 조건 -- [ ] provider catalog가 다룰 provider category와 표시 필드를 결정한다. -- [ ] local inference provider의 상태 추적 기준을 결정한다. +- [ ] 논리 model alias를 canonical routing key로 두고 provider candidate를 묶는 model pool 경계를 결정한다. +- [ ] provider candidate별 node, adapter instance, provider type, 실제 served target, capacity, priority/weight 표시 필드를 결정한다. +- [ ] Edge queue가 model alias 단위로 관리되고, dispatch 시 provider별 실제 target으로 rewrite되는 책임 경계를 정리한다. +- [ ] local inference provider의 health, capacity, in-flight, queue, model list 상태 추적 기준을 결정한다. - [ ] provider별 model lifecycle capability를 catalog 표시 필드로 볼지 후속 리포트 Milestone의 입력으로만 둘지 결정한다. -- [ ] 기존 provider validation Milestone과 중복되지 않는 운영 책임 경계를 정리한다. -- [ ] Control Plane/Client/CLI 중 provider 관리 MVP 표면을 결정한다. +- [ ] Control Plane/Client/CLI 중 provider pool 관리 MVP 표면을 결정한다. ## 구현 잠금 -- 상태: 잠금 +- 상태: 해제 - SDD: 필요 -- SDD 경로: `agent-roadmap/sdd/operational-observability-provider-management/provider-catalog-device-status/SDD.md` -- 잠금 해제 조건: SDD가 승인되고, provider catalog의 상태 필드, lifecycle capability 표시 범위, 운영 표면 책임 경계가 구현 계획을 만들 수 있을 만큼 확정되어야 한다. -- 결정 필요: 아래 체크리스트 - - [ ] provider category를 API, CLI, local inference 외에 어디까지 포함할지 결정한다. - - [ ] local device/provider 상태를 health, capacity, model list, queue, runtime process 중 어디까지 추적할지 결정한다. - - [ ] Ollama/Lemonade처럼 모델 lifecycle API가 있는 provider와 vLLM/SGLang처럼 process/container lifecycle 중심인 provider를 catalog에서 어떻게 구분할지 결정한다. - - [ ] provider catalog를 읽기 전용 관찰로 시작할지, enable/disable 같은 제어까지 포함할지 결정한다. +- SDD 문서: `agent-roadmap/sdd/operational-observability-provider-management/provider-catalog-device-status/SDD.md` +- 잠금 해제 조건: + - [x] SDD 잠금이 해제되어 있다 + - [x] SDD 사용자 리뷰가 없거나 승인/해결되었다 + - [x] Acceptance Scenario가 Milestone 기능 Task와 연결되어 있다 + - [x] Evidence Map이 plan의 `Spec Targets`와 완료 시 `Spec Completion`으로 검증 가능하게 연결되어 있다 + - [x] model alias provider pool의 config/API 계약, provider candidate 선택 기준, target rewrite 책임, catalog 상태 필드, 운영 표면 책임 경계가 구현 계획을 만들 수 있을 만큼 확정되어 있다 +- 결정 필요: 없음 ## 범위 +- model alias 기반 provider pool 계약과 catalog 표시 기준 +- provider candidate별 node/adapter instance/provider/served target/capacity/priority 표시 기준 +- Edge alias queue와 provider candidate 선택/target rewrite 책임 경계 - API, CLI, local inference provider category와 catalog 표시 기준 - local device/provider 상태 추적 기준 - provider별 model lifecycle capability 표시 기준 @@ -45,21 +51,31 @@ provider/device/model별 qualification report와 benchmark/품질 비교는 이 ## 기능 +### Epic: [model-pool] Model Alias Provider Pool + +논리 model alias를 중심으로 여러 provider candidate를 묶고 Edge가 실행 후보를 고르는 최소 산출물을 정리한다. + +- [ ] [alias-contract] `qwen3.6:35b` 같은 논리 model alias가 provider pool의 canonical key가 되는 계약이 정리되어 있다. +- [ ] [candidate-schema] provider candidate별 node, adapter instance, provider type, endpoint/target, capacity, priority/weight, auth reference 표시 필드가 정리되어 있다. +- [ ] [target-rewrite] provider마다 실제 served model id가 다를 때 Edge와 Node 중 어디서 target rewrite를 수행할지 책임 경계가 정리되어 있다. +- [ ] [selection-policy] Edge가 provider pool에서 health, capacity, in-flight, priority/fallback을 사용해 후보를 선택하고 queue timeout을 적용하는 초기 정책이 정리되어 있다. +- [ ] [pool-compat] 기존 `openai.model_routes`, `adapter + target`, Node provider instance 설정과의 호환/마이그레이션 방향이 정리되어 있다. + ### Epic: [provider-catalog] Provider Operations Catalog -운영자가 provider 상태와 category를 같은 기준으로 비교하기 위한 최소 산출물을 묶는다. +운영자가 model alias provider pool과 provider 상태를 같은 기준으로 비교하기 위한 최소 산출물을 묶는다. - [ ] [category-map] API, CLI, local inference provider category와 MVP 표시 필드가 정리되어 있다. - [ ] [device-status] 로컬 디바이스 provider의 health, capacity, model, queue 상태 후보가 정리되어 있다. - [ ] [lifecycle-cap] Ollama, Lemonade, vLLM, SGLang의 model lifecycle capability 차이를 catalog 필드 또는 후속 report 입력으로 정리한다. -- [ ] [boundary] provider adapter 구현과 운영 catalog의 책임 경계가 정리되어 있다. -- [ ] [ops-review] 사용자가 provider catalog MVP 범위와 2차 후보를 검토했다. +- [ ] [boundary] provider adapter 구현, provider pool routing, 운영 catalog의 책임 경계가 정리되어 있다. +- [ ] [ops-review] 사용자가 model alias provider pool과 provider catalog MVP 범위, 2차 후보를 검토했다. ## 완료 리뷰 - 상태: 없음 - 요청일: 없음 -- 완료 근거: 스케치 Milestone이며 기능 Task가 아직 충족되지 않았다. +- 완료 근거: 스케치 Milestone이며 model alias provider pool과 catalog 기능 Task가 아직 충족되지 않았다. - 리뷰 필요: - [ ] 사용자가 완료 결과를 확인했다 - [ ] archive 이동을 승인했다 @@ -68,6 +84,7 @@ provider/device/model별 qualification report와 benchmark/품질 비교는 이 ## 범위 제외 - vLLM, vLLM-MLX, Lemonade, SGLang provider adapter 구현 자체 +- provider pool scheduler 코드 구현과 config migration 실행 - provider/device/model qualification report 저장/조회/비교 - 자동 benchmark, 품질 평가, provider marketplace, cross-Edge provider balancing - cloud fallback과 품질 평가 feedback 구현 @@ -75,7 +92,8 @@ provider/device/model별 qualification report와 benchmark/품질 비교는 이 ## 작업 컨텍스트 - 관련 경로: `apps/edge`, `apps/node`, `apps/control-plane`, `apps/client`, `packages/go/config`, `proto/iop/runtime.proto` -- 표준선(선택): provider 실행 구현은 `adapter + target` 기준을 유지하고, catalog는 운영 관찰과 제어 경계를 별도로 정의한다. +- 기존 구조: 현재 OpenAI route는 외부 `model`을 단일 `adapter + target`으로 resolve하고, Edge queue는 `ModelGroupKey`를 쓰지만 후보 필터링은 같은 `adapter + target` 기준으로 동작한다. +- 새 표준선(선택): provider 실행 구현의 외부 계약은 논리 model alias를 canonical key로 두고, 내부 dispatch 직전에 provider candidate별 `adapter instance + served target`으로 resolve한다. - 선행 작업: Node provider 상태와 Capacity Queue 기반, Edge 모델 그룹 Queue 스케줄링 전환 -- 후속 작업: Provider-Device-Model Qualification 리포트와 Lifecycle 관리, provider enable/disable, benchmark/품질 평가 -- 확인 필요: provider category, 상태 추적 필드, 읽기 전용/제어 포함 여부 +- 후속 작업: provider pool scheduler 구현, Provider-Device-Model Qualification 리포트와 Lifecycle 관리, provider enable/disable, benchmark/품질 평가 +- 확인 필요: model pool config/API 형태, target rewrite 위치, provider 선택 정책, 상태 추적 필드, 읽기 전용/제어 포함 여부 diff --git a/agent-roadmap/sdd/operational-observability-provider-management/provider-catalog-device-status/SDD.md b/agent-roadmap/sdd/operational-observability-provider-management/provider-catalog-device-status/SDD.md new file mode 100644 index 0000000..dac9fd3 --- /dev/null +++ b/agent-roadmap/sdd/operational-observability-provider-management/provider-catalog-device-status/SDD.md @@ -0,0 +1,153 @@ +# SDD: Model Alias Provider Pool과 Provider Catalog + +## 위치 + +- Milestone: `agent-roadmap/phase/operational-observability-provider-management/milestones/provider-catalog-device-status.md` +- Phase: `agent-roadmap/phase/operational-observability-provider-management/PHASE.md` + +## 상태 + +[승인됨] + +## SDD 잠금 + +- 상태: 해제 +- 사용자 리뷰: 없음 +- 잠금 항목: + - [x] [D01] Edge config는 `models[]`를 model catalog이자 외부 model key 목록으로 두고, 각 model의 `providers`에 provider id와 실제 served model name을 매핑한다. provider 정의는 `nodes[].providers[]` 아래에 두며, 각 provider는 제공 가능한 `models[]` list를 가진다. + - [x] [D02] MVP provider 선택은 available provider 중 `in_flight / capacity` load ratio가 가장 낮은 후보를 우선한다. priority/weight/fallback 정책은 후속 확장으로 둔다. + - [x] [D03] provider별 실제 served target rewrite와 routing/control 책임은 Edge가 가진다. Node/provider adapter는 Edge가 전달한 concrete target을 실행한다. + - [x] [D04] MVP provider category는 `api`, `cli`, `local_inference`로 시작하고, 상태 추적은 `health`, `capacity`, `in_flight`, derived `load_ratio`, `models`, `queued`까지 포함한다. runtime process와 resource telemetry는 후속으로 둔다. + - [x] [D05] MVP catalog에는 provider별 lifecycle capability를 coarse flags로만 표시하고, 상세 lifecycle 동작, compatibility, benchmark, quality, model별 qualification 결과는 후속 Qualification Report Milestone으로 둔다. + - [x] [D06] MVP는 읽기 전용 관찰과 Edge config 기반 routing 계약까지만 포함한다. enable/disable, drain, fallback 우선순위 변경, capacity override 같은 runtime 제어는 후속 Milestone으로 둔다. + +## 문제 / 비목표 + +- 문제: 현재 OpenAI-compatible `model` route는 단일 `adapter + target`으로 해석되고, Edge queue도 같은 resolved target 기준으로 후보를 필터링한다. `qwen3.6:35b` 같은 논리 model alias 아래에 vLLM, Lemonade, Ollama, SGLang 같은 여러 provider candidate를 묶으려면 alias를 canonical routing key로 유지하는 계약, candidate schema, selection/queue 정책, served target rewrite 책임, catalog 표시 기준을 먼저 고정해야 한다. +- 비목표: + - vLLM, vLLM-MLX, Lemonade, SGLang provider adapter 구현 자체 + - provider pool scheduler 코드 구현과 config migration 실행 + - provider/device/model qualification report 저장/조회/비교 + - 자동 benchmark, 품질 평가, provider marketplace, cross-Edge provider balancing + - cloud fallback과 품질 평가 feedback 구현 + +## Source of Truth + +| 영역 | 기준 | 메모 | +|------|------|------| +| Roadmap | `agent-roadmap/phase/operational-observability-provider-management/milestones/provider-catalog-device-status.md` | Milestone 목표, 범위, 기능 Task, 잠금 해제 기준 | +| Code | `packages/go/config/config.go` | 현재 `openai.model_routes[]`, adapter instance config, capacity/queue config 구조 | +| Code | `apps/edge/internal/openai/routes.go` | `/v1/models`가 `model_routes`를 catalog처럼 노출하는 현재 외부 model 표면 | +| Code | `apps/edge/internal/service/run_dispatch.go` | `ModelGroupKey` 기반 queue, candidate filtering, capacity policy의 현재 dispatch 기준 | +| Code | `proto/iop/runtime.proto` | `ProviderSnapshot`의 provider 상태, capacity, in-flight, queued 기준 | +| External Provider | 없음 | 이번 Milestone은 외부 provider 상태를 변경하지 않고 IOP 내부 계약과 catalog 기준을 고정한다. | +| User Decision | `user_review_0.log` | D01-D06 resolved | + +## State Machine + +| 상태 | 진입 조건 | 다음 상태 | 근거 | +|------|-----------|-----------|------| +| Model Accepted | OpenAI-compatible `model` 또는 내부 실행 요청이 `models[].id`에 정의된 model id를 포함한다. | Candidate Resolving | `agent-contract/provided/openai-compatible-api.md`, `SubmitRunRequest.ModelGroupKey` | +| Candidate Resolving | Edge가 `models[].providers`에서 provider id와 실제 served model name 매핑을 읽는다. | Candidate Ready 또는 No Candidate | `packages/go/config/config.go`, `apps/edge/internal/service/run_dispatch.go` | +| Provider Matched | `models[].providers`의 provider id가 `nodes[].providers[].id`와 매칭되고, served model name이 해당 provider의 `models[]`에 존재한다. | Candidate Ready 또는 No Candidate | Edge config validation | +| Candidate Ready | candidate가 enabled이고 health/capacity/in-flight 기준을 만족한다. | Load Ranked | provider snapshot, adapter instance capacity, queue policy | +| Load Ranked | Edge가 available candidate의 `in_flight / capacity` load ratio를 계산한다. | Target Rewritten 또는 Queued | 낮은 load ratio 우선, 동률 시 deterministic tie-break | +| Target Rewritten | Edge가 선택된 provider id의 served model name을 `models[].providers[provider_id]`에서 읽는다. | Dispatched | Edge-owned routing/control 책임 | +| Queued | 즉시 사용 가능한 slot이 없고 queue policy가 대기를 허용한다. | Dispatched 또는 Timed Out | `ModelGroupKey` queue, `max_queue`, `queue_timeout_ms` | +| Dispatched | Edge가 선택한 node/provider와 concrete served target을 Node에 전달한다. | Completed 또는 Failed | Edge-Node run request, run event | +| Catalog Observed | Node/Edge가 provider snapshot 또는 catalog 상태를 갱신한다. | Available, Degraded, Unavailable | `health`, `capacity`, `in_flight`, `load_ratio`, `models`, `queued` | + +## Interface Contract + +- 계약 원문: `agent-contract/provided/openai-compatible-api.md` +- 입력: + - `models[].id`: OpenAI-compatible API의 `model`로 호출 가능한 model id이며, `qwen3.6:35b` 같은 형식을 유지한다. + - `models[].display_name`: 운영 화면에서 보여줄 model 이름이다. + - `models[].providers`: provider id를 key로, 해당 provider에서 실제 호출할 served model name을 value로 둔 map이다. + - `models[].providers.`: `nodes[].providers[].id`와 매칭되는 provider id다. + - `models[].providers[]`: provider가 실제로 제공하는 model id 또는 target profile이며, 해당 provider의 `models[]` list 안에 있어야 한다. + - `nodes[].id`: provider를 소유하는 Node identity다. + - `nodes[].providers[]`: provider 정의는 Node 아래에 둔다. 같은 Node 아래에 여러 provider가 있을 수 있다. + - `nodes[].providers[].id`: `models[].providers`의 key로 참조되는 provider id다. + - `nodes[].providers[].type`: provider runtime type이다. 예: `ollama`, `vllm`, `lemonade`, `sglang`, `openai_api`, `cli`. + - `nodes[].providers[].category`: MVP provider category다. 값은 `api`, `cli`, `local_inference`로 시작한다. + - `nodes[].providers[].models`: 해당 provider가 실제로 제공 가능한 served model name list다. + - `provider.health`: `available`, `unavailable`, `unknown` 중 하나의 최소 provider health 상태다. + - `provider.capacity`: provider가 동시에 처리할 수 있는 실행 slot 수다. + - `provider.in_flight`: provider에서 현재 실행 중인 요청 수다. + - `provider.load_ratio`: `in_flight / capacity`로 계산하는 선택 기준이다. capacity가 0이거나 알 수 없으면 선택 대상에서 제외하거나 unavailable로 본다. + - `provider.queued`: Edge queue에서 관측 가능한 provider 또는 model group 대기 요청 수다. + - `provider.lifecycle_capabilities`: provider별 model lifecycle capability를 coarse flags로 표시한다. 예: `list_models`, `load_model`, `unload_model`, `pull_model`, `delete_model`. + - `catalog.status`: MVP에서는 health, capacity, in-flight, derived load ratio, model list, queued, coarse lifecycle capability를 표시한다. runtime process/container detail과 CPU/GPU/RAM/VRAM resource telemetry는 후속으로 둔다. + - `catalog.control`: MVP에서는 읽기 전용 관찰과 Edge config 기반 routing 계약만 포함한다. runtime control은 후속 Milestone 책임이다. +- 출력: + - `resolution.adapter`: Node에 전달할 adapter type 또는 adapter instance key다. + - `resolution.target`: Node adapter가 실행할 concrete served target이다. + - `resolution.node_id`: 선택된 Node identity다. + - `resolution.provider_id`: Edge가 선택한 provider identity다. + - `resolution.model_group_key`: queue와 관측에 남길 `models[].id`다. + - `catalog.providers[]`: 운영자가 provider pool과 provider 상태를 비교할 수 있는 표시 record다. +- 금지: + - OpenAI-compatible 외부 경계에서 `model`을 제거하거나 caller에게 `adapter + target`을 직접 요구하지 않는다. + - `models[]`에 정의되지 않은 model id를 새 provider-pool 경로에서 암묵적으로 실행하지 않는다. + - 단일 provider model이라도 별도 축약 구조를 만들지 않고 `models[].providers`에 provider 한 개만 둔다. + - `models[].providers`에서 참조한 provider id가 `nodes[].providers[].id`에 없거나, served model name이 해당 provider의 `models[]`에 없으면 유효한 route로 보지 않는다. + - capacity가 남았다는 이유만으로 더 높은 load ratio의 provider를 우선 선택하지 않는다. + - MVP selection policy에 priority, weight, fallback policy를 필수 필드로 넣지 않는다. + - Node/provider adapter가 catalog model id나 alias를 자체적으로 provider별 served model name으로 rewrite하지 않는다. + - MVP catalog/status에 runtime process/container detail이나 CPU/GPU/RAM/VRAM resource telemetry를 필수 필드로 넣지 않는다. + - MVP catalog에 lifecycle API 상세 동작, compatibility, benchmark, quality score, model별 qualification 결과를 직접 넣지 않는다. + - MVP catalog/control 표면에 provider enable/disable, drain, fallback 우선순위 변경, capacity override 같은 runtime 제어를 넣지 않는다. + - Control Plane을 Edge-owned provider 상태의 canonical store로 만들지 않는다. + - SDD 본문에 agent-contract 원문을 복제하지 않는다. + - qualification report, benchmark, 품질 비교를 이번 Milestone의 필수 구현으로 끌어오지 않는다. + +## Acceptance Scenarios + +| ID | Milestone Task | Given | When | Then | +|----|----------------|-------|------|------| +| S01 | `alias-contract` | 운영자가 `models[]`에 `qwen3.6:35b` 같은 model id를 정의한다. | OpenAI-compatible 요청 또는 내부 실행 요청이 해당 model id를 사용한다. | model id는 queue와 catalog의 canonical key로 유지되고, dispatch 직전에만 provider별 served model name으로 해석된다. | +| S02 | `candidate-schema` | 하나의 `models[]` 항목에 여러 provider id와 served model name 매핑이 있다. | provider pool schema를 검토한다. | `models[].providers`가 provider id -> 실제 served model name map으로 정리되어 있고, provider 정의는 Node 아래 provider list로 분리되며, provider별 `models[]` list가 제공 가능 모델의 기준이 된다. | +| S03 | `target-rewrite` | provider마다 실제 served model id가 다르다. | Edge가 candidate를 선택한다. | Edge가 `models[].providers[provider_id]` 값을 concrete target으로 rewrite해 Node에 전달하고, Node/provider adapter는 전달받은 target만 실행한다. | +| S04 | `selection-policy` | 여러 candidate가 서로 다른 health, capacity, in-flight 값을 가진다. | Edge가 실행 후보를 고른다. | unavailable 후보를 제외하고 `in_flight / capacity` load ratio가 가장 낮은 provider를 우선 선택한다. 예: 1/3 provider가 2/3 provider보다 우선한다. | +| S05 | `pool-compat` | 기존 `openai.model_routes`, `adapter + target`, Node provider instance 설정이 존재한다. | 새 pool 계약을 도입하거나 compat layer를 설계한다. | 기존 route와 provider instance 설정의 호환/마이그레이션 방향이 정리되어 있다. | +| S06 | `category-map` | API, CLI, local inference provider가 같은 catalog에 노출된다. | catalog 표시 필드를 검토한다. | MVP category는 `api`, `cli`, `local_inference`로 정의되어 있다. | +| S07 | `device-status` | local inference provider가 health, capacity, in-flight, model list, queue 상태 일부를 제공한다. | 운영자가 상태를 조회한다. | MVP 상태 필드는 `health`, `capacity`, `in_flight`, derived `load_ratio`, `models`, `queued`이며 runtime/resource telemetry는 후속으로 분리되어 있다. | +| S08 | `lifecycle-cap` | Ollama/Lemonade와 vLLM/SGLang의 model lifecycle 동작이 다르다. | catalog 또는 후속 report 입력을 설계한다. | MVP catalog에는 coarse lifecycle capability flags만 표시하고 상세 lifecycle/compatibility/benchmark/quality/qualification 결과는 후속 Milestone으로 분리되어 있다. | +| S09 | `boundary` | adapter 구현, pool routing, 운영 catalog가 서로 다른 책임을 가진다. | 구현 계획을 작성한다. | provider adapter 구현, provider pool routing, read-only operations catalog, 후속 runtime control의 책임 경계가 분리되어 있다. | +| S10 | `ops-review` | SDD와 사용자 결정 항목이 준비되어 있다. | 사용자가 MVP 범위와 2차 후보를 검토한다. | D01-D06 결정이 `user_review_0.log`와 SDD에 반영되고 SDD 잠금이 해제되어 있다. | + +## Evidence Map + +| Scenario | Required Evidence | `agent-task` 연결 | `Spec Completion` 기대 | +|----------|-------------------|------------------|---------------------------| +| S01 | pool 계약 문서 또는 config/proto/API diff, OpenAI-compatible model id test | `agent-task/m-provider-catalog-device-status/...` | `alias-contract`가 `models[].id` canonical key와 dispatch resolution 기준을 충족했다는 근거 | +| S02 | candidate schema diff 또는 SDD/plan 확정 표, config validation test | `agent-task/m-provider-catalog-device-status/...` | `candidate-schema`가 `models[].providers` map, Node 하위 provider 정의, provider별 `models[]` list 검증 기준을 충족했다는 근거 | +| S03 | target rewrite 책임 문서, Edge/Node request mapping test | `agent-task/m-provider-catalog-device-status/...` | `target-rewrite`가 Edge-owned routing/control 원칙을 따르고 concrete target 전달을 검증했다는 근거 | +| S04 | queue/selection policy test 또는 smoke, timeout/overflow case evidence | `agent-task/m-provider-catalog-device-status/...` | `selection-policy`가 available provider 중 낮은 `in_flight / capacity` load ratio를 우선하고, 동률 tie-break와 queue timeout을 검증했다는 근거 | +| S05 | migration/compat note, 기존 `model_routes` regression test | `agent-task/m-provider-catalog-device-status/...` | `pool-compat`가 기존 OpenAI route와 Node provider instance 설정을 깨지 않는다는 근거 | +| S06 | catalog DTO/API/UI/CLI 표시 evidence | `agent-task/m-provider-catalog-device-status/...` | `category-map`이 `api`, `cli`, `local_inference` category를 확인했다는 근거 | +| S07 | provider snapshot/status test, unknown/unavailable case evidence | `agent-task/m-provider-catalog-device-status/...` | `device-status`가 health/capacity/in-flight/load-ratio/models/queued 범위를 검증하고 runtime/resource telemetry를 후속으로 분리했다는 근거 | +| S08 | lifecycle capability 표 또는 follow-up handoff evidence | `agent-task/m-provider-catalog-device-status/...` | `lifecycle-cap`이 coarse flags로 catalog에 표시되고 상세 qualification 항목은 후속 Milestone으로 분리되었다는 근거 | +| S09 | architecture boundary note, package/API ownership evidence | `agent-task/m-provider-catalog-device-status/...` | `boundary`가 adapter, routing, read-only catalog, 후속 runtime control 책임을 분리했다는 근거 | +| S10 | `user_review_0.log` 해결 log 또는 사용자 승인 기록 | `agent-task/m-provider-catalog-device-status/...` | `ops-review`가 완료되어 SDD 잠금 해제 상태를 확인했다는 근거 | + +## Cross-repo Dependencies + +- 없음 + +## Drift Check + +- [x] Milestone 기능 Task와 Acceptance Scenario가 일치한다. +- [x] Evidence Map이 plan/code-review/complete.log에서 검증 가능하다. +- [x] agent-contract를 쓰는 경우 SDD에 계약 원문을 복제하지 않았다. +- [x] 열린 사용자 리뷰가 없고 해결된 리뷰는 `user_review_0.log`에 남겼다. + +## 사용자 리뷰 이력 + +- `user_review_0.log`: D01-D06 결정 반영, SDD 잠금 해제 + +## 작업 컨텍스트 + +- 표준선: 외부 OpenAI-compatible 경계는 `model`을 유지하고, 내부 실행은 `adapter + target`으로 resolve한다. Edge는 queue와 dispatch를 담당하며, Edge-owned 상태의 canonical store는 Control Plane이 아니라 Edge/Node 쪽에 둔다. +- 후속 SDD: 없음. Provider-Device-Model Qualification 리포트 Milestone에서 lifecycle capability, benchmark, 품질 비교 저장/조회가 구현 범위가 되면 별도 SDD 필요 여부를 다시 판정한다. diff --git a/agent-roadmap/sdd/operational-observability-provider-management/provider-catalog-device-status/user_review_0.log b/agent-roadmap/sdd/operational-observability-provider-management/provider-catalog-device-status/user_review_0.log new file mode 100644 index 0000000..1ceb46f --- /dev/null +++ b/agent-roadmap/sdd/operational-observability-provider-management/provider-catalog-device-status/user_review_0.log @@ -0,0 +1,107 @@ +# SDD User Review + +## 상태 + +해결됨 + +## 검토 대상 + +- SDD: `agent-roadmap/sdd/operational-observability-provider-management/provider-catalog-device-status/SDD.md` +- Milestone: `agent-roadmap/phase/operational-observability-provider-management/milestones/provider-catalog-device-status.md` + +## 사용자 결정 항목 + +### [D01] Pool 계약 위치 + +- 결정 필요: model catalog와 provider pool을 Edge config에서 어떤 최소 구조로 표현할지 결정한다. +- 결정: `model_catalogs`나 `model_pools` 같은 별도 이름 대신 `models[]`를 사용한다. `models[].id`는 `qwen3.6:35b` 같은 외부 OpenAI-compatible model key이자 운영 catalog model id다. 단일 provider만 쓰는 model도 같은 구조로 정의하고, `providers`에 provider id 하나만 둔다. IOP는 `models[]`에 정의된 model만 새 provider-pool 경로에서 사용한다. +- 결정: `models[].providers`는 provider id를 key로, 해당 provider에서 실제 호출할 model name을 value로 둔다. provider 자체는 `nodes[].providers[]` 아래에 정의한다. 같은 Node 아래에 여러 provider가 있을 수 있고, 각 provider는 제공 가능한 실제 model name을 `models[]` list로 가진다. +- 결정: `models[].providers`의 key는 반드시 `nodes[].providers[].id`와 매칭되어야 하고, value는 해당 provider의 `models[]` list 안에 있어야 한다. +- 추천안: 승인됨. `models[]`가 model catalog와 외부 model key 목록을 동시에 담당하고, provider 매핑은 `providers: : ` 형태로 둔다. +- 대안: 없음. 기존 `openai.model_routes[]` 확장이나 별도 `model_pools[]` 분리는 D01 범위에서 채택하지 않는다. +- 영향: 외부 호출 모델명, 운영 model catalog, provider candidate 매핑이 한 구조에 고정된다. provider 상세 정의와 provider별 model list는 Node 하위 provider 계약으로 이어진다. +- 적용 위치: + - SDD: `Interface Contract`, `Acceptance Scenarios S01/S05` + - Milestone: `alias-contract`, `pool-compat`, `구현 잠금` + +### [D02] Candidate 선택 정책 + +- 결정 필요: provider candidate 선택 기준을 capacity/in-flight 중심으로 시작할지, priority/weight/fallback 정책까지 MVP에 포함할지 결정한다. +- 결정: MVP는 available provider 중 `in_flight / capacity` load ratio가 가장 낮은 후보를 우선 선택한다. 단순히 남은 slot이 있다는 이유로 더 높은 load ratio의 provider를 선택하지 않는다. 예를 들어 2/3 provider와 1/3 provider가 있으면 1/3 provider를 우선한다. +- 결정: capacity가 0이거나 알 수 없으면 selection 대상에서 제외하거나 unavailable로 본다. 동률이면 deterministic tie-break를 사용한다. +- 결정: priority, weight, fallback policy는 MVP 필수 필드로 넣지 않고 후속 확장으로 둔다. +- 추천안: 승인됨. health/available 여부를 먼저 보고, 그 다음 `in_flight / capacity` load ratio 기준으로 선택한다. +- 대안: priority/weight/fallback을 MVP에 포함한다. +- 영향: scheduler가 단순 여유 slot 기준보다 균등한 load distribution을 우선하게 된다. policy field를 아직 도입하지 않으므로 config 복잡도는 낮게 유지된다. +- 적용 위치: + - SDD: `State Machine`, `Acceptance Scenarios S04` + - Milestone: `selection-policy`, `구현 잠금` + +### [D03] Target rewrite 책임 + +- 결정 필요: provider마다 실제 served target이 다를 때 Edge가 target rewrite를 담당할지, Node adapter instance가 alias mapping을 담당할지 결정한다. +- 결정: target rewrite와 routing/control 책임은 모두 Edge가 가진다. Edge가 provider를 선택한 뒤 `models[].providers[provider_id]` 값을 concrete served target으로 해석해 Node에 전달한다. +- 결정: Node/provider adapter는 catalog model id나 alias를 provider별 served model name으로 자체 rewrite하지 않는다. Node는 Edge가 지정한 provider와 concrete target을 실행한다. +- 추천안: 승인됨. Edge-owned control 원칙으로 고정한다. +- 대안: 없음. Node adapter instance alias mapping은 채택하지 않는다. +- 영향: queue, provider selection, target rewrite, 관측/debug 책임이 Edge에 모인다. Node는 실행자 역할로 단순화된다. +- 적용 위치: + - SDD: `Interface Contract`, `Acceptance Scenarios S03` + - Milestone: `target-rewrite`, `구현 잠금` + +### [D04] Catalog/status 표시 범위 + +- 결정 필요: provider category를 API, CLI, local inference 외에 어디까지 포함하고, local device/provider 상태를 health, capacity, model list, queue, runtime process 중 어디까지 추적할지 결정한다. +- 결정: MVP provider category는 `api`, `cli`, `local_inference`로 시작한다. +- 결정: MVP 상태 추적은 `health`, `capacity`, `in_flight`, derived `load_ratio`, `models`, `queued`까지 포함한다. +- 결정: runtime process/container detail과 CPU/GPU/RAM/VRAM resource telemetry는 MVP 필수 범위에서 제외하고 후속으로 둔다. +- 추천안: 승인됨. D02 selection에 필요한 필드와 catalog 관측에 필요한 최소 상태만 포함한다. +- 대안: runtime process, container/process lifecycle, 상세 resource telemetry까지 MVP에 포함한다. +- 영향: Control Plane/Client/CLI가 provider 사용 가능 여부와 부하 상태를 볼 수 있고, 상세 host/process/resource 관측은 후속으로 분리된다. +- 적용 위치: + - SDD: `Source of Truth`, `Interface Contract`, `Acceptance Scenarios S06/S07` + - Milestone: `category-map`, `device-status`, `구현 잠금` + +### [D05] Lifecycle capability 표시 방식 + +- 결정 필요: Ollama/Lemonade처럼 모델 lifecycle API가 있는 provider와 vLLM/SGLang처럼 process/container lifecycle 중심인 provider를 catalog에서 어떻게 구분할지 결정한다. +- 결정: MVP catalog에는 provider별 lifecycle capability를 coarse flags로만 표시한다. 예: `list_models`, `load_model`, `unload_model`, `pull_model`, `delete_model`. +- 결정: 상세 lifecycle 동작, compatibility, benchmark, quality, model별 qualification 결과는 후속 Qualification Report Milestone으로 넘긴다. +- 추천안: 승인됨. catalog는 capability 차이를 볼 수 있는 정도로만 표시하고, 검증/품질/호환성 판단은 후속 리포트로 분리한다. +- 대안: lifecycle API 세부 동작과 제어 가능 여부를 catalog MVP에 직접 포함한다. +- 영향: catalog는 provider capability 비교 표면으로 유지되고, lifecycle 관리/검증/품질 판단 책임은 후속 Milestone으로 분리된다. +- 적용 위치: + - SDD: `Interface Contract`, `Acceptance Scenarios S08` + - Milestone: `lifecycle-cap`, `구현 잠금` + +### [D06] 운영 표면 제어 포함 여부 + +- 결정 필요: provider pool과 catalog를 읽기 전용 관찰로 시작할지, enable/disable 같은 제어까지 포함할지 결정한다. +- 결정: MVP는 읽기 전용 관찰과 Edge config 기반 routing 계약까지만 포함한다. +- 결정: enable/disable, drain, fallback 우선순위 변경, capacity override 같은 runtime 제어는 후속 Milestone으로 둔다. +- 추천안: 승인됨. provider catalog/pool MVP는 관찰 표면과 routing 계약을 확정하고, runtime 제어는 권한/audit/실패 처리와 함께 후속으로 분리한다. +- 대안: enable/disable, drain, fallback 우선순위 변경 같은 제어를 MVP에 포함한다. +- 영향: MVP의 권한, audit, failure handling 부담이 낮아지고, Control Plane/Client/CLI runtime control 책임은 후속 Milestone에서 별도로 설계한다. +- 적용 위치: + - SDD: `문제 / 비목표`, `Acceptance Scenarios S09/S10` + - Milestone: `boundary`, `ops-review`, `구현 잠금` + +## 승인 항목 + +- [x] 위 결정 항목을 승인했다. +- [x] SDD 잠금 해제를 승인했다. + +## 답변 기록 + +- D01: 사용자는 `model_catalogs`/`model_pools` 대신 `models[]`를 사용하고, 단일 provider model도 같은 구조로 정의하며, `models[].providers`를 provider id -> served model name map으로 두는 방향을 확정했다. provider 정의는 `nodes[].providers[]` 아래에 두고, 각 provider는 제공 가능한 실제 model name을 `models[]` list로 가진다. `models[].providers`의 key는 provider id와 매칭되고, value는 해당 provider의 `models[]` 안에 있어야 한다. +- D02: 사용자는 provider 선택 기준을 단순 remaining slot이 아니라 `in_flight / capacity` load ratio로 확정했다. available 후보 중 load ratio가 가장 낮은 provider를 우선하며, 2/3과 1/3이 있으면 1/3을 선택한다. priority/weight/fallback은 MVP 필수 필드에서 제외하고 후속 확장으로 둔다. +- D03: 사용자는 routing/control 책임은 Edge가 가져야 한다는 설계 원칙을 확정했다. Edge가 provider 선택과 target rewrite를 수행하고, Node/provider adapter는 Edge가 전달한 concrete target을 실행한다. +- D04: 사용자는 MVP provider category를 `api`, `cli`, `local_inference`로 확정했다. 상태 추적은 `health`, `capacity`, `in_flight`, derived `load_ratio`, `models`, `queued`까지 포함하고, runtime process/container detail과 CPU/GPU/RAM/VRAM resource telemetry는 후속으로 둔다. +- D05: 사용자는 MVP catalog에 provider별 lifecycle capability를 coarse flags로만 표시하고, 상세 lifecycle 동작, compatibility, benchmark, quality, model별 qualification 결과는 후속 Qualification Report Milestone으로 넘기는 방향을 확정했다. +- D06: 사용자는 MVP를 읽기 전용 관찰과 Edge config 기반 routing 계약까지만 포함하고, enable/disable, drain, fallback 우선순위 변경, capacity override 같은 runtime 제어는 후속 Milestone으로 두는 방향을 확정했다. + +## 해결 조건 + +- 모든 사용자 결정 항목의 답변이 SDD에 반영되어 있다. +- `USER_REVIEW.md`가 `user_review_N.log`로 이동되어 있다. +- 남은 잠금 항목이 없으면 SDD 상태가 `[승인됨]`이고 `SDD 잠금` 상태가 `해제`다. diff --git a/model_catalog b/model_catalog new file mode 100644 index 0000000..8728e91 --- /dev/null +++ b/model_catalog @@ -0,0 +1,23 @@ +models: + - id: qwen3.6:35b + display_name: Qwen 3.6 35B + providers: + ollama-m1: qwen35b + vllm-dgx: qwen35b-awq + +nodes: + - id: node-m1 + providers: + - id: ollama-m1 + type: ollama + models: + - qwen35b + - llama3.1-8b + + - id: node-dgx + providers: + - id: vllm-dgx + type: vllm + models: + - qwen35b-awq + - qwen35b-fp16