diff --git a/agent-roadmap/phase/operational-observability-provider-management/PHASE.md b/agent-roadmap/phase/operational-observability-provider-management/PHASE.md index 48871d6..3ff976e 100644 --- a/agent-roadmap/phase/operational-observability-provider-management/PHASE.md +++ b/agent-roadmap/phase/operational-observability-provider-management/PHASE.md @@ -46,6 +46,10 @@ Phase를 가로지르는 실제 다음 작업 선택은 [전역 마일스톤 실 - 경로: [provider-resource-admission-ownership-alignment](../../archive/phase/operational-observability-provider-management/milestones/provider-resource-admission-ownership-alignment.md) - 요약: 공유 provider의 capacity·long-context lease, 공통 queue policy, Node reconnect/offline fencing과 Control Plane snapshot을 정렬하고 local two-alias capacity-1 smoke까지 검증했다. +- [계획] Provider 기준 Usage Attribution Hot Path + - 경로: [provider-usage-attribution-hot-path](milestones/provider-usage-attribution-hot-path.md) + - 요약: OpenAI-compatible token usage를 실제 호출 provider·served model·실행 시도에 귀속하고, 명시적으로 같은 논리 모델로 승인된 group에서만 가상 model group 집계를 허용한다. + - [계획] Provider 부하 메트릭과 Live Queue Dashboard - 경로: [provider-load-metrics-queue-dashboard](milestones/provider-load-metrics-queue-dashboard.md) - 요약: provider별 capacity 사용률, in-flight, queue 적체, queue wait를 Prometheus time series와 Grafana dashboard로 노출해 시간대별 live 부하 분석을 가능하게 한다. diff --git a/agent-roadmap/phase/operational-observability-provider-management/milestones/provider-usage-attribution-hot-path.md b/agent-roadmap/phase/operational-observability-provider-management/milestones/provider-usage-attribution-hot-path.md new file mode 100644 index 0000000..fbe987e --- /dev/null +++ b/agent-roadmap/phase/operational-observability-provider-management/milestones/provider-usage-attribution-hot-path.md @@ -0,0 +1,80 @@ +# Milestone: Provider 기준 Usage Attribution Hot Path + +## 위치 + +- Roadmap: [ROADMAP.md](../../../ROADMAP.md) +- Phase: [PHASE.md](../PHASE.md) + +## 목표 + +OpenAI-compatible hot path의 provider-reported token usage를 가상 요청 모델명이 아니라 실제 호출된 provider와 served model에 귀속한다. 가상 `model_group` 집계는 명시적으로 동일 논리 모델로 승인된 group에서만 허용하고, 단독·하이브리드·재시도/fallback 경로는 각 실제 호출 시도의 provider usage를 분리해 기록한다. + +## 상태 + +[계획] + +## 승격 조건 + +- 없음 + +## 구현 잠금 + +- 상태: 해제 +- SDD: 필요 +- SDD 문서: [SDD.md](../../../sdd/operational-observability-provider-management/provider-usage-attribution-hot-path/SDD.md) +- SDD 사유: OpenAI usage metric의 attribution contract, direct route provider identity, provider-pool retry/fallback의 시도별 관측과 Grafana query 기준을 함께 바꾼다. +- 잠금 해제 조건: + - [x] SDD 잠금이 해제되어 있다. + - [x] SDD 사용자 리뷰가 없거나 승인/해결되었다. + - [x] Acceptance Scenario가 Milestone 기능 Task와 연결되어 있다. + - [x] Evidence Map이 완료 시 `Roadmap Completion`과 최종 검증 evidence로 검증 가능하게 연결되어 있다. +- 결정 필요: 없음 + +## 범위 + +- provider-reported input/output/reasoning/cached-input token을 실제 `provider_id`와 served model에 귀속하는 OpenAI metric attribution contract +- `models[].usage_attribution=model_group`으로 명시 승인된 동일 논리 모델 group만 가상 model-group rollup을 허용하고, 기본값 `provider`를 적용하는 config/validation 기준 +- direct/legacy route와 provider-pool hybrid route 모두에서 실제 provider identity를 dispatch 결과로 보존하는 경로 +- retry/fallback을 포함한 각 실제 provider 호출 시도별 usage emission 및 저-cardinality label guard +- Grafana usage query와 운영 가이드의 provider 기준 migration + +## 기능 + +### Epic: [attribution] Actual Provider Usage Attribution + +단일·하이브리드 실행에서 token 사용량을 실제 provider 호출에 정확히 귀속하는 hot-path capability를 묶는다. + +- [ ] [group-policy] `models[].usage_attribution=model_group`으로 명시 승인된 동일 논리 모델 group만 가상 rollup query를 허용하고, 기본값 및 그 밖의 route에는 provider 기준 attribution을 강제한다. 검증: group·direct·hybrid config/route test에서 attribution basis가 기대값과 일치하고 별도 group counter가 중복 emit되지 않는다. +- [ ] [dispatch-binding] direct/legacy의 `openai.model_routes[].provider_id`와 top-level fallback `openai.provider_id`, provider-pool의 normalized/tunnel dispatch가 실제 `provider_id`, served model, node identity를 metric emitter까지 전달한다. 검증: adapter 이름만으로 provider를 대체하지 않고 각 dispatch binding을 검증한다. +- [ ] [attempt-usage] hybrid selection, retry, fallback에서 provider-reported token 및 reasoning observation usage를 실제 호출 시도별 provider binding으로 emit한다. 검증: provider가 바뀌는 deterministic test에서 token series가 각 provider에 분리되어 증가하고 request terminal counter는 한 번만 증가한다. + +### Epic: [operations] Usage Metric Migration + +provider 기준 운영 조회를 기존 OpenAI usage metric과 Grafana 가이드에 정착시킨다. + +- [ ] [metric-contract] metric label allowlist와 OpenAI-compatible 관측 계약을 provider attribution 기준으로 갱신하고 기존 `model_group`은 `route_model` trace와 승인된 rollup query로 migration한다. 검증: secret/high-cardinality label guard와 metric contract test가 통과한다. +- [ ] [grafana-migration] Grafana query와 usage 운영 가이드를 provider 기준 집계 및 승인된 model-group rollup 기준으로 갱신한다. 검증: 대표 provider·group query가 metric label schema와 일치한다. + +## 완료 리뷰 + +- 상태: 없음 +- 요청일: 없음 +- 완료 근거: 계획 Milestone이며 기능 Task가 아직 충족되지 않았다. +- 검토 항목: 기능 Task의 deterministic attribution 검증, Grafana query migration, SDD Evidence Map 충족과 구현 잠금 해제를 함께 확인한다. +- 리뷰 코멘트: 없음 + +## 범위 제외 + +- request ledger storage, 장기 retention, export API, billing/chargeback +- provider routing 알고리즘, capacity/queue timeout 정책 변경 +- provider가 보고하지 않은 token의 추정 또는 billing-grade 복원 +- Control Plane/Flutter client의 신규 usage 화면 + +## 작업 컨텍스트 + +- 관련 경로: `apps/edge/internal/openai`, `apps/edge/internal/service`, `packages/go/config`, `configs/edge.yaml`, `docs/openai-usage-grafana.md`, `agent-contract/outer/openai-compatible-api.md` +- 표준선(선택): canonical token attribution은 실제 dispatch provider binding이며, `model_group`은 `models[].usage_attribution=model_group`으로 명시 승인된 동일 논리 모델의 query-time rollup에만 사용한다. 기본 attribution은 `provider`다. +- 표준선(선택): provider-pool 재시도/fallback은 client 응답이 하나여도 provider-reported usage가 있는 각 실제 호출 시도를 독립 provider series로 기록한다. +- 선행 작업: [Provider Resource Admission Ownership 정합화](../../../../archive/phase/operational-observability-provider-management/milestones/provider-resource-admission-ownership-alignment.md) +- 후속 작업: [Provider 부하 메트릭과 Live Queue Dashboard](provider-load-metrics-queue-dashboard.md), [요청 실행 로그와 Usage Ledger 기반](request-execution-log-usage-ledger-foundation.md) +- 확인 필요: 없음 diff --git a/agent-roadmap/sdd/operational-observability-provider-management/provider-usage-attribution-hot-path/SDD.md b/agent-roadmap/sdd/operational-observability-provider-management/provider-usage-attribution-hot-path/SDD.md new file mode 100644 index 0000000..3e67288 --- /dev/null +++ b/agent-roadmap/sdd/operational-observability-provider-management/provider-usage-attribution-hot-path/SDD.md @@ -0,0 +1,105 @@ +# SDD: Provider 기준 Usage Attribution Hot Path + +## 위치 + +- Milestone: [Milestone 문서](../../../phase/operational-observability-provider-management/milestones/provider-usage-attribution-hot-path.md) +- Phase: [PHASE.md](../../../phase/operational-observability-provider-management/PHASE.md) + +## 상태 + +[승인됨] + +## SDD 잠금 + +- 상태: 해제 +- 사용자 리뷰: 없음 +- 잠금 항목: 없음 + +## 문제 / 비목표 + +- 문제: 현재 OpenAI-compatible token counter는 provider-reported token 수를 받지만, 요청의 가상 `model_group`으로 귀속한다. 단독·하이브리드·재시도/fallback 실행에서는 실제 provider 사용량과 집계 series가 달라질 수 있다. +- 비목표: + - request ledger 저장, 장기 보관, export 또는 billing/chargeback 구현 + - provider routing, queue admission, capacity 정책 변경 + - provider가 보고하지 않은 token 수의 billing-grade 추정 + +## Source of Truth + +| 영역 | 기준 | 메모 | +|------|------|------| +| Roadmap | [Milestone 문서](../../../phase/operational-observability-provider-management/milestones/provider-usage-attribution-hot-path.md) | 완료 Task와 검증 기준 | +| Code | `apps/edge/internal/openai/usage_metrics.go` | OpenAI request/token metric label과 emitter source of truth | +| Code | `apps/edge/internal/service/run_types.go` | actual dispatch의 provider/model binding source of truth | +| Contract | [OpenAI-compatible API 계약](../../../../agent-contract/outer/openai-compatible-api.md) | external model route와 OpenAI usage 관측 계약 | +| Config | `packages/go/config` 및 `configs/edge.yaml` | `models[].usage_attribution`, direct route `provider_id`와 fallback provider identity 기준 | +| User Decision | 현재 사용자 요청 | 동일 논리 model group만 virtual rollup, 그 밖의 실제 provider별·시도별 귀속을 사용한다. | + +## State Machine + +| 상태 | 진입 조건 | 다음 상태 | 근거 | +|------|-----------|-----------|------| +| route resolved | 요청 model의 group/direct route와 `usage_attribution`이 확정됨 | provider selected | OpenAI route resolution/config validation | +| provider selected | provider-pool candidate 또는 config가 검증한 direct provider binding이 확정됨 | provider usage observed / dispatch failed | `RunDispatch` 또는 tunnel dispatch binding | +| provider usage observed | 해당 실제 provider 호출이 token usage를 보고함 | emitted | provider binding별 metric emission | +| emitted | token series가 provider binding으로 기록됨 | provider selected / terminal | retry/fallback이면 새 실제 provider selection, 아니면 terminal | +| terminal | 모든 호출 시도가 종료됨 | 없음 | request terminal status metric | + +## Interface Contract + +- 계약 원문: [OpenAI-compatible API 계약](../../../../agent-contract/outer/openai-compatible-api.md) +- 입력: + - `route_model`: 외부 request `model` alias; routing trace용 값이며 canonical usage key가 아니다. + - `usage_attribution`: `models[].usage_attribution`의 `model_group` 또는 `provider`; 기본값은 `provider`이며 `model_group`은 operator가 동일 논리 모델이라고 승인할 때만 설정한다. + - `provider_id`: 실제 dispatch한 globally unique provider resource identity + - `served_model`: 해당 provider가 실제 호출한 model target + - `usage`: 해당 provider 호출이 보고한 input/output/reasoning/cached-input token 수 + - direct binding: `openai.model_routes[].provider_id` 또는 top-level fallback `openai.provider_id`; 둘 다 없으면 provider-attribution direct route config를 거부한다. +- 출력: + - canonical token/reasoning series: 실제 `provider_id`·`served_model`에 귀속된 provider-reported usage를 호출 시도마다 한 번 기록한다. + - 승인된 group rollup: `usage_attribution=model_group`인 series만 `route_model` 기준으로 PromQL에서 합산한다. 별도 group counter를 emit하지 않아 이중 집계를 막는다. + - request terminal counter: HTTP 요청당 한 번만 기록하며, provider별 token series의 호출 횟수 대용으로 사용하지 않는다. +- 금지: + - direct route의 provider identity를 `adapter` 이름만으로 대체하지 않는다. + - hybrid/retry/fallback 요청의 usage를 최초 또는 외부 request model에 단일 귀속하지 않는다. + - virtual model group용 token counter를 provider token counter와 별도로 emit해 같은 usage를 이중 집계하지 않는다. + - raw token, request/session id, prompt/response를 metric label에 넣지 않는다. + +## Acceptance Scenarios + +| ID | Milestone Task | Given | When | Then | +|----|----------------|-------|------|------| +| S01 | `group-policy` | `usage_attribution=model_group`으로 승인된 group과 기본 provider route | provider-reported usage가 수신됨 | 승인된 group만 query-time rollup이 가능하고, 모든 usage는 actual provider series 하나로 시작한다. | +| S02 | `dispatch-binding` | direct/legacy 또는 provider-pool route | dispatch가 성공함 | metric emitter가 adapter 대체값이 아닌 config/dispatch가 검증한 actual provider id와 served model을 받는다. | +| S03 | `attempt-usage` | hybrid request가 retry/fallback으로 다른 provider를 호출함 | 각 provider가 usage를 보고함 | 각 usage가 해당 실제 provider series에 한 번씩 기록되고 HTTP request counter는 한 번만 증가한다. | +| S04 | `metric-contract` | metric scrape와 OpenAI contract | label schema를 검증함 | secret/high-cardinality label 없이 provider attribution contract가 유지된다. | +| S05 | `grafana-migration` | provider·승인된 group series가 존재함 | 대표 Grafana query를 실행함 | provider 기준 집계와 허용된 group rollup이 모두 정확히 조회된다. | + +## Evidence Map + +| Scenario | Required Evidence | `agent-task` 연결 | 완료 Evidence 기대 | +|----------|-------------------|------------------|---------------------------| +| S01 | config/route table test와 provider series/group rollup metric delta assertion | `agent-task/m-provider-usage-attribution-hot-path/...` | `group-policy` Task id, test command와 PASS output | +| S02 | direct config provider ref, pool normalized·tunnel dispatch binding test | `agent-task/m-provider-usage-attribution-hot-path/...` | `dispatch-binding` Task id, provider id/served model assertion | +| S03 | deterministic retry/fallback provider switch test와 request counter assertion | `agent-task/m-provider-usage-attribution-hot-path/...` | `attempt-usage` Task id, provider별 token series delta와 request counter 1회 | +| S04 | `go test ./apps/edge/internal/openai`와 metric label guard | `agent-task/m-provider-usage-attribution-hot-path/...` | `metric-contract` Task id, command output | +| S05 | Grafana guide/query schema check | `agent-task/m-provider-usage-attribution-hot-path/...` | `grafana-migration` Task id, query evidence | + +## Cross-repo Dependencies + +- 없음 + +## Drift Check + +- [x] Milestone 기능 Task와 Acceptance Scenario가 일치한다. +- [x] Evidence Map이 code-review/complete.log에서 검증 가능하다. +- [x] agent-contract를 쓰는 경우 SDD에 계약 원문을 복제하지 않았다. +- [x] 사용자 리뷰가 필요한 항목은 `USER_REVIEW.md`에만 남겼다. + +## 사용자 리뷰 이력 + +- 없음 + +## 작업 컨텍스트 + +- 표준선: `models[].usage_attribution`의 기본값은 `provider`다. 동일 논리 model group이라고 operator가 명시 승인한 경우에만 `model_group`을 설정하고, canonical usage attribution은 항상 actual provider binding에서 출발한다. +- 후속 SDD: 없음