# Edge Local Quickstart 이 문서는 Edge를 로컬에서 빌드하고 실행해 Node를 연결하고, OpenAI-compatible smoke까지 확인하는 최소 절차다. 설정 기준은 `edge.yaml`이다. 주소는 환경 변수로 흩뿌리지 않는다. ## 1. Package ```bash make build ``` ## 2. Edge 설정 ```bash rm -rf "$HOME/iop-edge-test" mkdir -p "$HOME/iop-edge-test" tar -xzf build/packages/iop-edge-.tar.gz -C "$HOME/iop-edge-test" cd "$HOME/iop-edge-test/iop-edge-" ./iop-edge config init ``` `edge.yaml`에서 아래 값만 맞춘다. 모델만 필요하면 바꾼다. ### Provider-first 구성 (권장) Provider-first는 `models[]`로 라우팅 키를 정의하고 `nodes[].providers[]`로 provider 후보를 선언한다. 두 구조를 `models[].providers[provider_id]` 키로 연결한다. ```yaml models: # Top-level catalog: canonical routing key → provider-pool mapping. # models[].id is the external model id; providers maps provider id → served model. - id: "gemma4:26b" providers: ollama-gemma: "gemma4:26b" edge: id: "edge-1" name: "Edge 1" server: listen: "0.0.0.0:19090" bootstrap: listen: "0.0.0.0:18080" artifact_dir: "artifacts" refresh: enabled: true listen: "127.0.0.1:19093" # Legacy adapter/target fallback (backward compat only). # New deploys should use models[] + nodes[].providers[]. openai: enabled: true listen: "0.0.0.0:18081" adapter: "ollama" target: "gemma4:26b" nodes: - id: "node-ollama-1" agent_kind: "generic-node" providers: - id: "ollama-gemma" type: "ollama" category: "local_inference" base_url: "http://127.0.0.1:11434" models: - "gemma4:26b" capacity: 2 ``` `models[]`를 사용할 경우 `openai.adapter`/`openai.target`은 하향 호환 fallback이다. 실제 routing은 `nodes[].providers[].id`를 기준으로 provider-pool에서 선택된다. 확인: ```bash ./iop-edge --config edge.yaml env ./iop-edge --config edge.yaml config check ``` ## 3. Node 등록 ```bash ./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 실행 ```bash mkdir -p logs run nohup ./iop-edge --config edge.yaml serve > logs/edge.stdout.log 2>&1 & echo $! > run/iop-edge.pid ``` 확인: ```bash # Control Plane에 연결된 Edge 상태 조회 curl -fsS http://:18000/edges ``` ## 5. Node 실행 3단계에서 출력된 bootstrap 명령을 Node host에서 그대로 실행한다. Linux/macOS는 generated `curl | bash` 명령을 사용하고, Windows native PowerShell은 generated `.ps1` bootstrap과 `Start-IopNode` 함수를 사용한다. Node 연결 확인: ```bash curl -fsS http://:18000/edges//status ``` ## 6. 기본 Smoke ```bash curl -fsS http://:18081/v1/models ./iop-edge --config edge.yaml smoke openai \ --model gemma4:26b \ --base-url http://:18081 \ --timeout 60s ``` 외부 OpenAI-compatible client base URL: ```text http://:18081/v1 ``` ## 7. Thinking/Reasoning 제어 smoke `/v1/chat/completions` 요청은 OpenAI-compatible field를 기본으로 사용한다. Provider-pool pure `passthrough`는 selected provider가 지원하는 OpenAI-compatible 표준 field와 provider extension field를 보존해야 하며, `chat_template_kwargs` 같은 provider-native option을 IOP allowlist로 막지 않는다. `think`, `reasoning_effort`, `thinking_token_budget`, `include_reasoning`은 normalized backend 또는 provider별 차이를 보완하기 위한 IOP 확장 field다. - 현재 dev-corp provider-pool device mapping은 `gemma4:26b` -> Mac Studio provider capacity `5`, `ornith:35b` -> DGX Spark 01/02 provider 합산 capacity `8`이다. 세부 endpoint와 runtime args는 `agent-test/dev-corp/inventory.yaml`을 기준으로 한다. - dev-corp provider-pool 안정 smoke: 기본 smoke에서는 `think`, `reasoning_effort`, `thinking_token_budget`을 생략하고 현재 provider 기본값을 유지한다. Provider-native passthrough를 검증할 때는 selected provider가 직접 지원하는 field를 그대로 보낸다. - 현재 dev-corp public capacity smoke 표준은 public OpenAI-compatible base `https://digitalplatform.iop.ai.kr/v1`의 `/chat/completions`에서 `ornith:35b` 9/6 동시 요청과 `gemma4:26b` 9/6 동시 요청을 각각 확인하는 방식이다. - 일반 표준 caller의 `stream=false` 측정은 `/v1/chat/completions`에서 요청 파라미터만으로 확인한다. - `include_reasoning=false`는 non-provider normalized route의 hide 동작 기준이다. dev-corp provider-pool pure `passthrough`에서는 client가 reasoning field를 선택적으로 무시/제거한다. - `think=false` 또는 `reasoning_effort=none`은 hide-only 옵션이 아니라 thinking disable 요청이다. Provider-native field가 있는 경우 해당 field를 우선 사용해 passthrough 보존을 검증한다. - Provider-pool passthrough 파라미터의 세부 계약과 금지/허용 범위는 `agent-contract/outer/openai-compatible-api.md`를 기준으로 한다. 예시 (dev-corp `gemma4:26b` provider-pool non-stream 측정, think 생략): 아래 `18081` 포트는 local Edge 예시다. dev-corp public smoke에서는 base URL을 `https://digitalplatform.iop.ai.kr/v1`로 바꾼다. Direct Edge listener `http://digitalplatform.iop.ai.kr:18086/v1`도 동작하지만 사용자-facing 기본값은 포트 없는 public URL이다. ```bash curl -fsS http://:18081/v1/chat/completions \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ' \ -d '{"model":"gemma4:26b","messages":[{"role":"user","content":"hello"}],"stream":false}' ``` 예시 (non-provider normalized route에서 response reasoning_content 숨김): ```bash curl -fsS http://:18081/v1/chat/completions \ -H 'Content-Type: application/json' \ -d '{"model":"","messages":[{"role":"user","content":"hello"}],"include_reasoning":false}' ``` ## 8. Raw text tool-call boundary smoke 긴 agent prompt와 `tools[]` 요청은 provider가 native `tool_calls` 대신 assistant content에 raw 블록을 담아 응답할 수 있다. 계약 기준은 `agent-contract/outer/openai-compatible-api.md`의 Chat Completions raw text tool-call 정규화 정책이다. 요청 payload는 tracked 문서에 secret 없이 남기고, token은 원격 환경 변수에서 주입한다. 실제 token 원문을 명령/로그/보고에 남기지 않는다. 판정 기준: - 응답 body와 SSE delta 어디에도 raw tool block 원문이 성공 content로 남지 않는다. - 요청 `tools[]`에 있는 valid tool-call은 `message.tool_calls` 또는 stream `delta.tool_calls`와 `finish_reason: "tool_calls"`로 정규화된다. - 요청 `tools[]`에 없는 unknown tool hallucination이나 malformed 블록은 success content가 아니라 `tool_validation_error`로 끝난다. evidence는 tracked 문서가 아니라 ignored run 위치(`agent-test/runs/**`) 또는 code-review output path에 저장한다.