iop/agent-roadmap/archive/sdd/routing-policy-model-orchestration/model-group-mixed-provider-dispatch/SDD.md

16 KiB

SDD: Model Group Mixed Provider Dispatch

위치

상태

[승인됨]

SDD 잠금

  • 상태: 해제
  • 사용자 리뷰: 없음
  • 잠금 항목:
    • 없음

문제 / 비목표

  • 문제: 현재 provider-pool/model group route는 provider pool이면 raw tunnel을 먼저 가정하는 경향이 있어, 같은 model group 안에 Ollama 같은 normalized-only provider가 들어오면 선택된 provider의 OpenAI-compatible 지원 여부와 실행 경로가 어긋날 수 있다. 반대로 model group 전체를 normalized로 낮추면 vLLM/vLLM-MLX/Lemonade/openweight cloud provider의 provider-original passthrough 장점이 사라진다. Model group은 provider 후보를 동일하게 평가하되, 선택된 provider의 OpenAI-compatible 지원 여부에 따라 실행 경로를 자동 결정해야 한다.
  • 비목표:
    • provider 선택 기준을 capacity + priority 밖의 score policy로 바꾼다.
    • Ollama를 model group에서 제외한다.
    • Ollama를 고동시성 기본 provider로 취급한다.
    • client 요청 field로 passthrough/normalized/transformed 경로를 선택하게 한다.
    • 이 Milestone에서 cloud fallback, route learning loop, provider auth 정책을 추가한다.

Source of Truth

영역 기준 메모
Roadmap Model Group Mixed Provider Dispatch 목표, 기능 Task, 범위 제외 기준
Contract openai-compatible-api.md, edge-node-runtime-wire.md, edge-config-runtime-refresh.md 외부 OpenAI-compatible model group surface, provider tunnel, normalized run dispatch, provider config 계약
Spec openai-compatible-surface.md, provider-pool-config-refresh.md, edge-node-execution.md 현재 구현 surface와 runtime behavior 문서
Code packages/go/config, apps/edge/internal/openai, apps/edge/internal/service, apps/edge/internal/node, apps/node/internal/adapters/openai_compat, apps/node/internal/adapters/ollama, apps/node/internal/runtime, proto/iop/runtime.proto config validation, provider selection, OpenAI handler, Edge-Node wire, adapter implementation 기준
User Decision 현재 사용자 요청 Ollama는 model group에서 제외하지 않는다. 후보는 동일하게 두고 capacity/priority로 가중한다. model group request에는 response path selector를 두지 않는다. OpenAI-compatible 호출 방식을 지원하는 provider는 모두 passthrough 방식으로 처리하고, Ollama/CLI/native provider는 normalized로 처리한다. Seulgivibe Claude/OpenAI aliases는 passthrough provider에 포함한다. custom request fields는 provider-pool ingress에서 보존한다.

State Machine

상태 진입 조건 다음 상태 근거
ingress OpenAI-compatible Chat 또는 Responses request가 models[] catalog의 model group id를 사용한다 route-envelope-parsed 또는 invalid-request Edge OpenAI handler
route-envelope-parsed raw body는 보존하고 routing에 필요한 model, metadata, stream 등 최소 envelope를 읽었다 candidate-selection provider-pool route
invalid-request model group request가 metadata.iop_response_mode 또는 동등한 execution path selector를 포함하거나 필수 routing field가 없다 terminal error model group client surface contract
candidate-selection model group의 provider mapping과 connected node status가 있다 provider-selected 또는 no-capacity existing capacity/priority/health rules
no-capacity 사용 가능한 provider candidate가 없다 terminal error queue policy
provider-selected queue slot이 특정 provider id/node/adapter/served target에 할당되었다 execution-path-resolved selected provider의 OpenAI-compatible 지원 여부
execution-path-resolved selected provider가 OpenAI-compatible 호출 방식을 지원한다 passthrough-dispatch OpenAI-compatible provider
execution-path-resolved selected provider가 normalized-only다 normalized-dispatch Ollama/CLI/native provider
passthrough-dispatch raw request body를 model rewrite와 provider auth/header 정책만 적용해 Node tunnel로 보낸다 provider-response-relayed 또는 provider-error ProviderTunnelRequest
normalized-dispatch standard OpenAI-compatible request subset을 internal RunRequest로 변환해 selected adapter로 보낸다 normalized-response-built 또는 provider-error RunRequest/adapter Execute
provider-response-relayed provider tunnel frames가 caller response로 relay되고 sideband/log/metric observation이 기록된다 terminal success passthrough bridge
normalized-response-built normalized runtime events가 OpenAI-compatible response shape로 변환되고 sideband/log/metric observation이 기록된다 terminal success normalized response builder
provider-error provider HTTP/tunnel 또는 adapter execution이 실패한다 terminal error OpenAI-compatible error mapping

Interface Contract

  • 계약 원문: openai-compatible-api.md
  • 입력:
    • model: caller-facing model group id다. models[] catalog와 provider mapping이 source of truth다.
    • metadata.workspace, metadata.task_id 등 routing/operation metadata는 기존 OpenAI-compatible surface를 따른다.
    • metadata.iop_response_mode 또는 같은 의미의 execution path selector는 model group route에서 지원하지 않는다. 포함 시 silent fallback 없이 400 invalid_request_error로 거부한다.
    • unknown/Codex/provider-specific request fields는 provider-pool ingress에서 strict decode로 버리거나 거부하지 않는다.
    • nodes[].providers[].capacity, priority, enabled, health/status, model membership은 기존 provider selection 기준이다.
  • 실행 경로:
    • OpenAI-compatible 호출 방식을 지원하는 provider는 모두 passthrough 실행 경로를 사용한다.
    • OpenAI-compatible provider는 Node adapter가 ProviderTunnelAdapter interface를 구현해야 한다. 이 interface가 없으면 normalized fallback이 아니라 구현 결함 또는 unsupported 상태로 처리한다.
    • ollama, cli 및 OpenAI-compatible 호출 방식을 지원하지 않는 native provider는 normalized RunRequest 실행 경로를 사용한다.
    • provider type/label/선언된 지원 방식이 openai_compat, openai_api, vllm, vllm-mlx, lemonade, sglang, seulgivibe_claude, seulgivibe_openai 계열이면 OpenAI-compatible provider로 분류한다.
    • provider type/선언된 지원 방식이 ollama, cli이면 normalized-only provider로 분류한다.
    • Seulgivibe Claude/OpenAI provider는 현재 Seulgivibe Milestone에서 다루는 auth/catalog/Responses passthrough 구현을 유지하면서도, 이 classifier에서는 OpenAI-compatible passthrough provider에 포함된다.
    • selection에서 provider type만을 이유로 Ollama를 제외하지 않는다. 운영자는 작은 capacity/priority로 Ollama 동시성 한계를 표현한다.
  • 출력:
    • 표준 OpenAI-compatible client 요청에는 표준-compatible response를 반환하고 불필요한 IOP custom field/event를 섞지 않는다.
    • OpenAI-compatible provider 선택 시 provider HTTP status/header/body 또는 provider SSE를 최대한 보존하며, model rewrite와 문서화된 IOP extension-safe 지점만 예외다.
    • normalized provider 선택 시 runtime event를 OpenAI-compatible Chat/Responses response shape로 변환한다.
    • 모든 실행 경로는 내부 observation으로 selected provider id/type, adapter, served target, execution path, queue decision, usage 후보를 남긴다.
    • IOP-aware/custom request surface가 문서화된 extension-safe 지점을 사용하면 sideband/custom observation을 받을 수 있다. 표준-only request에는 응답 custom field를 만들지 않는다.
  • custom field 처리:
    • OpenAI-compatible provider가 선택되면 raw body의 unknown/Codex/provider-specific field는 model rewrite와 명시 변환 외에는 provider로 보존 전달한다.
    • normalized-only provider가 선택되면 standard OpenAI-compatible subset과 IOP가 아는 extension만 native adapter request로 변환한다. 변환할 수 없는 provider-specific required field는 dispatch 전 명시적 unsupported error로 끝내고, 단순 unknown field는 observation에 남기되 native provider request에 임의로 invent하지 않는다.
  • 금지:
    • model group 전체를 normalized로 낮춰 vLLM/vLLM-MLX/Lemonade/openweight cloud provider의 raw passthrough 경로를 잃지 않는다.
    • provider pool이라는 이유만으로 Ollama/CLI/native provider에 ProviderTunnelRequest를 보내지 않는다.
    • client가 metadata.iop_response_mode로 model group의 passthrough/normalized/transformed 경로를 고르게 하지 않는다.
    • provider selection을 두 번 수행해 queue slot과 실제 실행 provider가 달라지게 하지 않는다.

Acceptance Scenarios

ID Milestone Task Given When Then
S01 selection-first-path mixed model group에 vLLM provider와 Ollama provider가 있고 둘 다 healthy/capacity가 있다 provider-pool route를 실행한다 기존 capacity/priority 기준으로 provider를 한 번 선택하고, 같은 selected provider로 tunnel 또는 normalized 실행을 수행한다
S02 selection-first-path selected provider가 Ollama다 Chat Completions request를 처리한다 Edge가 ProviderTunnelRequest를 보내지 않고 normalized RunRequest로 Ollama adapter를 실행한다
S03 provider-path-classifier provider type/label/선언된 지원 방식이 vllm, vllm-mlx, lemonade, openai_compat, seulgivibe_claude, seulgivibe_openai 중 하나이거나 OpenAI-compatible 호출 방식을 지원한다 execution path를 resolve한다 passthrough path를 선택한다
S04 provider-path-classifier provider type/선언된 지원 방식이 ollama 또는 cli execution path를 resolve한다 normalized-only로 분류하고 model group 후보에서는 제외하지 않는다
S05 mixed-model-group Ollama-only model group config가 있다 OpenAI-compatible Chat request를 보낸다 provider-pool route가 정상 후보를 찾고 normalized OpenAI-compatible response를 반환한다
S06 no-client-response-mode model group request가 metadata.iop_response_mode를 포함한다 Edge handler가 route envelope를 parse한다 request는 400 invalid_request_error로 거부되고 provider dispatch가 발생하지 않는다
S07 custom-field-preservation Chat request에 Codex/provider-specific unknown field가 있고 selected provider가 OpenAI-compatible provider다 provider tunnel request body를 만든다 unknown field가 model rewrite 외에는 그대로 provider로 전달된다
S08 custom-field-preservation 같은 unknown field request에서 selected provider가 Ollama다 normalized request를 만든다 standard field는 Ollama request로 변환되고, 변환 불가능한 required field는 explicit unsupported error 또는 observation으로 처리된다
S09 sideband-observation 표준 OpenAI-compatible client가 model group을 호출한다 provider가 성공 응답을 반환한다 caller response에는 불필요한 IOP custom field가 없고, internal log/metric에는 selected provider와 execution path가 남는다
S10 contract-sync contract/spec 문서를 검토한다 Milestone 구현 diff가 준비된다 model group의 provider-derived execution path, selector 금지, custom field 보존 기준이 문서와 구현에 동일하게 반영되어 있다

Evidence Map

Scenario Required Evidence agent-task 연결 완료 Evidence 기대
S01 service queue/selection unit tests agent-task/m-model-group-mixed-provider-dispatch/... Roadmap Completionselection-first-pathgo test ./apps/edge/internal/service -count=1 결과
S02 Edge service/openai handler tests proving no tunnel for Ollama agent-task/m-model-group-mixed-provider-dispatch/... Roadmap Completionselection-first-path와 Ollama normalized dispatch assertion
S03 provider classifier tests for OpenAI-compatible aliases agent-task/m-model-group-mixed-provider-dispatch/... Roadmap Completionprovider-path-classifier, config/node/adapters test 결과
S04 provider classifier tests for Ollama/CLI agent-task/m-model-group-mixed-provider-dispatch/... Roadmap Completionprovider-path-classifier, normalized-only provider candidate assertion
S05 mixed and Ollama-only model group fixtures agent-task/m-model-group-mixed-provider-dispatch/... Roadmap Completionmixed-model-group, go test ./apps/edge/internal/openai -count=1, go test ./apps/edge/internal/service -count=1 결과
S06 handler rejection tests and contract/spec diff agent-task/m-model-group-mixed-provider-dispatch/... Roadmap Completionno-client-response-mode, 400 invalid_request_error assertion
S07 Chat raw body preservation tunnel test agent-task/m-model-group-mixed-provider-dispatch/... Roadmap Completioncustom-field-preservation, provider request body fixture
S08 normalized custom field policy test agent-task/m-model-group-mixed-provider-dispatch/... Roadmap Completioncustom-field-preservation, unsupported/observation assertion
S09 standard response and observation tests agent-task/m-model-group-mixed-provider-dispatch/... Roadmap Completionsideband-observation, response body/log/metric fixture
S10 contract/spec sync review agent-task/m-model-group-mixed-provider-dispatch/... Roadmap Completioncontract-sync, linked contract/spec paths and final test output

Cross-repo Dependencies

  • 없음

Drift Check

  • Milestone 기능 Task와 Acceptance Scenario가 일치한다.
  • Evidence Map이 code-review/complete.log에서 검증 가능하다.
  • agent-contract를 쓰는 경우 SDD에 계약 원문을 복제하지 않았다.
  • 사용자 리뷰가 필요한 항목은 USER_REVIEW.md에만 남겼다.

사용자 리뷰 이력

  • 없음

작업 컨텍스트

  • 표준선: Model group provider 후보는 provider type 때문에 제외하지 않고 기존 capacity/priority/health/model membership으로 선택한다.
  • 표준선: 선택된 provider가 OpenAI-compatible 호출 방식을 지원하면 passthrough path를 사용하고, Ollama/CLI/native provider면 normalized path를 사용한다. Seulgivibe Claude/OpenAI aliases는 passthrough provider에 포함한다.
  • 표준선: OpenAI-compatible provider에서 tunnel/passthrough 구현이 누락된 경우 normalized fallback으로 처리하지 않는다.
  • 표준선: model group client request는 provider execution path를 지정하지 않는다. metadata.iop_response_mode는 model group route에서 제거/거부 대상이다.
  • 표준선: Chat provider-pool ingress는 Responses provider-pool ingress처럼 raw body와 route envelope를 분리해 custom/provider-specific field를 보존할 준비를 한다.
  • 후속 SDD: 없음