13 KiB
13 KiB
| spec_doc_type | spec_id | status | source_evidence | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| spec | input/openai-compatible-surface | 부분 |
|
스펙: OpenAI-Compatible 입력 표면
목적
Edge가 OpenAI-compatible HTTP 요청을 받아 내부 adapter + target 실행으로 넘기는 현재 동작을 설명한다.
기능 목록
| 기능 | 설명 |
|---|---|
| OpenAI-compatible HTTP server | openai.enabled=true이면 Edge input manager가 /healthz, /v1/models, /v1/chat/completions, /v1/responses, /api/ route를 제공한다. |
| bearer auth | openai.bearer_token이 있으면 matching bearer authorization header를 요구한다. |
| principal token auth | openai.principal_tokens[]가 설정된 경우 raw token의 SHA-256 hash를 token_hash_sha256과 매칭하고, 매칭 시 iop_principal_ref, iop_principal_alias, iop_token_ref, iop_principal_source metadata를 채운다. |
| multi-token principal | 같은 principal_ref에 여러 token_ref를 연결할 수 있으며, 사용량 metric은 사용자 합산과 token/app별 breakdown을 모두 가능하게 한다. |
| model catalog | /v1/models는 provider-pool models[], legacy openai.model_routes[], openai.models 또는 openai.target 순서로 노출 모델을 만든다. |
| model dispatch | request model은 provider-pool catalog, legacy model route, single target fallback 순서로 해석된다. |
| provider-pool handoff | provider-pool catalog에 model이 있으면 service 요청은 ProviderPool=true로 전달되고 adapter/target은 provider selection 이후 확정된다. |
| legacy route 변환 | legacy route는 외부 model을 route entry의 adapter, target, node, session_id, queue policy로 변환한다. |
| metadata/workspace 처리 | metadata.workspace는 RunRequest.workspace로 분리하고, 일반 metadata는 최대 16개 string key/value만 허용한다. |
| Chat Completions | /v1/chat/completions는 non-streaming과 streaming SSE를 지원한다. |
| Chat Completions response mode | OpenAI-compatible provider route는 metadata.iop_response_mode 생략 시 passthrough로 동작하고, 명시적으로 passthrough+sideband 또는 transformed를 선택할 수 있다. |
| provider raw passthrough | passthrough는 provider status/header/body bytes를 기존 Edge-Node tunnel로 relay하고 pure response body에 IOP sideband를 섞지 않는다. |
| sideband extension | Chat Completions passthrough+sideband는 provider body와 IOP route/usage/assembled observation을 명시적 extension stream/envelope로 함께 노출한다. Responses passthrough+sideband는 응답 metadata 또는 event: iop.sideband를 확장 지점으로 사용한다. 둘 다 provider-original byte identity로 표시하지 않는다. |
| OpenAI usage metering | Edge는 OpenAI-compatible request terminal status와 provider-reported input, output, reasoning, cached_input token usage를 Prometheus counter로 집계한다. |
| reasoning observation metric | provider가 reasoning token을 보고하지 않고 reasoning text만 관측되면 token 추정 없이 관측 횟수와 character count 보조 metric만 emit한다. |
| Grafana usage surface | 1차 조회 표면은 Prometheus/Grafana query guide이며 daily/monthly rollup, usage origin breakdown, operator-managed cloud price baseline, cloud-equivalent cost, avoided-cost ROI 기준을 문서로 제공한다. Control Plane/Client dashboard와 request-level ledger는 후속 범위다. |
| Responses API | normalized(non-provider) /v1/responses는 string input의 non-streaming 요청만 지원한다. provider model group route는 /v1/responses를 raw passthrough로 provider POST /v1/responses에 전달한다. |
| Responses provider passthrough | provider route의 /v1/responses는 model만 served target으로 rewrite하고 unknown/Codex field를 보존하며 stream:true를 raw SSE로 relay한다. provider auth forwarding을 적용하고 response model echo rewrite는 하지 않는다. 명시적 passthrough+sideband는 non-stream 응답의 top-level metadata 또는 streaming event: iop.sideband를 확장 지점으로 사용한다. usage metric은 endpoint=responses, response_mode=passthrough 또는 passthrough+sideband, model_group=request alias로 집계한다. |
| strict output | strict output이 켜져 있으면 XML completion contract 기반 instruction 또는 prompt prefix를 추가할 수 있다. |
| tool call 처리 | Chat Completions tools는 provider native metadata 복원 또는 text tool-call synthesis/validation 경로를 사용한다. |
| cancel 전파 | HTTP caller timeout/cancel이 cancel-worthy error이면 Node CancelRun으로 전파한다. |
범위
- 포함: OpenAI-compatible HTTP auth, request validation, route resolution, metadata/workspace 처리, chat/responses 변환, provider-pool dispatch handoff, tool/reasoning/strict output 처리.
- 제외: OpenAI 원문 API 전체 호환, legacy
/v1/completions, A2A JSON-RPC, Node adapter별 provider HTTP 세부, Control Plane 운영 API.
주요 흐름
sequenceDiagram
participant Caller
participant OpenAI as OpenAI handler
participant Service as Edge service
participant Runtime as Edge-Node runtime
Caller->>OpenAI: chat/responses request(model)
OpenAI->>OpenAI: auth, metadata, route 검증
alt provider route + passthrough mode
OpenAI->>Service: SubmitProviderTunnel(ProviderPool/direct)
Service->>Runtime: ProviderTunnelRequest
Runtime-->>Service: ProviderTunnelFrame stream
Service-->>OpenAI: tunnel frames
OpenAI-->>Caller: provider-original bytes or sideband extension
else transformed/normalized path
OpenAI->>Service: SubmitRun(adapter/target or ProviderPool)
Service->>Runtime: RunRequest
Runtime-->>Service: RunEvent stream
Service-->>OpenAI: run stream
OpenAI-->>Caller: OpenAI-compatible response or SSE
end
계약
iop.openai-compatible-api:agent-contract/outer/openai-compatible-api.md- 내부 실행 wire:
agent-contract/inner/edge-node-runtime-wire.md - config/provider pool:
agent-contract/inner/edge-config-runtime-refresh.md
설정/데이터/이벤트
configs/edge.yaml의openai섹션이 listener, bearer token, legacy adapter/target, model routes, strict output을 제공한다.- top-level
models[]가 있으면 OpenAI model list와 provider-pool dispatch에서 legacy route보다 우선한다. - OpenAI request의
metadata.workspace는 absolute path가 필요한 route에서만 필수 검증된다. - OpenAI Chat Completions와 provider route Responses request의
metadata.iop_response_mode는passthrough,passthrough+sideband,transformed만 허용한다. provider route에서 생략하면passthrough다. Responses provider route의transformed는 지원하지 않는다. - run metadata에는
openai_model,openai_stream,strict_output,estimated_input_tokens,context_class가 들어갈 수 있다. - provider tunnel metadata에는 response mode와 routing context가 들어가고, sideband mode는 route/usage/assembled observation을 확장 surface로 만든다.
- Node complete event metadata의
openai_tool_calls와openai_text_tool_fallback은 response tool call 복원에 쓰인다. - usage metric은
iop_openai_requests_total,iop_openai_usage_tokens_total,iop_openai_reasoning_observed_total,iop_openai_reasoning_chars_total로 emit된다. - usage label은
edge_id,principal_ref,principal_alias,token_ref,model_group,endpoint,response_mode,status,usage_source,token_type처럼 낮은 cardinality 값만 사용한다. principal_ref는 사용자/테넌트 참조값이고token_ref는 앱/통합/용도별 token 참조값이다. 같은 principal에 여러 token이 있으면principal_ref기준 합산과token_ref기준 분해를 함께 사용할 수 있다.request_id,session_id, raw bearer token, provider token, raw prompt/response는 metric label에 넣지 않는다.- provider body usage와 provider tunnel
USAGEframe이 모두 있으면 body input/output을 우선하고 proto-only reasoning/cached input을 보조로 병합해 중복 집계를 피한다.
검증
go test ./apps/edge/internal/openaigo test ./apps/edge/internal/servicego test ./apps/edge/internal/openai -run 'Sideband|UsageMetrics|ToolValidation|Dispatch|Reasoning|Retry'rg --fixed-strings "cloud_equivalent_cost" docs/openai-usage-grafana.mdmake test-openai-ollama- provider별 실제 runtime smoke는 환경별 agent-test/dev 또는 dev-corp profile을 따른다.
한계와 주의사항
- normalized(non-provider)
/v1/responses는 non-streaming string input만 지원한다. provider model group route의/v1/responses는 raw passthrough로 streaming과 Codex/unknown field를 그대로 provider에 전달한다. /v1/completions는 제공하지 않는다.- OpenAI-compatible request에 provider/Ollama 전용 root field를 추가하지 않는다.
- workspace는 prompt 본문에 섞지 않고 metadata에서 분리한다.
- pure
passthroughbody는 provider-original byte stream이며 IOP sideband나 transformed label을 포함하지 않는다. passthrough+sideband와transformed는 provider-original byte identity로 취급하지 않는다.- Responses provider route의
passthrough+sideband는 Chat Completions sideband envelope를 쓰지 않는다. non-streaming JSON object 응답은metadataobject를 병합하고, streaming 응답은event: iop.sideband를 끼운다. - text tool-call synthesis는 요청
tools[]schema를 기준으로만 수행한다. 자연어 추론으로 tool call을 만들지 않는다. - private token이나 endpoint 원문은 tracked spec/docs에 남기지 않는다.
metadata.user는 identity source가 아니며 사용되지 않는다.- caller가
metadata.iop_principal_*를 보내도 authenticated context 값이 overwrite한다. openai.principal_tokens[]변경은 restart-required로 분류된다.- principal token auth가 실패하면 legacy
openai.bearer_token이 unmapped fallback으로 동작한다. - provider가 별도 reasoning token을 보고하지 않으면 reasoning text를 token으로 추정하지 않는다.
- Grafana guide는 metric 조회와 operator-managed price baseline 예시이며 live cloud pricing, billing, chargeback, long-term ledger, 사용자별 제한 enforcement의 source of truth가 아니다.
변경 기록
- 2026-07-07: 현재 코드와 OpenAI-compatible 계약 기준으로 bootstrap spec 작성.
- 2026-07-07: 기능 목록 중심으로 축소하고 주요 흐름을 Mermaid sequence diagram으로 정리.
- 2026-07-08: Chat Completions provider raw tunnel, response mode, sideband/transformed semantics를 현재 코드와 계약 기준으로 반영.
- 2026-07-10: principal token 기반 usage metering, Prometheus metric, Grafana query guide, reasoning/cached token breakdown을 Milestone completion evidence 기준으로 반영.
- 2026-07-10: 일별 Usage 비용/ROI 리포트 MVP 종료 검토에서 daily/monthly rollup, usage origin breakdown, cloud-equivalent cost, avoided-cost ROI 문서 표면을 반영.
- 2026-07-11: provider model group
/v1/responsesraw passthrough 동작(모델 rewrite, unknown/Codex field 보존, streaming relay, provider auth forwarding)과 endpoint=responsesusage metric label을 현재 코드 기준으로 반영. - 2026-07-11: Responses provider route의 명시적
passthrough+sideband동작을 반영. non-stream은 응답metadata, stream은event: iop.sideband를 확장 지점으로 사용한다.