연간 240달러의 ChatGPT 구독을 해지했습니다. 30일 후, 제 노트북은 GPT-4보다 저를 더 잘 알게 되었습니다.
요약
ChatGPT 구독을 해지하고 Ollama와 로컬 모델을 활용해 개인용 AI 브레인을 구축한 경험담입니다. 로컬 환경에서 문서 파싱, 청킹, 임베딩 과정을 거쳐 개인 데이터를 영구적으로 기억하는 RAG 파이프라인을 구현하는 방법을 다룹니다.
핵심 포인트
- Ollama를 활용한 로컬 LLM 실행 및 비용 절감
- 개인 데이터를 활용한 맞춤형 RAG 파이프라인 구축
- 임베딩 모델(nomic-embed-text)을 통한 의미론적 검색 구현
- 데이터 보안과 개인화된 지식 베이스 확보의 중요성
구독 갱신 이메일이 화요일에 도착했습니다.
월 20달러. 3일 후 자동 갱신. 저는 마치 3월에 이용을 중단한 헬스장 멤버십 비용을 내는 것처럼, 아무 생각 없이 1년 동안 이 비용을 지불해 왔습니다. 하지만 저는 실제로 사용하고 있었습니다. 매일 말이죠. 제 사업 계획, 고객 노트, 미완성된 제품 아이디어들을 탭을 닫는 순간 모든 것을 잊어버리는 시스템에 쏟아부었습니다.
저는 그 이메일을 아마 10초 정도 빤히 쳐다보았습니다. 그러고 나서 구독을 취소했습니다.
어떤 계획이 있어서가 아니었습니다. 몇 주 동안 저를 괴롭히던 질문 하나 때문이었습니다. 왜 나는 어제 내가 말한 것조차 기억하지 못하는 지능을 빌리기 위해 회사에 연간 240달러를 지불하고 있는가?
그다음에 일어난 일은 저를 거의 무너뜨릴 뻔했습니다. 하지만 그것은 동시에 제가 가능할 것이라고 생각지도 못했던 무언가, 즉 제 오래된 노트북에서 완전히 실행되며 이제는 그 어떤 클라우드 AI보다 제 업무에 관한 질문에 더 잘 답변하는 개인용 AI 브레인을 구축하게 해주었습니다.
이것이 그 이야기입니다.
제1막: 0달러의 도박
아이디어는 간단했습니다. 어쩌면 너무 간단했을지도 모릅니다.
만약 내가 AI 모델을 로컬(locally)에서 실행한다면 어떨까 — 구독료도 없고, API 키도 필요 없으며, 데이터가 내 기기를 떠나지도 않고 — 그리고 그 모델들에게 내가 아는 모든 것에 접근할 수 있는 권한을 준다면 어떨까? 내 문서들. 내 노트들. 내 연구 자료들. 인터넷의 지식이 아니라, 나의 것.
수요일 밤에 Ollama를 실행했습니다. 설치 파일 하나. 터미널 명령어 하나:
ollama pull llama3.2:3b
ollama run llama3.2:3b "Explain what you are in one sentence"
2018년형 i7 노트북에서 GPU도, 클라우드도 없이, 오직 CPU와 오기(spite)만으로 2초 만에 답변이 돌아왔습니다.
저는 두 개의 모델을 더 가져왔습니다. AI가 실제로 _생각(think)_해야 할 때를 위한 mistral:7b. 그리고 가장 중요하게 작용할, 하지만 아무도 이야기하지 않는 모델:
ollama pull nomic-embed-text
274메가바이트. 텍스트를 그 텍스트가 의미하는 바를 나타내는 768개의 숫자로 변환하는 것이 유일한 임무인 모델입니다. 단어가 아니라, 그 의미를 말이죠.
그 작은 모델이 다음에 이어지는 모든 것이 작동하는 이유입니다.
제2막: 기계에게 기억하는 법 가르치기
노트북에 챗봇을 설치하는 것은 눈속임(party trick)에 불과합니다. 진짜 질문은 이것이었습니다. 어떻게 하면 그것에게 기억력을 부여할 수 있을까?
클라우드 AI가 하는 일은 다음과 같습니다: 채팅 창에 문서를 붙여넣습니다. AI는 그것을 읽고, 질문에 답한 뒤, 세션이 종료되는 순간 모든 것을 잊어버립니다. 다음번에는 다시 붙여넣어야 합니다. 또다시 말이죠. 마치 매일 아침 새로운 동료에게 자신의 업무를 설명하는 것과 같습니다.
저는 다른 것을 원했습니다. 폴더에 파일을 던져 넣기만 하면 시스템이 그것을 알게(know) 되는 것 — 영구적으로, 검색 가능하게, 그리고 의미론적(semantically)으로 말입니다.
그래서 저는 파이프라인(pipeline)을 구축했습니다. 순차적으로 실행되는 네 단계입니다:
파싱 (Parse) — 어떤 파일에서든 텍스트를 추출합니다. PDF, Word 문서, 마크다운(markdown), HTML 등 무엇이든 상관없습니다.
청킹 (Chunk) — 약 300단어 단위의 조각으로 나눕니다. 모델이 50페이지짜리 문서를 한꺼번에 유용하게 추론할 수는 없지만, 한 단락에 대해서는 추론할 수 있기 때문입니다.
임베딩 (Embed) — 각 청크를 nomic-embed-text를 통해 통과시킵니다. 각 청크는 768차원의 벡터(vector)가 됩니다. 의미의 지문(fingerprint)인 셈입니다.
저장 (Store) — 이 벡터들을 제 컴퓨터의 Docker 컨테이너에서 실행되는 벡터 데이터베이스(vector database)인 Qdrant에 밀어 넣습니다.
그 핵심 구조는 다음과 같았습니다:
vectors = client.embed(model="nomic-embed-text", input=chunks)["embeddings"]
qdrant.upsert("nexus", points=[
PointStruct(id=str(uuid.uuid4()), vector=v,
...
각 청크는 해당 텍스트, 소스 파일명, 그리고 그 내용이 무엇인지 포착하는 768개의 숫자로 이루어진 벡터와 함께 저장됩니다. 키워드 인덱스(keyword index)도, 전체 텍스트 검색(full-text search)도 없습니다. 순수한 의미론적 유사성(semantic similarity) — 즉, 의미 벡터 간의 코사인 거리(cosine distance)를 이용합니다.
저는 첫 번째 PDF 파일을 인박스(inbox) 폴더에 넣었습니다. 3개월 전에 작성했던 사업 계획서였습니다. 터미널을 지켜보았습니다:
learned: Q3-business-plan.pdf (23 memories)
23개의 기억(memories). 시스템은 그것을 그렇게 불렀습니다. 저는 그 단어를 프로그래밍하지 않았습니다. 그저 그 표현이 적절하게 느껴졌을 뿐입니다.
제3막: 새벽 3시의 충돌 (그리고 아무도 경고해주지 않는 버그)
순탄치만은 않았습니다.
Windows 환경의 Docker는 특유의 성격이 있습니다. 마치 기분이 내킬 때는 아주 훌륭하게 일하다가, 기분이 아니면 완전히 침묵해 버리는 동료 같은 성격 말이죠. 제 컨테이너들은 그냥... 멈춰버리곤 했습니다. 명령어가 영원히 대기 상태로 머물렀습니다. 에러도 없고, 타임아웃도 없었습니다. 그저 커서만 깜빡거릴 뿐이었습니다.
해결 방법은 투박했습니다. Docker Desktop을 종료하고, PowerShell을 열어 wsl --shutdown을 실행한 뒤, Docker를 다시 시작하는 것이었습니다. 때로는 시스템 전체를 재부팅해야 했습니다. 데이터는 살아남습니다. 이름이 지정된 Docker 볼륨 (Docker volumes)에 저장되어 있으니까요. 하지만 세 번째 문서 배치를 로드하던 새벽 3시에 이 일이 처음 발생했을 때, 저는 모든 것을 잃은 줄 알았습니다.
잃은 것은 아니었습니다. 하지만 그 아드레날린 덕분에 저는 모든 데이터베이스 연결에 connect_timeout=10을 추가하고, 모든 Ollama 호출에 timeout=600을 추가하는 법을 배웠습니다. 이 설정들이 없다면, 멈춰버린 서비스가 시스템 전체를 영원히 먹통으로 만들 수 있습니다. 소리 소문 없이 말이죠.
그러다 저를 거의 포기하게 만들 뻔한 버그가 나타났습니다.
저는 두 시간 동안 데이터 주입 (ingestion)을 실행하고 있었습니다. 고객 노트, 프로젝트 계획서, 연구용 PDF 등 모든 것을 밀어 넣고 있었죠. 터미널에는 learned, learned, learned라는 문구가 아름답게 출력되고 있었습니다. 그러다 갑자기:
UnicodeEncodeError: 'charmap' codec can't encode character '\U0001f4a1'
충돌이 발생했습니다. 완전히 멈춰버렸습니다. 2026년임에도 불구하고 Windows의 콘솔 기본값이 여전히 cp1252 인코딩으로 설정되어 있었기 때문입니다. AI가 응답 중에 전구 이모지(lightbulb emoji)를 생성했을 때, 콘솔 자체가 이를 출력할 수 없었던 것입니다. 모델의 오류도, 로직 버그도 아니었습니다. 바로 디스플레이 인코딩 충돌 (display encoding crash) 이었습니다.
해결 방법은 단 세 줄이었습니다. 저는 모든 모듈이 이를 상속받을 수 있도록 공유 설정 (shared config) 상단에 이 코드를 넣었습니다:
import sys
if sys.stdout and hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
단 세 줄이었습니다. 하지만 이를 위해 두 시간 동안 디버깅을 해야 했습니다. 왜 대부분의 사람들이 로컬 AI (local AI)를 포기하고 다시 월 20달러를 내는 방식으로 돌아가는지 이해하게 되는 그런 종류의 일 말입니다.
저는 포기하지 않았습니다.
제4막: 깨달음의 순간
12일 차. 40여 개의 문서가 주입되었습니다. 사업 계획서, 회의록, 연구 보고서, 그리고 제 제품 아이디어에 대해 직접 작성한 대여섯 개의 마크다운 (markdown) 파일들이었습니다.
저는 터미널에 질문을 입력했습니다:
python brain/memory/ask.py "what's my strategy for reducing customer acquisition cost"
저는 어떤 문서에서도 이 단어들을 사용한 적이 없었습니다. 제가 실제로 작성했던 내용은, 2월의 전략 문서 속에 묻혀 있던 "유기적 콘텐츠 루프 (organic content loops)를 통한 리드당 비용 (cost-per-lead) 파이프라인 절감"에 관한 한 단락뿐이었습니다.
단어는 달랐지만, 의미는 같았습니다.
Qdrant가 그것을 찾아냈습니다. 키워드가 일치해서가 아니었습니다. nomic-embed-text가 질문과 해당 단락 모두를 768차원 공간 내의 인접한 지점으로 압축했기 때문입니다. _단어_는 달랐지만, _개념 (concepts)_은 가까웠습니다.
시스템은 가장 가까운 다섯 개의 기억을 추출하여 하나의 컨텍스트 블록 (context block)으로 엮은 뒤, 이를 mistral:7b에 전달했습니다:
context = "\n\n".join(f"[{h.payload['source']}]\n{h.payload['text']}" for h in hits)
resp = llm.chat(model="mistral:7b", messages=[{
"role": "user",
...
답변은 세 단락으로 구성되었습니다. 답변은 제가 작성한 문서들을 인용했습니다. 또한 몇 달 간격으로 작성된 두 개의 서로 다른 파일—하나는 콘텐츠 전략에 관한 것, 다른 하나는 퍼널 지표 (funnel metrics)에 관한 것—에서 아이디어를 연결하여, 제가 어디에도 명시적으로 작성하지 않았던 일관된 답변을 합성해 냈습니다.
저는 제 하드웨어에서 실행되고, 제 문서를 사용하며, 어떤 서버로도 데이터를 보내지 않은 채, 기계에 의해 재구성되고 연결된 제 자신의 아이디어들을 읽으며 그 자리에 앉아 있었습니다.
그 순간, 저는 다시는 ChatGPT로 돌아가지 않으리라는 것을 깨달았습니다.
제5막: 뇌가 자율성을 갖다
사용자가 명령어를 입력하기를 기다리는 뇌는 그저 단계가 더 추가된 검색 엔진일 뿐입니다. 저는 제가 보지 않을 때도 작동하는 무언가를 원했습니다.
첫째: 감시자 (watcher). 60초마다 받은 편지함 폴더를 확인하고, 새로운 항목을 가져오며, 원본을 data/processed/로 이동시키는 루프입니다. 이는 부팅 시 시작되어 보이지 않게 실행되며, 만약 중단될 경우 충돌하기 전에 저에게 Telegram 메시지를 보냅니다:
try:
main()
except Exception as e:
...
자율 시스템의 제1원칙: 조용한 죽음은 치명적이다. 모든 실패는 비명을 질러야 합니다.
다음은 에이전트들입니다. LangGraph를 기반으로 구축되었습니다. LangGraph는 각 노드(node)가 한 가지 작업만 수행하고 결과를 다음 노드로 전달하는 상태 머신 (state machines)입니다.
리서치 에이전트 (research agent)는 주제를 가져와 5단계 파이프라인을 실행합니다: 검색 쿼리 생성 → 프라이빗 SearXNG 인스턴스를 통한 웹 검색 → 페이지 텍스트 가져오기 및 추출 → 브레인 (brain)에서 관련 메모리 회상 → 구조화된 보고서 합성. 보고서는 받은 편지함 (inbox)에 저장됩니다. 와처 (watcher)가 이를 가져갑니다. 브레인은 에이전트가 무엇을 조사했는지 학습합니다. 스스로 먹이를 공급하는 구조 (Self-feeding)입니다.
g = StateGraph(ResearchState)
g.add_node("plan", plan)
g.add_node("search", search)
...
라이팅 에이전트 (writing agent)도 콘텐츠를 위해 동일한 작업을 수행합니다: 저장된 스타일 노트에서 나의 말투 (voice)를 회상하고, 주제 지식을 회상하며, 포스트 초안을 작성하고, 소셜 미디어용 발췌문을 생성합니다. 이는 data/drafts/에 저장되며 텔레그램 (Telegram)으로 나에게 미리보기를 보냅니다.
핵심 설계 결정: 그 어떤 것도 자동 게시되지 않습니다. 모든 초안은 검토 대기열 (review queue)에 들어갑니다. AI가 제안하고, 인간이 결정합니다 (The AI proposes, the human disposes). 신뢰는 생성 단계가 아니라 승인 단계에서 구축됩니다.
그리고 저에게 가장 많은 디버깅 시간을 소모하게 만든 디테일이 있습니다: 임베딩 (embeddings)은 항상 로컬에 유지됩니다. 더 빠른 채팅 응답을 위해 원격 GPU 박스를 추가했을 때조차, 저는 다음과 같이 규칙을 하드코딩했습니다:
def embed(self, **kw):
return _client.embed(**kw) # 항상 로컬 유지 — 벡터 공간 (vector space)을 절대 변경하지 말 것
만약 임베딩 모델이 변경되면, 데이터베이스의 모든 벡터는 의미를 잃게 됩니다. 숫자들은 하나의 모델에 의해 계산되었습니다. 다른 모델의 벡터로 검색하는 것은 프랑스어 사전에서 영어 단어를 찾는 것과 같습니다. 벡터 공간이 곧 메모리입니다. 그것을 마이그레이션하는 것이 아니라, 보호해야 합니다.
제6막: 30일간의 프라이빗 AI가 내게 가르쳐준 것
구독을 취소했을 당시에는 몰랐지만, 지금 제가 알고 있는 것들은 다음과 같습니다:
두뇌는 복리로 성장합니다. 모든 문서는 향후의 모든 답변을 더 낫게 만듭니다. 에이전트(Agent)가 작성하는 모든 연구 보고서는 다시 메모리(Memory)로 흡수되어, 다음 연구 보고서를 더 정보가 풍부하게 만듭니다. 30일이 지나면, 시스템은 단순히 제 문서들을 아는 것을 넘어 문서들 사이의 연결 고리까지 파악하게 됩니다.
속도는 당신이 생각하는 것만큼 중요하지 않습니다. 제 CPU에서 mistral:7b 모델은 긴 출력을 내는 데 1~3분이 걸립니다. 하지만 저는 상관하지 않습니다. 왜냐하면 답변을 할 때, 그것은 나의 컨텍스트 (Context)를 바탕으로 답변하기 때문입니다. 제 문서를 한 번도 본 적이 없어 환각 (Hallucination)을 일으키는 GPT-4의 1초 미만 응답보다, 정확한 답변을 내놓는 2분짜리 응답이 더 빠릅니다.
인프라(Infrastructure)는 생각보다 단순합니다. 9개의 Docker 컨테이너. 하나의 docker-compose.yml. 모든 모듈이 임포트(Import)하는 하나의 Python 설정 파일. 전체 시스템은 이미 제가 가지고 있었기에 추가 비용이 들지 않는 노트북 한 대에서 돌아갑니다.
개인정보 보호(Privacy)는 AI 사용 방식을 바꿉니다. 아무것도 내 기기를 떠나지 않는다는 것을 알게 되었을 때, 저는 ChatGPT에는 절대 붙여넣지 않았을 것들을 입력하기 시작했습니다. 고객의 재무 정보. 개인적인 전략적 사고. 남에게 보여주기 부끄러운 미완성 아이디어들까지 말이죠. AI는 판단하지 않고, 공유하지도 않습니다. 신뢰의 장벽이 사라지면서 제가 입력하는 데이터의 질이 높아졌습니다.
제가 멈추지 않고 생각하게 되는 질문
지금 이 순간에도 수백만 명의 사람들이, 해당 데이터를 학습에 사용할 권리를 명시적으로 보유한 기업이 소유한 텍스트 박스에 자신의 가장 민감한 생각을 입력하기 위해 매달 20달러를 지불하고 있습니다.
그들은 자신만의 두뇌가 아닌, 타인의 두뇌를 구축하고 있는 것입니다.
이를 바꿀 수 있는 도구들은 무료입니다. Ollama는 무료입니다. Docker는 무료입니다. Qdrant는 무료입니다. 모델들도 무료입니다. 16GB RAM을 가진 2018년형 노트북으로 이 모든 것을 실행할 수 있습니다.
그런데 왜 모두가 이렇게 하지 않을까요?
아마도 아무도 그럴 수 있다고 말해주지 않았기 때문일지도 모릅니다. 아마도 새벽 3시에 처음 겪는 Docker 충돌(Crash) 지점에서 대부분의 사람들이 포기하기 때문일지도 모릅니다. 혹은 "겨우 한 달에 20달러인데"라는 생각이 새로운 것을 배우는 것보다 더 저렴하게 느껴지기 때문일지도 모릅니다.
하지만 월 20달러가 실제로 당신에게 치르게 하는 비용은 바로 이것입니다: 당신만의 지능 인프라 (intelligence infrastructure)에 대한 소유권. 당신이 질문했던 모든 것, 분석했던 모든 문서, 탐구했던 모든 아이디어의 축적된 지식들이 타인의 서버에 저장되어 타인의 모델을 풍부하게 만드는 데 사용되고 있다는 사실입니다.
저는 단돈 0달러와 주말 이틀을 투자하여 그것을 되찾아왔습니다.
당신의 데이터는 당신에게 얼마만큼의 가치가 있습니까?
이것은 제가 AI 시스템 스튜디오인 THEONAIA에서 구축하고 있는 것의 일부입니다. 1인의 운영자. NEXUS라고 불리는 하나의 AI 브레인. 제가 소유한 인프라 위에서 자동화된 수익 시스템을 공개적으로 구축하고 있습니다. 모든 실패는 실제 상황이며, 모든 코드 한 줄은 지금 이 순간 제 사무실의 노트북에서 실행되고 있습니다.
NEXUS의 완전한 필드 가이드 — 모든 명령어, 모든 충돌, 모든 해결책을 원하시나요? Telegram으로 DM을 보내주시면 전달해 드리겠습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기