[{"content":"1주차에는 Mac에 Ollama를 설치하고 터미널에서 모델과 대화했다. 2주차에는 Python으로 질문을 보내고, 답변을 스트리밍으로 출력하고, 대화 기록을 관리하는 코드를 공부했다.\n범위는 『Build Applications with Local AI Models on a Mac』 CH4~7이다. 모델 크기와 양자화, Python 가상환경, Ollama Python 라이브러리 사용법을 정리했다.\n1. Python에서 모델까지 # %%{init: {\"flowchart\": {\"rankSpacing\": 24, \"padding\": 10}}}%% flowchart TB subgraph MAC[\"내 Mac\"] T[\"터미널\nPython 파일 실행\"] P[\"Python 프로그램\n질문·기록·출력 관리\"] L[\"Ollama 라이브러리\n요청·응답 처리\"] S[\"Ollama 서버\n127.0.0.1:11434\"] M[\"모델 실행\nGemma 3 가중치로 추론\"] T --\u003e|\"실행\"| P P --\u003e L L --\u003e|\"HTTP 요청\"| S S --\u003e M M --\u003e|\"생성 결과\"| S S --\u003e|\"HTTP 응답\"| L L --\u003e P end 터미널에서 Python 파일을 실행하면 코드가 Ollama 라이브러리를 호출한다. 라이브러리는 로컬 서버에 HTTP 요청을 보내고, 서버는 모델을 실행해 응답을 돌려준다. Python에서는 이 응답을 출력하거나 파일에 저장한다.\n구성 요소 역할 터미널 Python 파일 실행과 출력 확인 Python 프로그램 질문, 대화 기록, 출력 관리 Ollama Python 라이브러리 서버 요청과 응답 처리 Ollama 서버 모델 로딩과 추론 관리 모델 가중치 응답 계산에 사용하는 학습된 수치 실습에는 Ollama 실행 도구, gemma3:4b 모델 파일, Python의 ollama 패키지를 사용한다. Ollama Python 라이브러리\n2. 모델 크기와 양자화 # gemma3:4b의 gemma3는 모델 계열이고, 4b는 약 40억 개 규모의 파라미터를 가진 버전을 뜻한다.\n3Blue1Brown의 LLM 설명 영상에서는 파라미터를 수많은 다이얼에 비유한다. 다이얼의 값이 바뀌면 다음 토큰에 부여하는 확률도 달라진다. 학습은 예측이 정답에 가까워지도록 이 값들을 조정하는 과정이다.\n추론에서는 학습된 가중치를 사용한다. 입력 문맥을 토큰과 벡터로 바꾸고, 여러 층의 계산을 거쳐 다음 토큰의 확률을 구한다. 선택한 토큰을 문맥에 붙여 같은 과정을 반복하면 답변이 만들어진다.\n파라미터 수가 늘면 더 복잡한 패턴을 표현할 여지가 커진다. 답변 품질에는 학습 데이터와 학습 방식, 모델 구조, 질문의 종류도 영향을 준다. 내 Mac에서 사용할 모델은 답변 품질, 생성 속도, 메모리 사용량을 함께 보며 고르려고 한다.\n수업의 기준 모델은 gemma3:4b다. Gemma 3 모델 정보\n양자화: 다이얼의 눈금을 줄이기 # 미팅에서는 양자화를 숫자 표현을 줄이는 압축으로 설명했다. 가중치 하나를 16비트로 저장하던 모델을 8비트로 표현하면, 가중치 저장에 쓰는 공간이 대략 절반으로 줄어든다. Mac의 메모리에 들어갈 모델을 고르는 데 이 차이가 영향을 준다.\n다이얼에 아주 촘촘한 눈금이 있다고 생각해보면, 양자화는 그 값을 더 적은 수의 눈금으로 옮기는 과정이다. 원래 값과 가까운 눈금에 맞추면서 수치에 근사 오차가 생긴다. 더 낮은 비트 수를 사용하면 저장 공간은 줄고, 표현할 수 있는 값의 종류도 줄어든다.\n정수 표현에 쓰는 비트 수 가능한 코드 값의 수 8비트 256개 4비트 16개 2비트 4개 실제 가중치는 그룹별 범위에 맞춰 스케일 등을 정하고 이 코드 값에 대응시킨다. 양자화 개념\n%%{init: {\"flowchart\": {\"rankSpacing\": 24, \"padding\": 10}}}%% flowchart LR A[\"가중치 범위 확인\"] --\u003e B[\"스케일과\n낮은 비트의 값 저장\"] B --\u003e C[\"근삿값으로 연산\"] 눈금 간격 0.25로 계산해보기 # 간단한 반올림으로 보면 수치가 어떻게 달라지는지 알 수 있다. 눈금 간격을 0.25로 정하고, 원래 값을 가장 가까운 눈금에 옮겨본다.\n정수 코드 q = round(원래 값 / 0.25) 복원한 근삿값 = q × 0.25 원래 값 정수 코드 q 근삿값 근삿값 − 원래 값 -0.83 -3 -0.75 +0.08 -0.27 -1 -0.25 +0.02 0.34 1 0.25 -0.09 0.91 4 1.00 +0.09 스케일과 작은 정수 값으로 원래 가중치에 가까운 수를 표현한 것이다. 모델에서는 많은 가중치에 이런 근사가 적용되며, 기법에 따라 그룹의 크기와 스케일, 중요한 값에 배정하는 정밀도가 달라진다.\n메모리에는 얼마나 차이가 날까? # 가중치 40억 개를 모두 같은 비트 수로 저장하는 조건으로 계산했다. 아래 단위는 십진 GB다.\n가중치 저장량 = 40억 × 가중치당 비트 수 ÷ 8\n가중치당 비트 수 계산한 저장량 16비트 대비 32비트 16GB 2배 16비트 8GB 기준 8비트 4GB 1/2 4비트 2GB 1/4 실제 모델 파일에는 양자화용 스케일과 메타데이터, 다른 정밀도로 저장한 구성 요소가 함께 들어간다. 실행할 때는 가중치에 더해 KV 캐시와 연산용 버퍼도 메모리를 사용한다.\n미팅에서는 macOS와 다른 앱이 쓰는 통합 메모리까지 살펴보며 모델 크기를 고르는 흐름을 설명했다. 활동 상태 보기의 메모리 압력, 모델 로딩 후의 사용량을 함께 기록할 수 있다.\n낮은 정밀도에서 답변 품질 유지하기 # 가중치를 근사하면 다음 토큰의 점수에도 변화가 생길 수 있다. 후보 토큰의 점수가 가까운 곳에서는 작은 차이가 이후 문장을 바꾸기도 한다.\n양자화는 이 오차를 줄이면서 저장량과 메모리 이동량을 낮추는 방향으로 설계한다. 학습을 마친 뒤 적용하는 PTQ와, 학습 중 양자화 효과를 반영하는 QAT가 있다. 추론 속도에는 실행 엔진과 하드웨어의 저정밀 연산 지원, 변환 비용도 영향을 준다. Hugging Face 양자화 기법\n이번 실습에서는 같은 모델의 정밀도를 바꿨을 때 한국어 설명, 계산 문제, 짧은 코드의 결과가 얼마나 유지되는지 비교해보고 싶다.\n내 모델의 Q4_K_M # /show info에서 확인한 양자화 이름은 Q4_K_M이다.\n이름의 부분 의미 Q4 주로 4비트 계열로 가중치를 표현 K 가중치를 블록으로 묶어 스케일 등을 저장하는 K 계열 방식 M 같은 계열의 S/M 구분 중 중간 크기의 양자화 구성 이 구성은 텐서에 따라 더 높은 정밀도를 섞어 사용한다. llama.cpp 구현에서도 Q4_K_M을 선택하면 일부 텐서에 Q6_K 등을 배정하는 경로를 볼 수 있다. llama.cpp 양자화 구현\n내 모델은 3.9B, Q4_K_M으로 표시됐고 다운로드된 패키지 크기는 3.4 GB였다. /show info에는 이미지 입력을 처리하는 Projector 정보도 함께 나온다.\n/show info로 본 모델 정보 # 대화 모드에서 /show info를 실행했다.\n/show info 항목 출력 값 모델 구조 gemma3 파라미터 수 3.9B 모델의 컨텍스트 길이 131072 토큰 임베딩 길이 2560 양자화 Q4_K_M 기능 completion, vision Temperature 1 Top-k 64 Top-p 0.95 Projector에는 clip, 419.82M 파라미터가 표시됐다. 이미지 입력을 처리하는 구성 요소의 정보도 함께 볼 수 있었다.\n3. 작업으로 살펴본 모델 계열 # 모델을 고를 때 내가 먼저 비교해보고 싶은 작업을 정리했다. 공부 노트 요약, 한국어 설명, 짧은 코드 작성처럼 같은 질문을 두 모델에 보내 결과를 모아볼 생각이다.\n해보고 싶은 작업 비교할 후보 기록할 항목 공부 노트 요약·설명 Gemma 3 · Llama 3.2 빠진 내용, 설명 순서, 응답 길이 한국어 질의·번역 Gemma 3 · Qwen 3.5 자연스러운 표현, 용어와 형식 유지 작은 앱의 대화 기능 Phi-4-mini · Ministral 3 메모리 사용량, 첫 응답 시간, 지시 준수 수학·코드 문제 풀이 Qwen · DeepSeek-R1-Distill 답의 정확성, 생성 토큰 수, 실행 가능한 코드 이미지와 텍스트 함께 입력 Gemma 3 · Qwen 3.5 이미지 내용 파악, 글자 읽기, 답변 근거 Gemma — 현재 실습의 기준 # Google DeepMind의 공개 가중치 모델 계열이다. 이 글에서는 gemma3:4b를 기준으로 사용한다. Gemma 3의 4B·12B·27B 모델은 텍스트와 이미지를 입력받아 텍스트를 생성하고, 1B 모델은 텍스트 입력을 다룬다. 공식 모델 카드는 질문 응답, 요약, 추론과 이미지 이해를 사용 사례로 제시한다. Gemma 3 모델 카드\n먼저 지금 모델로 결과를 모아두고 다른 계열의 답변과 비교할 예정이다.\nQwen — 같은 4B 크기에서 비교 # Alibaba의 Qwen 계열은 다국어와 코드, 추론, 시각 입력을 다루는 모델을 제공한다. 수업의 두 번째 모델은 qwen3.5:4b다. Qwen 3.5는 언어·시각 입력을 함께 학습하고 다국어 지원을 넓힌 계열이다. Qwen 3.5 4B 모델 카드\nGemma와 같은 4B 규모에서 한국어 설명의 구성과 길이, 코드의 실행 결과를 비교해볼 수 있다.\nLlama — 작은 텍스트 챗봇 후보 # Meta의 Llama 계열에는 세대별로 크기와 구조가 다른 모델이 있다. Mac에서 작은 모델부터 비교하는 후보로 Llama 3.2의 1B·3B 텍스트 모델을 골랐다. Instruct 버전은 대화, 요약, 검색 기반 응용을 위한 지시 학습을 거쳤다. Llama 3.2 3B Instruct 모델 카드\n공부 노트를 짧게 요약하는 작업에 써보고 싶다. 한국어 출력도 별도 항목으로 기록할 예정이다.\nMistral / Ministral — 작은 앱에 넣을 모델 # Mistral AI는 범용 Mistral과 소형 Ministral, 코드용 Codestral 등 작업별 모델을 제공한다. 여기서는 로컬·엣지 배포를 지향하는 Ministral 3를 비교 후보로 잡았다. Ministral 3 3B Instruct는 텍스트와 이미지를 처리하고, 함수 호출과 JSON 출력을 지원한다. Ministral 3 3B Instruct 모델 카드\n짧은 대화와 정해진 JSON 형식으로 답하게 하는 앱을 만들어볼 때 살펴볼 계열이다.\nPhi — 메모리와 대기 시간을 줄여보기 # Microsoft의 Phi 계열은 소형 모델에 집중한다. Phi-4-mini-instruct는 추론에 밀도 높은 합성 데이터와 필터링한 웹 데이터를 활용하고, 메모리·연산 자원이 제한된 환경과 수학·논리 작업을 사용 사례로 제시한다. Phi-4-mini 모델 카드\n수업 연습 문제에는 phi3:mini가 등장한다. 추가 비교에서는 Phi-4-mini도 후보로 두고 버전과 태그를 따로 기록하려 한다.\nDeepSeek — 풀이 과정이 긴 작업 # DeepSeek 계열에서는 추론용 R1과 소형 Distill 모델을 살펴봤다. DeepSeek-R1-Distill-Qwen-7B는 Qwen2.5-Math-7B를 바탕으로 R1이 생성한 예제를 사용해 학습한 모델이다. DeepSeek-R1-Distill 모델 카드\n증류는 큰 모델이 만든 예제로 작은 모델을 학습하는 과정이고, 양자화는 가중치 등의 수치를 낮은 정밀도로 표현하는 과정이다. Distill 모델에도 양자화를 적용해 배포할 수 있다. 수학 문제나 코드 오류를 설명하게 한 뒤 답의 정확성과 출력 길이를 함께 비교해보고 싶다.\n4. 모델 다운로드와 실행 # 내려받은 모델 파일은 디스크에 보관된다. 대화를 요청하면 모델을 메모리에 준비하고 입력을 처리한다. 응답 후에는 설정에 따라 모델을 메모리에 유지하다가 해제한다.\n%%{init: {\"flowchart\": {\"rankSpacing\": 24, \"padding\": 10}}}%% flowchart TD A[\"모델 다운로드\"] --\u003e B[\"디스크에 모델 파일 보관\"] B --\u003e C[\"대화 요청\"] C --\u003e D{\"모델이 메모리에\n준비되어 있는가?\"} D --\u003e|\"아니요\"| E[\"모델 로딩·실행 준비\"] D --\u003e|\"예\"| F[\"입력 처리·응답 생성\"] E --\u003e F F --\u003e G[\"응답 반환\"] G --\u003e H[\"설정에 따라 메모리에 유지\"] H --\u003e I[\"언로드 후에도\n디스크의 모델 파일은 유지\"] 명령어 동작 ollama pull gemma3:4b 모델 다운로드 ollama list 로컬 모델 목록 ollama show gemma3:4b 파라미터 수, 양자화 등 상세 정보 ollama run gemma3:4b 대화 시작 ollama ps 현재 로드된 모델 확인 ollama stop gemma3:4b 모델 언로드 ollama rm gemma3:4b 로컬 모델 삭제 list는 디스크에 보관된 모델을, ps는 현재 메모리에 로드된 모델을 보여준다. 처음 요청할 때는 모델 로딩 시간이 포함될 수 있다. Ollama CLI 문서\nollama ps의 PROCESSOR 열에는 모델의 CPU·GPU 배치 상태가 표시된다. 실제 연산 중 GPU 이용률은 활동 상태 보기 등의 도구로 확인한다.\n서버 실행과 모델 목록 # 한 터미널에서 서버를 실행하고, 다른 터미널에서 모델 목록을 조회했다.\nollama serve ollama list Ollama 0.40.11이 127.0.0.1:11434에서 실행 중이다. 서버 로그에 Apple M5 Pro와 Metal이 표시됐고, 모델 목록에는 gemma3:4b가 3.4 GB로 나왔다. 모델 ID는 68ceab7e468a다.\n같은 질문, 다른 답변 # 자료의 비결정성(nondeterministic) 설명을 보고 gemma3:4b에 Hello! who are you?를 두 번 입력했다. 첫 답변은 텍스트와 이미지를 입력받을 수 있다고 소개했고, 두 번째는 챗봇이라는 설명과 함께 이모지를 붙였다. 같은 질문 문구에 소개 방식과 표현이 달라졌다.\n샘플링을 사용하는 생성에서는 다음 토큰을 확률에 따라 선택하며, temperature와 seed 등의 설정이 결과에 영향을 준다. Ollama 생성 설정\n신경망을 10살 아이에게 설명해 달라고 요청하기 # Explain what a neural network is in simple terms, like I\u0026#39;m 10 years old. 고양이 사진을 구분하도록 강아지를 가르치는 비유로 답했다. 뉴런을 작은 일꾼과 전구에 빗대고, 층을 거치는 신호 전달과 패턴 인식, 실수를 통한 학습을 여섯 항목으로 풀어 설명했다.\n두 번째 모델 다운로드 # 비교할 두 번째 모델로 qwen3.5:4b를 내려받았다.\nollama pull qwen3.5:4b ollama list 다운로드가 success로 끝난 뒤 목록에 두 모델이 함께 표시됐다.\n모델 ID 다운로드 크기 gemma3:4b 68ceab7e468a 3.4 GB qwen3.5:4b 7f3251fa6878 4.0 GB 간단한 모델 비교 테스트 # 두 모델에 같은 질문을 보냈다.\nWhat is the meaning of life? 왼쪽: Gemma 3 · 오른쪽: Qwen 3.5 Gemma는 본문 답변이 바로 나와 Qwen보다 간결하고 빠르게 느껴졌다. 철학, 종교, 인간적인 관점으로 나눠 삶의 의미를 설명했다.\nQwen은 Thinking...이 표시된 뒤 질문 분석, 답변 방향, 내용 구성과 검토 항목을 순서대로 길게 출력했다. 답변을 준비하는 과정이 더 세분되어 보였다.\n두 모델의 show 결과 비교 # ollama show gemma3:4b ollama show qwen3.5:4b Gemma 3 Qwen 3.5 항목 Gemma 3 Qwen 3.5 모델 태그 gemma3:4b qwen3.5:4b Architecture gemma3 qwen3_5 Parameters 3.9B 4.5B Context length 131072 262144 Embedding length 2560 2560 Quantization Q4_K_M nvfp4 Capabilities completion, vision completion, vision, thinking, tools Temperature 1 1 Top-k 64 20 Top-p 0.95 0.95 Qwen의 thinking 항목에는 levels: false, true, default: true가 표시됐다. 양자화 방식과 Top-k 설정에서도 차이를 확인했다.\n연습문제: 세 모델의 중력 설명 비교 # 연습문제에서 비교할 phi3:mini를 추가로 내려받았다.\nollama pull phi3:mini 세 모델에 “다섯 살 아이에게 중력을 설명해 달라”는 같은 질문을 보냈다.\nollama run gemma3:4b \u0026#34;Explain gravity to a five-year-old.\u0026#34; ollama run qwen3.5:4b \u0026#34;Explain gravity to a five-year-old.\u0026#34; ollama run phi3:mini \u0026#34;Explain gravity to a five-year-old.\u0026#34; 모델 응답에서 본 점 Gemma 3 공을 던졌다가 떨어지는 예시와 지구의 보이지 않는 포옹에 비유해 설명했다. Qwen 3.5 긴 Thinking... 출력 뒤 미끄럼틀, 사과, 장난감의 예시를 들고 목록과 이모지를 사용했다. Phi 3 Mini 슈퍼히어로의 힘, 자석, 보이지 않는 줄을 비유로 사용해 한 문단으로 답했다. 점프 후 내려온다는 표현이 반복됐다. Gemma 3 Qwen 3.5 — 최종 답변 Qwen 3.5 — Thinking 출력 앞부분 뒷부분 Phi 3 Mini 세 모델 중에서는 Phi 3 Mini가 가장 마음에 들었다. 한 문단으로 짧게 설명해주는 방식이 좋았다.\n메모리 탐정 # ollama list ollama ps ollama show phi3:mini 질문 내 기록 내려받은 모델은 몇 개인가? 3개: gemma3:4b, qwen3.5:4b, phi3:mini 전체 디스크 공간은 얼마나 차지하는가? ollama list에 표시된 크기의 합계는 약 9.6 GB다. Gemma 3.4 GB + Qwen 4.0 GB + Phi 2.2 GB. 메모리에 로드된 모델이 있는가? ollama ps 조회 당시 phi3:mini가 로드돼 있었다. SIZE는 15 GB, PROCESSOR는 100% GPU로 표시됐다. 가장 마음에 드는 모델의 컨텍스트 길이는? Phi 3 Mini. ollama show phi3:mini의 context length는 131072토큰이었다. Phi의 show에 표시된 모델 컨텍스트 길이는 131072토큰이고, 조회 당시 ps의 실행 컨텍스트는 32768토큰이었다.\n집 정리하기 # 연습용 모델로 smollm2:135m을 내려받고 한 문장으로 자기소개를 요청했다.\nollama pull smollm2:135m ollama run smollm2:135m Introduce yourself in one sentence. 여러 분야의 일을 돕는 AI 도우미라고 한 문장으로 답했다.\n/bye로 채팅을 종료한 뒤 모델을 삭제했다.\nollama rm smollm2:135m ollama list 단계 기록 모델 다운로드 success 질문과 응답 자기소개를 한 문장으로 요청하고 응답을 받았다. 모델 삭제 deleted 'smollm2:135m' 삭제 후 목록 확인 SmolLM2가 목록에서 사라지고 Phi, Qwen, Gemma가 남았다. 도전: 원샷 모드 # 명령어 끝에 질문을 붙여 Gemma 3에 서로 다른 질문 다섯 개를 보냈다.\nollama run gemma3:4b \u0026#34;Summarize the plot of Romeo and Juliet in three sentences.\u0026#34; ollama run gemma3:4b \u0026#34;Explain photosynthesis in two sentences.\u0026#34; ollama run gemma3:4b \u0026#34;Translate \u0026#39;I enjoy learning new things\u0026#39; into Korean.\u0026#34; ollama run gemma3:4b \u0026#34;Give three tips for remembering English words.\u0026#34; ollama run gemma3:4b \u0026#34;Write a Python function that returns the larger of two numbers.\u0026#34; 요청 출력에서 본 점 로미오와 줄리엣 줄거리 세 문장 짧은 안내 문구 뒤 줄거리를 세 문장으로 출력했다. 광합성 두 문장 광합성 과정과 산소 방출을 두 문장으로 설명했다. 한국어 번역 번역 후보 세 가지와 로마자 표기, 단어와 표현에 관한 설명을 덧붙였다. 영어 단어 암기 팁 세 가지 연상법, 문장 속 활용, 간격 반복과 능동 회상을 세 항목으로 설명했다. 두 수 중 큰 값을 반환하는 Python 함수 find_larger(num1, num2) 함수와 사용 예시, 코드 설명을 작성했다. 원샷 응답 캡처 5개 줄거리 요약 광합성 설명 한국어 번역 단어 암기 방법 Python 함수 작성 짧은 번역이나 요약, 함수 작성처럼 한 번 묻고 끝나는 작업에 원샷 모드를 사용할 수 있다. 질문이 포함된 명령어를 다시 실행하거나 스크립트에 넣어 반복하기도 편하다.\n5. Python 가상환경 # Python을 설치하고 터미널에서 Python 3.13.18로 표시되는 것을 확인했다.\npython3.13 --version 프로젝트마다 필요한 패키지와 버전이 다르다. 가상환경을 만들면 각 프로젝트의 Python 패키지를 나누어 관리할 수 있다.\n%%{init: {\"flowchart\": {\"rankSpacing\": 24, \"padding\": 10}}}%% flowchart TB subgraph SHARED[\"패키지 환경을 공유하는 경우\"] A[\"프로젝트 A\n패키지 1.x 필요\"] --\u003e X[\"공유 설치 환경\n버전 충돌 가능\"] B[\"프로젝트 B\n패키지 2.x 필요\"] --\u003e X end subgraph ISOLATED[\"가상환경으로 분리하는 경우\"] C[\"챗봇 프로젝트\"] --\u003e E[\"챗봇용 .venv\n필요한 패키지와 버전\"] D[\"다른 프로젝트\"] --\u003e F[\"별도의 .venv\n다른 패키지와 버전\"] end 수업 자료는 Python 3.13의 venv와 pip를 기본으로 사용한다.\nmkdir -p ~/local-ai-study/week-02 cd ~/local-ai-study/week-02 python3.13 -m venv .venv source .venv/bin/activate python --version which python python -c \u0026#34;import sys; print(sys.executable)\u0026#34; python -m pip --version 프롬프트에 (.venv)가 붙었고, which python은 …/week-02/.venv/bin/python으로 표시됐다.\nvenv는 환경을 만드는 모듈이고, .venv는 생성할 폴더 이름이다. source .venv/bin/activate를 실행하면 현재 셸의 PATH가 바뀌어 해당 환경의 Python을 우선 사용한다.\n프로젝트에서 사용하는 Python의 위치는 sys.executable로 확인한다. 활성화를 해제할 때는 deactivate, 실행 파일을 직접 지정할 때는 .venv/bin/python을 쓴다. Python 가상환경 문서\n영상에서는 uv로 Python 3.13 환경을 만드는 방법도 소개했다. 아래는 환경 생성의 대안이다.\nuv venv --python 3.13 --seed source .venv/bin/activate --seed는 pip 같은 기본 패키지 관리 도구를 환경에 준비하는 옵션이다. uv 환경 안내\n실습 도구 버전 확인 # brew --version, ollama --version, python3 --version으로 버전을 확인했다.\n도구 버전 Homebrew 7.0.11 Ollama 0.40.11 Python 3.13.18 패키지 설치와 환경 기록 # ollama와 streamlit 패키지를 설치했다. Streamlit은 이후 웹 화면을 만들 때 사용한다.\npython -m pip install ollama python -m pip install streamlit pip list로 설치된 패키지와 버전을 확인하고, requirements.txt에 저장한 뒤 파일 내용을 확인했다.\npip list pip freeze \u0026gt; requirements.txt cat requirements.txt pip list requirements.txt 패키지 확인한 버전 ollama 0.6.3 streamlit 1.66.1 pip 26.2.2 새 환경에서는 이 파일을 읽어 패키지를 설치한다.\npython -m pip install -r requirements.txt 프로젝트를 공유할 때는 소스 코드, requirements.txt, Python 버전을 함께 남기고 .venv는 각 환경에서 다시 만든다. pip freeze 문서\n6. Python으로 질문 보내기 # VS Code에서 Python 파일 작성 # 터미널에서 code --version을 실행해 1.143.1, arm64를 확인했다.\nVS Code에서 프로젝트 폴더 ~/local-ai-study/week-02를 열고 Microsoft의 Python 확장을 설치한다. 명령 팔레트의 Python: Select Interpreter에서 앞서 만든 .venv의 Python을 선택한다. VS Code의 Python 환경 설정\nmy-ai-chatbot 폴더에서 hello.py를 실행했다.\npython3.13 hello.py 첫 질문: 프랑스의 수도 # chat_basic.py에서 gemma3:4b에 프랑스의 수도를 물었다.\nimport ollama response = ollama.chat( model=\u0026#34;gemma3:4b\u0026#34;, messages=[ {\u0026#34;role\u0026#34;: \u0026#34;user\u0026#34;, \u0026#34;content\u0026#34;: \u0026#34;What is the capital of France?\u0026#34;} ], ) print(response[\u0026#34;message\u0026#34;][\u0026#34;content\u0026#34;]) chat_basic.py 코드 화면 가상환경의 터미널에서 실행했다.\npython3 chat_basic.py 프랑스의 수도는 Paris라고 답했고, 예술·패션·미식·문화의 중심지라는 설명을 덧붙였다.\n코드 역할 ollama.chat(...) 모델에 대화 목록을 보내고 응답 받기 model 사용할 모델 messages 전달할 대화 목록 response[\u0026quot;message\u0026quot;][\u0026quot;content\u0026quot;] 응답에서 답변 텍스트 꺼내기 응답을 Python 값으로 받으면 화면 출력, 파일 저장, 다른 프로그램과의 연결에 사용할 수 있다. Ollama Python 사용법\n메시지의 역할 # 채팅 메시지는 role과 content를 묶어 표현한다. role은 메시지의 종류를, content는 실제 내용을 담는다. 이번 실습에서는 세 가지 role을 사용했다. 채팅 메시지 구조\n{\u0026#34;role\u0026#34;: \u0026#34;user\u0026#34;, \u0026#34;content\u0026#34;: \u0026#34;How does gravity work?\u0026#34;} role 담는 내용 이번 실습의 예 system 프로그램에서 정하는 응답 지침. 말투, 설명 방식, 답변 길이 등을 지정한다. 친근한 과학 선생님처럼 비유를 사용하고 100단어 미만으로 답하기 user 사용자가 보낸 질문이나 요청 How does gravity work? assistant 모델이 생성한 답변. 이전 답변도 이 role로 대화 기록에 넣는다. 트램펄린과 볼링공으로 중력을 설명한 답변 과학 선생님이나 셰익스피어 배우 같은 설정은 role=\u0026quot;system\u0026quot; 메시지의 content에 작성한다. user 메시지에는 실제 질문을 넣고, 모델이 돌려준 답변은 assistant 메시지로 이어진다.\n%%{init: {\"flowchart\": {\"rankSpacing\": 24, \"padding\": 10}}}%% flowchart LR S[\"system\n응답 지침\"] --\u003e H[\"messages\n순서대로 쌓인 대화\"] U[\"user\n사용자의 질문\"] --\u003e H A[\"assistant\n이전 모델 답변\"] --\u003e H H --\u003e M[\"Ollama·모델\"] M --\u003e R[\"새 assistant 답변\"] R -. \"대화 기록에 추가\" .-\u003e H 첫 요청은 system 지침과 user 질문으로 시작할 수 있다. 응답을 받은 뒤에는 답변을 assistant로 저장하고, 다음 user 질문을 붙여 메시지 목록을 다시 보낸다. 이전 답변을 가리키는 “방금 추천한 책을 더 설명해줘” 같은 질문에도 이 기록이 사용된다. Ollama 채팅 API\n메시지 목록은 모델에 맞는 채팅 템플릿을 거쳐 역할 구분 정보가 포함된 토큰 시퀀스로 변환된다. 모델은 이 시퀀스를 이어서 다음 출력을 생성한다. Hugging Face 채팅 템플릿 설명\nsystem 메시지로 역할 지정 # chat_system.py에는 친근한 과학 선생님처럼 재미있는 비유를 사용하고, 답변은 100단어 미만으로 작성하라는 system 메시지를 넣었다. 질문은 How does gravity work?다.\nimport ollama response = ollama.chat( model=\u0026#34;gemma3:4b\u0026#34;, messages=[ { \u0026#34;role\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;content\u0026#34;: ( \u0026#34;You are a friendly science teacher who explains \u0026#34; \u0026#34;concepts using fun analogies. Keep your answers \u0026#34; \u0026#34;under 100 words.\u0026#34; ), }, { \u0026#34;role\u0026#34;: \u0026#34;user\u0026#34;, \u0026#34;content\u0026#34;: \u0026#34;How does gravity work?\u0026#34;, }, ], ) print(response[\u0026#34;message\u0026#34;][\u0026#34;content\u0026#34;]) chat_system.py 코드 화면 python3 chat_system.py 트램펄린 가운데 볼링공을 놓으면 천이 움푹 들어가는 모습에 빗대어 중력을 설명했다. 지구처럼 질량을 가진 물체와 그쪽으로 움직이는 다른 물체를 이 비유에 연결했다.\n셰익스피어 배우 역할 # 같은 chat_system.py에서 system 메시지를 셰익스피어 배우 역할로 바꿨다. 모델은 gemma3:4b, 질문은 How does gravity work?로 유지했다.\n{ \u0026#34;role\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;content\u0026#34;: ( \u0026#34;You are a dramatic Shakespearean actor. Explain everything \u0026#34; \u0026#34;as if you\u0026#39;re performing on stage.\u0026#34; ), } 셰익스피어 배우 역할의 코드 화면 python3 chat_system.py thee, 'tis, doth 같은 옛 영어 표현을 사용해 긴 독백처럼 답했다. 지구본을 들고 몸짓하거나 목소리를 낮추고 무대를 걷는 동작도 괄호 안에 함께 출력했다.\n항목 과학 선생님 역할 셰익스피어 배우 역할 요청한 방식 재미있는 비유, 100단어 미만 무대에서 공연하듯 설명 설명에 사용한 소재 트램펄린과 볼링공 지구본과 보이지 않는 손 말투와 구성 일상적인 문장, 짧은 두 문단 옛 영어 표현, 긴 독백과 무대 동작 지문 성격 바꾸기: 같은 광합성 질문 # 01_personality_swap.py에서 gemma3:4b에 What is photosynthesis?를 물었다. 각 요청에 같은 질문을 넣고 system 메시지만 바꿨다. 실행 코드\n역할 응답에서 나타난 차이 엄격한 수학 교수 광합성의 정의, 반응식, 명반응과 캘빈 회로를 설명하고 엽록소의 기능을 되물었다. 열정적인 유치원 교사 샌드위치를 만드는 과정에 비유했다. 햇빛·물·공기를 재료로 설명하고 칭찬과 이모지를 넣었다. 까칠한 사서 식물을 작은 화학 공장에 빗대어 설명하고 Elizabeth Kolbert의 The Sixth Extinction: An Unnatural History를 추천했다. 엄격한 수학 교수 열정적인 유치원 교사 까칠한 사서 설명한 주제는 같았지만 전문 용어의 양, 비유, 말투, 마지막에 덧붙이는 내용이 달라졌다. 교수는 추가 설명을 요구했고, 교사는 그림을 그려 보자고 했으며, 사서는 책을 추천했다.\n번역 도우미 # 03_translator.py에서는 system 메시지에 번역할 언어와 출력 형식을 지정했다. 실행 코드\nSYSTEM_MESSAGE = ( \u0026#34;You are a translator. When the user gives you text, \u0026#34; \u0026#34;translate it into Japanese, Spanish, and French. \u0026#34; \u0026#34;Format your response as a clean list.\u0026#34; ) 한국어로 직업을 소개하는 문장과 나이·여행에 관한 문장을 입력했다.\n첫 문장은 세 언어로 번역했다. 두 번째 문장의 일본어 번역에는 추천해 주세요가 한국어로 남았다. 입력 문장에 여행지 추천 요청이 들어 있어도 여행지를 답하는 대신 그 요청 문장 자체를 번역했다.\n7. 스트리밍 응답 # 비스트리밍은 전체 답변이 완성된 뒤 결과를 받는다. 스트리밍은 응답 조각을 도착하는 대로 출력한다. 영상에서도 두 설정을 바꾸며 화면에 답변이 나타나는 차이를 보여줬다.\nsequenceDiagram participant P as Python 프로그램 participant O as Ollama 서버·모델 rect rgba(128, 128, 128, 0.12) Note over P,O: 비스트리밍 P-\u003e\u003eO: 질문 전송 Note over O: 답변 생성 O--\u003e\u003eP: 완성된 응답 반환 Note over P: 전체 답변 표시 end rect rgba(128, 128, 128, 0.12) Note over P,O: 스트리밍 P-\u003e\u003eO: 질문 전송 Note over O: 입력 처리 후 생성 시작 O--\u003e\u003eP: 응답 조각 O--\u003e\u003eP: 다음 응답 조각 O--\u003e\u003eP: 이후 조각·종료 정보 Note over P: 도착하는 대로 표시 end 생성 과정은 입력 문맥을 처리하는 Prefill과, 다음 토큰을 순서대로 생성하는 Decode로 나눌 수 있다.\n단계 처리 내용 Prefill 입력 토큰을 처리하고 이후 생성에 사용할 상태 준비 Decode 앞선 문맥과 생성 결과를 바탕으로 다음 토큰 계산 스트리밍에서는 응답이 완성되기 전부터 내용을 읽을 수 있다. 첫 출력까지의 대기 시간에는 모델 로딩과 입력 처리 시간이 영향을 준다. 전체 완료 시간과 첫 출력 시간은 각각 측정한다. Ollama 스트리밍 설명\nchat_stream.py 실행 # chat_stream.py에서 인터넷이 어떻게 작동하는지 쉽게 설명해 달라고 요청했다. stream=True를 설정하고 응답 조각을 받을 때마다 출력했다.\nimport ollama stream = ollama.chat( model=\u0026#34;gemma3:4b\u0026#34;, messages=[ { \u0026#34;role\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;content\u0026#34;: ( \u0026#34;You are a helpful assistant. Provide detailed, \u0026#34; \u0026#34;thoughtful answers.\u0026#34; ), }, { \u0026#34;role\u0026#34;: \u0026#34;user\u0026#34;, \u0026#34;content\u0026#34;: \u0026#34;Explain how the internet works in simple terms.\u0026#34;, }, ], stream=True, ) for chunk in stream: print(chunk[\u0026#34;message\u0026#34;][\u0026#34;content\u0026#34;], end=\u0026#34;\u0026#34;, flush=True) print() chat_stream.py 코드 화면 end=\u0026quot;\u0026quot;는 조각마다 줄바꿈을 붙이지 않는 설정이고, flush=True는 출력 버퍼를 즉시 비우도록 요청하는 설정이다. 마지막 print()는 답변이 끝난 뒤 줄바꿈을 추가한다.\npython3 chat_stream.py 응답 앞부분 응답 뒷부분 인터넷을 우편 서비스에 비유하면서 패킷, IP 주소, 라우터, TCP/IP, DNS를 단계별로 설명했다. 뒤에서는 레시피를 여러 조각으로 나눠 친구에게 보내는 비유도 덧붙였다.\n응답 시간 측정 # 요청 후 첫 번째 비어 있지 않은 응답 조각을 화면에 출력하기까지의 시간과 전체 응답이 끝날 때까지의 시간을 각각 잰다. Python의 time.perf_counter()를 요청 전후에 호출해 경과 시간을 구할 수 있다. Python 시간 측정 함수\nOllama 응답의 load_duration, eval_count, eval_duration으로 모델 로딩 시간과 출력 토큰 수, 생성 시간을 살펴볼 수 있다. 시간 필드는 나노초 단위이며, 스트리밍의 사용량 정보는 마지막 조각에 담긴다. Ollama 측정 지표\n04_stream_timer.py에서는 요청 직전에 측정을 시작하고, 첫 텍스트를 출력한 시점과 응답 반복문이 끝난 시점을 기록했다. 실행 코드\n측정 항목 결과 첫 텍스트 출력까지 0.101초 전체 응답 완료까지 16.331초 모델 로딩 0.001초 출력 토큰 수 1,138 8. 대화 기록 유지하기 # chat_history.py를 실행해 이름을 알려준 뒤 다시 물었다. 답변에 앞서 입력한 이름인 빵주야가 다시 나왔다.\n%%{init: {\"flowchart\": {\"rankSpacing\": 24, \"padding\": 10}}}%% flowchart TD S[\"system 메시지로\nhistory 초기화\"] --\u003e I[\"사용자 입력\"] I --\u003e Q{\"종료 명령인가?\"} Q --\u003e|\"예\"| E[\"프로그램 종료\"] Q --\u003e|\"아니요\"| U[\"history에\nuser 메시지 추가\"] U --\u003e M[\"messages=history로\nOllama에 요청\"] M --\u003e R[\"응답 조각 출력\nresponse_text에 누적\"] R --\u003e A[\"완성된 답변을\nassistant 메시지로 추가\"] A --\u003e I 두 번째 질문을 보낼 때 history에는 다음 순서로 메시지가 들어간다.\n순서 role 내용 1 system 친절하게 돕고, 간결하면서도 꼼꼼하게 답하라는 지침 2 user 이름 소개 3 assistant 이름을 부르며 인사한 답변 4 user 이름을 다시 묻는 질문 messages=history로 이 목록 전체를 보내면서 이전 소개와 답변도 다음 요청에 함께 전달했다.\n스트리밍과 대화 기록을 합친 코드 # 실행한 chat_history.py 코드다.\nimport ollama history = [ { \u0026#34;role\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;content\u0026#34;: ( \u0026#34;You are a friendly and helpful assistant. \u0026#34; \u0026#34;Be concise but thorough in your answers.\u0026#34; ), } ] print(\u0026#34;Chat with AI! (type \u0026#39;quit\u0026#39;, \u0026#39;exit\u0026#39;, or \u0026#39;bye\u0026#39; to exit)\u0026#34;) print(\u0026#34;-\u0026#34; * 40) while True: user_input = input(\u0026#34;\\nYou: \u0026#34;) if user_input.lower() in (\u0026#34;quit\u0026#34;, \u0026#34;exit\u0026#34;, \u0026#34;bye\u0026#34;): print(\u0026#34;\\nGoodbye!\u0026#34;) break history.append({ \u0026#34;role\u0026#34;: \u0026#34;user\u0026#34;, \u0026#34;content\u0026#34;: user_input, }) stream = ollama.chat( model=\u0026#34;gemma3:4b\u0026#34;, messages=history, stream=True, ) print(\u0026#34;\\nAI: \u0026#34;, end=\u0026#34;\u0026#34;) response_text = \u0026#34;\u0026#34; for chunk in stream: piece = chunk[\u0026#34;message\u0026#34;][\u0026#34;content\u0026#34;] print(piece, end=\u0026#34;\u0026#34;, flush=True) response_text += piece print() history.append({ \u0026#34;role\u0026#34;: \u0026#34;assistant\u0026#34;, \u0026#34;content\u0026#34;: response_text, }) chat_history.py 코드 화면 response_text에는 화면에 출력한 조각을 계속 이어 붙인다. 응답이 끝나면 이 문자열을 assistant 메시지로 history에 추가하고 다음 입력을 받는다.\npython3 chat_history.py chat_history.py 실행 시작 화면 입력 응답·결과 이름 소개 이름을 부르며 인사했다. 이름을 다시 묻기 You already told me your name is 빵주야!라고 답했다. 초보 프로그래머에게 책 추천 요청 Al Sweigart의 Automate the Boring Stuff with Python을 추천했다. quit Goodbye!를 출력하고 종료했다. 코드에서는 quit, exit, bye를 입력하면 while 반복문을 끝내도록 작성했다.\n퀴즈 봇 # 02_quiz_bot.py에서도 질문과 답변을 history에 누적했다. system 메시지에는 한 번에 한 문제를 내고, 답변 뒤 정답 여부와 해설을 알려 주며 점수를 유지하도록 요청했다. 실행 코드\nStart the quiz!를 입력하자 상대성이론을 정립한 과학자를 묻는 객관식 문제가 나왔다. B를 입력하니 Albert Einstein이 정답이라고 답하고 상대성이론에 대한 해설을 덧붙였다.\n9. 대화 저장과 컨텍스트 # 대화에 사용하는 정보는 여러 곳에 나뉘어 있다.\n구분 보관하는 내용 모델 가중치 학습 과정에서 조정된 수치 Python의 history 현재 프로그램의 메시지 목록 대화 로그 파일 다음 실행에서도 읽을 수 있도록 저장한 메시지 추론 캐시 계산 재사용을 위한 실행 상태 일반적인 대화 요청은 준비된 가중치로 응답을 계산한다. 대화의 문맥은 프로그램이 messages에 구성해 전달한다.\n대화를 텍스트 파일로 저장 # 05_conversation_logger.py를 실행해 대화한 뒤 chat_log.txt를 열었다. system, user, assistant 메시지가 순서대로 저장돼 있었다. 실행 코드\nwith args.output.open(\u0026#34;w\u0026#34;, encoding=\u0026#34;utf-8\u0026#34;) as file: for message in history: file.write(f\u0026#34;[{message[\u0026#39;role\u0026#39;].upper()}]\\n{message[\u0026#39;content\u0026#39;]}\\n\\n\u0026#34;) 이 코드는 while 반복문 뒤에 둔다. quit, exit, bye로 반복문을 끝내면 누적한 대화 목록을 UTF-8 텍스트로 저장한다. 기본 저장 경로는 Path(__file__).with_name(\u0026quot;chat_log.txt\u0026quot;)로 지정했다.\n저장 위치를 묻자 모델은 Google에 저장된다고 답했다. 실제 파일은 실행한 Python 코드에 따라 프로젝트의 ch7_exercises/chat_log.txt에 생성됐다.\n메시지 구조를 유지하는 JSON 저장 # role과 content를 다시 읽어 대화 목록으로 사용하려면 JSON으로 저장할 수 있다.\nimport json from pathlib import Path log_path = Path(__file__).with_name(\u0026#34;chat_log.json\u0026#34;) log_path.write_text( json.dumps(history, ensure_ascii=False, indent=2), encoding=\u0026#34;utf-8\u0026#34;, ) 파일은 스크립트와 같은 폴더에 저장되며, 이 예시는 기존 파일을 덮어쓴다. 다음 실행에서 대화를 이어가려면 파일을 읽어 history를 복원한다.\n컨텍스트 윈도우 # 컨텍스트 윈도우는 모델이 한 번에 다룰 수 있는 토큰 범위다. 역할 지시, 이전 대화, 새 질문이 문맥을 구성하고 생성할 응답도 이 범위 안에서 다뤄진다.\nollama show에서는 모델 정보를, ollama ps에서는 실행 중인 모델의 상태를 확인한다.\nollama show gemma3:4b ollama ps 모델이 지원하는 최대 길이와 현재 실행에 할당된 길이를 각각 살펴본다. 큰 컨텍스트는 더 많은 메모리를 요구할 수 있다. 긴 대화에서는 최근 메시지를 유지하거나 이전 대화를 요약해 전달하는 방식으로 입력을 구성한다. Ollama 컨텍스트 설명\n10. 두 모델의 토론 # 06_debate.py에서 gemma3:4b는 고양이, phi3:mini는 강아지가 더 좋은 반려동물이라는 입장을 맡도록 설정했다. 각 모델에 별도의 대화 기록을 두고, 상대의 응답을 다음 입력으로 전달했다. 실행 코드\n모델 system 메시지 gemma3:4b You believe cats are better pets than dogs. Argue your position. phi3:mini You believe dogs are better pets than cats. Argue your position. 첫 질문은 Why are cats the best pets?로 시작했다.\n발언 모델 A의 기록 모델 B의 기록 A가 한 말 assistant user B가 한 말 user assistant 각 모델은 자기 발언을 assistant, 상대 발언을 user로 받는다. 정해진 횟수만큼 반복하면 토론 루프가 된다.\n토론 실행 중 고양이의 장점을 설명하는 구간에서 The Joy of Discovery, The Connection to Nature, The Sense of Peace, The Legacy of Kindness라는 제목과 문단이 반복됐다.\n코드는 한 모델의 응답을 끝까지 받은 뒤 상대 모델을 호출한다. 한 번의 답변이 길어지면 다음 발언으로 넘어가는 시간도 길어진다.\n11. 정리 # 공부한 내용 정리 모델 크기와 양자화 파라미터 수와 수치의 저장 정밀도가 모델 파일 크기와 실행 메모리에 영향을 준다. 모델 정보와 실제 응답을 함께 살펴봤다. Python 실행 환경 .venv로 패키지 환경을 나누고, requirements.txt에 설치 버전을 기록했다. 메시지 역할 system에 응답 지침을, user에 질문을 넣는다. 모델 답변은 assistant로 기록한다. 같은 질문도 역할 지침에 따라 말투와 설명 방식이 달라졌다. 스트리밍 stream=True로 응답 조각을 받아 즉시 출력했다. 첫 텍스트가 나타나는 시간과 전체 응답이 끝나는 시간을 따로 측정했다. 대화 기록 질문과 답변을 history에 순서대로 쌓고 다음 요청에 함께 보냈다. 앞서 알려 준 이름을 다시 묻는 대화로 문맥 유지를 확인했다. 파일 저장 대화 목록을 텍스트 파일로 저장했다. role과 content 구조를 유지하는 JSON 저장 방식도 정리했다. 두 모델 연결 각 모델의 대화 기록을 따로 관리하고, 한쪽의 답변을 다른 쪽의 user 메시지로 전달했다. 실행 중 같은 문단이 반복되는 모습도 관찰했다. ","date":"2026.11.01","externalUrl":null,"permalink":"/local-ai-models-on-a-mac/week-02/","section":"Local AI Models on a Mac","summary":"모델 크기와 양자화, Python 가상환경부터 Ollama 호출, 스트리밍과 대화 기록까지. 2주차 공부 기록.","title":"[2주차] Python으로 로컬 AI 챗봇 만들기: 모델, 가상환경, 스트리밍과 대화 기록","type":"local-ai-models-on-a-mac"},{"content":"『Build Applications with Local AI Models on a Mac』을 따라 Mac에서 로컬 AI 모델을 실행하고 애플리케이션을 만드는 스터디 기록입니다.\nOllama, MLX Whisper, Python, Streamlit 등을 공부하며 이해한 내용과 실습 과정을 남깁니다.\n","date":"2026.11.01","externalUrl":null,"permalink":"/local-ai-models-on-a-mac/","section":"Local AI Models on a Mac","summary":"『Build Applications with Local AI Models on a Mac』을 따라 Mac에서 로컬 AI 모델을 실행하고 애플리케이션을 만드는 스터디 기록입니다.\nOllama, MLX Whisper, Python, Streamlit 등을 공부하며 이해한 내용과 실습 과정을 남깁니다.\n","title":"Local AI Models on a Mac","type":"local-ai-models-on-a-mac"},{"content":"","date":"2026.11.01","externalUrl":null,"permalink":"/series/local-ai-models-on-a-mac/","section":"Series","summary":"","title":"Local AI Models on a Mac","type":"series"},{"content":"","date":"2026.11.01","externalUrl":null,"permalink":"/tags/mac/","section":"Tags","summary":"","title":"Mac","type":"tags"},{"content":"","date":"2026.11.01","externalUrl":null,"permalink":"/tags/ollama/","section":"Tags","summary":"","title":"Ollama","type":"tags"},{"content":"","date":"2026.11.01","externalUrl":null,"permalink":"/tags/python/","section":"Tags","summary":"","title":"Python","type":"tags"},{"content":"","date":"2026.11.01","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"},{"content":"","date":"2026.11.01","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"2026.11.01","externalUrl":null,"permalink":"/tags/%EA%B0%80%EC%83%81%ED%99%98%EA%B2%BD/","section":"Tags","summary":"","title":"가상환경","type":"tags"},{"content":"","date":"2026.11.01","externalUrl":null,"permalink":"/tags/%EB%A1%9C%EC%BB%AC-ai/","section":"Tags","summary":"","title":"로컬 AI","type":"tags"},{"content":"YOUNGSPLACE · LEARNING ARCHIVE 읽고 끝내지 않기. 이해한 것을 내 언어로 남기기.\n사진과 코드, 논문과 실험을 오가며 쌓아가는 공부의 기록입니다.\n01 / STUDYLocal AI Models on a MacMac에서 로컬 AI 모델을 공부하는 스터디 기록. 02 / LEARN공부 노트개념과 코드, 직접 해본 실험. 03 / READ논문 리뷰핵심 질문부터 나의 해석까지. 04 / OBSERVE사진 기록눈에 담은 장면과 배운 것들. 05 / READ \u0026 REMEMBER서재읽은 책과, 책장을 덮고도 남은 생각들. ","date":"2026.11.01","externalUrl":null,"permalink":"/","section":"배운 것을, 내 것으로 만드는 기록.","summary":"YOUNGSPLACE · LEARNING ARCHIVE 읽고 끝내지 않기. 이해한 것을 내 언어로 남기기.\n사진과 코드, 논문과 실험을 오가며 쌓아가는 공부의 기록입니다.\n01 / STUDYLocal AI Models on a MacMac에서 로컬 AI 모델을 공부하는 스터디 기록. 02 / LEARN공부 노트개념과 코드, 직접 해본 실험. 03 / READ논문 리뷰핵심 질문부터 나의 해석까지. 04 / OBSERVE사진 기록눈에 담은 장면과 배운 것들. 05 / READ \u0026 REMEMBER서재읽은 책과, 책장을 덮고도 남은 생각들. ","title":"배운 것을, 내 것으로 만드는 기록.","type":"page"},{"content":"","date":"2026.11.01","externalUrl":null,"permalink":"/tags/%EC%B1%97%EB%B4%87/","section":"Tags","summary":"","title":"챗봇","type":"tags"},{"content":"AI 서비스를 사용하는 데서 한 걸음 더 나아가, 내 Mac에서 모델을 직접 실행해 보기로 했다. 이번 스터디에서는 『Build Applications with Local AI Models on a Mac』을 따라 로컬 AI 애플리케이션을 만들어 간다.\n1주차의 범위는 1~3장이다. 왜 로컬 AI를 쓰는지 이해하고, 터미널과 Homebrew에 익숙해진 뒤 Ollama를 준비한다. 스터디 자료에 포함된 4장 미리 실습에서는 gemma3:4b 모델을 내려받아 대화하는 흐름도 살펴본다.\n1. 왜 AI를 내 컴퓨터에서 실행할까? # 클라우드 AI는 설치 부담이 작고 강력한 모델을 바로 사용할 수 있다는 장점이 있다. 그렇다면 로컬 AI는 어떤 경우에 의미가 있을까?\n스터디에서 다룬 내용을 내 기준으로 정리하면 데이터의 이동, 실행 환경의 통제, 작동 원리에 대한 이해로 나눌 수 있다.\n비교 기준 클라우드 AI 로컬 AI 추론이 실행되는 곳 서비스 제공자의 서버 내 컴퓨터 입력 데이터 사용하는 서비스로 전송 로컬 추론 경로 안에서 처리 가능 준비 과정 서비스 가입·접속 중심 실행 도구와 모델 준비 필요 실행 제약 서비스 정책과 사용 한도 내 기기의 메모리·연산 성능 로컬이라는 이유만으로 애플리케이션 전체가 자동으로 오프라인이 되는 것은 아니다. 모델 다운로드에는 인터넷이 필요하고, 검색이나 외부 API를 연결했다면 그 부분에서는 통신이 발생한다. 어떤 모델을 어디서 실행하고, 어떤 데이터가 밖으로 나가는지를 구분해서 보는 것이 중요하다.\n이번 스터디에서는 가장 큰 모델을 쓰는 것보다, 모델을 실행하고 애플리케이션과 연결하는 과정을 이해하는 데 초점을 맞추려 한다.\n2. 미팅에서 짚은 개념: 모델, 가중치, 통합 메모리 # 설치 과정뿐 아니라 LLM이 작동하는 방식과 Mac 하드웨어의 특징도 함께 다뤘다. 미팅 녹화에서 설명한 내용을 다음처럼 정리했다.\n학습과 추론은 다르다 # 학습은 데이터를 바탕으로 모델의 가중치를 조정하는 과정이고, 추론은 준비된 가중치를 이용해 입력에 대한 출력을 계산하는 과정이다. 이번 주의 ollama pull과 ollama run은 이미 학습된 모델을 내려받아 추론하는 흐름이다. 모델을 다운로드한다고 해서 내가 직접 모델을 학습시키는 것은 아니다.\nLLM은 다음 토큰을 이어 만든다 # 미팅에서는 Transformer Explainer로 GPT-2 Small의 동작을 살펴봤다. 입력 문장은 토큰과 벡터 표현으로 바뀌고, 여러 Transformer 블록을 거쳐 다음 토큰의 확률을 계산한다. 생성된 토큰을 문맥에 붙여 같은 과정을 이어 가며 응답을 만든다.\n여기서 토큰은 항상 단어 하나와 일치하지 않는다. 또 여러 Transformer 블록을 통과하는 것과 학습 데이터를 반복해서 읽는 에포크(epoch)는 다른 개념이다. 이 둘을 구분해서 기억해 두려 한다.\nMac에서는 메모리 구조도 함께 봐야 한다 # GPU는 행렬곱처럼 병렬화하기 좋은 계산을 처리하는 데 유리하다. 다만 CPU에서도 모델을 실행할 수 있으므로, GPU가 없으면 추론 자체가 불가능하다는 뜻은 아니다.\nApple Silicon의 통합 메모리는 CPU와 GPU가 같은 메모리 풀을 활용하는 구조다. 모델 크기를 고를 때는 메모리 총량뿐 아니라 운영체제와 다른 앱이 사용하는 공간, 실행 중 필요한 추가 메모리도 고려해야 한다. Apple의 MLX 설명도 이 구조와 CPU·GPU 연산을 함께 소개한다.\n따라서 다음 실습에서는 칩 이름만 적기보다 메모리 용량과 실제 사용한 모델 태그를 함께 남기려고 한다.\n3. 이번 스터디가 만들려는 애플리케이션 # 최종 목표는 Mac 안에서 음성 입력을 받아 답하는 로컬 채팅 애플리케이션이다. 미팅 초반에 설명한 구성은 다음과 같다.\n마이크 음성 → MLX Whisper: 음성을 텍스트로 변환 → Ollama + 로컬 LLM: 응답 생성 → Streamlit 웹 화면: 사용자에게 표시 Ollama는 모델 자체가 아니라 모델을 실행하는 런타임이다. 실행 도구와 그 안에서 사용하는 모델을 나눠 이해하면, 이후 Python 코드와 연결하는 과정도 더 명확해진다.\n4. 터미널: 현재 위치부터 확인하기 # Ollama를 실행하기 전에 터미널의 기본 동작부터 익힌다. 처음부터 많은 명령어를 외우기보다, 지금 어디에 있고 어떤 파일이 있는지 확인하는 흐름부터 잡는다.\n명령어 역할 pwd 현재 작업 중인 디렉터리 확인 ls 현재 디렉터리의 파일과 폴더 목록 확인 cd 다른 디렉터리로 이동 mkdir 새 디렉터리 생성 스터디용 폴더를 만드는 예시는 다음과 같다.\npwd mkdir -p ~/local-ai-study/week-01 cd ~/local-ai-study/week-01 pwd ls -la ~는 내 홈 디렉터리를 뜻한다. 폴더 이름에 공백이 있다면 cd \u0026quot;My Folder\u0026quot;처럼 경로를 따옴표로 묶는다.\n명령어를 복사할 때는 설명에 붙은 $나 % 같은 프롬프트 기호까지 입력하지 않도록 구분한다. 명령어와 실행 결과도 따로 기록해 두면 나중에 같은 환경을 다시 준비할 때 도움이 된다.\n5. Homebrew: 설치와 경로 설정은 별개다 # Homebrew는 필요한 개발 도구를 명령줄에서 설치하고 관리하는 패키지 매니저다. 설치 명령어는 바뀔 수 있으므로 Homebrew 공식 사이트에서 확인한다.\n설치 후에는 안내문에 표시된 Next steps도 확인해야 한다. 프로그램이 설치되어 있어도 셸이 실행 파일의 위치를 찾지 못하면 명령어를 사용할 수 없기 때문이다. 이때 관련되는 설정이 PATH다.\nApple Silicon Mac의 일반적인 Homebrew 설치 경로는 /opt/homebrew다. 다만 경로를 외워서 적용하기보다 설치 프로그램이 내 환경에 맞춰 출력한 안내를 따르는 편이 정확하다. Homebrew 공식 설명\n설치 확인에는 다음 명령어를 사용한다.\nbrew --version brew doctor 첫 번째는 버전을, 두 번째는 환경의 잠재적인 문제를 확인한다. brew doctor의 경고가 곧 설치 실패를 뜻하는 것은 아니므로 내용을 읽고 판단한다.\n1주차 자료에서는 wget으로 패키지 설치를 연습한다.\nbrew install wget wget --version 설치와 업데이트도 구분해 둔다. brew update는 Homebrew와 패키지 정보를 갱신하고, brew upgrade는 설치된 패키지를 업그레이드한다. Homebrew 명령어 문서\n6. Ollama: 서버 창과 명령어 창을 나누기 # Ollama는 모델을 내려받고 실행하는 도구다. 이번 실습은 Homebrew로 설치한 CLI를 기준으로 정리한다.\nbrew install ollama ollama --version 가장 헷갈리기 쉬운 부분은 Ollama 서버를 실행한 터미널은 계속 요청을 기다리고 있다는 점이다. 명령어가 멈춘 것처럼 보여도 서버가 실행 중인 상태일 수 있다.\n터미널 A: 서버 실행 # ollama serve 이 창은 서버 실행용으로 둔다. 이미 Ollama 앱이나 다른 서비스로 서버가 실행 중이라면, 같은 서버를 중복으로 시작할 필요는 없다. Ollama 설치 정보 · CLI 문서\n터미널 B: 모델 준비와 대화 # 새 터미널 창을 열어 모델을 내려받고 목록을 확인한다.\nollama pull gemma3:4b ollama list 그다음 대화형 실행을 시작한다.\nollama run gemma3:4b 실행 후 프롬프트에 다음처럼 입력해 본다.\nHello! Who are you? 스터디에서 사용한 모델 태그는 gemma3:4b다. 다른 모델과 비교할 때도 태그를 함께 남겨야 같은 조건인지 확인할 수 있다. 모델의 실제 내려받기 용량은 사용하는 태그와 배포 파일에 따라 확인한다. Gemma 3 모델 페이지\n대화에서 나갈 때는 /bye를 입력한다. 이것은 대화형 클라이언트 종료이며, 별도 창에서 실행한 서버까지 종료하는 것은 아니다. 직접 ollama serve로 띄운 서버를 중지하려면 해당 창에서 Ctrl+C를 누른다.\n7. 설치 성공과 모델 실행 성공을 따로 확인하기 # 서버 시작 로그와 추가 터미널에서의 요청 확인을 함께 보여 준다. 특히 Listening on 127.0.0.1:11434는 로컬 주소와 포트에서 요청을 기다린다는 의미다.\n실습 기록에서는 다음 상태를 구분해 두려 한다.\nHomebrew 명령어를 찾을 수 있는가? Ollama가 설치되어 있는가? Ollama 서버가 실행 중인가? 모델이 내려받아졌는가? 선택한 모델로 응답을 생성할 수 있는가? 예를 들어 ollama --version이 보인다고 해서 모델까지 준비된 것은 아니다. 서버 연결 오류와 모델 다운로드 문제도 서로 다른 단계에서 발생한다. 문제가 생겼을 때는 실패한 명령어와 오류 메시지를 그대로 남기고, 어느 단계까지 성공했는지 함께 적어 두는 편이 좋다.\n8. 내 실습 기록 # 항목 내 기록 Mac 모델 / 칩 메모리 / macOS 버전 Homebrew 버전 Ollama 버전 실행한 모델 태그 첫 질문과 모델의 응답 Ollama GPU 점유 확인 이번 주 정리 # 이번 주의 출발점은 모델의 성능 비교보다 실행 환경의 구조를 이해하는 것이다. 터미널로 작업 위치를 확인하고, Homebrew로 도구를 설치하고, Ollama 서버와 모델을 구분해서 실행한다. 다음 실습에서는 같은 모델에 한국어 질문도 던져 보고, 어떤 응답이 나오는지 내 환경과 함께 남겨보려 한다. 이후 Python과 연결할 때도 서버와 클라이언트를 나눠 이해한 경험이 도움이 될 것 같다. 본 스터디 외 시간에 내 Macbook에 맞는 더 좋은 모델을 사용해서 성능을 측정해보면, Codex Token 의존도를 조금은 낮출 수 있을 것 같다.\n참고 자료 # Homebrew · 명령어 문서 Ollama CLI · Gemma 3:4b ","date":"2026.10.25","externalUrl":null,"permalink":"/local-ai-models-on-a-mac/week-01/","section":"Local AI Models on a Mac","summary":"로컬 AI를 쓰는 이유부터 터미널 기본 명령어, Homebrew와 Ollama로 Gemma 3를 실행하는 흐름까지 정리한다.","title":"[1주차] Mac에서 로컬 AI 시작하기: 터미널, Homebrew, Ollama","type":"local-ai-models-on-a-mac"},{"content":"","date":"2026.10.25","externalUrl":null,"permalink":"/tags/homebrew/","section":"Tags","summary":"","title":"Homebrew","type":"tags"},{"content":"","date":"2026.10.25","externalUrl":null,"permalink":"/tags/%ED%84%B0%EB%AF%B8%EB%84%90/","section":"Tags","summary":"","title":"터미널","type":"tags"},{"content":"이 블로그는 글 파일과 사진을 GitHub에 저장하면 웹사이트가 만들어지는 방식이다. 글은 Markdown으로 쓰고, 그림·코드·수식·그래프를 필요한 자리에 섞어 넣으면 된다.\n처음부터 전부 읽을 필요는 없다. 새 글을 쓸 때는 1–4번, 사진을 넣을 때는 6–8번처럼 필요한 부분을 골라 보자. 이 안내의 예시 자료는 실제 공부 결과가 아닌 기능 설명용이다.\n먼저 고르기: 지금 무엇을 하고 싶은가? # 하고 싶은 일 이 안내에서 볼 부분 처음으로 글 한 편 만들기 1–3. 폴더와 새 글 만들기 남에게 안 보이게 쓰고 싶기 4. 초안과 비공개의 차이 글 수정·공개·게시 확인 5. 수정과 게시 확인 사진·스크린샷·직접 그린 그림 넣기 6–7. 이미지와 캡션 사진을 나란히, 대표 사진 넣기 8. 갤러리와 표지 제목·강조·목록·링크·접는 글 쓰기 9. 본문 서식 코드·터미널 결과·오류 기록 10. 코드와 로그 논문 수식·표·각주 넣기 11–12. 수식과 표 그래프·순서도 넣기 13–14. 그래프와 Mermaid 영상·PDF·다운로드 파일 넣기 15. 영상과 첨부 스터디·논문·실험 글의 틀이 필요하기 16. 복사용 틀 Mac에서 완성 화면을 보며 쓰기 17. 로컬 미리보기 사진이나 글이 안 보이기 18. 문제 해결 다음부터 나에게 작업을 부탁하기 19. 요청 예시 1. 글 한 편은 폴더 하나로 묶는다 # 한 글의 index.md와 그 글에서 쓸 자료를 같은 폴더에 모으는 방식이 가장 관리하기 편하다.\ncontent/ └── local-ai-models-on-a-mac/ └── week-02/ ├── index.md ← 글 본문 ├── feature.jpg ← 대표 사진: 선택 사항 ├── terminal.png ← 본문 스크린샷 ├── architecture.svg ← 직접 그린 구성도 ├── loss.png ← 그래프 이미지 └── notes.pdf ← 공개할 첨부 파일 사진을 전부 미리 넣을 필요는 없다. 글을 쓰다가 같은 폴더에 추가해도 된다.\n어떤 폴더에 글을 만들까? # 현재 메뉴 GitHub에서 들어갈 폴더 Local AI Models on a Mac content/local-ai-models-on-a-mac 공부 노트 content/notes 논문 리뷰 content/papers 사진 기록 content/journal 서재 content/books 폴더 이름은 영문 소문자·숫자·하이픈으로 정하면 주소와 파일 연결을 다루기 편하다. 제목은 한글로 자유롭게 써도 된다.\n예를 들어 content/local-ai-models-on-a-mac/week-02/index.md는 게시 후 /local-ai-models-on-a-mac/week-02/ 주소가 된다. 글의 주소를 유지하려면 공개 후 폴더 이름을 바꾸지 않는 편이 좋다.\n2. GitHub 화면에서 새 글 만들기 # YoungsPlace 저장소를 연다. 로그인 계정이 맞는지 확인한다. content → 글을 넣을 폴더로 들어간다. 스터디 글이면 local-ai-models-on-a-mac이다. Add file → Create new file을 누른다. 파일 이름에 week-02/index.md처럼 입력한다. 이미 해당 메뉴 폴더에 들어왔다면 content/...를 또 붙이지 않는다. 아래 기본 양식을 붙여 넣고 제목과 본문을 고친다. Commit changes\u0026hellip; → Commit changes로 저장한다. 여기서 Commit은 변경 내용을 GitHub에 저장하는 동작이다. --- title: \u0026#34;[2주차] 오늘 공부한 제목\u0026#34; date: 2026-10-25 draft: true summary: \u0026#34;무엇을 공부했고 어떤 내용을 다루는지 한두 문장.\u0026#34; tags: [\u0026#34;로컬 AI\u0026#34;, \u0026#34;Mac\u0026#34;] series: [\u0026#34;Local AI Models on a Mac\u0026#34;] math: false --- ## 이번에 공부한 것 여기부터 본문을 쓴다. ## 직접 해본 것 명령어와 결과를 나눠 적는다. ## 배운 점과 다음 질문 아직 이해가 덜 된 것도 남긴다. 이 예시의 draft: true는 블로그 화면에 글을 내보내지 않는 설정이다. 저장소 원본까지 비공개로 만드는 기능은 아니다. 다음 4번을 먼저 읽고 보관 방식을 고르자.\n3. 글 맨 위 설정은 무엇을 뜻할까? # 맨 위 --- 두 줄 사이가 글의 설정이고, 그 아래가 본문이다. 설정 이름 뒤의 :와 들여쓰기를 유지한다.\n설정 용도 예시·주의점 title 화면에 보이는 제목 특수문자가 있어도 편하게 쓰도록 큰따옴표로 감싸기 date 글의 날짜 2026-10-25처럼 쓰기. 미래 날짜는 기본 게시에서 제외됨 lastmod 나중에 수정한 날짜 크게 고쳤다면 추가 가능 draft 게시 제외 여부 true: 제외, false: 게시 대상 summary 글 목록 카드의 소개 제목을 반복하기보다 내용 한두 문장 tags 검색·분류용 꼬리표 [\u0026quot;Ollama\u0026quot;, \u0026quot;실험\u0026quot;] series 연재 글 묶기 같은 연재에서는 이름을 정확히 동일하게 쓰기 math 수식 표시 기능 수식을 쓰는 글은 true showTableOfContents 목차 표시 긴 글은 true, 짧은 메모는 false showHero 본문 위 대표 이미지 false면 본문 위 큰 표지를 숨김 showDateUpdated 수정일 표시 lastmod와 함께 true로 사용 가능 메뉴 폴더와 태그는 다르다. 글을 papers 폴더에 넣으면 논문 리뷰 메뉴에 들어가고, tags는 그 글을 다른 관점으로 묶어 준다. 새 태그를 만들었다고 상단 메뉴가 자동으로 생기지는 않는다.\n날짜와 불리언 값은 예시처럼 쓰고, true·false는 소문자로 쓴다. 제목에 큰따옴표 자체를 넣고 싶으면 title: '\u0026quot;작은 모델\u0026quot;을 실행해 보기'처럼 바깥을 작은따옴표로 감싸도 된다.\n4. 초안과 비공개는 다르다 # 나만 보는 초안이 필요할 때 # Mac의 파일로만 저장하고 GitHub에 올리지 않는다. 이 저장소는 공개 상태이므로 GitHub에 저장한 글 원본과 첨부 파일은 다른 사람도 볼 수 있다.\n로컬에서 draft: true로 두고 쓰다가, 공개할 준비가 됐을 때 파일과 자료를 올리면 된다.\n본문은 공개돼도 되지만 블로그 목록에는 아직 안 올릴 때 # GitHub에 draft: true로 저장할 수 있다. 정식 블로그 빌드에서는 페이지·목록·검색에서 제외되지만, GitHub 원본은 공개다.\n공개할 준비가 됐을 때 # 본문과 사진을 확인한다. draft: false로 바꾼다. 날짜가 미래가 아닌지 확인한다. Commit changes로 저장한다. 게시 작업이 끝나면 실제 블로그 주소를 연다. 이미 올린 글을 블로그에서 숨기고 싶을 때 # draft: true로 바꾸고 저장한다. 새 게시가 끝나면 블로그에서 빠진다. 다만 이미 공개된 원본·Git 기록·검색 결과까지 지워지는 것은 아니다. 다시 숨길 수도 있다는 생각으로 민감한 내용을 올리지 않는다.\n5. 기존 글 수정과 게시 확인 # 글을 고칠 때 # GitHub에서 해당 글의 index.md를 연다. Edit this file 또는 연필 버튼을 누른다. 내용을 고치고 Commit changes로 저장한다. Actions에서 가장 최근 Publish blog 작업을 확인한다. 초록 체크가 나오면 실제 블로그에서 새로고침한다. 대기·진행 중이면 게시가 아직 끝나지 않은 상태다. GitHub 편집기의 Preview는 기본 Markdown 미리보기다. 이 블로그의 수식·그래프·특수 이미지 배치는 실제 사이트나 로컬 미리보기에서 확인한다.\n제목만 바꿀 때와 주소까지 바꿀 때 # title만 바꾸면 폴더가 같으므로 글 주소는 유지된다. week-02 같은 폴더 이름이나 slug를 바꾸면 주소가 달라질 수 있다. 이미 공유한 글은 제목부터 고치고, 폴더는 가능한 한 유지하는 편이 관리하기 쉽다. 설정 파일은 어디까지 만질까? # 본문은 content, 상단 메뉴는 config/_default/menus.ko.toml에서 바꾼다. 단순 글쓰기에는 .github/workflows, layouts, themes를 고칠 필요가 없다. 새 메뉴가 필요하면 19번 예시처럼 요청해도 된다.\n6. 사진·스크린샷·그림 한 장 넣기 # GitHub에 사진 올리기 # 해당 글의 index.md가 있는 폴더를 연다. Add file → Upload files → Choose your files를 선택한다. JPG·PNG·WebP·SVG 등의 파일을 고른다. 업로드 목록이 모두 나타나면 Commit changes로 저장한다. index.md를 수정해 아래 문법을 원하는 위치에 넣는다. ![Ollama 모델 목록을 확인한 화면](terminal.png) 이 예시는 **같은 폴더의 terminal.png**를 가리킨다. ![ ] 안에는 사진 내용을 설명하는 문장을 넣는다. 사진이 보이지 않을 때와 화면 읽기 도구에서도 쓰인다.\n/Users/이름/Desktop/terminal.png 같은 내 컴퓨터 경로는 웹사이트에서 열 수 없다. 클립보드에 복사한 것만으로도 파일이 올라가지 않는다. GitHub의 이슈·댓글 입력창에 사진을 붙이는 것과 블로그 폴더에 파일을 올리는 것도 서로 다른 작업이다.\n사진이 여러 폴더로 나뉠 때 # week-02/ ├── index.md └── images/ └── terminal.png ![실행 결과](images/terminal.png) images는 선택 사항이다. 처음에는 한 폴더에 모아도 충분하다.\n어떤 파일 형식을 쓰면 좋을까? # 자료 보관 방식 예시 일반 사진 JPG 또는 WebP 글씨가 많은 화면·투명 이미지 PNG 직접 그린 도식·벡터 그래프 SVG 움직이는 짧은 설명 GIF 또는 짧은 MP4 차트·논문 결과 그림 PNG·SVG. 글씨가 읽히는지 확인 Mac의 Shift + Command + 4로 영역을 캡처한 뒤 파일 이름을 정해 올릴 수 있다. Keynote·그림 도구에서 만든 그림이나 AI로 만든 이미지도 파일로 내보내면 같은 방식으로 넣는다. 이 블로그가 자동으로 그림을 생성하거나 Python 코드를 실행하는 것은 아니다.\n파일 이름은 experiment-01.png처럼 간단히 정한다. 업로드 이름과 본문 이름의 확장자·대소문자를 맞춘다. result.png와 Result.PNG는 다르게 취급될 수 있다.\n브라우저 업로드는 현재 파일당 25 MiB 제한이 있다. 실무적으로 사진 한 장은 가능하면 몇 MB 이내로 줄이면 읽는 사람이 빠르게 열 수 있다. GitHub 업로드 제한\n7. 사진 설명·크기·정렬 바꾸기 # 사진 아래 설명을 붙일 때 # 이 블로그에서는 Markdown 이미지 뒤의 따옴표를 캡션으로 표시한다.\n![실험 진행 과정](sample-workflow.svg \u0026#34;예시: 질문에서 실험 기록까지\u0026#34;) 아래가 실제 표시 예시다.\n예시: 질문에서 실험 기록까지. 이 매뉴얼을 위해 만든 도식. 캡션에 출처 링크를 넣을 때 # ![논문 구조도](paper-figure.png) *그림 1. 논문 구조를 설명한 그림. 출처: [논문 원문](https://example.com/paper)* 설명을 별도 문단으로 적는 방식도 간단하다. 다른 자료를 넣을 때는 출처 링크와 직접 다시 그린 것인지 여부를 함께 남긴다.\n이미지 폭을 줄이고 가운데 놓을 때 # \u0026lt;img src=\u0026#34;terminal.png\u0026#34; alt=\u0026#34;터미널 실행 결과\u0026#34; style=\u0026#34;display:block; width:560px; max-width:100%; height:auto; margin:1.5rem auto;\u0026#34;\u0026gt; 560px을 바꾸면 폭이 달라진다. max-width:100%는 작은 화면에서 넘치지 않게 한다. 이 HTML 방식은 Markdown 이미지의 자동 크기 최적화와 확대 동작이 똑같이 적용되지는 않는다. 기본적으로는 Markdown을 쓰고, 크기 조절이 꼭 필요할 때 선택하면 된다.\n그림과 캡션을 한 묶음으로 넣을 때 # 아래는 이 테마가 제공하는 figure 문법이다. 중괄호까지 그대로 복사하고 파일 이름과 설명만 바꾼다.\n{{\u0026lt; figure src=\u0026#34;terminal.png\u0026#34; alt=\u0026#34;실행 결과\u0026#34; caption=\u0026#34;그림 1. 모델 목록을 확인한 화면\u0026#34; \u0026gt;}} 8. 여러 사진 나란히, 갤러리, 대표 사진 # 두 장을 항상 두 칸으로 놓을 때 # \u0026lt;div style=\u0026#34;display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:12px;\u0026#34;\u0026gt; \u0026lt;figure style=\u0026#34;margin:0;\u0026#34;\u0026gt; \u0026lt;img src=\u0026#34;before.png\u0026#34; alt=\u0026#34;변경 전\u0026#34; style=\u0026#34;width:100%; height:auto;\u0026#34;\u0026gt; \u0026lt;figcaption\u0026gt;변경 전\u0026lt;/figcaption\u0026gt; \u0026lt;/figure\u0026gt; \u0026lt;figure style=\u0026#34;margin:0;\u0026#34;\u0026gt; \u0026lt;img src=\u0026#34;after.png\u0026#34; alt=\u0026#34;변경 후\u0026#34; style=\u0026#34;width:100%; height:auto;\u0026#34;\u0026gt; \u0026lt;figcaption\u0026gt;변경 후\u0026lt;/figcaption\u0026gt; \u0026lt;/figure\u0026gt; \u0026lt;/div\u0026gt; 사진 속 글씨가 많다면 모바일의 두 칸 배치가 작게 보일 수 있다. 이럴 때는 기본 Markdown으로 한 장씩 놓는 편이 낫다.\n사진 수가 많아 갤러리로 보여줄 때 # {{\u0026lt; gallery \u0026gt;}} \u0026lt;img src=\u0026#34;photo-01.jpg\u0026#34; alt=\u0026#34;첫 번째 관찰 사진\u0026#34;\u0026gt; \u0026lt;img src=\u0026#34;photo-02.jpg\u0026#34; alt=\u0026#34;두 번째 관찰 사진\u0026#34;\u0026gt; \u0026lt;img src=\u0026#34;photo-03.jpg\u0026#34; alt=\u0026#34;세 번째 관찰 사진\u0026#34;\u0026gt; {{\u0026lt; /gallery \u0026gt;}} 사진을 같은 글 폴더에 올리고 파일 이름을 맞춘다. 일반 Markdown 사진 세 장은 세로로 쌓이고, 위 gallery는 여러 사진을 갤러리로 배치한다.\n실제 갤러리 배치 예시다. 아래 두 장은 매뉴얼을 위해 만든 도식이다.\n글 목록에 대표 사진을 넣을 때 # 같은 폴더에 feature.jpg 또는 feature.png처럼 feature로 시작하는 이미지 한 장을 둔다. 현재 테마가 대표 이미지로 찾는다.\n대표 이미지는 카드와 본문 위 표지에 사용될 수 있다. 본문 위 큰 표지만 숨기고 싶으면 글 설정에 다음을 추가한다.\nshowHero: false 대표 사진과 같은 사진을 본문에도 다시 넣으면 두 번 보일 수 있다. 실제 화면을 보고 한쪽을 빼면 된다. 대표 이미지는 한 글에 여러 장 두지 않는 편이 명확하다.\n9. 제목·문단·강조·링크·목록·접는 글 # 제목과 문단 # 글의 큰 제목은 맨 위 title이 담당한다. 본문은 보통 ##부터 시작한다.\n## 큰 항목 본문 문장. 문단 사이에는 빈 줄을 넣는다. ### 작은 항목 다른 문단. 그냥 Enter 한 번은 문단을 나누지 않을 수 있다. 기본적으로 빈 줄 하나를 넣으면 새 문단이다. 꼭 줄만 바꾸려면 문장 끝에 공백 두 개를 넣거나 \u0026lt;br\u0026gt;를 쓴다.\n강조와 링크 # **중요한 내용** *그림 설명이나 짧은 메모* `명령어 또는 파일 이름` [참고 문서](https://example.com) [내 스터디 목록](/local-ai-models-on-a-mac/) 강조 표시가 그대로 보이면 별표 양옆을 확인한다. 특히 괄호와 한글 조사가 붙을 때는 **학습**과 **추론**처럼 표시 범위를 단순하게 쓰면 편하다.\n목록과 할 일 # - 읽은 것 - 이해한 것 - 다음 질문 1. 설치한다. 2. 실행한다. 3. 결과를 기록한다. - [x] 자료 읽기 - [ ] 직접 실행하기 - [ ] 결과 화면 넣기 체크박스 상태를 저장하려면 글 파일의 [ ]를 [x]로 고친다. 웹 화면의 체크박스를 눌러도 GitHub 원본이 자동 수정되지는 않는다.\n인용과 메모 # \u0026gt; 원문에서 가져온 짧은 문장. \u0026gt; \u0026gt; 출처: 문서 제목과 링크 인용과 내가 해석한 내용은 문단을 나눠 적는다. 긴 원문 전체를 붙이기보다 필요한 부분을 짧게 인용하고 원문을 연결한다.\n긴 설명을 접어두기 # \u0026lt;details\u0026gt; \u0026lt;summary\u0026gt;오류 메시지 전체 보기\u0026lt;/summary\u0026gt; 여기에 긴 설명이나 코드 블록을 넣는다. \u0026lt;/details\u0026gt; summary 다음과 닫는 태그 앞에 빈 줄을 둔다. 다음은 실제 예시다.\n눌러서 글쓰기 팁 보기 긴 설치 로그는 접고, 본문에는 오류 원인과 해결 방법부터 적으면 읽기 편하다.\n10. 코드·터미널 명령어·오류 로그 # 코드 블록 넣기 # 백틱 세 개 다음에 언어 이름을 붙이고, 끝에서도 백틱 세 개로 닫는다.\n```python message = \u0026#34;Hello, local AI!\u0026#34; print(message) ``` 주로 쓰는 이름은 python, sh, json, yaml, text다. 실행 결과와 오류는 text로 넣으면 된다. 복사 버튼도 코드 블록에 표시된다.\n명령어와 결과를 나눠 적기 # 실행한 명령어: ```sh ollama list ``` 실제 결과: ```text 여기에 내 터미널의 실제 출력을 붙인다. ``` 성공한 것처럼 예시 출력을 적지 말고, 예시라면 예시라고 표시한다. 이 블로그의 코드 블록은 보여주는 기능이다. Python 코드가 블로그 안에서 자동 실행되지는 않는다.\n일부 줄을 강조할 때 # ```python {linenos=true,hl_lines=[2]} model = \u0026#34;gemma3:4b\u0026#34; print(model) ``` linenos=true는 줄 번호, hl_lines=[2]는 두 번째 줄 강조다.\n오류 해결 글의 기본 순서 # 상황 → 실행 명령 → 오류 원문 → 원인 → 바꾼 것 → 재실행 결과 순서가 좋다. 긴 오류 로그는 9번의 접는 영역에 넣으면 된다.\n11. 논문 수식 넣기 # 글 맨 위 설정에 math: true를 넣는다. 현재 블로그는 이 값을 켜면 KaTeX를 불러오도록 설정되어 있다.\n문장 안의 짧은 수식 # 오차는 \\(y - \\hat{y}\\)로 표현한다. 실제 표시: 오차는 \\(y - \\hat{y}\\)로 표현한다.\n이 블로그에서 인라인 수식은 \\(와 \\)를 쓰는 방식으로 안내한다. 달러 기호 하나로 감싸는 방식과 섞지 않는 편이 편하다.\n별도 줄의 큰 수식 # $$ L = \\frac{1}{n}\\sum_{i=1}^{n}(y_i-\\hat{y}_i)^2 $$ 실제 표시:\n$$ L = \\frac{1}{n}\\sum_{i=1}^{n}(y_i-\\hat{y}_i)^2 $$수식이 그대로 글자로 보이면 math: true, 시작·끝 구분자, 역슬래시를 확인한다. Markdown 코드 블록 안에 넣은 수식은 계산식이 아니라 문법 예시로 표시되는 것이 정상이다.\n12. 표·각주·논문 정보 # 간단한 비교표 # | 항목 | 모델 A | 모델 B | | --- | --- | --- | | 파라미터 | 실제 값 | 실제 값 | | 실행 환경 | 내 환경 | 내 환경 | | 관찰 결과 | 측정 후 기록 | 측정 후 기록 | 복잡하고 가로로 긴 표는 모바일에서 읽기 어렵다. 핵심 열만 본문에 남기고 전체 데이터는 CSV 파일이나 원문 링크로 연결해도 된다. 표 셀 안 줄바꿈은 \u0026lt;br\u0026gt;를 쓸 수 있다. 셀 안에서 | 자체를 쓰려면 \\|처럼 적는다.\n각주 # 이 부분은 추가 설명이 필요하다.[^memo] [^memo]: 추가 설명과 참고 링크. 실제 예시: 숫자와 조건을 함께 남겨야 실험을 다시 비교할 수 있다.1\n논문 리뷰에서 남기면 좋은 정보 # 제목, 저자, 발표 연도, 원문·코드 링크, 해결하려는 문제, 핵심 아이디어, 실험 조건, 한계, 내 생각을 나눠 쓴다. 표나 그림을 가져오면 논문 내 번호와 출처를 남기고, 직접 다시 그렸다면 그렇게 적는다.\n13. 그래프 넣기: 이미지와 인터랙티브 차트 # 경우 A. Python이나 스프레드시트에서 만든 그래프 # 그래프를 PNG·SVG로 저장하고 사진처럼 넣는 방식이 가장 간단하다.\n```python import matplotlib.pyplot as plt steps = [1, 2, 3, 4] loss = [0.9, 0.6, 0.4, 0.3] # 문법 설명용 예시 데이터 plt.plot(steps, loss, marker=\u0026#34;o\u0026#34;) plt.xlabel(\u0026#34;Step\u0026#34;) plt.ylabel(\u0026#34;Loss\u0026#34;) plt.savefig(\u0026#34;loss.png\u0026#34;, dpi=180, bbox_inches=\u0026#34;tight\u0026#34;) ``` ![학습 단계별 손실 변화](loss.png) 위 Python 코드는 내 컴퓨터에서 실행해서 loss.png를 만든 뒤 업로드해야 한다. 코드를 글에 붙이는 것만으로 이미지가 만들어지지는 않는다.\n축 이름·단위·범례를 넣고, 다크 모드에서도 글씨가 읽히는지 확인한다. 아래는 실제 측정값이 아닌 예시 그래프 이미지다.\n예시 데이터: 그래프 이미지를 글에 넣은 모습 경우 B. 마우스를 올리면 값이 나오는 차트 # 작은 데이터는 Chart.js 차트 문법으로 본문에 직접 넣을 수 있다.\n{{\u0026lt; chart \u0026gt;}} type: \u0026#39;line\u0026#39;, data: { labels: [\u0026#39;1\u0026#39;, \u0026#39;2\u0026#39;, \u0026#39;3\u0026#39;, \u0026#39;4\u0026#39;], datasets: [{ label: \u0026#39;예시 loss\u0026#39;, data: [0.9, 0.6, 0.4, 0.3], borderColor: \u0026#39;#c9ae55\u0026#39;, backgroundColor: \u0026#39;#c9ae55\u0026#39;, tension: 0.2 }] }, options: { responsive: true, scales: { x: { title: { display: true, text: \u0026#39;Step\u0026#39; } }, y: { title: { display: true, text: \u0026#39;Loss\u0026#39; } } } } {{\u0026lt; /chart \u0026gt;}} 실제 표시 예시:\nlabels와 data의 개수를 맞춘다. type: 'bar'로 바꾸면 막대 차트를 만들 수 있다. 데이터를 고칠 때 쉼표와 괄호를 빠뜨리면 차트가 보이지 않을 수 있다.\n경우 C. Plotly처럼 이미 만든 HTML 그래프 # 다른 방식으로는 자립적으로 열리는 HTML 그래프 파일을 같은 폴더에 올리고 연결할 수 있다.\n[인터랙티브 그래프 새 창으로 보기](plot.html) 본문 안에 보이게 하려면 다음처럼 넣는다.\n\u0026lt;iframe src=\u0026#34;plot.html\u0026#34; title=\u0026#34;모델 비교 그래프\u0026#34; style=\u0026#34;width:100%; height:520px; border:0;\u0026#34; loading=\u0026#34;lazy\u0026#34;\u0026gt;\u0026lt;/iframe\u0026gt; HTML 파일이 외부 서비스나 별도 파일을 필요로 한다면 그것도 함께 준비해야 한다. 비공개 분석 파일이나 믿을 수 없는 외부 HTML을 그대로 올리지 않는다. 처음에는 그래프 이미지, 필요할 때 Chart.js나 별도 HTML로 넓혀 가면 된다.\n14. 흐름도·구조도 넣기 # 그림 도구로 그린 파일을 이미지로 넣어도 되고, Mermaid로 텍스트를 도식으로 바꿀 수도 있다. 이 블로그에서는 아래 전용 문법을 사용한다.\n{{\u0026lt; mermaid \u0026gt;}} flowchart LR A[질문] --\u0026gt; B[실험] B --\u0026gt; C[결과 기록] {{\u0026lt; /mermaid \u0026gt;}} 실제 표시:\nflowchart LR A[질문] --\u003e B[실험] B --\u003e C[결과 기록] LR은 왼쪽에서 오른쪽, TD는 위에서 아래다. 긴 문구나 괄호가 들어가면 A[\u0026quot;긴 문구 (설명)\u0026quot;]처럼 따옴표로 감쌀 수 있다. 복잡한 논문 도식은 직접 그린 SVG·PNG가 더 자유롭다.\n15. 영상·PDF·첨부 파일 # 짧은 MP4를 본문에서 재생하기 # 글 폴더에 demo.mp4를 올리고 다음 문법을 넣는다.\n{{\u0026lt; video src=\u0026#34;demo.mp4\u0026#34; controls=\u0026#34;true\u0026#34; ratio=\u0026#34;16/9\u0026#34; \u0026gt;}} 영상이 크면 저장소와 페이지 로딩 부담이 커진다. 긴 미팅 녹화는 영상 서비스에 보관하고 링크로 연결하는 방식이 더 편하다. 멤버 전용 자료는 접근 권한을 확인한 뒤 공개 가능한 범위만 정리한다.\nYouTube 연결 # 가장 간단한 방식은 링크다.\n[관련 영상 보기](https://www.youtube.com/watch?v=영상ID) 본문에 플레이어를 넣으려면 아래의 실제영상ID를 주소의 v= 뒤 값으로 바꾼다.\n{{\u0026lt; youtubeLite id=\u0026#34;실제영상ID\u0026#34; \u0026gt;}} PDF·CSV·ZIP 다운로드 링크 # 글 폴더에 파일을 올린 뒤 연결한다.\n[내가 만든 정리 PDF](notes.pdf) [실험 데이터 CSV](results.csv) [실습 예제 ZIP](example.zip) 링크를 누르면 브라우저와 파일 종류에 따라 열리거나 다운로드된다. 원본 논문은 파일을 다시 올리기보다 논문 공식 페이지나 공개 원문 링크를 연결하는 방식도 좋다.\n16. 바로 복사하는 글 틀 # 아래에서 필요한 틀 하나를 새 index.md에 복사한다. 날짜·제목·태그·본문을 고치고, 공개 전에는 4번 내용을 다시 확인한다.\n스터디 주차별 기록 # --- title: \u0026#34;[2주차] 공부한 주제\u0026#34; date: 2026-10-25 draft: true summary: \u0026#34;이번 주 핵심과 직접 해본 내용을 한두 문장으로.\u0026#34; tags: [\u0026#34;로컬 AI\u0026#34;, \u0026#34;실습\u0026#34;] series: [\u0026#34;Local AI Models on a Mac\u0026#34;] --- ## 이번 주 범위 ## 핵심 개념 ## 실습 환경 ## 실행한 명령어와 실제 결과 ## 막힌 부분과 해결 과정 ## 배운 점과 다음 질문 ## 참고 자료 논문 리뷰 # --- title: \u0026#34;논문 제목: 내가 이해한 핵심\u0026#34; date: 2026-10-25 draft: true summary: \u0026#34;논문이 해결하려는 문제와 핵심 아이디어.\u0026#34; tags: [\u0026#34;논문 리뷰\u0026#34;] math: true --- ## 논문 정보 - 제목: - 저자 / 연도 / 발표처: - 원문 / 코드: ## 한 문장 요약 ## 문제와 기존 방법의 한계 ## 핵심 아이디어와 방법 ## 실험 조건과 결과 ## 한계와 의문 ## 내 생각 / 직접 해볼 것 ## 참고 자료 실험·오류 해결 기록 # --- title: \u0026#34;문제 또는 실험 이름\u0026#34; date: 2026-10-25 draft: true summary: \u0026#34;어떤 상황에서 무엇을 확인했는지.\u0026#34; tags: [\u0026#34;실험\u0026#34;, \u0026#34;문제 해결\u0026#34;] --- ## 목적 또는 증상 ## 환경과 재현 조건 ## 명령어 / 코드 / 오류 원문 ## 시도한 방법 ## 실제 결과 ## 원인과 배운 점 사진 중심의 짧은 기록 # --- title: \u0026#34;사진으로 남기는 오늘의 기록\u0026#34; date: 2026-10-25 draft: true summary: \u0026#34;장면과 생각을 한두 문장으로.\u0026#34; tags: [\u0026#34;사진 기록\u0026#34;] --- ![장면 설명](photo-01.jpg \u0026#34;장소나 맥락 설명\u0026#34;) 이 장면에서 관찰한 것과 떠오른 생각. ## 배운 것 ## 다음에 살펴볼 것 서재에 독서 기록 남기기 # 상단 서재 메뉴에 쌓이는 독서 기록은 content/books/책-이름/index.md에 만든다. 책마다 폴더 하나를 만들고, 표지는 같은 폴더에 feature.jpg(또는 feature.png, feature.webp)로 올린다. 표지가 없으면 책 제목과 저자로 만든 책 모양이 대신 표시된다.\n아래 양식에서 제목·저자·날짜·한 줄 감상을 바꾼다. readingStatus에는 읽는 중, 완독, 다시 읽는 중처럼 지금 상태를 적으면 된다. draft: true와 비공개의 차이는 4번을 확인한다. 게시할 때 draft: false로 바꾸면 서재에 날짜순으로 나타난다.\n--- title: \u0026#34;책장을 덮고 남은 생각\u0026#34; date: 2026-10-25 draft: true bookTitle: \u0026#34;책 제목\u0026#34; bookAuthor: \u0026#34;저자 이름\u0026#34; readingStatus: \u0026#34;완독\u0026#34; description: \u0026#34;이 책이 나에게 남긴 것을 한 문장으로.\u0026#34; tags: [\u0026#34;독서\u0026#34;] showHero: false showTableOfContents: true --- ## 이 책을 펼친 이유 ## 오래 남은 문장 \u0026gt; 짧은 인용문 — 저자, p.00 이 문장이 나에게 닿은 이유. ## 책장을 덮고 남은 생각 ## 내 일상으로 가져갈 것 책 표지는 서재 카드에서 보이고 showHero: false이면 글 상단에는 크게 반복되지 않는다. 본문에도 넣고 싶으면 ![책 표지](feature.jpg)를 쓴다. 원문 인용은 필요한 짧은 부분에 출처와 페이지를 함께 남기고, 내 감상과 구분한다.\n로컬에서 Hugo를 쓰는 경우 hugo new content books/책-이름/index.md로 준비된 독서 양식을 생성할 수 있다. archetypes/books/index.md가 그 원본이다.\n17. Mac에서 완성 화면을 보며 쓰기 # GitHub 업로드 전부터 실제 테마 화면을 보려면 로컬 미리보기를 쓴다. 아래 명령어의 /path/to/study-blog는 내 Mac에 저장한 블로그 폴더의 실제 경로로 바꾼다. Hugo 빌드 도구가 필요하다.\ncd /path/to/study-blog hugo server -D 터미널에 표시된 로컬 주소를 연다. 보통 http://localhost:1313/이며, 글 파일을 저장하면 화면도 갱신된다. -D는 로컬 미리보기에서 초안을 포함하는 옵션이다. 중지하려면 해당 터미널에서 Ctrl+C를 누른다.\n현재 Hugo 실행 파일이 일반 명령어로 준비되어 있지 않다면 hugo: command not found가 나올 수 있다. 이 작업 폴더는 Hugo Extended 0.167.0과 내려받은 Blowfish 테마로 검증했다. 저장소 안내에 초기 준비 방법을 적어뒀고, 설정이 낯설다면 로컬 미리보기 준비를 요청해도 된다.\nVS Code 같은 편집기에서는 폴더를 열고 index.md를 수정한 뒤 저장한다. Markdown 미리보기와 실제 Hugo 화면은 다를 수 있으니 최종 확인은 로컬 블로그에서 한다.\n로컬에서 저장한 것과 GitHub에 저장한 것은 별개다. 로컬 파일을 고쳤다고 자동으로 GitHub에 올라가지는 않는다. 공개할 때는 확정한 글 폴더와 첨부 자료를 GitHub에 올린다. Git을 익혔다면 버전 관리로 동기화할 수 있지만, 아직 공개하지 않을 초안까지 한꺼번에 추가하지 않도록 파일 목록을 확인한다.\n18. 자주 막히는 경우 # 상황 먼저 확인할 것 새 글이 안 보인다 draft: false인지, 미래 날짜인지, 최근 Publish blog 작업이 성공했는지 사진 자리에 설명만 보인다 글과 같은 폴더에 올렸는지, 상대 경로·파일명·대소문자가 맞는지 스크린샷을 붙였는데 안 올라간다 파일로 저장한 뒤 해당 글 폴더의 Upload files로 올렸는지 수식이 문자 그대로 나온다 math: true, 구분자와 역슬래시, 코드 블록 밖인지 그래프가 안 나온다 shortcode 시작·종료, 쉼표·괄호, 데이터 개수를 확인 대표 사진이 두 번 나온다 표지와 본문에 같은 사진을 중복으로 넣었는지 GitHub Preview에서 모양이 이상하다 실제 블로그·로컬 미리보기로 확인. GitHub는 테마 전용 기능을 모두 실행하지 않음 본문 일부가 전부 코드처럼 나온다 백틱 세 개로 연 코드 블록을 닫았는지 글이 옆 메뉴에 없다 content 아래 올바른 메뉴 폴더에 넣었는지. static에 글을 넣지는 않았는지 제목을 바꿨더니 공유 주소가 안 열린다 제목 대신 폴더 이름이나 slug까지 바꾸지 않았는지 사진을 바꿨는데 예전 사진이다 게시 성공 후 새로고침. 새 파일 이름으로 교체하고 본문 경로도 함께 변경 가능 저장했는데 사이트 전체가 안 바뀐다 Actions의 최신 실패 작업에서 build 단계 오류를 확인. 설정 문법이나 shortcode 오류일 수 있음 문제 해결을 요청할 때는 해당 글 주소 또는 파일 위치 + 원하는 모습 + 현재 보이는 모습 + 오류 메시지를 알려주면 빨리 확인할 수 있다.\n19. 나에게 부탁할 때 쓸 수 있는 말 # 아래처럼 원하는 결과와 공개 여부를 함께 알려주면 된다.\n“Local AI Models on a Mac 2주차 글 초안을 만들어줘. 자료와 내 실행 결과는 이거야. 아직 게시하지 말고 채팅에서 먼저 보여줘.”\n“이 사진 세 장을 1주차 글의 실습 결과 아래에 넣어줘. 순서는 설치 화면 → 모델 목록 → 첫 대화야. 각각 설명도 붙이고, 아직 로컬 초안에만 반영해줘.”\n“이 논문 구조도를 내가 그린 그림으로 바꾸고 싶어. 설명할 요소는 A, B, C야. 먼저 그림을 보여줘.”\n“이 CSV로 그래프를 만들고 글에 넣어줘. X축은 모델, Y축은 응답 시간(초)이야. 예시 수치는 넣지 말고 실제 데이터만 써줘.”\n“이 초안에서 개인 정보와 출처를 확인하고, 내가 승인한 최종본만 블로그에 공개해줘.”\n“새 메뉴를 만들어줘. 이름은 독서 기록이고, 글쓰기 화면이 아니라 지금 블로그의 글 목록처럼 만들어줘.”\n사진을 보낼 때는 어느 글의 어느 위치인지, 표지로도 쓸지 알려주면 좋다. 초안과 실제 경험을 구분할 수 있도록 직접 실행한 결과인지, 자료에 나온 시연인지도 함께 적어주면 된다.\n공개 전 짧은 확인 # 제목·요약·날짜·태그가 맞는가? 내 경험과 자료 속 사례를 구분했는가? 사진·표·수식·코드가 실제 화면에서 읽히는가? 출처와 링크가 필요한 곳에 붙어 있는가? 계정 정보·API 키·미공개 자료가 들어가지 않았는가? 지금 이 글을 공개하려는 것이 맞는가? 더 찾아보기 # GitHub에서 파일 업로드 Hugo 글과 폴더 묶기 Blowfish 이미지·그래프·영상 문법 이 안내는 현재 YoungsPlace 설정과 고정한 Blowfish 테마 버전에 맞춰 작성했다. 실제 화면과 함께 확인한 복사 예시를 기준으로 사용하면 된다.\n같은 모델 이름이어도 태그·실행 버전·입력·설정이 다르면 결과가 달라질 수 있다. 이 각주는 문법 설명용이다.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2026.10.24","externalUrl":null,"permalink":"/notes/writing-guide/","section":"공부 노트","summary":"GitHub에서 글 만들기, 비공개 초안 보관, 사진·그림·코드·수식·그래프 넣기, 수정과 공개까지 상황별로 따라 하는 안내.","title":"YoungsPlace 글쓰기 매뉴얼","type":"notes"},{"content":"이해한 것과 아직 궁금한 것.\n","date":"2026.10.24","externalUrl":null,"permalink":"/notes/","section":"공부 노트","summary":"이해한 것과 아직 궁금한 것.\n","title":"공부 노트","type":"notes"},{"content":"","date":"2026.10.24","externalUrl":null,"permalink":"/tags/%EC%82%AC%EC%9A%A9-%EC%95%88%EB%82%B4/","section":"Tags","summary":"","title":"사용 안내","type":"tags"},{"content":"","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"빵주(kbbangzoo)의 공부 기록 공간입니다. 사진과 코드, 논문과 실험을 함께 담습니다.\nLocal AI Models on a Mac — 로컬 AI 모델 스터디 기록 공부 노트 — 개념, 코드, 직접 해본 실험 논문 리뷰 — 핵심 질문, 방법, 결과, 나의 해석 사진 기록 — 관찰과 생각을 사진으로 남기기 서재 — 읽은 책과 마음에 남은 문장, 나의 생각 ","externalUrl":null,"permalink":"/about/","section":"배운 것을, 내 것으로 만드는 기록.","summary":"빵주(kbbangzoo)의 공부 기록 공간입니다. 사진과 코드, 논문과 실험을 함께 담습니다.\nLocal AI Models on a Mac — 로컬 AI 모델 스터디 기록 공부 노트 — 개념, 코드, 직접 해본 실험 논문 리뷰 — 핵심 질문, 방법, 결과, 나의 해석 사진 기록 — 관찰과 생각을 사진으로 남기기 서재 — 읽은 책과 마음에 남은 문장, 나의 생각 ","title":"YoungsPlace","type":"page"},{"content":"논문의 질문부터 내 생각까지.\n","externalUrl":null,"permalink":"/papers/","section":"논문 리뷰","summary":"논문의 질문부터 내 생각까지.\n","title":"논문 리뷰","type":"papers"},{"content":"사진으로 남기는 관찰과 배움.\n","externalUrl":null,"permalink":"/journal/","section":"사진 기록","summary":"사진으로 남기는 관찰과 배움.\n","title":"사진 기록","type":"journal"},{"content":"책장을 덮고도 남는 문장들.\n읽은 책과, 그 책을 읽던 나를 기록합니다.\n","externalUrl":null,"permalink":"/books/","section":"서재","summary":"책장을 덮고도 남는 문장들.\n읽은 책과, 그 책을 읽던 나를 기록합니다.\n","title":"서재","type":"books"}]