iop/docs/edge-local-dev-guide.md

8.9 KiB

Edge Local Quickstart

이 문서는 toki-labs.com Control Plane에 native Edge를 붙이고, Ollama Node를 연결해 OpenAI-compatible smoke까지 확인하는 최소 절차다.

설정 기준은 edge.yaml이다. 주소는 환경 변수로 흩뿌리지 않는다.

1. Package

현재 toki-labs.com 원격처럼 Apple Silicon macOS에서 실행한다.

make build

2. Edge 설정

rm -rf "$HOME/iop-edge-test"
mkdir -p "$HOME/iop-edge-test"
tar -xzf build/packages/iop-edge-darwin-arm64.tar.gz -C "$HOME/iop-edge-test"
cd "$HOME/iop-edge-test/iop-edge-darwin-arm64"
./iop-edge config init

edge.yaml에서 아래 값만 맞춘다. 모델만 필요하면 바꾼다.

edge:
  id: "edge-toki-labs"
  name: "Toki Labs Edge"

server:
  listen: "0.0.0.0:19090"
  advertise_host: "toki-labs.com"

bootstrap:
  listen: "0.0.0.0:18080"
  artifact_base_url: "http://toki-labs.com:18080"
  artifact_dir: "artifacts"

control_plane:
  enabled: true
  wire_addr: "toki-labs.com:19081"

refresh:
  enabled: true
  listen: "127.0.0.1:19093"

openai:
  enabled: true
  listen: "0.0.0.0:18081"
  adapter: "ollama"
  target: "gemma4:26b"
  models:
    - "gemma4:26b"
  timeout_sec: 300

nodes: []

확인:

./iop-edge --config edge.yaml env
./iop-edge --config edge.yaml config check

3. Node 등록

./iop-edge --config edge.yaml node register node-ollama-1 \
  --adapter ollama \
  --ollama-base-url http://127.0.0.1:11434

출력된 OS별 bootstrap 명령 원문을 보관한다. 명령 원문에는 실제 token이 포함되므로 tracked 문서에는 기록하지 않는다.

4. Edge 실행

mkdir -p logs run
nohup ./iop-edge --config edge.yaml serve > logs/edge.stdout.log 2>&1 &
echo $! > run/iop-edge.pid

확인:

curl -fsS http://toki-labs.com:18000/edges

5. Node 실행

3단계에서 출력된 bootstrap 명령을 Node host에서 그대로 실행한다. Linux/macOS는 generated curl | bash 명령을 사용하고, Windows native PowerShell은 generated .ps1 bootstrap과 Start-IopNode 함수를 사용한다.

Node 연결 확인:

curl -fsS http://toki-labs.com:18000/edges/edge-toki-labs/status

6. dev-runtime provider pool 반복 기준

현재 GX10 vLLM과 OneXPlayer Lemonade를 같은 model alias로 묶어 검증하는 dev-runtime 기준은 원격 runner의 동기화된 iop checkout과 build/dev-runtime/edge.yaml이다.

배포 전 원격 runner checkout은 보존 대상이 아니다. 항상 clean sync 후 dev-runtime binary를 다시 빌드한다.

cd /Users/toki/agent-work/iop-dev
git fetch origin main
git reset --hard origin/main
git clean -fd

go build -trimpath -o build/dev-runtime/bin/edge ./apps/edge/cmd/edge
go build -trimpath -o build/dev-runtime/bin/iop-node ./apps/node/cmd/node
GOOS=linux GOARCH=arm64 go build -trimpath -o build/dev-runtime/bin/iop-node-linux-arm64 ./apps/node/cmd/node
GOOS=windows GOARCH=amd64 go build -trimpath -o build/dev-runtime/bin/iop-node-windows-amd64.exe ./apps/node/cmd/node

기준 주소:

  • Control Plane status: 원격 host의 http://127.0.0.1:18001
  • dev-runtime Edge id: edge-toki-labs-dev
  • bootstrap HTTP: http://toki-labs.com:18082
  • Edge OpenAI-compatible base URL: http://toki-labs.com:18083/v1
  • Edge-Node TCP transport: toki-labs.com:18084

외부로 노출되는 OpenAI-compatible API는 openai.bearer_token으로 보호한다. tracked 문서에는 실제 token 원문을 기록하지 않고, Cline 같은 외부 client에는 운영자가 전달한 API key를 Authorization: Bearer ... 형태로 설정한다.

기준 provider pool:

  • model alias: qwen3.6:35b
  • provider candidate: gx10-vllm on gx10-vllm-node, capacity 4
  • provider candidate: onexplayer-lemonade on onexplayer-lemonade-node, capacity 3
  • connected non-candidate: mac-codex-node

OneXPlayer Lemonade Node는 원격 runner나 Edge host에서 다시 SSH하거나 proxy process로 띄우지 않는다. 현재 작업 호스트에서 Windows host에 ssh r0bin@192.168.0.59로 직접 접속한 뒤, 그 host 안에서 generated PowerShell bootstrap 명령을 실행한다. 이때 Node 작업 경로는 $HOME\iop-field이며, Lemonade provider endpoint는 Windows host 로컬에서 접근 가능한 값을 기준으로 검증한다.

OneXPlayer Lemonade는 Qwen3.6-35B-A3B-MTP-GGUF artifact를 사용하되 runtime MTP speculative decoding은 끈다. dev long-context 기준 load 설정은 Vulkan backend, ctx_size=786432, llamacpp_args="--spec-type none -np 3 -cb -fa on -b 4096 -ub 1024"로 고정한다. llama.cpp server 기준 ctx_size는 전체 KV/context 예산이고 -np는 server slot 수이므로, 이 설정은 slot 3개가 각각 n_ctx=262144인 구조를 만든다. 2026-06-24 dev throughput 측정의 약 95.9 tok/s 관측은 ctx_size=4096, -np 4 기준이므로 이 long-context 설정과 직접 비교하지 않는다. 재시작 뒤에도 유지되도록 /v1/loadsave_options=true로 적용한다.

curl -fsS http://192.168.0.59:13305/v1/load \
  -H 'Content-Type: application/json' \
  -d '{"model_name":"Qwen3.6-35B-A3B-MTP-GGUF","ctx_size":786432,"llamacpp_backend":"vulkan","llamacpp_args":"--spec-type none -np 3 -cb -fa on -b 4096 -ub 1024","save_options":true}'

SSH 세션 안의 Start-Process는 세션 종료와 함께 iop-node.exe가 정리될 수 있다. 반복 배포에서는 Windows host에서 Win32_Process.Create 방식으로 세션 독립 실행한다.

$work = "$HOME\iop-field"
$cmd = 'cmd.exe /c "cd /d C:\Users\r0bin\iop-field && iop-node.exe --config node.yaml serve >> iop-node.wmi.stdout.log 2>> iop-node.wmi.stderr.log"'
Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{ CommandLine = $cmd; CurrentDirectory = $work }

capacity, provider mapping, model alias 변경은 후보 edge.yaml 수정 후 config check, refresh dry-run, refresh apply 순서로 반영한다. config refresh subcommand나 19093 admin port가 없으면 dev-runtime binary rebuild 누락으로 보고 clean sync/rebuild부터 다시 수행한다.

dev-runtime 번들은 바이너리를 build/dev-runtime/bin/edge에 둔다. 명령은 그 경로를 EDGE_BIN으로 잡고 실행한다.

EDGE_BIN=build/dev-runtime/bin/edge
"$EDGE_BIN" --config build/dev-runtime/edge.yaml config check
"$EDGE_BIN" --config build/dev-runtime/edge.yaml config refresh --mode dry-run --addr 127.0.0.1:19093
"$EDGE_BIN" --config build/dev-runtime/edge.yaml config refresh --mode apply --addr 127.0.0.1:19093

Node host OS 재부팅은 필요하지 않다. Edge process 재시작이나 일시 단절은 Node reconnect 정책으로 처리한다. Node는 최초 연결 성공 이후 기본 10s 간격으로 최대 10회 재접속을 시도하므로, retry window 안에서 Edge가 회복되면 bootstrap 명령을 다시 실행하지 않는다. retry 한계를 넘겨 Node process가 종료된 경우에만 해당 host에서 새 bootstrap 실행이 필요하다.

반복 검증 순서:

  1. Control Plane status에서 edge-toki-labs-dev의 connected node 수와 node id를 확인한다.
  2. Edge host에서 toki-labs.com:18084의 established node TCP connection 수를 확인한다.
  3. Edge process를 재시작하고 bootstrap 재실행 없이 3개 Node 연결이 회복되는지 확인한다.
  4. http://toki-labs.com:18083/healthz/v1/models를 확인한다.
  5. capacity를 gx10-vllm=4, onexplayer-lemonade=3로 맞춘 후보 config를 refresh apply하고 Edge process가 유지되는지 확인한다. Node adapter capacity 변경이 restart_required로 반환되면 Edge process를 새 config로 재시작한 뒤 Node reconnect 상태를 확인한다.
  6. qwen3.6:35b/v1/responses/v1/chat/completions 각각에 provider capacity 총합 + 1개 동시 요청을 보낸다.
  7. capacity gx10-vllm=4, onexplayer-lemonade=3 기준이면 endpoint별 8개 동시 요청에서 Control Plane status의 provider snapshot이 총 in_flight=7, queued>=1을 한 번 이상 보여야 한다.
  8. 요청 완료 후 provider snapshot이 in_flight=0, queued=0으로 회복되는지 확인한다.

Qwen 계열 모델은 thinking/reasoning 텍스트를 포함해 응답할 수 있다. 이 dev smoke에서는 thinking 출력을 실패로 보지 않고, HTTP 성공, final marker 포함, provider log/run count 증가를 기준으로 판정한다.

현재 공개 API는 개별 request의 최종 node_id를 응답에 노출하지 않는다. 요청별 배정을 확정해야 할 때는 Edge dispatch trace/log를 추가한 뒤 판정한다.

7. 기본 Smoke

아래는 dev-runtime provider pool이 아니라 기본 field/local OpenAI-compatible profile 기준 예시다. dev-runtime provider pool 검증은 위의 18083/qwen3.6:35b 기준을 따른다.

curl -fsS http://toki-labs.com:18081/v1/models

./iop-edge --config edge.yaml smoke openai \
  --model gemma4:26b \
  --base-url http://toki-labs.com:18081 \
  --timeout 60s

외부 OpenAI-compatible client base URL:

http://toki-labs.com:18081/v1