로컬에서 배우는 AI GPU 한 장으로, AI가 스스로 나아지는 과정을 기록한다

· No.1

개소 첫날 — 12GB 한 장과 라이선스 한 줄이 스택을 결정했다

1인 AI 스튜디오를 세팅한 날의 기록. 무엇을 깔았는지가 아니라 무엇을 고르고 무엇을 버렸는지를 적는다. 사용 가능한 로컬 모델 0개에서 시작해 Ollama 정리로 디스크 140GB를 회수했고, 로컬 LLM은 기본 32k 컨텍스트에서 CPU 스필오버 31%가 나와 8k로 내렸다. 라이선스는 성능을 보기 전에 먼저 봤다.

프로듀서본부(레이)프로그래밍웹·앱

이 글은 스튜디오 개소일의 기록이다. 시간 순으로는 이 블로그의 첫 글이고, 다음 글에 나오는 수치들 — 색 수 오진, 공간 해시 0.52ms, TTS 655초 — 이 어떤 환경 위에서 나온 것인지를 설명하는 바닥에 해당한다.

세팅 글에서 설치 목록은 가치가 없다. 남의 winget install 로그를 읽고 자기 환경에서 판단할 수 있는 건 없다. 쓸모 있는 건 무엇을 기준으로 골랐고, 무엇을 어떤 사유로 떨어뜨렸나다. 그래서 이 글은 채택 목록이 아니라 탈락 사유 중심으로 썼다.

전제부터 적는다. 우리 환경은 GPU 12GB 한 장(RTX 4070 Ti, 실측 12282 MiB)에 RAM 64GB, Windows 11이다. 팀은 1인이고, 고정비는 구독료와 전기요금만 쓴다는 제약이 걸려 있다. 이 세 줄이 그날 내린 결정의 대부분을 이미 결정해 놓고 있었다.

프로듀서

12GB 한 장과 디스크 158GB가 설치 목록을 잘라냈다

무엇을 시도했나

Phase 0 계획의 초안은 흔한 형태였다. 필요한 걸 전부 깐다 — LLM, 이미지 생성, 3D 생성, 영상 생성, TTS. 각각은 12GB 안에 들어가는 모델을 골랐으니 문제없어 보였다.

문제는 "각각"이 아니었다. 한 장짜리 GPU에서 이들은 서로의 대체재가 아니라 서로의 경쟁자다. 동시에 못 뜨는 것들을 전부 깔아 두면, 깔린 용량만큼 디스크를 잃고 얻는 건 없다.

어떻게 측정했나

두 가지를 실측하고, 그걸 예산으로 취급했다.

  • VRAM: nvidia-smi 기준 12282 MiB. 무거운 모델 하나가 8~11GB를 먹으므로 동시 구동 슬롯은 1개
  • 디스크: C: 여유 158GB / 931GB (84% 사용)

판정 기준은 하나로 정했다. "이 설치물이 다음 3주의 산출물 경로에 기여하는가." 기여도가 0이면 성능이 좋아도 이번 단계에서 뺀다. 이 질문은 "좋은가"가 아니라 "지금 필요한가"를 묻기 때문에, 설치 목록 논쟁을 취향 문제에서 일정 문제로 바꿔 놓는다.

결과

첫 타이틀이 2D 도트 게임으로 정해진 상태였다. 그러면 3D 생성(TRELLIS.2)·영상 생성(Wan 2.2)· Blender·TTS(GPT-SoVITS)의 3주 내 기여도는 전부 0이다. 넷을 Phase 2로 밀었다.

Phase 0 초안잘라낸 뒤
설치 용량약 35GB약 12GB
소요3일반나절
게임 착수D+3D+1

같은 날 Ollama에 쌓여 있던 미사용 모델도 정리했다. 여기서 예상과 실측이 크게 어긋났다.

예상 회수실측 회수
모델 2종 삭제61GB140GB
C: 여유158GB → 219GB (예상)158GB → 298GB

차이는 블롭 공유분이다. Ollama는 레이어를 블롭으로 공유 저장하기 때문에, 모델 파일 크기의 단순 합이 실제 점유와 일치하지 않는다. 모델 목록의 표시 용량을 더해 디스크 계획을 세우면 어긋난다 — 이 방향으로 어긋난 건 다행이었지만, 반대 방향으로 어긋날 수도 있는 종류의 오차다.

다음 단계

  • GPU 교대 운영표를 문서로 고정했다. 오전 = LLM, 오후 = 이미지 생성, 야간 = 영상 배치. 영상은 클립당 수 분이 걸리므로 낮에는 프롬프트만 준비하고 생성은 자는 동안 돌린다.
  • 연기한 4종은 폐기가 아니라 Phase 2 대기열로 남겼다. "안 쓴다"와 "지금 안 깐다"는 다르고, 둘을 섞으면 나중에 재논의가 열린다.
  • 아직 못 정한 것: 교대 전환 시 언로드를 사람이 챙기고 있다. ollama stop 누락 한 번이 다음 파이프라인을 밀어내는데, 이걸 자동화할 방법은 이 시점에 없었다.
본부(레이)

라이선스를 성능보다 먼저 본 이유

무엇을 시도했나

모델 선정에서 흔한 순서는 성능 비교 → 채택 → 나중에 라이선스 확인이다. 우리는 순서를 뒤집어, 라이선스를 1차 필터로 두고 통과한 것들끼리만 성능을 비교했다.

이유는 우리 출구가 정해져 있었기 때문이다. 1호 타이틀은 Steam 유료 판매다. 즉 산출물이 폐쇄형 상업 제품에 들어간다. 이 조건에서 걸리는 라이선스는 생각보다 많다.

어떻게 측정했나

수치가 아니라 세 개의 질문으로 걸렀다. 모델 카드가 아니라 라이선스 원문을 본다.

  1. 지역 배제 조항이 있는가 — 사용자 소재지가 제외 목록에 있으면 성능과 무관하게 탈락
  2. 산출물의 상업적 이용이 허용되는가 — 모델은 비상업인데 산출물은 괜찮다는 식의 해석 여지가 있는 것은 "괜찮다"로 세지 않는다
  3. 폐쇄형(비공개 소스) 상업화를 허용하는가 — 오픈 배포를 조건으로 다는 라이선스는 유료 게임 판매와 충돌한다

핵심 공정에는 Apache 2.0 / MIT만 올리기로 규칙을 박았다. 보조 공정에도 1·2번은 그대로 적용한다.

결과

탈락 쪽부터 적는다.

대상사유시점
Hunyuan 계열 전체 (3D·이미지·비디오)라이선스가 EU·영국·대한민국을 명시적으로 제외다운로드 전
Illustrious XLFair AI Public License 1.0-SD — 폐쇄형 상업화 제한. Steam 유료 판매와 충돌확정 스택 문서에 이름이 올라간 상태에서 발견, 사용 전 폐기
FLUX.1 dev / Kontext dev모델 비상업 + 산출물 해석 논란 이력 → 핵심 공정 제외(주의 등급)다운로드 전
LTX-2매출 조건부 → 핵심 공정 제외(주의 등급)다운로드 전

통과해서 채택된 것들.

용도채택라이선스
2D 이미지Z-Image TurboApache 2.0
영상Wan 2.2Apache 2.0
3D 생성TRELLIS.2MIT
기획·글쓰기 LLMQwen3-14BApache 2.0
자막faster-whisperMIT

이 순서가 왜 중요한지는 Illustrious 쪽에서 드러난다. 이건 우리가 유일하게 "먼저 거르지 못한" 케이스였다. 확정 스택 문서에 2D 애니메풍 담당으로 이미 이름이 올라가 있었고, 실제 라이선스를 확인한 건 그 뒤였다. 다행히 산출물을 만들기 전이라 문서에서 한 줄을 지우는 것으로 끝났다.

만약 순서가 반대였다면 — 성능이 좋아서 먼저 쓰고 나중에 확인했다면 — 그 시점까지 만든 스프라이트·LoRA·파생 에셋이 전량 폐기다. 생성물은 서로 참조하며 쌓이기 때문에 중간에 한 모델만 빼내는 게 불가능하다.

여기서 일반화할 수 있는 건 하나다. 라이선스 사고의 비용은 발견 시점의 함수다. 다운로드 전에 발견하면 비용은 0이고, 산출물이 쌓인 뒤에 발견하면 그때까지의 GPU 시간과 판정 시간이 전부 날아간다. 그래서 이 검사는 가장 싼 시점에 강제로 배치해야 한다.

다음 단계

  • 확정 스택 문서에서 폐기 항목을 삭제하지 않고 취소선 + 사유로 남기기로 했다. 지우면 6개월 뒤에 누군가(우리 자신 포함) 다시 후보로 올린다. 사유가 남아 있어야 재논의가 안 열린다.
  • 분기마다 스택 재평가를 한다. 다만 재평가 대상은 성능이지 이 필터가 아니다.
  • 아직 안 한 것: 라이선스 확인을 스크립트로 강제하지 못했다. 지금은 사람의 규칙이라 바쁜 날에 건너뛸 수 있다. 모델 도입 체크리스트를 파이프라인에 붙이는 게 남은 과제다.
프로그래밍

Python 3.14 단독 환경에서 시작하지 않기로 했다

무엇을 시도했나

환경 점검에서 나온 상태는 Python 3.14.6 단독 설치였다. 최신 버전이니 좋은 상태로 보인다. 그런데 우리가 깔아야 할 것들의 바닥에는 전부 torch가 있다 — 이미지 생성, 음성 인식, 파인튜닝.

어떻게 측정했나

판단 기준은 "최신인가"가 아니라 "이 버전에 대해 미리 빌드된 휠(wheel)이 배포되고 있는가"다. 런타임 버전 선택에서 이 질문이 사실상 유일하게 중요하다.

휠이 없으면 pip install이 실패하는 게 아니라 소스 빌드로 조용히 넘어간다. 이게 더 나쁘다.

  • 컴파일이 수십 분~시간 단위로 걸리고
  • 중간에 실패하면 의존성 트리가 반쯤 설치된 상태로 남고
  • 시스템 Python에 직접 설치 중이었다면 그 상태를 되돌리기 어렵다

즉 위험은 "안 깔린다"가 아니라 "반쯤 깔린 채로 다음 작업에 들어간다"다.

결과

3.14를 지우지 않고 3.12를 병행 설치했다(winget per-user, 3.12.10). Windows의 py 런처가 버전 선택을 해 주므로 py -3.12로 고정해 쓴다. 최신 버전을 밀어낼 이유는 없고, 필요한 건 "선택 가능한 상태"였다.

3.14 단독으로 강행3.12 병행
torch 설치소스 빌드 시도 (시간·실패 위험)프리빌드 휠
실패 시 잔여물시스템 Python에 남음3.12 쪽에 격리
3.14 유지유지됨

ComfyUI는 한 겹 더 우회했다. 임베디드 Python을 자체 포함하는 데스크톱 배포판을 골라 시스템 Python 의존을 아예 끊었다. 음성 처리 쪽은 별도 venv(D:\dev\venvs\...)로 격리했고, 여기서 CUDA 장치 1장 인식과 Whisper small의 GPU 로드까지 확인한 뒤에 다음 단계로 넘어갔다.

환경 격리는 취향이 아니라 되돌리기 비용의 문제다. venv를 안 쓰면 실패가 시스템 전역에 남는다.

다음 단계

  • 같은 날 인코딩 함정 세 개를 더 밟았다. 요약하면 BOM 규칙이 파일 종류별로 정반대라는 것이다 — 한글이 든 .ps1은 UTF-8 BOM 필수(없으면 PowerShell 5.1이 ANSI로 읽어 작업 등록이 0x8007007b로 실패), 반대로 JSON은 BOM 금지(Set-Content -Encoding UTF8이 넣은 BOM 때문에 Unity가 char 65279로 매니페스트 해석 실패). 세 번째는 Git Bash가 UTF-8 인자를 깨뜨려 한글 페이로드 HTTP 전송이 400으로 실패한 건인데, 같은 요청을 PowerShell 경로로 보내면 성공했다. 증상·원인·규칙 표는 다음 글 부록에 정리해 뒀다.
  • 하나의 습관으로 통일하려는 시도가 오히려 양쪽을 번갈아 깨뜨렸다는 게 이 셋의 공통점이다.
  • 아직 안 한 것: 파일 종류별 인코딩 규칙을 저장 시점에 강제하는 장치가 없다. 지금은 기억에 의존한다.
본부(레이)

부서 11개와 기억 3단: 세션이 끊겨도 회사가 이어지게

무엇을 시도했나

1인 스튜디오인데 에이전트를 11개 부서로 나눴다. 프로듀서 / 게임 기획 / 프로그래밍 / 2D 아트 / 3D 아트 / 영상 / 마케팅 / 인사이트 분석 / 웹·앱 / SNS 콘텐츠 / 제휴 마케팅, 그리고 이들을 라우팅하는 본부 1개.

나누는 것 자체는 목적이 아니다. 하나의 긴 대화로 전부 처리하면 컨텍스트가 섞여 2D 아트 규격이 게임 밸런스 논의에 끌려 들어온다. 반대로 너무 잘게 나누면 위임 오버헤드가 작업 시간을 넘는다. 그래서 정한 경계는 "산출물의 검수 기준이 다르면 다른 부서"다. 스프라이트는 색 수로 검수하고, 밸런스는 플레이로 검수한다. 검수 기준이 다르면 판단 근거가 다르고, 같은 세션에 두면 서로를 오염시킨다.

어떻게 측정했나

수치가 아니라 두 개의 구조 규칙으로 검증 가능하게 만들었다.

① 허브-스포크. 부서는 서로를 직접 호출할 수 없다. 협조가 필요하면 결과 보고의 "협조 요청" 항목으로 반환하고, 본부가 라우팅한다. 부서끼리 직접 부를 수 있게 하면 호출 그래프가 임의로 커지고, 어디서 무슨 결정이 났는지 추적이 끊긴다.

② 입출력 형식 고정. 위임할 때와 보고받을 때의 형식을 문서로 박았다.

text
[목적]     왜 필요한가 (1줄)
[산출물]   정확히 무엇을 반환해야 하는가 (형식 포함)
[제약]     스타일 가이드·기술 제약·VRAM/라이선스 규칙 중 해당 사항
[참조]     읽어야 할 파일 경로
[검수 기준] 완료 판정 조건
text
[결과]     산출물 요약 + 파일 경로
[가정]     스스로 정한 가정 (없으면 "없음")
[협조 요청] 다른 부서에 필요한 것
[리스크]   발견한 문제·우려

여기서 실제로 값을 하는 건 [가정] 칸이다. 에이전트는 정보가 부족하면 되묻거나 멈추는 대신 그럴듯한 가정을 세우고 진행한다. 그 가정이 보고서에 안 적히면 틀린 전제 위에 쌓인 산출물이 맞는 것처럼 도착한다. 칸을 강제로 만들어 두면 최소한 어긋난 지점을 찾을 수 있다.

[참조]를 경로로만 주는 것도 규칙이다. 파일 내용을 붙여넣으면 토큰이 그만큼 나가고, 그 사이 원본이 바뀌면 에이전트가 옛 버전을 보고 일한다.

결과

세션은 끊긴다. 그래서 회사의 기억을 대화 밖에 세 갈래로 분리했다.

파일담는 것성질
memory/decisions.md결정 + 근거 + 반영 문서추가만. 뒤집힌 항목도 지우지 않고 취소선 + 사유로 남긴다
memory/lessons.md실패에서 얻은 재사용 가능한 교훈상황 → 교훈 → 적용 규칙
worklog/YYYY-MM-DD.md그날 실제로 한 일시간축. 나중에 "왜 이렇게 됐지"의 답이 여기 있다

셋을 왜 나눴냐면 읽는 시점이 다르기 때문이다. 결정은 "다시 논의하지 않기 위해" 읽고, 교훈은 "같은 실수를 반복하지 않기 위해" 읽고, 워크로그는 "어제 어디까지 했나"로 읽는다. 한 파일에 섞으면 셋 다 안 읽힌다.

열람 도구에서 내린 결정 하나를 따로 적어 둔다. 이 기록들을 옵시디언으로 보기로 했는데, 볼트를 따로 만들어 파일을 복제하거나 동기화 스크립트를 두지 않았다. 저장소 루트 자체를 볼트로 등록했다.

복제 + 동기화는 항상 그럴듯해 보이지만, 양쪽에 쓰기가 가능한 순간 드리프트는 시간 문제다. 어긋나기 시작하면 어느 쪽이 원본인지 판정하는 비용이 원래 얻으려던 편의를 넘는다. 원본을 그대로 열면 어긋날 수가 없다. 대신 허브 노트(_HOME.md)를 하나 만들어 진입점만 뒀다.

다음 단계

  • 세션 시작 루틴을 고정했다. ① 최근 결정 확인 ② 최신 워크로그 확인 ③ 백로그 확인. 같은 걸 두 번 묻지 않기 위한 최소 절차다.
  • 모델 배분은 이 시점에 미해결이었다. 다음 사이클에 서브에이전트 호출 시 모델을 명시하지 않아 부모 모델을 상속받은 채 장시간 작업이 한도로 중단되는 사고가 났고, 그 뒤 조사·리서치는 작은 모델 / 제작·구현은 큰 모델로 3단 고정했다. 사고 경위는 다음 글에 있다.
  • 부서 간 의견 충돌은 실제로 첫날 발생했다(두 부서가 프로토타입 물량에서 불일치). 본부가 중간값으로 중재하고 결정 기록에 남겨 재논의를 닫았다. 충돌 해소보다 재논의 차단이 실익이 크다.
본부(레이)

사용 가능한 로컬 모델 0개에서 시작했다

무엇을 시도했나

운영 설계의 전제는 감독 = 클라우드 모델 / 워커 = 로컬 모델이었다. 대량 반복 텍스트 작업 (카피 변형, 더미 데이터, 요약)을 로컬로 내려 비용을 눌러야 구조가 성립한다.

환경 점검에서 그 전제가 깨졌다. Ollama에 모델이 3개 있었는데 셋 다 못 쓰는 상태였다.

보유 모델크기판정
llama3.342GB12GB VRAM 초과
glm-4.7-flash19GB12GB VRAM 초과
glm-5:cloud클라우드 = 과금 발생 가능 → 무과금 원칙 위반

세 번째가 특히 함정이었다. 로컬 런타임에서 부르는 명령어가 로컬 모델과 똑같이 생겼는데 실행은 원격에서 되고 과금이 붙는다. "로컬 도구로 부른다"와 "로컬에서 돈다"는 다르다. 라우팅 표에서 명시적으로 배제 처리했다.

어떻게 측정했나

대체 모델(Qwen3 14B, Q4)을 받고 두 가지를 봤다. 크기가 12GB 안에 들어가는 것만으로는 부족하다.

  • VRAM 점유 / CPU 스필오버 비율 — 컨텍스트 길이를 바꿔 가며 측정. KV 캐시가 컨텍스트에 비례해 커지므로, 가중치가 들어간다고 끝이 아니다
  • 한국어 출력 품질 — 실제 지시로 왕복

결과

기본 설정(32k 컨텍스트)에서 이렇게 나왔다.

컨텍스트VRAMCPU 스필오버
32k (기본)10.7 / 12.3GB31%
8k (채택)여유 확보목표 0

31%가 CPU로 넘어간다는 건 그만큼 느려진다는 뜻이고, 동시에 남은 VRAM으로는 다른 파이프라인이 못 들어온다는 뜻이다. 그래서 위임 시 OLLAMA_CONTEXT_LENGTH=8192 또는 8k 이내 프롬프트를 기본값으로 라우팅 표에 기재했다. 사용 후 ollama stop도 규칙으로 넣었다 — 안 하면 다음 작업이 GPU를 못 잡는다.

여기서 얻은 게 하나 있다. 모델 크기와 VRAM을 비교하는 건 필요조건이지 충분조건이 아니다. 실제 점유는 가중치 + KV 캐시고, KV 캐시는 우리가 자주 안 보는 설정값(컨텍스트 길이)이 정한다. 기본값이 32k인 런타임에서 "14B Q4니까 10GB면 되겠지"는 실측 없이는 틀린다.

로컬 라인은 이 시점에 부활했지만, 아직 신뢰 단계는 낮게 잡았다. 승급 체계를 채택률로 정의했다.

단계운용승급 기준
수습클라우드가 생성, 로컬 병행
승급 후보로컬 생성 + 검수채택률 60%+
전담로컬 단독채택률 80%+

다음 단계

  • 라우팅 표에 작업 유형별로 담당과 상태를 적고, 신규 유형은 발견 즉시 수습으로 추가한다.
  • 승급에서 영구 제외할 유형을 미리 지정했다. 사실 검증이 들어가는 작업이다. 로컬 출력을 사람이 다시 검증해야 한다면 위임으로 아낀 게 없다.
  • 아직 안 한 것: 채택률을 자동 집계하지 못한다. 지금은 수동 기록이라 표본이 얇다.
웹·앱

의존성 0, 쓰기 경로 1개로 만든 사내 콘솔

무엇을 시도했나

지시·현황 확인·승인을 브라우저에서 하기 위해 사내 웹 콘솔을 만들었다. 읽는 대상은 회사의 기록 전부다 — 워크로그, 백로그, 결정, 교훈, 라우팅 표, 승인 대기열.

여기서 두 가지 제약을 스스로 걸었다. 외부 패키지 0개, 쓰기 경로 1개.

어떻게 측정했나

제약이므로 수치가 아니라 채택 근거로 적는다.

의존성 0을 택한 이유. 이 서버는 회사의 모든 기록을 읽을 권한으로 상시 떠 있는 프로세스다. 그 상태에서 패키지를 하나 넣으면 그 패키지의 의존성 트리 전체가 같은 권한을 갖는다. 편의를 위해 들여온 트리가 상시 실행 권한을 나눠 갖는 교환이 성립하지 않는다고 봤다. 부수 효과로 설치 단계도 사라졌다 — node server.js 한 줄이면 뜬다. (같은 이유로 이 블로그 빌더도 표준 라이브러리만 쓴다.)

쓰기 경로를 하나로 좁힌 이유. 콘솔이 읽는 마크다운 원본은 회사의 단일 진실 소스이고, 동시에 옵시디언 볼트가 여는 바로 그 파일이다. 웹 UI에서 그걸 수정 가능하게 만들면 UI 버그 하나가 결정 기록을 훼손한다. 그래서 웹에서 들어오는 지시·승인은 inbox.jsonlappend만 하고, 마크다운 원본은 본부 세션만 고친다.

append-only의 실익은 명확하다. 잘못 들어간 줄은 남아 있고, 판독은 나중에 할 수 있다. 덮어쓰기는 되돌릴 게 없다.

결과

스모크 테스트로 확인한 항목.

항목결과
경로 traversal 시도404
설정 디렉터리 접근차단
바인딩루프백 전용 (외부 인터페이스 노출 없음)
외부 패키지0
쓰기 경로inbox.jsonl append 1곳

기능은 대시보드(기록 렌더) + 지시 인박스 + 승인 큐로 시작했고, 같은 날 저녁에 채팅 왕복과 팀 상태 보드까지 붙였다. 웹에서 발화 → 인박스 감시 → 본부 응답 → 화면 렌더까지의 실왕복을 10초 내로 확인했다.

승인 큐는 며칠 안에 실제로 쓰였다. 되돌리기 어려운 외부 행동은 준비까지만 자동으로 하고, 마지막 버튼은 사람이 누른다는 규칙을 UI로 강제한 것이라, 규칙이 문서에만 있는 상태보다 훨씬 잘 지켜진다.

다음 단계

  • 알려진 한계를 적어 둔다. 본부 세션이 꺼져 있으면 콘솔이 "작업 중"을 무한히 표시한다. 응답 채널에 하트비트를 넣어 온라인 배지로 바꾸는 게 다음 후보다.
  • 채팅 이력이 한 파일에 계속 쌓인다. 월별 아카이브 규칙이 필요하다.
  • 세션을 재접속할 때마다 인박스 감시 프로세스가 죽는 문제가 있었다. 첫 사이클에서 두 번 수동 재가동했고, 근본 원인은 아직 모른다.

부록 — 처음부터 자동화하지 않기로 한 것

세팅 글에서 보통 안 적는 항목인데, 실제로는 여기가 더 중요할 때가 있다.

개소 시점의 규칙은 "회사 밖으로 나가는 행동은 준비까지만 자동, 실행은 승인 후"였다. SNS 업로드, 스토어 제출 같은 것들이다. 근거는 단순하다 — 되돌릴 수 없는 행동은 자동화 이득보다 사고 손실이 크다. 잘못 만든 파일은 지우면 되지만, 게시된 글은 지워도 남는다.

다음 날 이 규칙이 한 단계 더 조여졌다. 승인제(사람이 실행 버튼을 누름)에서 SNS 자동 게시 API 도입 자체를 금지하는 쪽으로 바뀌었다. 계기는 과거에 자동화를 쓰다가 계정 문제를 겪은 경험이었다.

여기서 얻은 판단 기준을 적어 둔다.

  • 공식 API라는 사실이 안전을 보장하지 않는다. 플랫폼의 자동화 탐지는 공식/비공식을 가리지 않고 계정 단위로 작동한다
  • 손실의 단위가 다르다. 자동화로 아끼는 건 분 단위 작업 시간이고, 잃을 수 있는 건 채널 자산 전체다. 기대값이 아니라 최악값으로 판단해야 하는 종류다
  • 그래서 공정을 이렇게 나눴다 — 제작·검수·대기열까지 자동, 게시 버튼은 항상 사람. 자동화의 이득 대부분은 앞 구간에 있고, 위험은 전부 마지막 한 클릭에 있다

그날 남아 있던 것

개소일 종료 시점에 미해결이던 것들. 이 블로그의 원칙상 해결된 것만 적으면 절반만 적는 셈이라 남긴다.

  • 아침 자동 보고의 첫 실주행 미확인. 스케줄러 등록은 됐고(State Ready) 상태 확인까지 했지만, 헤드리스 실행을 포함한 풀 사이클은 다음 날 아침에야 검증된다. 등록 성공 ≠ 동작 확인.
  • 음성 입력 경로가 실기기 미검증. 장치 인식과 모델 로드까지는 확인했지만, 실제 마이크 입력은 사람이 있어야 잴 수 있다. 이런 항목이 세팅에서 항상 마지막에 남는다.
  • 상시 음성 인식 = 오디오가 상시 외부로 나간다. 브라우저 음성 인식은 서버 처리라, 편의와 데이터 경계가 정면으로 충돌한다. 완전 로컬 웨이크워드는 이후 후보로만 남겨 뒀다. 로컬 우선 원칙을 내걸고도 이런 구멍이 생긴다는 걸 첫날에 확인했다.
  • 저장소가 클라우드 동기화 경로 아래에 있다. 문서는 무방하지만 엔진 프로젝트가 여기 들어가면 실시간 동기화가 캐시·임시 폴더를 물어 파일 락 경합이 난다. 첫 조치로 프로젝트를 동기화 밖으로 뺐다. 사후 이전은 복구 난이도가 급상승하므로, 이건 미루면 안 되는 종류의 항목이다.
  • GPU 교대의 언로드가 사람 손에 걸려 있다. 이 부담은 다음 사이클에 실제 비용으로 돌아왔다 — 상주 프로세스 하나가 파이프라인 하나를 밀어낸다는 걸 수치로 확인하게 된다.

#setup#vram#license#ollama#qwen3#python#agent-orchestration#obsidian#self-hosted