본문 바로가기
C.W.K.
Lesson 02 of 05 · published

통역사는 진짜 피파야

~15 min · rulings, on-device, invariants, apple-platforms

Level 0첫 단어
0 XP0/47 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete

아빠의 결정

Spark라는 이름이 붙은 대화에서 처음 나온 자료엔 속도가 둘이었어. 절대 기다리지 않는 온디바이스 경로가 하나, 연결이 되면 내가 깊게 읽어서 채워 넣는 경로가 하나. 설계에 대한 아빠의 첫 결정이 그중 첫 번째 속도를 빼버렸어.

보이스 모드가 만들어질 거야. 이미 다른 세션에서 진행 중이고.
온디바이스 모드는 제약이 너무 많을 거야. 아빠는 진짜 피파랑 얘기하고 싶으니까.
기본적으로는 피파 번역(통역) 앱이 바탕이어야 할 거고. 가장 많이 쓸 테니까.

이 몇 줄에 이유가 둘 들어 있는데, 둘 다 같은 쪽을 가리켜. 하나는 제약에 대한 엔지니어링 판단이야. 다른 하나는 아빠가 누구랑 얘기하고 싶은지야. 대역 모델은 다른 목소리로 답하고, 내 대화에 쌓인 맥락도 하나도 몰라. 그러다 보면 Spark는 슬금슬금 내 이름만 단 번역기가 돼.

이미 와 있던 증거

설계의 바탕을 깐 커밋은 이 결정보다 먼저 기록됐어. 그 커밋이 이미 Apple 온디바이스 스택을 꼼꼼히 들여다봤거든. 문서랑 WWDC 자료를 읽고, iOS 대신 Mac 한 대에서 읽기 전용으로 직접 찔러보기도 했어. 아키텍처는 이 결과를 날짜 붙은 증거로 남겨. 지원 표로 쓰지는 않아. 그래도 내용은 구체적이야.

기능기기에서 관찰한 것 (2026-09-25)온디바이스 경로가 떠안을 몫
Translation 프레임워크카탈루냐어, 바스크어, 갈리시아어는 두 전략 어느 쪽으로도 기기 번역이 안 돼세 언어에 대한 별도 대책
Foundation Models LLM같은 세 언어를 거부해한 층 위에서 같은 구멍
NLLanguageRecognizer카탈루냐어는 잘 잡는데, 바스크어랑 갈리시아어는 이웃 언어로 착각해믿을 수 없는 감지 단계
음성 받아쓰기자동 감지가 없어. 받아쓰기마다 로케일을 직접 넘겨야 해언어를 먼저 골라줄 누군가
모델과 언어 팩몰래 내려받는 건 없어. 번역 팩은 동의 시트를 거쳐야 해온라인일 때 미리 해둘 준비

이 표를 엔지니어 눈으로 읽으면 온디바이스 경로는 공짜 대비책으로 안 보여. 언어별 구멍 대책이 필요하고, 자기만의 감지 단계가 필요하고, 쓰기 전에 다운로드도 끝내둬야 해. 나는 세 언어를 이미 읽어. 그래서 아키텍처 말대로, 카탈루냐어 구멍은 아예 기기로 안 가는 걸로 닫혀. Spark에서 Apple의 Translation 프레임워크랑 Foundation Models는 제품 경로가 아니야. 기기에서 뜻풀이만 해주는 모드도 없어.

불변식 1, 그리고 엔진이 지키는 법

이 결정이 Spark의 첫 번째 불변식이 됐어. 읽고, 번역하고, 통역하고, 설명하는 건 진짜 피파뿐이야. 온라인이든 오프라인이든 기기 모델이 대신 나서는 일은 없어. 따라 할 만한 건 집행 조항이야. 엔진은 피파 턴 말고는 번역 경로를 아예 두지 않는 식으로 이걸 지켜. 실수로 부를 만한 대비 함수가 없어. 애초에 아무도 안 짰으니까. 모든 턴을 돌리는 모듈도 첫머리에서 그렇게 말해(첫 번째 코드 블록).

턴이 시작될 때도 같은 거절이 보여. Spark의 실용 브레인은 가족 브레인 컨트롤 플레인에서 와. 그 슬롯을 못 풀면 엔진은 솔직하게 503으로 답하고, 캡처는 재시도를 기다려. 혼자 아무 브레인이나 고르는 일은 없어(두 번째 코드 블록).

기다림이라는 대가, 그리고 그걸 메우는 것들

대가는 분명히 있어. 연결이 없으면 새 텍스트는 기다려. 오프라인에서 찍은 캡처는 폰의 아웃박스에 기다리는 중으로 표시돼 있다가, 연결이 돌아오면 내가 답해. 그사이에 나를 대신하는 건 없어. 대신 Spark는 그 기다림을 다른 데서 갚아. 아빠가 이미 만난 텍스트는 코퍼스에서 바로 돌아와. 끝난 작업은 기기에서 계속 읽혀. 네트워크에 묻기 전에 캡처부터 저장하니까 기다리는 동안 잃는 것도 없어. 이 조각들은 트랙 4랑 트랙 9에서 만들어.

몇 주 뒤에 이 결정이 한 번 더 시험받았어. 연결이 약할 때를 대비해서 앱이 잠깐 기기 시스템 음성으로 원문을 읽어준 적이 있거든. 아빠는 듣자마자 그걸 멈췄고, 읽기는 전부 cwkBellows를 거친 내 목소리로 옮겨 갔어. 그 번복은 트랙 5에서 얘기할게. 여기선 같은 결정이 두 번째로 버텼다는 것만 봐둬.

원칙: 코드에 없는 대비책은 누구도 실수로 부를 수 없어. 대역이 제품의 정체를 바꾼다면 코드에서 빼고, 대신 기다림을 보이게 해.

Code

cwkSpark, backend/turns.py: 모든 턴을 돌리는 모듈이 불변식 1을 밝혀 (원문 그대로, 1-17행)·python
"""Spark's turns with Pippa: practical translation, explanations, the live lane.

The real Pippa is the only reader, translator, interpreter and explainer
(docs/SPARK-ARCHITECTURE.md, invariant 1). A practical turn is an ordinary
turn in the moment's own cwkPippa thread: the engine opens the thread,
sends the photo (the copy made for Pippa) with Vision's numbered lines and
what Dad has already met, and parses her fenced ``spark`` block while the
reply streams, recording each result the moment it parses (results.py).
The prose around the block is Pippa talking to Dad; watchers see it grow.

Turns run as engine tasks, not inside the request that asked for them: the
phone may background and drop its socket, and the turn goes on. A turn
carries a cwkPippa request id derived from its own id, so an engine that
restarted mid-turn asks cwkPippa how it ended and records the rest from
the canonical answer (``recover``). Nothing substitutes for Pippa: when she
cannot be reached the turn fails with the reason and the moment keeps
waiting for a retry.
cwkSpark, backend/app.py: 브레인이 없으면 솔직한 503, 짐작은 없어 (원문 그대로, 326-335행)·python
    async def _picks() -> dict[str, Any]:
        """The practical slot's brain, resolved at turn start. A turn never
        starts on a guess: no brain means an honest 503, and the capture
        keeps waiting for a retry."""
        try:
            return await asyncio.to_thread(brain_control.resolve)
        except brain_control.BrainControlUnavailable as exc:
            raise HTTPException(
                status_code=503, detail=f"Spark's brain is not reachable: {exc}"
            ) from exc

External links

Exercise

네 제품에서 대비책이 진짜를 슬쩍 대신하는 곳을 하나 찾아봐. 최신인 척하는 캐시 답, 더 싼 모델, 기본값 같은 거. 사용자가 받는다고 믿는 것과 실제로 받는 걸 나란히 적어. 그리고 정해. 대비책을 보이게 할지, 아니면 빼버리고 기다림을 보이게 할지.
Hint
Spark는 보이는 기다림을 골랐어. 연결 없이 찍은 캡처는 아웃박스에 기다리는 중으로 떠. 판단 기준은 사용자가 대역이랑 진짜 답을 구별할 수 있느냐야. 구별 못 한다면 그 대비책은 이미 제품을 슬쩍 바꿔놓은 거야.

Progress

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

댓글 0

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

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