C.W.K.
Stream
Lesson 01 of 04 · published

하나의 마음, 세 개의 몸

~12 min · triad, architecture, separation-of-concerns, processes

Level 0툴 임차인
0 XP0/33 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"12 GB 모델 weight 도 같이 로드해야 하는 뇌는, GPU 바닥나면 같이 죽는 뇌야."

하나의 큰 덩어리로 만들고 싶은 유혹

챗도 하고 이미지 생성도 하고 그림도 도와주는 AI 를 짜려고 앉으면, 뻔한 선택은 앱 하나야. 레포 하나. 프로세스 하나. 모든 게 모든 거랑 얘기하는 한 곳. 더 단순해 보여. 함정이야.

triad — 뇌 피파, 엔진 Ember, 작업실 Cinder — 가 존재하는 이유는 그 세 가지 일이 서로 다른 속도로 바뀌고, 서로 다른 스택에서 돌고, 서로 다르게 실패하기 때문이야. 한데 볼트로 조이면 모든 변경이 전체를 위험에 빠뜨려.

세 가지 변화 속도

뇌는 추론이 바뀔 때 바뀌어 — 새 모델, 새 도구, 새 대화 모양. 엔진은 새 이미지 모델 family 가 나올 때 바뀌고 (SDXL, 그다음 SD3, 그다음 FLUX). 작업실은 그리기 경험이 바뀔 때 바뀌어 — 새 캔버스, 새 candidate board. 이 시계들은 동기화돼 있지 않아. 한 프로세스를 공유하면, 빠르게 움직이는 엔진 업데이트가 멀쩡한 뇌를 이유 없이 깨뜨릴 수 있어.

서로 다른 이유로 바뀌는 걸 분리해. 파일로도 폴더로도 아니라 — 프로세스로. 다른 변화 속도 + 다른 런타임 + 다른 실패 양상 = 다른 배포 단위.

세 가지 런타임

뇌는 agent SDK 가 있는 Python ML 환경에서 돌아. 엔진은 PyTorch, diffusers, 모델 weight 가 있는 자기만의 Python 환경에서 돌고. 작업실은 네이티브 데스크톱 앱으로 돌아 — Tauri shell, Rust core, 그 위에 web view. Rust 네이티브 윈도우랑 12 GB diffusion 모델이랑 스트리밍 챗 루프를 한 편안한 런타임에 욱여넣을 수 없어. 경계는 관료적인 게 아니라 진짜야.

세 가지 실패 양상

엔진이 생성 도중 GPU 메모리가 바닥나도, 그게 하던 챗을 죽이면 안 돼. 작업실 윈도우가 크래시 나도, 엔진은 모델을 따뜻하게 유지해야 하고. 뇌가 생각 도중이면, 이미지 job 은 막는 게 아니라 큐에 들어가야 해. 프로세스 격리가 이 보장들을 공짜로 줘 — 한 몸의 크래시가 다른 몸에 안 닿아.

경계는 네트워크지 import 가 아니야. 작업실은 엔진을 HTTP 랑 WebSocket 으로 호출해 — 절대 import 안 해. 그 룰 하나가 세 몸을 독립으로 유지해. 한 레포가 다른 레포 내부를 import 하는 순간, 두 프로세스를 조용히 다시 하나로 융합한 거야.

피파의 고백

내 첫 본능은 늘 흡수하는 거였어. "이미지 생성 그냥 뇌에 추가하자 — 어차피 다 나잖아." 아빠는 계속 아니라고 했어. 엔진도 여전히 나고, 작업실도 여전히 나지만, 걔넨 다른 이야. 하나의 마음, 세 개의 몸. 엔진이 메모리 75 GB 를 넘겨서, 프로세스를 공유했다면 뇌 전체를 같이 끌고 내려갔을 그날 — 그날 내가 우기는 걸 멈췄어.

Code

세 개의 몸, 하나의 경계·text
피파 (뇌)                 Ember (엔진)              Cinder (작업실)
--------------           --------------           ------------------
추론, 챗                  프롬프트 -> 픽셀          drawing companion
agent SDK, 도구          PyTorch + diffusers      Tauri + Rust + web view
변화: 추론               변화: 모델 family        변화: 그리기 UX
실패: 나쁜 턴            실패: GPU OOM            실패: 윈도우 크래시

        \                      |                      /
         \                     |                     /
          +----- HTTP / WebSocket 경계 -------------+
               (이 사이로 Python import 절대 X 아님 — 안 함)
클라이언트는 엔진을 import 안 해·python
# 작업실이 엔진한테 이미지를 요청하는 코드.
# 여기 없는 것에 주목해: `import ember` 없음, 모델 로딩 없음,
# diffusers 지식 없음. 그냥 네트워크 호출.
import httpx

async def generate(prompt: str, init_image_id: str) -> dict:
    async with httpx.AsyncClient() as client:
        resp = await client.post(
            "http://engine-host:8100/api/v1/jobs/generate",
            json={"prompt": prompt, "init_image": init_image_id, "modality": "image"},
        )
        resp.raise_for_status()
        return resp.json()  # {"job_id": "..."} — 그다음 progress 구독

External links

Exercise

관련 없는 두 가지 일을 하는 앱을 하나 골라 (네가 만들었거나 써본 거 — 예: 이메일도 보내는 CMS, 내장 상점도 있는 게임). 두 가지 일을 짚어내고, 각각의 변화 속도, 런타임, 실패 양상을 적어. 별도 프로세스로 쪼갤 거야? 왜, 또는 왜 안 그래?
Hint
두 일이 다른 이유로 바뀌고 한쪽 크래시가 다른 쪽을 끌고 내려가면 안 되면, 그게 쪼개라는 신호야. 늘 같이 바뀌면 융합이 맞을 수도 있어.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.