스터브(Stub)를 먼저 게시하고, 원격 통신이 성공한 후에만 무료 모델을 연결하라
요약
AI 시스템 개발 시, 모든 단계를 증거를 남기며 점진적으로 구축하는 것이 중요합니다. 특히, 실제 모델이나 네트워크 연결 없이 로컬에서 '스텁(stub)'을 먼저 구현하여 계약(contract)과 기본 구조의 안정성을 확보해야 합니다.
핵심 포인트
- 모든 단계는 증거를 방출하며, 이는 문제 발생 시 원인 파악에 도움을 줍니다.
- 가장 먼저 수락할 데이터 형태(JSON Schema)라는 '계약'을 고정하는 것이 필수입니다.
- 실제 모델이나 네트워크 연결 없이 로컬에서 스텁을 구현하여 기본 구조의 안정성을 검증해야 합니다.
무료 모델 접근과 무료 서버는 빈 노트북처럼 저렴합니다. 제약은 돈이 아니라 출처 표기입니다. 네 번째 단계에서 문제가 발생했을 때, 모든 것을 재실행하지 않고 프롬프트, 배포(deploy), 또는 네트워크 중 무엇이 문제였는지 알고 싶습니다.
따라서 아래의 전체 튜토리얼은 한 문장으로 요약됩니다: 모든 단계는 증거를 방출하며, 이 증거가 나중에 올바른 단계를 지목할 수 있게 해줍니다. 여섯 개의 체크포인트, 네 개의 파일, 하나의 검증기(verifier).
네, 이번 주 프론트 페이지 토론의 상당 부분은 AI 피로감과 모든 것에 동의하는 모델에 관한 것이었습니다. 공정합니다. 이 게시물은 의도적으로 작게 유지됩니다: 단일 엔드포인트, 단일 JSON 형태, 대시보드 없음, 오케스트레이션(orchestration) 없음.
구축할 슬라이스 (The slice you are building)
GET /answer라는 하나의 HTTP 엔드포인트는 하나의 고정된 객체를 반환합니다. 그것이 전부입니다.
gate-demo/
├── contract/response.schema.json # 수락할 내용
├── prompt/extract.v1.txt # 보낼 내용
...
저 나무 구조에는 프레임워크가 없다는 점에 주목하세요. 표준 라이브러리만 사용하므로, 무언가 실패했을 때 그것은 의존성이 아닌 당신의 책임입니다.
Stage 0 — 다른 것이 존재하기 전에 계약(contract)을 고정하라 (Freeze the contract before anything else exists)
Step 1. 수락할 형태를 작성하세요. 희망하는 형태가 아니라, 모든 것을 거부할 기준이 될 형태입니다.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
...
Step 2. 파일 자체가 파싱 가능한지 증명하세요:
mkdir -p contract && $EDITOR contract/response.schema.json
python -c "import json; json.load(open('contract/response.schema.json'))" && echo GATE0_OK
Gate 0은 의도적으로 약합니다. 파싱은 파일이 JSON임을 증명할 뿐입니다. 당신의 서비스가 그것을 준수한다는 것을 증명하지는 못합니다. 그것은 Stage 1의 임무이며, 둘을 혼합하는 것이 자정 시간에 자신의 스키마와 논쟁하게 되는 방식입니다.
Stage 1 — 모델도 네트워크도 없이 로컬에서 스텁(stub)을 증명하라 (Prove a stub locally, with no model and no network)
Step 1. 스텁은 정렬된 캐낸 바디(canned body)와 Content-Length를 반환합니다:
stage1_stub.py — 모델 없음, 네트워크 없음, 고정된 응답 하나
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
...
Step 2. 나머지 기사에서 사용할 유일한 하네스(harness) 작성:
#!/usr/bin/env python3
# verify.py <url> <stage> [--require-stable]
# 종료 코드 0 = 게이트 통과. 2 = 스키마 오류. 3 = 바이트 불안정.
...
Step 3. 게이트 설정:
python stage1_stub.py &
python verify.py http://127.0.0.1:8080/answer 1 --require-stable; echo "exit=$?"
바이트 안정성(byte stability)이 여기서 어려운 게이트인 이유는 나중에가 아니라 지금이어야 하기 때문입니다. 캐시된 응답은 세 번 중 세 번 모두 동일해야 합니다. 그렇지 않다면, 하네스가 고장난 것이지 AI가 잘못된 것이 아닙니다. 스텁에서 이를 알아내는 것은 아무 비용이 들지 않습니다. 모델 호출을 연결한 후에 이를 알아내는 것은 오후 시간 동안 의심에 빠지는 것을 의미합니다.
Stage 2 — 프롬프트를 파일로 버전 관리하고, 해시(hash)하기
Step 1. 프롬프트는 코드 내의 문자열이 아니라 아티팩트(artifact)입니다:
mkdir -p prompt cases
printf 'Extract the single subject of the text below.\nReturn only JSON: {"subject": string, "confidence": number}\nTEXT:\n' > prompt/extract.v1.txt
sha256sum prompt/extract.v1.txt | tee prompt/extract.v1.sha256
Step 2. 실행 전에 항상 재확인하기:
sha256sum -c prompt/extract.v1.sha256
이것이 전체 게이트이며, 의도적으로 지루합니다. 실패하면 사람이 프롬프트를 수정했다는 뜻이고, 서비스가 마음을 바꿨다고 가장하는 것을 멈출 수 있습니다. 입력은 cases/에 넣고, 절대 고객의 텍스트를 사용하거나 prompt/ 안에 넣지 마십시오.
Stage 3 — 동일한 엔드포인트 뒤에 하나의 제한된 모델 호출 연결하기
이곳에서 무료 모델 접근 권한을 얻습니다: 한 번의 호출, 하나의 형태(shape), 도구 없음(no tools), 루프 없음(no loop), 에이전트 없음(no agent). MonkeyCode는 제가 이 단계에 사용한 프로젝트이며, 무료 서버 옵션은 아래 Stage 4가 사용하는 것입니다. 둘 다 저의 벤치마크가 아니라 해당 프로젝트의 가용성 주장입니다. 공개합니다: 본 기사는 MonkeyCode의 제품 홍보의 일환으로 준비되었습니다.
Step 1. 호출 래퍼(call wrapper) — SDK가 다르기 때문에 의도적으로 유사 코드(pseudocode)로 작성했습니다:
Stage 4 — 변경되지 않은 스텁을 무료 서버에 게시하기
중요한 단어는 '변경되지 않은(unchanged)'입니다. 이미 로컬에서 스텁이 작동한다는 것을 알고 있습니다. 만약 원격에서 실패한다면, 그 실패는 모델이 아니라 호스트의 문제입니다.
Step 1. 비밀 정보가 포함되지 않은 두 파일만 복사합니다:
scp contract/response.schema.json stage1_stub.py user@instance:~/gate-demo/
Step 2. 인스턴스에서 실행하고 박스 안에서 확인합니다:
cd ~/gate-demo && (nohup python3 stage1_stub.py &> stub.log &)
curl -s localhost:8080/answer
Step 3. Stage 1과 동일한 검증기(verifier)를 사용하여 노트북에서 게이팅합니다:
python verify.py https://<instance-host>/answer 4 --require-stable; echo "exit=$?"
게이트 4는 다음을 의미합니다: 같은 바이트, 같은 스키마, 다른 기계입니다. scp로 자격 증명(credentials)을 복사하지 마십시오. 나중에 인스턴스에서 환경 변수(environment variable)로 MODEL_KEY를 설정하십시오. 포트를 노출하는 방법은 선택한 무료 서버에 따라 다르므로 해당 페이지를 읽어보십시오. 여기에는 어떤 것도 특정 방식을 가정하고 있지 않습니다.
Stage 5 — 모델 호출을 원격으로, 여전히 한 줄로 이동하기
이제 스텁을 app.py 변형으로 교체하고, 키를 설정하고, 재시작한 다음, 검증기를 다시 실행합니다:
python verify.py https://<instance-host>/answer 5; echo "exit=$?"
Schema 3/3이 관문(gate)입니다. 지연 시간(Latency)은 아닙니다. 본인의 연결 상태에서 순차적인 요청을 다섯 번 실행하고 측정된 숫자를 기록해 보세요. 제가 측정한 수치는 귀하의 것과는 아무 관련이 없으므로, 저는 어떤 것도 제공하지 않겠습니다.
하나의 표에 담긴 모든 관문
| 단계 (Stage) | 증명하는 것 (What it proves) | 하드 관문 (Hard gate) | 기록되는 경우 (Recorded only) |
|---|---|---|---|
| 0 | 계약 파일이 파싱됨 (the contract file parses) | JSON parse OK | — |
| ... |
여기서 문제가 생기는 지점과 건너뛰어야 할 사람
- 경계를 벗어날 수 없는 데이터. 호스팅되는 무료 모델 티어는 프롬프트가 귀하의 기기를 떠난다는 의미입니다. 이것이 규정 준수(compliance) 문제라면, Stage 2에서 멈추고 동일한 엔드포인트를 로컬 모델에 연결하세요.
- 지속성이 필요한 워크로드. 상태(state)가 재시작 후에도 살아남아야 한다면, 무료 인스턴스는 이를 발견하기에 적절하지 않은 장소입니다. 배포하는 날짜의 무료 티어에 무엇이 포함되는지는 제공업체의 현재 약관을 읽으세요.
- 고정된 모델 버전이 필요한 팀. 이 워크플로우는 실행(run)마다 모델 ID를 기록하지만, 내일 호출했을 때 동일한 모델이 반환된다는 것을 보장하지 않습니다.
- 부하 수치(load numbers)가 필요한 사람. 세 번의 요청과 손으로 타이핑한 샘플은 벤치마크가 아니라 스모크 테스트입니다.
- 평가 세트(eval set) 없이 프로덕션에 배포할 사람. Stage 3은 모양(shape)을 증명할 뿐, 정확성(correctness)을 증명하지 않습니다.
또 하나: 할당량(quotas)과 플랜은 변합니다. 예산을 책정하고 있다면, 이 블로그 게시물보다 제품의 현재 플랜 페이지를 읽으세요.
지켜야 할 단 하나의 것
모든 6개 단계에 걸쳐 Stage 0의 계약 파일(contract file)을 바이트 단위로 동일하게 유지하세요. 스텁(stub), 프롬프트, 호스트, 그리고 모델은 모두 교체 가능합니다. 계약이 무엇을 알려주는지—무엇인가 잘못되었을 때 어떤 단계가 깨졌는지—그것이 핵심입니다.
만약 자체적으로 연결하는 대신 무료 모델 호출과 무료 서버를 대상으로 Stage 3부터 5까지 실행하고 싶다면, 그것이 MonkeyCode가 제공하는 설정이며 제가 위에서 사용한 것입니다. 계약 파일로 시작하여 무언가가 실패했을 때 무엇을 말하는지 확인해 보세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기