iop/docs/architecture.md
toki f285db2310 docs: add Domain Agent concept and OTO bootstrap direction
- Add Domain Agent section to README (specialized build/deploy agent)
- Update architecture diagram with OTO Agent under Edge Group
- Add Edge bootstrap/enrollment surface for domain agents
- Document OTO agent bootstrap flow (Jenkins-like node connection UX)
- Add deploy-dev.md section for OTO Agent bootstrap direction
- Support HTTP local/insecure mode with token/pinning/verification
2026-05-21 08:49:17 +09:00

10 KiB

IOP Architecture

개요

IOP(Inference Operations Platform)는 모델 서빙과 CLI Agent/Automation 실행을 함께 다루는 실행 오케스트레이션 플랫폼을 지향한다. 단순한 OpenAI-compatible proxy나 모델 라우터가 아니라, Control Plane - Edge - Node 계층으로 로컬 실행 그룹을 관리하는 구조를 목표로 한다.

현재 구현은 Edge-Node 실행 스켈레톤을 검증하는 단계다. Control Plane과 worker는 placeholder이며, 세부 계약은 후속 작업에서 정리한다.

계층 구조

Control Plane
├─ Edge Group A
│  ├─ Node 1
│  │  ├─ adapter: cli
│  │  └─ adapter: ollama
│  ├─ Node 2
│  │  └─ adapter: vllm
│  └─ OTO Agent
│     └─ domain: build/deploy
└─ Edge Group B
   └─ Node 3
      └─ adapter: cli

Control Plane은 Node에 직접 연결하지 않는다. Control Plane은 Edge 연결을 관리하고, Edge 상태를 조회하고, Edge 설정을 조정하고, Edge에 명령을 전달하는 중앙 관리 계층이다.

Edge는 여러 Node를 묶는 실행 그룹 컨트롤러다. Edge는 Node registry, adapter/profile configuration, routing, stream relay, session handling, event aggregation을 담당한다.

Node는 실제 실행자다. Node는 Edge에 연결되어 adapter execution을 수행하고, RuntimeEvent를 Edge로 돌려준다. 연결 생명주기와 이후 제어/상태성 이벤트는 RunEvent와 분리된 EdgeNodeEvent envelope로 다룬다.

Edge는 Node만 관리하는 컨트롤러로 고정하지 않는다. OTO처럼 독립 바이너리와 독립 실행 도메인을 가진 도구는 specialized domain agent로 Edge에 직접 연결할 수 있다. 이 경우 OTO agent는 iop-node의 하위 실행물이 아니라 Edge가 별도 agent type으로 등록하고 제어하는 build/deploy 실행자다.

현재 Edge-Node 흐름

현재 검증 중인 기본 흐름은 다음과 같다.

Edge
└─ accepts Node connection
   └─ validates token
      └─ sends NodeConfigPayload
         └─ relays RunRequest / NodeCommandRequest

Node
└─ receives adapter/runtime config
   └─ builds adapter registry
      └─ resolves adapter + target
         └─ executes adapter
            └─ emits RuntimeEvent / EdgeNodeEvent

OTO Agent
└─ installed by Edge bootstrap command
   └─ registers as build/deploy domain agent
      └─ receives run/cancel/status/capability messages
         └─ executes YAML pipeline
            └─ emits step/log/artifact/result events

현재 실행 이력은 Node의 local SQLite store에서 검증 중이다. Edge 단위 이력 집계와 로컬 실행 그룹 상태 소유권은 로드맵에 따라 정리한다.

edge-local ops console의 / 명령은 ops console의 수동 테스트 표면이다. ops console은 edge/internal/service를 호출하는 얇은 어댑터로 유지하고, 이후 HTTP/API 표면(central/remote management surface)도 같은 service와 edge/internal/events bus를 재사용한다.

ops console과 HTTP/API를 구분한다: ops console은 edge-local diagnostic surface이고, HTTP/API는 central/remote management surface다.

내부 실행 모델

내부 실행은 adapter + target으로 표현한다.

  • adapter: 실행 방식. 예: mock, ollama, vllm, cli
  • target: adapter 안의 실행 대상. 예: 모델 이름, CLI profile, agent/toolchain
  • execution: 특정 adapter와 target으로 수행되는 단일 실행

외부 OpenAI-compatible API에서는 호환성을 위해 model 필드가 남을 수 있다. 그러나 내부 실행 계약에서는 target을 우선한다.

외부 API 표면

Edge의 외부 입력 표면은 두 방식을 병행한다.

  • OpenAI-compatible HTTP API: 외부 모델 클라이언트, Cline류 도구, 단순 chat completion/inference 호환을 위한 입력이다. 이 경계에서는 model을 받을 수 있지만 Edge 내부에서는 adapter + target으로 변환한다.
  • A2A JSON-RPC HTTP API: NomadCode Core나 외부 agent가 작업을 위임하고 Task 상태, artifact, cancel/polling을 공유해야 할 때 사용하는 agent delegation 입력이다. 이 경계도 Edge 내부에서는 adapter + target으로 변환한다.

두 입력 방식은 Edge inbound/input surface로 함께 관리하고, 내부 실행은 기존 RunRequest/RunEvent 흐름으로 수렴시킨다.

IOP native protocol은 Control Plane, Portal, 운영 CLI, 고급 자동화 클라이언트를 위한 IOP 고유 wire protocol이다. 기존 protobuf-socket 흐름을 기준으로 RunRequest, RunEvent, NodeCommandRequest, EdgeNodeEvent 계열 계약을 확장한다. OpenAI-compatible API와 A2A API는 외부 호환 입력으로 유지하지만, node 선택, logical session, background run, terminate-session, capabilities/status/session/transport command, node lifecycle event 같은 운영 기능을 억지로 model이나 vendor extension에 싣지 않는다. 이런 기능은 IOP native protocol에서 명시적인 필드와 이벤트로 다룬다.

apps/node 내부 구조

Hexagonal Architecture

         ┌───────────────────────────────┐
         │           node.Node           │  application core
         │                               │
  TCP    │  transport.Handler interface  │
─────────►  OnRunRequest()               │
  edge   │  OnCancel()                   │
         │  OnCommandRequest()           │
         └───────┬───────────────────────┘
                 │
          router.Resolve()     -> ExecutionSpec
                 │
          adapter.Execute()    -> RuntimeEvent stream
                 │
          store.CompleteRun()  -> SQLite

어댑터 패턴

type Adapter interface {
    Name() string
    Capabilities(ctx) (Capabilities, error)
    Execute(ctx, spec ExecutionSpec, sink EventSink) error
}

새 어댑터를 추가할 때는 runtime.Adapter를 구현하고 registry에 등록한다. CLI Agent, 모델 런타임, 도구 실행은 모두 같은 adapter execution 경로로 다루는 방향을 유지한다.

통신 방향

  • Edge-Node 내부 통신은 TCP + protobuf 기반 소켓 흐름을 우선한다.
  • Node는 Edge에 연결한다.
  • OTO 같은 domain agent도 Edge에 직접 outbound 연결한다.
  • Control Plane은 향후 Edge와 소켓 기반 연결을 맺는다.
  • Control Plane이 Node에 직접 연결하거나 매 요청마다 Node를 직접 스케줄링하는 구조는 목표가 아니다.
  • OTO agent는 Control Plane이나 iop-node에 직접 종속되지 않고 Edge의 agent registry와 bootstrap/enrollment 계약을 따른다.
  • Portal-Control Plane, Control Plane-Edge, Edge-Node의 장기 통신 기준은 IOP Wire Protocol(protobuf-socket)이다. 브라우저가 직접 TCP를 사용할 수 없는 구간은 Web Portal이 직접 wire client가 되기보다 Control Plane의 server-side bridge를 통해 연결한다.
  • OpenAI-compatible HTTP API와 A2A JSON-RPC HTTP API는 Edge 외부 입력 표면으로 유지하며, Control Plane 운영 제어 프로토콜의 기본값으로 삼지 않는다.

배포 철학

Control Plane과 Web은 중앙 운영면으로 묶어 compose 기반 서비스로 배포한다. dev 필드 테스트 compose에는 Control Plane DB와 Redis 후보를 함께 포함해 이후 schema, audit, event, queue 작업을 같은 배포 단위 안에서 진행한다.

Edge와 Node는 Docker 이미지로 만들지 않고 호스트 단일 바이너리로 배포한다. Jenkins는 Edge/Node 바이너리만 빌드하고, 각 호스트는 배포된 바이너리의 setup 명령을 통해 systemd 실행 환경을 준비한다. OTO는 별도 프로젝트의 단일 바이너리 build/deploy agent로 두고, 장기적으로는 Edge가 OTO agent 생성과 bootstrap command 발급을 담당한다.

Edge bootstrap UX는 Jenkins node 연결 방식과 유사하게 둔다. Edge에서 agent를 먼저 만들고 one-time token이 포함된 bootstrap command를 발급하면, 대상 머신이 이 command를 실행해 agent 바이너리 설치, 설정 생성, service 등록, Edge 등록을 완료한다. 폐쇄망과 개발망을 고려해 HTTPS를 권장하되 강제하지 않고, HTTP local/insecure 모드는 one-time token, Edge fingerprint 또는 public key pinning, checksum/signature 검증을 함께 요구한다.

운영 CLI는 분기된 설치 방식을 만들지 않는다. 공식 경로는 iop-edge setupiop-node setup 하나로 고정하고, 검토나 CI 확인은 별도 render 명령이 아니라 --dry-run 옵션으로 흡수한다.

build:
  Jenkins -> bin/build/field-binaries.sh -> iop-edge, iop-node

control host:
  docker compose -> postgres, redis, control-plane, web

edge host:
  iop-edge setup -> systemd unit + config/data directories   [구현 완료]
  systemd -> iop-edge serve --config /etc/iop/edge.yaml

node host:
  iop-node setup -> systemd unit + config/data directories   [구현 완료]
  systemd -> iop-node serve --config /etc/iop/node.yaml

oto build host:
  edge bootstrap command -> oto binary + agent config/service
  systemd -> oto agent --config /etc/oto/agent.yaml

setup은 idempotent해야 한다. 기존 설정 파일은 기본적으로 덮어쓰지 않고, 필요한 디렉터리와 unit만 생성/갱신하며, --enable, --start, --restart, --dry-run 같은 옵션으로 운영 차이를 표현한다. status, logs, start, stop, restart 같은 명령은 초기 CLI에 넣지 않고 systemctljournalctl을 기준 운영 도구로 둔다.

라이브러리 선택

라이브러리 역할
go.uber.org/fx 의존성 주입
go.uber.org/zap 구조화 로깅
github.com/spf13/cobra CLI
github.com/spf13/viper 설정 파일
google.golang.org/protobuf Protobuf
github.com/prometheus/client_golang 메트릭
modernc.org/sqlite 현재 Node local 실행 이력 저장

금지 사항

  • gRPC (grpc-go) 사용 금지
  • WebSocket 기본 transport 사용 금지
  • Actor framework 사용 금지
  • External worker pool 사용 금지
  • FSM framework 사용 금지
  • Plugin framework 사용 금지
  • Kubernetes 의존성 금지