GitHub - chessire/shelter-puppy
Contribute to chessire/shelter-puppy development by creating an account on GitHub.
github.com
1. 강아지를 입양했다
기술을 먼저 정하고 문제를 찾은 게 아닙니다.
한 마리를 데려오고 나서야
풀어야 할 문제가 보였습니다.
AI로 무언가를 만들어보려던 참이었습니다. 도구는 손에 있는데 무엇을 풀지가 없던 흔한 상태였습니다.
최근에 강아지를 입양해왔습니다. 5월 초부터 마음을 정해두고, 아내가 매일같이 보호 글을 들여다보며 인연을 찾았습니다. 그렇게 5월 24일, 강릉의 한 보호소와 연계된 임시보호자님에게 있던 아기 강아지를 데려왔습니다.
이 아이의 사정은 이랬습니다. 떠돌이 어미가 낳은 새끼들 중 하나였고, 새끼들만 구조되었고 어미는 끝내 구조되지 못했다고 들었습니다. 세 마리 중 둘은 먼저 가족을 찾았고, 가장 오래 떠나지 못하고 남아 있던 아이가 우리에게 왔습니다.
데려오는 과정에서 예상하지 못한 걸 봤습니다. 임시보호자와 입양 희망자 사이에서 오가는 소통, 정보, 그 사이의 불편함이 분명히 존재했습니다. 사람 손만으로는 메우기 버거운 자리였습니다.
그 순간 두 가지가 겹쳤습니다. 풀 문제를 찾던 나, 그리고 눈앞에 보인 진짜 불편함. 마침 AI를 만들고 싶었던 저는 그 틈을 AI로 메울 수 있겠다 싶었습니다. 그래서 결심했습니다. 이 틈을 내 능력으로 메워보자고요.
이 글은 그 결심에서 출발한 기록입니다. 그리고 다음 이야기들은 "왜 로컬인지", "왜 이렇게 도구를 쪼갰는지"를 다뤄보고자 합니다.

2. 영상 - 왜 전부 LLM에 맡기지 않을까?
"AI한테 영상 던지고 '이 강아지 뭐 해?' 물어보면 되잖아."
이 방법은 가장 비싸고 가장 느리게 도착하는 방법입니다.
보호소 강아지의 영상들을 가지고 입양 공고 콘텐츠로 만든다고 해봅시다. 멀티모달 LLM에 영상을 통째로 밀어 넣으면 끝날 것 같습니다. 하지만 이 출발점은 비용도 속도도 가장 안 좋은 형태로 시작됩니다.
여기서 짚어야 할 게 있습니다. "AI"는 한 덩어리가 아니라 파이프라인입니다. 영상 한 편을 처리하는 데에도 성격이 다른 셋이 섞입니다.
- 고전 알고리즘 (OpenCV) - 학습이 없습니다. 수학과 규칙으로 돕니다. 빠르고, 싸고, 결과가 일정합니다.
- 학습된 전용 신경망 (YOLO) - AI지만 "검출" 한 가지에 특화돼 있습니다. 프레임마다 강아지의 박스와 위치를 찾습니다.
- 생성형 LLM (gemma) - 의미를 판단합니다. "이 강아지는 지금 사람을 반기는 중"이라는 해석. 강력하지만 느리고, 비싸고, 가끔 틀립니다.
만약 강아지가 화면 어디 있는지 박스 좌표를 찾는 일까지 LLM에 시키면 어떻게 될까요? 느리고, 부정확하고, 비용만 듭니다. 그건 YOLO가 훨씬 잘하고 싸게 하는 일입니다.
그래서 설계의 핵심은 이렇게 정리됩니다.
잘 만든 설계는 무거운 생성형 LLM을 '꼭 필요한 한 스텝'에만 씁니다. 나머지는 싸고 빠른 도구로 분리합니다.
실제 영상 한 편은 이렇게 흘러갑니다.
- 프레임 자르기·인코딩·자막 입히기 -> ffmpeg (그냥 도구)
- 강아지가 어디 있나(박스) -> YOLO (검출)
- 그 강아지를 영상 내내 같은 ID로 유지 -> ByteTrack (추적)
- 마지막에 딱 한 번, "이 장면을 입양 공고용으로 어떻게 설명할까"를 저작 -> gemma (의미·생성)
- 대본을 나레이션 음성으로 입힌다 -> mlx-audio (TTS)
작은 비영리에서 이건 취향이 아닌 비용 절감입니다. LLM 호출 한 번이 곧 비용이고 솔로 운영에서 느린 파이프라인은 곧 굴리지 못하는 파이프라인이 됩니다. 무거운 도구를 아껴 쓰는 설계가 비영리 사업을 지속 가능하게 만드는 조건이 될 수 있습니다.
이 "계층 분리"는 영상에만 해당하는 이야기가 아닙니다. 사실 이 프로젝트 전체를 관통하는 질문이고 다음 DB 이야기도 똑같은 자리에서 출발합니다.
3. DB - 왜 Postgres와 벡터DB를 같이 둘까?
하나는 "정확히 일치하는 것"을 찾고
다른 하나는 "비슷한 의미"를 찾습니다.
DB를 두 개나 쓴다고 하면 과해 보입니다. "그냥 데이터베이스 하나면 되지 않나?" 하지만 이건 중복이 아니라 2번에서 본 것과 똑같은 역할 분리입니다. 두 DB는 애초에 답하는 질문이 다릅니다.
- PostgreSQL
"정확히 일치하는 것"을 찾는다. 회원, 강아지 공고, 입양 신청처럼 행과 열로 떨어지는 데이터입니다. "보호 중이고, 중성화 완료이고, 3살 이하인 강아지" — 조건이 명확하고, 답도 딱 떨어집니다. 이러한 과정은 관계형 DB가 최적입니다. - 벡터DB(chromadb)
"비슷한 의미"를 찾는다. "사람을 잘 따르고 아파트에서도 키울 만한 순한 아이" 같은 질문은 다릅니다. 어느 칸에도 그렇게 적혀 있지 않습니다. 이건 의미가 가까운 데이터를 찾는 일이고 텍스트를 숫자 벡터로 바꿔(임베딩) 거리로 비교해야 됩니다. 관계형 DB의 WHERE 조건으로는 풀기 어려운 문제입니다.
그래서 둘은 대체재가 아닙니다. 하나는 사실을 정확히 찾고, 하나는 의미를 비슷하게 찾습니다. 응대봇이 "이 조건에 맞는 강아지"(Postgres)와 "이 느낌의 강아지"(벡터DB)를 동시에 답하려면 둘 다 필요합니다.
이게 2번의 영상 이야기와 똑같은 자리인 이유가 여기 있습니다. "만능 도구 하나로 다 해결한다"가 아니라 "질문의 성격에 맞는 도구를 선택한다". LLM에 전부 안 시키듯, DB도 한 종류에 전부 안 맡깁니다.
다만 솔직히 둘 다 끌고 가는 건 비용입니다. 운영할 DB가 둘이 되니까요. 그래서 지금은 명확히 분리해 두되, 규모가 커지면 한쪽으로 합치는 길도 열어둡니다. PostgreSQL에 벡터 검색 확장(pgvector)을 얹어 한 DB에서 사실과 의미를 같이 다루는 선택지입니다. 초기에는 역할을 선명하게 분리하고, 규모가 커지면 운영 부담을 줄이는 쪽으로 통합하려 합니다.
4. 응대봇 - 왜 로컬이며, 왜 이 모델일까?
똑똑한 모델 하나를 고르는 문제가 아닙니다.
"무엇을 사용해야 하는가"와
"어떤 일에 어떤 모델을 쓰는가"입니다.
입양 문의에 답하는 봇을 만든다고 해봅시다. 가장 쉬운 길은 외부 API(예: GPT)를 부르는 겁니다. 그런데 그 길을 택하는 순간, 1편 첫머리에서 던졌던 질문이 그대로 돌아옵니다. 무엇을 로컬에 두고 무엇을 밖에 맡길 것인가.
왜 로컬(Ollama)인가. 세 가지 이유입니다.
- 데이터. 강아지 정보, 보호 기록, 입양 신청자 문의가 매 호출마다 외부 서버로 나갑니다. 명분 사업에서 보호 동물과 신청자의 데이터를 남의 서버에 흘리는 것은 가볍지 않습니다. 로컬은 그 정보들이 내 기기 밖으로 안 흘러나갑니다.
- 비용. 외부 API는 호출당 과금입니다. 응대봇은 많이 부를수록 가치가 큰데 많이 부를수록 그대로 토큰 값이 됩니다. 로컬 모델은 전기값 외에 호출당 비용이 0입니다.
- 통제. 모델이 갑자기 바뀌거나 가격이 오르거나 정책으로 막히는 일에서 자유롭습니다. 예측 가능함이 곧 안정성입니다.
왜 이 모델 조합인가. 여기서도 2번의 "계층 분리"가 그대로 반복됩니다. 응대봇은 모델 하나가 아니라 역할이 다른 둘로 작동합니다.
- bge-m3 (임베딩) — 대화하지 않습니다. 텍스트를 숫자 벡터로 바꾸는 일만 합니다. "이 강아지 설명"과 "사용자 질문"을 같은 좌표 공간에 올려 의미가 가까운지를 잴 수 있게 만듭니다. 한국어 성능이 좋아 강아지 데이터에 적합합니다.
- gemma (생성) — 답을 만듭니다. 검색해 온 데이터를 읽고, 영상을 해석하며, 사람에게 건넬 문장으로 풀어냅니다.
이 둘이 3번의 두 DB와 맞물려 하나의 흐름이 됩니다. 이게 RAG입니다.
- 사용자가 묻습니다. "사람 잘 따르고 아파트에서도 키울 만한 아이 있어요?"
- bge-m3가 질문을 벡터로 바꾸고 벡터DB에서 의미가 가까운 강아지를 꺼냅니다. (동시에 Postgres로 "보호중, 입양가능" 같은 사실 조건도 거릅니다.)
- 그렇게 추려진 진짜 데이터를 gemma에게 건네며 답을 만들게 합니다.
RAG의 핵심은 gemma가 아는 척 지어내지 않게 만드는 겁니다. 모델의 메모리가 아니라 우리 DB의 실제 강아지 데이터를 근거로 답하니까요. 있지도 않은 강아지를 추천하는 환각은 단순 오류가 아니라 신뢰 문제입니다. RAG는 그 위험을 구조로 막습니다.
모델 사양의 선택. gemma는 26B 규모지만 MoE 구조라 토큰당 약 4B만 활성화됩니다. 전체는 메모리에 올라가되 속도는 작은 모델처럼 나오는 절충입니다. 거기에 4비트 양자화(q4_K_M)를 더해 메모리를 줄여 워크스테이션이 아닌 한 대의 맥 안에 들어오게 맞췄습니다. "가장 큰 모델"이 아니라 "이 기기에서 굴러가는 충분히 똑똑한 모델"을 고른 겁니다.
결국 이 섹션도 같은 자리로 돌아옵니다. 강력한 모델 하나로 다 하는 게 아니라 일을 쪼개 각자에게 맞는 도구를 붙이고, 그 전부를 로컬에 두는 것입니다.
5. 프론트엔드와 백엔드 - 왜 Django며 왜 Vite에서 Remix일까?
지금 필요한 것과 나중에 필요할 것은 다릅니다.
좋은 선택은 지금을 빠르게 해결하고
나중의 선택지도 닫지 않습니다.
플랫폼엔 두 축이 있습니다. 데이터를 다루는 백엔드와 화면을 그리는 프론트엔드입니다. 둘 다 선택지가 넘치는데 기준은 하나였습니다. 지금 단계에서 가장 적은 공수로 가장 멀리 가는 길.
왜 FastAPI가 아니라 Django인가.
파이썬 백엔드라면 가벼운 FastAPI도 강력한 후보입니다. 그런데 이 프로젝트는 CRUD가 많은 플랫폼으로 예상됩니다. 강아지 공고 등록과 수정, 임보자 관리, 입양 신청 처리에 데이터를 넣고 빼는 화면이 끝없이 필요합니다.
Django는 여기서 결정적인 걸 공짜로 줍니다.
- Admin 패널 내장. 공고·신청·회원 관리 화면을 자동으로 생성해줍니다. 프론트를 한 줄도 안 짜도 데이터를 넣고 바로 운영·테스트할 수 있습니다. 솔로 운영에서 이건 몇 주를 아끼는 차이입니다.
- ORM과 마이그레이션, 인증 기본 제공. FastAPI라면 직접 골라 붙여야 할 조각들이 처음부터 한 묶음으로 옵니다.
무엇보다 4번까지 만든 AI 코드(Ollama, RAG, YOLO)가 전부 파이썬입니다. Django도 파이썬이라 같은 백엔드 안에서 AI와 플랫폼 로직이 함께 돕니다. 언어가 갈리지 않는다는 것은 곧 개발 속도를 빠르게 합니다.
FastAPI의 가벼움이 빛나는 자리도 분명 있습니다. 다만 CRUD가 많은 플랫폼, 1인 운영이라는 이 조건에선 덜어주는 일의 양이 Django 쪽이 압도적이었습니다.
왜 한 번에 안 가고 단계적으로 Vite에서 Remix인가.
프론트는 처음부터 정답을 고르지 않았습니다. 단계마다 필요가 다르기 때문입니다.
- MVP 단계 = Vite + React. 지금 필요한 건 빠른 출시입니다. Vite는 가볍고 빠른 개발 환경으로 React 화면을 즉시 띄웁니다. 단점도 분명합니다. 순수 SPA라 SSR이 없어 검색 노출(SEO)과 링크 미리보기가 약합니다. MVP에선 감수할 수 있는 약점입니다. 아직 공개 공고를 검색에 태울 단계가 아니니까요.
- 프로덕트 단계 = Remix(SSR). 공개 입양 공고가 검색에 잡히고, 카톡·인스타에 링크를 붙였을 때 미리보기가 떠야 하는 순간이 옵니다. 그때 SSR이 필요해지고, Remix로 넘어갑니다. Django API 백엔드와 역할이 겹치지 않아 조합도 깔끔합니다.
그래서 핵심은 단계 전략입니다. 지금은 발견성(SEO)을 포기하고 출시 속도를 빠르게 합니다. 나중에 발견성이 필요해지면 그때 SSR로 갈아탑니다. 처음부터 Remix로 시작해 무겁게 가는 대신 지금의 문제를 가장 빨리 풀면서 나중의 선택지도 닫지 않습니다.
맺음말
다섯 개의 질문은 사실 하나인 듯합니다. 영상도, DB도, 응대봇도, 프론트엔드도, 백엔드도 전부 같은 자리로 수렴했습니다. 강력한 도구 하나로 다 풀지 않는다. 일을 쪼개 각자에게 맞는 도구를 붙인다. 그리고 가능한 많은 것을 로컬에 둔다는 것입니다.
이건 취향이 아니었습니다. 개인이 굴리는 작은 비영리에서 무거운 것을 아껴 쓰는 설계만이 지속 가능하니까요. 가장 비싼 도구를 가장 적게 쓰는 법을 아는 것, 그것이 노하우가 됩니다.
도구는 이렇게 깔았고(1편), 왜 그렇게 골랐는지도 풀었습니다(2편). 다음은 이걸로 실제로 무엇을 만드는가입니다.
이 글에서 다룬 고정 함수 분류층은 ProjectDavid의 일부입니다.
전체를 바닥부터 만드는 과정은 강의 3부작으로 정리하고 있고, 10월에 오픈 예정입니다.
→ 오픈 알림 받기
다음글
YOLO11 해상도 함정: 골든셋으로 검증 - Measurement First AI
좋은 모델이 좋은 파이프라인을 만드는 게 아닙니다.좋은 채점 기준이,모델을 갈아끼울 수 있게 해줍니다. "AI 영상 분석이면 일단 모델부터 돌려보는 거 아냐?" 틀린 말은 아닙니다. YOLO를 붙이
chessire.tistory.com
이전글
맥 로컬 LLM 구축 - Local First AI
AI는 한 덩어리가 아닙니다.역할이 다른 도구들을,한 대의 맥 위에 포개는 일입니다."유기견 입양에 AI를 붙인다"고 하면, 보통 이렇게 떠올립니다."그냥 ChatGPT API 부르면 되는 거 아냐?" 틀린 말은
chessire.tistory.com
관련글
오픈소스 LLM vs 빅테크 LLM API: AI 사업의 비용과 리스크
모델은 커모디티가 된다.마진은 판단에 남는다. 2025년 2월, OpenAI는 당시 가장 비싼 모델 GPT-4.5를 출시했습니다. 백만 토큰당 입력 75 달러, 출력 150 달러. 그리고 다섯 달이 지나기 전, API에서 제거
chessire.tistory.com
'AI > Pipeline' 카테고리의 다른 글
| LLM은 지시만: 프롬프트 오염을 막는 설계 - Ownership First AI (0) | 2026.07.23 |
|---|---|
| 로컬 TTS(mlx-audio)로 영상 타임라인 컨트롤 - Narration First AI (0) | 2026.07.20 |
| 결정론적 AI 파이프라인 설계 - Deterministic First AI (0) | 2026.07.13 |
| YOLO11 해상도 함정: 골든셋으로 검증 - Measurement First AI (0) | 2026.07.08 |
| 맥 로컬 LLM 구축 - Local First AI (0) | 2026.07.01 |
