<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>mo_ongh.log</title>
        <link>https://velog.io/</link>
        <description>AI</description>
        <lastBuildDate>Wed, 18 Mar 2026 04:15:10 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>mo_ongh.log</title>
            <url>https://velog.velcdn.com/images/mo_ongh/profile/93d92051-b17b-47ca-9440-c07f2bf31aa1/image.webp</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. mo_ongh.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/mo_ongh" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[평가지표]]></title>
            <link>https://velog.io/@mo_ongh/%ED%8F%89%EA%B0%80%EC%A7%80%ED%91%9C</link>
            <guid>https://velog.io/@mo_ongh/%ED%8F%89%EA%B0%80%EC%A7%80%ED%91%9C</guid>
            <pubDate>Wed, 18 Mar 2026 04:15:10 GMT</pubDate>
            <description><![CDATA[<p>이 논문(ARROW)에서 사용된 세 가지 평가지표는 추천 시스템이 &#39;얼마나 정확하게&#39;, 그리고 &#39;얼마나 개인의 취향에 맞게&#39; 추천했는지를 측정하는 도구들이에요.</p>
<ol>
<li>AUC (Area Under the Curve)
의미: 모델이 &quot;사용자가 이 아이템을 좋아할 것인가?&quot;를 예측하는 전체적인 정확도를 나타냅니다.
해석: 1에 가까울수록 모델이 긍정적인 반응(클릭 등)과 부정적인 반응을 아주 잘 구분해낸다는 뜻이에요.</li>
<li>UAUC (User-specific AUC)
의미: &#39;개인화&#39; 성능을 측정하는 핵심 지표로, 각 사용자별로 AUC를 계산한 뒤 그 값들을 평균 낸 것입니다.
중요성: 전체 평균만 보는 AUC와 달리, 사용자 한 명 한 명의 고유한 취향을 얼마나 잘 맞췄는지를 보여줍니다.
결과: ARROW는 특히 이 UAUC 지표에서 기존 모델들보다 큰 향상을 보였는데, 이는 ARROW의 추론 방식이 개별 사용자의 복잡한 선호도를 깊이 있게 이해하고 있음을 증명합니다.</li>
<li>NDCG (Normalized Discounted Cumulative Gain)
의미: 추천된 리스트의 &#39;순위(Ranking)&#39;가 얼마나 정확한지를 평가합니다.
해석: 사용자가 정말 좋아할 만한 아이템이 추천 리스트의 상단(앞부분)에 위치할수록 점수가 높게 나옵니다. 즉, &quot;좋은 걸 먼저 보여줬는가&quot;를 측정하는 지표예요.
요약하자면,</li>
</ol>
<p>AUC: &quot;전체적으로 잘 맞췄니?&quot;
UAUC: &quot;개개인의 취향을 존중했니?&quot; (ARROW의 강점!)
NDCG: &quot;가장 좋아하는 걸 맨 앞에 뒀니?&quot;</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[통계공부]]></title>
            <link>https://velog.io/@mo_ongh/%ED%86%B5%EA%B3%84%EA%B3%B5%EB%B6%80</link>
            <guid>https://velog.io/@mo_ongh/%ED%86%B5%EA%B3%84%EA%B3%B5%EB%B6%80</guid>
            <pubDate>Tue, 03 Mar 2026 11:29:41 GMT</pubDate>
            <description><![CDATA[<h3 id="분산">분산</h3>
<p>: 데이터가 평균을 중심으로 얼마나 흩어져 있는지를 표현하는 개념</p>
<p>각 값과 평균 사이의 거리를 제곱한 후 합산한 값 / 데이터 개수</p>
<p>: 분산은 제곱된 단위다 보니 해석하기 어려운 면이 있어서 제곱근을 씌운 표준 편차를 사용</p>
<h3 id="표준-편차-standard-deviation">표준 편차, Standard Deviation</h3>
<p>: 분산의 제곱 근</p>
<h3 id="평균-표준-편차">평균, 표준 편차</h3>
<p>표본의 평균 : 모집단의 평균을 추정</p>
<p>표준 편차 : 추정의 정확성을 판단</p>
<hr>
<h2 id="모수와-통계량">모수와 통계량</h2>
<p>추론 통계 : 표본의 특성을 바탕으로 모집단의 특성을 추론하는 과정</p>
<h3 id="모수-parameter">모수, Parameter</h3>
<p>: 모집단의 특성을 나타내는 수치</p>
<h3 id="통계량-statistic">통계량, Statistic</h3>
<p>: 표본의 특성을 나타내는 수치</p>
<h3 id="추론-통계">추론 통계</h3>
<p>: 표본의 통계량으로 모수를 추정하는 과정</p>
<p>모평균 : 모집단의 평균
표본평균 : 표본의 평균</p>
<hr>
<h3 id="표본을-통한-모집단의-추정">표본을 통한 모집단의 추정</h3>
<ol>
<li>모집단에서 표본을 추춣해 표본의 값을 관찰한다</li>
<li>관찰된 결과가 특정 모집단 아래에서 어느 정도의 확률로 나타날 수 있는지 생각한다.</li>
<li>데이터의 배후에 있는 모집단에 대해 추정한다</li>
</ol>
<p>&quot; 불확실성을 인정하고 가장 확률이 높은 쪽으로 추정하는 사고방식 &quot;</p>
<hr>
<h3 id="확률-변수-random-variable">확률 변수, Random Variable</h3>
<p>: 특정 상황에서 발생할 수 있는 결과를 숫자로 표현하는 규칙
ex) 동전 던지기의 경우 앞면을 1, 뒷면을 0으로 표현하면 그게 확률변수가 됨.</p>
<p>이산확률변수, Discrete Random Variable
: 동전던지기, 주사위 던지기 처럼 값이 딱딱 떨어지는 경우</p>
<p>연속확률변수, Continous Random Variable
: 사람의 키처럼 연속적인 경우</p>
<hr>
<h2 id="정규분포-normal-distribution보통의-분포">정규분포, Normal Distribution(보통의 분포)</h2>
<p>(가우스 분포, Gaussian Distribution)
<img src="https://velog.velcdn.com/images/mo_ongh/post/e32c45a5-f512-46f6-b02f-56d1213f8748/image.png" alt=""></p>
<p>중심극한정리, CLT, Central Limit Theorem
: 모집단의 분포와 관계없이, 이 모집단에서 추출된 표본의 크기가 충분히 크다면 반복적으로 추출된 표본평균의 분포는 정규분포에 가까워진다.</p>
<p>표본의 크기
: 표본에 포함된 data의 수
보통 30개 이상이면 충분히 크다고 판단</p>
<p><img src="https://velog.velcdn.com/images/mo_ongh/post/38be1ea8-1c32-440e-bf7d-5e5e6c468c71/image.png" alt=""></p>
<p>표본이 충분히 크다면 그 표본 자체의 분포가 정규분포에 가까워진다는 뜻이 아님.</p>
<p><img src="https://velog.velcdn.com/images/mo_ongh/post/65f5d0d5-11f8-4d5b-8afe-3aae9a95aca0/image.png" alt=""></p>
<p>모집단에서 표본을 여러 번 뽑으면 각 표본마다 평균이 다를 텐데
그 표본평균들의 분포가 정규분포를 따른다는 얘기임.</p>
<p><img src="https://velog.velcdn.com/images/mo_ongh/post/7e51ea36-7bf5-4408-b545-a4ee8bbaba0f/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/mo_ongh/post/58f46f63-0338-437f-8f7b-5c95cfa23d88/image.png" alt=""></p>
<ol>
<li>표본의 크기가 커질수록 수집된 표본의 평균이</li>
</ol>
<p><img src="https://velog.velcdn.com/images/mo_ongh/post/6b59528a-a373-46b0-9872-e43065089bab/image.png" alt=""></p>
<ol start="2">
<li>중심극한정리에 의해 모평균 u에 가까워 진다는 것임.</li>
</ol>
<p>-&gt; 이 개념이 바로 추론 통계의 핵심 원리.</p>
<p><img src="https://velog.velcdn.com/images/mo_ongh/post/9408893d-362c-428d-97d9-60fe4e52dc29/image.png" alt=""></p>
<hr>
<p>중심극한정리</p>
<p><img src="https://velog.velcdn.com/images/mo_ongh/post/dbd0e321-bc28-40b6-b8ef-2bfa3250ba45/image.png" alt=""></p>
<ol>
<li>모집단에서 표본을 여러 번 뽑고</li>
</ol>
<p><img src="https://velog.velcdn.com/images/mo_ongh/post/4757c0ca-8263-4af9-98b5-2cc8ed289c88/image.png" alt=""></p>
<ol start="2">
<li>그 표본들의 평균을 모으면 평균이 모평균 u이고</li>
</ol>
<p><img src="https://velog.velcdn.com/images/mo_ongh/post/82acc2f5-9aec-4f01-aedb-cda3052c459a/image.png" alt="">
3. 표준편차가 시그마/루트n 인 정규분포에 가까워짐.</p>
<p>-&gt; 통계학에서는 표본평균의 표준편차를 부르는 용어가 &#39;표준오차&#39;</p>
<h3 id="표준오차-standard-error">표준오차, Standard Error</h3>
<p>: 표본평균이 모평균에서 얼마나 떨어져 있는지 간접적으로 보여주는 지표</p>
<p>-&gt; 표본평균의 표준편차니까, 특정 표본의 평균이 모평균에서 얼마나 떠ㅓㄹ어져 있는지를 간접적으로 보여 주는 지표가 됨. </p>
<p>그럼 표본을 하나 뽑았을 ㄹ때 표본평균과 표준 오차를 알면 모평균이 어디쯤 있는지 추정할 수 있음</p>
<p>(문제가 있음)
<img src="https://velog.velcdn.com/images/mo_ongh/post/62f271aa-1661-4dc7-8e67-177cd94ceea1/image.png" alt="">
중심극한정리에서 봤듯 이론적으로 평균의 표준오차는 시그마/루트n 으로 계산됨</p>
<p>But, 모집단은 우리가 모르기 때문에 알고 싶은 대상임.</p>
<p>그래서 보통은 모집단의 표준편차인 시그마 대신,
<img src="https://velog.velcdn.com/images/mo_ongh/post/ac4227e4-d7b6-451c-9d63-b772e95121ad/image.png" alt="">
표본의 표준편차인 s를 사용해서 추정함</p>
<p><img src="https://velog.velcdn.com/images/mo_ongh/post/a81c13a3-583f-4e90-bc2b-01aa02279782/image.png" alt=""></p>
<p>표본의 크기가 클수록,
표준편차가 작을수록 </p>
<p>표준오차가 작아짐
표준오차가 작다는 건</p>
<p><img src="https://velog.velcdn.com/images/mo_ongh/post/235e76b1-f5e9-4c5c-9297-c82fd4c0d32d/image.png" alt="">
표본평균이 모평균에 가까이 있을 확률이 높다는 뜻.</p>
<p>? 구체적으로 표본평균이 모평균과 얼마나 가까이 있는지는 어떻게 표현가능한가? -&gt; &#39;신뢰구간&#39; 개념을 배워야함</p>
<hr>
<h3 id="신뢰구간-confidence-interval">신뢰구간, Confidence Interval</h3>
<p>: 모집단의 값이 포함될 것으로 예상되는 구간을 뜻함
보통 &#39;몇 % 신뢰구간&#39;이라고 이야기함</p>
<p>95% 신뢰구간
: 이 방식으로 구간을 여러 번 구할 때, 그 구간이 모집단의 값을 포함할 확률이 95%이다</p>
<p>평균에 대한 85% 신뢰구간</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[numpy]]></title>
            <link>https://velog.io/@mo_ongh/numpy</link>
            <guid>https://velog.io/@mo_ongh/numpy</guid>
            <pubDate>Sat, 07 Feb 2026 12:08:51 GMT</pubDate>
            <description><![CDATA[<p>Numerical Python
수치적인 연산에 최적화된 파이썬 도구</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[github - jupyterlab]]></title>
            <link>https://velog.io/@mo_ongh/github-jupyterlab</link>
            <guid>https://velog.io/@mo_ongh/github-jupyterlab</guid>
            <pubDate>Sat, 07 Feb 2026 11:10:24 GMT</pubDate>
            <description><![CDATA[<h2 id="앞으로-매일-워크플로우-5분-정리"><strong>앞으로 매일 워크플로우 (5분 정리)</strong></h2>
<h3 id="1-jupyterlab-실행"><strong>1. JupyterLab 실행</strong></h3>
<pre><code class="language-bash">cd /Users/moon/Desktop/lecture/codeit/data_science
jupyter lab</code></pre>
<p><strong>설명</strong>: JupyterLab 실행 (브라우저 자동 열림)</p>
<hr>
<h3 id="2-매일-git-명령어-순서"><strong>2. 매일 Git 명령어 순서</strong></h3>
<table>
<thead>
<tr>
<th>단계</th>
<th>명령어</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>준비</strong></td>
<td><code>git status</code></td>
<td>현재 변경사항 확인</td>
</tr>
<tr>
<td><strong>추가</strong></td>
<td><code>git add .</code> 또는 <code>git add lecture_XX.ipynb</code></td>
<td>변경된 파일 준비</td>
</tr>
<tr>
<td><strong>저장</strong></td>
<td><code>git commit -m &quot;메시지&quot;</code></td>
<td>스냅샷 저장 + 설명</td>
</tr>
<tr>
<td><strong>업로드</strong></td>
<td><code>git push</code></td>
<td>GitHub에 업로드</td>
</tr>
</tbody></table>
<hr>
<h2 id="각-명령어-자세한-설명"><strong>각 명령어 자세한 설명</strong></h2>
<h3 id="git-status"><strong><code>git status</code></strong></h3>
<pre><code>현재 상태 확인 (가장 먼저!)</code></pre><pre><code>예: On branch main
  Changes not staged for commit:
    modified:   lecture_02.ipynb</code></pre><h3 id="git-add-"><strong><code>git add .</code></strong></h3>
<pre><code>📂 현재 폴더 모든 변경파일 준비</code></pre><pre><code>git add lecture_02.ipynb  ← 특정 파일만</code></pre><h3 id="git-commit--m-lecture-02---data-preprocessing"><strong><code>git commit -m &quot;Lecture 02 - Data Preprocessing&quot;</code></strong></h3>
<pre><code>📸 변경사항을 스냅샷으로 저장 + 제목</code></pre><p><strong>좋은 커밋 메시지</strong>:</p>
<pre><code>git commit -m &quot;Lecture 02 - Pandas 데이터 전처리&quot;
git commit -m &quot;Lecture 03 - Matplotlib 시각화 추가&quot;</code></pre><h3 id="git-push"><strong><code>git push</code></strong></h3>
<pre><code>☁️ 로컬 스냅샷 → GitHub 업로드</code></pre><p><strong>처음 한 번만</strong>: <code>git push -u origin main</code></p>
<hr>
<h2 id="📋-매일-체크리스트"><strong>📋 매일 체크리스트</strong></h2>
<pre><code>✅ 1. cd /Users/moon/.../data_science
✅ 2. jupyter lab
✅ 3. 새 노트북: lecture_XX.ipynb
✅ 4. 강의 코드 작성 → Ctrl+S
✅ 5. Git 탭 → Terminal:
     git status
     git add .
     git commit -m &quot;Lecture XX - 제목&quot;
     git push
✅ 6. GitHub.com 확인</code></pre><hr>
<h2 id="⚠️-주의사항"><strong>⚠️ 주의사항</strong></h2>
<pre><code>1. .gitignore 덕분에 .DS_Store 등 자동 무시됨
2. data/ 폴더는 강의 데이터셋 → 그대로 유지
3. 매일 커밋 메시지는 &quot;Lecture XX - 주제&quot; 형식 추천</code></pre><hr>
<h2 id="🔄-업데이트-예시"><strong>🔄 업데이트 예시</strong></h2>
<pre><code>Day 1: git commit -m &quot;Lecture 01 - Introduction&quot;
Day 2: git commit -m &quot;Lecture 02 - Pandas basics&quot;  
Day 3: git commit -m &quot;Lecture 03 - Data visualization&quot;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[github-1]]></title>
            <link>https://velog.io/@mo_ongh/github-1</link>
            <guid>https://velog.io/@mo_ongh/github-1</guid>
            <pubDate>Sat, 07 Feb 2026 11:03:41 GMT</pubDate>
            <description><![CDATA[<h2 id="1-git-기본-3단계-명령어-뜻"><strong>1. Git 기본 3단계 명령어 뜻</strong></h2>
<pre><code>git add .           → &quot;변경된 파일들을 준비함&quot;
git commit -m &quot; &quot;   → &quot;변경사항을 사진 찍어서 저장함&quot;  
git push            → &quot;내 사진을 GitHub에 업로드함&quot;</code></pre><h3 id="git-add-"><strong><code>git add .</code></strong></h3>
<pre><code>📂 현재 폴더의 모든 변경된 파일을 &quot;준비 목록&quot;에 올림
✅ 1.ipynb, data/ 폴더, .DS_Store 등을 준비</code></pre><h3 id="git-commit--m-first"><strong><code>git commit -m &quot;first&quot;</code></strong></h3>
<pre><code>📸 준비된 파일들을 &quot;스냅샷&quot;으로 저장 + 설명 &quot;first&quot; 추가
✅ 6개 파일 변경사항 기록 (해시: 73eba50)</code></pre><h3 id="git-push"><strong><code>git push</code></strong></h3>
<pre><code>☁️ 내 스냅샷을 GitHub(원격 저장소)로 업로드</code></pre><hr>
<h2 id="2-git-push--u-origin-main-뜻"><strong>2. <code>git push -u origin main</code> 뜻</strong></h2>
<pre><code>git push                    → 스냅샷 업로드
-u (set-upstream)           → &quot;앞으로 이 브랜치와 자동 연결&quot;
origin                      → GitHub 저장소 이름
main                        → 브랜치 이름</code></pre><p><strong>처음 한 번만 <code>-u</code> 필요!</strong> 이후엔 <code>git push</code>만 써도 자동 업로드.</p>
<hr>
<h2 id="3-네-git-push-결과-해석"><strong>3. 네 <code>git push</code> 결과 해석</strong></h2>
<pre><code>오브젝트 나열하는 중: 10, 완료.           → 10개 파일 준비
오브젝트 개수 세는 중: 100% (10/10)       → 10개 모두 확인
Delta compression using up to 12 threads   → M4 Pro 12코어 압축
오브젝트 압축하는 중: 100% (9/9)          → 9개 압축 완료
Total 9 (delta 1), reused 0               → 9개 업로드 (1개 최적화)
remote: Resolving deltas: 100% (1/1)      → GitHub 처리 완료

To https://github.com/moon-gh/data_science.git
   355c861..73eba50  main -&gt; main          → 성공! (73eba50 커밋 업로드)
branch &#39;main&#39; set up to track &#39;origin/main&#39; → 자동 연결 완료!</code></pre><hr>
<h2 id="4-github-화면-확인"><strong>4. GitHub 화면 확인</strong></h2>
<p><strong>새로고침하면</strong>:</p>
<pre><code>✅ 1.ipynb 업로드됨!
✅ data/burger.csv 등 4개 데이터 파일
✅ 커밋 &quot;first&quot; (73eba50)</code></pre><hr>
<h2 id="5-앞으로-워크플로우-매일"><strong>5. 앞으로 워크플로우 (매일)</strong></h2>
<pre><code>1. 새 노트북: lecture_02.ipynb
2. 코드 작성 → Ctrl+S
3. 3단계:
   git add .
   git commit -m &quot;Lecture 02&quot;
   git push    ← -u는 처음만!</code></pre><hr>
<h2 id="6-정리"><strong>6. 정리</strong></h2>
<pre><code>✅ git add .     = 파일 준비
✅ git commit    = 스냅샷 저장  
✅ git push      = GitHub 업로드
✅ -u origin main = 처음 한 번만 (자동 연결)</code></pre><p><strong>강의용 Git 완벽 마스터!</strong> 이제 매일 노트북 만들고 <code>git push</code>만 하면 GitHub에 자동 업로드돼.</p>
<p><strong>각 명령어와 옵션의 상세 설명</strong> (Git 처음 사용자 기준):</p>
<hr>
<h2 id="1-rm-ds_store-license-readmemd"><strong>1. <code>rm .DS_Store LICENSE README.md</code></strong></h2>
<pre><code>rm = &quot;Remove&quot; (파일 삭제 명령어)
.DS_Store = macOS가 자동 생성하는 쓰레기 파일
LICENSE = 소프트웨어 라이선스 파일 (강의용엔 불필요)
README.md = 프로젝트 설명 파일 (임시로 삭제)</code></pre><p><strong>결과</strong>: 로컬 폴더에서 3개 파일 삭제됨</p>
<hr>
<h2 id="2-cat--gitignore--eof--eof"><strong>2. <code>cat &gt; .gitignore &lt;&lt; EOF</code> ~ <code>EOF</code></strong></h2>
<pre><code>cat &gt; 파일명 = 새 파일에 내용 쓰기
.gitignore = &quot;Git이 무시할 파일 목록&quot;
&lt;&lt; EOF ~ EOF = &quot;여기까지 여러 줄 내용을 파일에 넣기&quot;</code></pre><h3 id="gitignore-각-줄-설명"><strong><code>.gitignore</code> 각 줄 설명</strong>:</h3>
<pre><code># OS (macOS 불필요 파일)
.DS_Store           = macOS Finder가 만드는 숨김 파일
.DS_Store?          = macOS 다른 숨김 파일들

# Jupyter (노트북 임시 파일)
.ipynb_checkpoints/ = Jupyter가 저장할 때 백업 폴더
*.ipynb_checkpoints = 모든 Jupyter 임시 파일 무시

# Python (실행 후 생성 파일)
__pycache__/        = Python 컴파일된 캐시 폴더
*.py[cod]           = .pyc, .pyo 컴파일 파일들
*$py.class          = Java/Python 혼합 클래스 파일

# Environments (가상환경)
.env                = 환경변수 파일 (비밀번호 등 민감정보)
.venv               = Python 가상환경 폴더
env/                = 다른 가상환경 폴더들
venv/               = pip 가상환경 폴더들</code></pre><p><strong><code>.env</code>, <code>.venv</code> 설명</strong>:</p>
<ul>
<li><code>.env</code> = API키, 비밀번호 등 <strong>민감정보</strong> 저장 파일 (GitHub에 절대 올리면 안됨!)</li>
<li><code>.venv</code>, <code>venv/</code> = <strong>Python 가상환경</strong> 폴더들 (conda 환경과는 다름)</li>
</ul>
<hr>
<h2 id="3-git-add-gitignore"><strong>3. <code>git add .gitignore</code></strong></h2>
<pre><code>.gitignore을 &quot;Git 준비 목록&quot;에 추가
&quot;이제부터 이 무시 설정을 추적하자!&quot;</code></pre><hr>
<h2 id="4-git-rm---cached-ds_store-license-readmemd"><strong>4. <code>git rm --cached .DS_Store LICENSE README.md</code></strong></h2>
<pre><code>git rm = Git에서 파일 삭제
--cached = &quot;로컬 파일은 남기고 Git 추적만 중지&quot;
.DS_Store 등 = 이미 커밋된 불필요 파일들</code></pre><p><strong><code>--cached</code> 핵심</strong>:</p>
<pre><code>❌ 일반 git rm: 로컬 + Git 둘 다 삭제
✅ git rm --cached: 로컬은 남기고 Git 추적만 삭제</code></pre><p><strong>왜 필요한가?</strong></p>
<ul>
<li>이미 <code>git add .</code> → <code>git commit</code> → <code>git push</code>로 GitHub에 올라간 파일</li>
<li>새 <code>.gitignore</code> 설정 후에도 <strong>GitHub에는 계속 보임</strong></li>
<li><code>git rm --cached</code>로 <strong>GitHub에서만 삭제</strong></li>
</ul>
<hr>
<h2 id="5-git-commit--m-clean-up-"><strong>5. <code>git commit -m &quot;Clean up: ...&quot;</code></strong></h2>
<pre><code>commit = 변경사항을 &quot;스냅샷&quot;으로 저장
-m = 메시지 추가
&quot;Clean up: remove unnecessary files, update gitignore&quot; = 커밋 설명</code></pre><hr>
<h2 id="6-git-push"><strong>6. <code>git push</code></strong></h2>
<pre><code>로컬 스냅샷을 GitHub로 업로드</code></pre><hr>
<h2 id="전체-흐름-요약"><strong>전체 흐름 요약</strong></h2>
<pre><code>1. rm 파일들           → 로컬에서 삭제
2. .gitignore 생성     → 앞으로 무시할 파일 설정
3. git add .gitignore  → 무시 설정 파일 저장
4. git rm --cached     → GitHub에서만 불필요 파일 삭제 (로컬은 이미 삭제됨)
5. git commit          → 변경사항 스냅샷 저장  
6. git push            → GitHub에 반영</code></pre><p><strong>최종 GitHub 결과</strong>:</p>
<pre><code>✅ 1.ipynb (네 노트북)
✅ data/ 폴더
✅ .gitignore (깔끔)
❌ .DS_Store, LICENSE, README.md (삭제됨)</code></pre><hr>
<p><strong>이해했으면 Terminal에서 실행하고 GitHub 결과 알려줘!</strong><br>강의용 깔끔한 저장소 완성하자 🚀</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[차원 수]]></title>
            <link>https://velog.io/@mo_ongh/%EC%B0%A8%EC%9B%90-%EC%88%98</link>
            <guid>https://velog.io/@mo_ongh/%EC%B0%A8%EC%9B%90-%EC%88%98</guid>
            <pubDate>Sun, 31 Aug 2025 09:33:31 GMT</pubDate>
            <description><![CDATA[<hr>
<h1 id="임베딩-차원-수-제대로-고르기--384-vs-768-vs-1024">임베딩 차원 수, 제대로 고르기 — 384 vs 768 vs 1024</h1>
<blockquote>
<p>“임베딩 차원이 높을수록 무조건 좋을까?”
RAG/검색/추천에서 자주 받는 질문을, <strong>숫자·차원·메모리·속도</strong> 중심으로 정리했습니다.</p>
</blockquote>
<h2 id="tldr">TL;DR</h2>
<ul>
<li><p><strong>차원 수(=d)</strong> 는 한 문장을 표현하는 <strong>벡터 좌표의 길이</strong>. 예: SBERT 768차원 → 길이 768의 실수 벡터.</p>
</li>
<li><p><strong>차원이 높으면</strong> 표현력↑(미세한 의미 구분), <strong>하지만</strong> 메모리·연산비용·“허브니스(hubness)” 리스크↑.</p>
</li>
<li><p><strong>차원이 낮으면</strong> 메모리·속도↑(빠름), <strong>하지만</strong> 정보 손실로 성능↓ 가능.</p>
</li>
<li><p>실무 기준:</p>
<ul>
<li><strong>문서 수 적고 속도 여유</strong> → 768~1024</li>
<li><strong>대규모(≥ 수백만)·지연 민감</strong> → 384~512 + <strong>2단계 검색(저차원 1차 후보 + 고차원 재랭크)</strong></li>
<li><strong>Elasticsearch</strong> 사용 시 <code>dense_vector.dims == 모델 차원</code> 꼭 맞추기.</li>
</ul>
</li>
</ul>
<hr>
<h2 id="1-임베딩-차원이란">1) 임베딩 차원이란?</h2>
<ul>
<li>한 문장/청크를 <strong>d차원 실수 벡터</strong>로 매핑한 결과의 길이(d).
예) <code>snunlp/KR-SBERT-...</code> → <strong>768차원</strong></li>
<li>이 d는 모델이 학습 중 “의미를 담을 수 있는 용량(표현력)”과 연관.</li>
</ul>
<blockquote>
<p>직관:</p>
<ul>
<li>d가 크면 더 많은 “축”으로 의미를 분해해 담을 수 있음 (세밀한 구분).</li>
<li>d가 작으면 압축이 심해져 서로 다른 의미가 섞일 수 있음(충돌/정보손실).</li>
</ul>
</blockquote>
<hr>
<h2 id="2-차원-수가-클수록-생기는-일">2) 차원 수가 <strong>클수록</strong> 생기는 일</h2>
<h3 id="장점">장점</h3>
<ul>
<li><strong>표현력/세분화↑</strong>: 유사하지만 다른 개념을 더 잘 분리(특히 다국어, 도메인 다양, 문맥 복잡).</li>
<li><strong>충분한 학습 데이터</strong>가 있으면 <strong>일반화 성능↑</strong>(문장 의미의 다양한 측면을 담을 수 있음).</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li><strong>메모리·스토리지↑</strong>: N개 문서면 저장량이 <code>≈ N × d × 4byte(float32)</code> 로 증가.</li>
<li><strong>거리 계산 비용↑</strong>: ANN/Brute-force 모두 <strong>연산량이 d에 선형</strong>으로 증가.</li>
<li><strong>Hubness↑</strong>: 고차원에서 특정 벡터가 **과도하게 “가까운 이웃”**으로 자주 등장하는 현상 → 검색 랭킹이 왜곡될 수 있음.</li>
<li><strong>데이터가 적을수록 과적합 위험</strong>: d가 크면 모델/인덱스가 “잡음”까지 설명하려고 함.</li>
</ul>
<hr>
<h2 id="3-차원-수가-작을수록-생기는-일">3) 차원 수가 <strong>작을수록</strong> 생기는 일</h2>
<h3 id="장점-1">장점</h3>
<ul>
<li><strong>빠름 &amp; 가벼움</strong>: 도커/서버리스/모바일 등에서 유리.</li>
<li><strong>대규모 인덱스</strong> 운영 비용↓: 메모리/디스크·네트워크 전송량↓, 캐시 효율↑.</li>
</ul>
<h3 id="단점-1">단점</h3>
<ul>
<li><strong>정보 손실</strong>: 문장 의미의 중요한 축이 사라져 <strong>정확도/재현율 저하</strong> 가능.</li>
<li><strong>도메인 다양성</strong>이 큰 경우 분리 한계.</li>
</ul>
<hr>
<h2 id="4-언젠가-들어본-그-법칙-차원d-vs-데이터-수n">4) 언젠가 들어본 그 법칙: “차원(d) vs 데이터 수(n)”</h2>
<ul>
<li>이론적으로, 거리(유사도)를 보존하려면 필요한 차원 수가 대략 <strong>데이터 수의 로그에 비례</strong>(존슨–린덴스트라우스 류의 직관).</li>
<li>하지만 <strong>학습된 임베딩</strong>은 단순 랜덤 투영이 아니기 때문에, 이 법칙은 <strong>엄밀한 규칙이라기보단 감각</strong>으로만 참고.</li>
</ul>
<p><strong>실무 감</strong></p>
<ul>
<li><strong>n이 아주 크다(≥ 수백만)</strong> → d를 너무 크게 잡으면 비용이 눈덩이.</li>
<li><strong>n이 중간(수만~수십만)</strong> → 384~768선에서 “성능 vs 비용”의 <strong>엘보(elbow)</strong> 지점을 찾아 실험.</li>
<li><strong>n이 작다(≤ 수천~수만)</strong> → 768도 무난. 다만 과적합·허브니스는 체크.</li>
</ul>
<hr>
<h2 id="5-메모리--속도-숫자로-감-잡기">5) 메모리 &amp; 속도, <strong>숫자로</strong> 감 잡기</h2>
<h3 id="저장량대략">저장량(대략)</h3>
<ul>
<li>공식: <strong><code>N × d × 4 bytes</code></strong> (float32 가정)</li>
</ul>
<p>예) <strong>N = 100,000 문서</strong></p>
<ul>
<li>d=384  → 100,000 × 384 × 4 = <strong>153,600,000 bytes ≈ 146.5 MB</strong></li>
<li>d=768  → 100,000 × 768 × 4 = <strong>307,200,000 bytes ≈ 293.0 MB</strong></li>
<li>d=1024 → 100,000 × 1024 × 4 = <strong>409,600,000 bytes ≈ 390.6 MB</strong></li>
</ul>
<blockquote>
<p>팁:</p>
<ul>
<li><strong>float16</strong>(2 bytes)나 **양자화(quantization, PQ/OPQ/INT8)**를 쓰면 절반 이하로 줄일 수 있음(검색 정확도 하락과 트레이드오프).</li>
<li>Elasticsearch <code>dense_vector</code>는 내부 구현 제약이 있어 <strong>저정밀도 저장/양자화</strong>는 보통 <strong>FAISS/HNSW 라이브러리</strong>가 더 유연함.</li>
</ul>
</blockquote>
<h3 id="연산대략">연산(대략)</h3>
<ul>
<li>코사인/내적 1회 비용 <strong>∝ d</strong>.</li>
<li>KNN(HNSW)도 후보 간 거리 계산량이 d에 비례 → <strong>d가 두 배면 대략 연산량도 두 배</strong>로 본다(상수항 제외).</li>
</ul>
<hr>
<h2 id="6-언제-차원을-키우고줄일까-의사결정-표">6) <strong>언제</strong> 차원을 키우고/줄일까 (의사결정 표)</h2>
<table>
<thead>
<tr>
<th>상황</th>
<th>추천 차원/전략</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td><strong>문서 수 적음(≤ 수만)</strong>, 다국어·전문용어 많음</td>
<td>768~1024</td>
<td>의미 공간을 넉넉히, 표현 손실 방지</td>
</tr>
<tr>
<td><strong>대규모(≥ 수백만)</strong>, 응답시간 엄격</td>
<td>384~512 + <strong>2단계 검색</strong></td>
<td>1단계 저차원 ANN으로 후보 200개, 2단계 고차원/크로스인코더 재랭크</td>
</tr>
<tr>
<td><strong>메모리 빡셈(EC2 t3.small 등)</strong></td>
<td>256~384 + 양자화</td>
<td>비용 절감, 충분한 품질이면 승</td>
</tr>
<tr>
<td><strong>짧은 질의·짧은 청크</strong>(FAQ, 타이틀 중심)</td>
<td>384~512</td>
<td>과도한 차원은 이득↓ 비용↑</td>
</tr>
<tr>
<td><strong>길고 복잡한 설명/약관</strong>(한국어 문단 위주)</td>
<td>768</td>
<td>문맥 풍부, 한국어 SBERT 768과 궁합</td>
</tr>
</tbody></table>
<hr>
<h2 id="7-elasticsearch에서의-포인트">7) Elasticsearch에서의 포인트</h2>
<ul>
<li><p><code>dense_vector</code>의 <code>dims</code>는 <strong>임베딩 길이와 반드시 같아야</strong> 색인됨.</p>
</li>
<li><p><strong>Cosine</strong> 쓰려면 <strong>L2 정규화</strong> 권장(정규화 후 dot = cosine).</p>
</li>
<li><p>대규모·지연 민감이면 <code>knn_vector</code> + HNSW(근사 KNN) 고려.</p>
</li>
<li><p><strong>스코어링 예시</strong>(정규화되어 있다면):</p>
<pre><code class="language-json">&quot;script&quot;: {
  &quot;source&quot;: &quot;cosineSimilarity(params.q, &#39;embedding&#39;) + 1.0&quot;,
  &quot;params&quot;: {&quot;q&quot;: [ ... 768 floats ... ]}
}</code></pre>
</li>
<li><p><strong>두 단계 검색</strong>:</p>
<ol>
<li><code>knn_vector</code>(저차원 or 양자화)로 <strong>Top-k 후보</strong></li>
<li>후보에 대해 <strong>고차원 벡터</strong> 혹은 <strong>Cross-Encoder</strong>로 재랭크</li>
</ol>
</li>
</ul>
<hr>
<h2 id="8-차원을-바꿔보며-성능-비용-곡선-보기-실험-프로토콜">8) 차원을 “바꿔보며” 성능-비용 곡선 보기 (실험 프로토콜)</h2>
<ol>
<li><strong>기준 임베딩</strong>(예: 768) 만들기</li>
<li>PCA로 차원 축소(예: 128/256/384/512)</li>
<li>동일 인덱싱 조건에서 <strong>Recall@k / NDCG@k / MRR</strong> 측정</li>
<li><strong>엘보 지점</strong>(성능 크게 떨어지지 않으면서 비용 낮은 지점)을 채택</li>
<li>필요한 경우 <strong>두 단계 검색</strong>으로 타협</li>
</ol>
<pre><code class="language-python">from sklearn.decomposition import PCA
import numpy as np

base_vecs = ...  # (N, 768)
for d in [128, 256, 384, 512]:
    pca = PCA(n_components=d, random_state=42)
    vecs_d = pca.fit_transform(base_vecs)  # (N, d)
    # 1) 이 vecs_d로 인덱싱
    # 2) 동일한 쿼리셋으로 Recall@10, NDCG@10 측정
    # 3) 비용/성능 비교해 선택</code></pre>
<blockquote>
<p>PCA는 “기존 768을 줄였을 때”의 실험용. 실제론 <strong>저차원 모델</strong> 자체를 쓰는 편이 관리가 쉬움(예: MiniLM 384).</p>
</blockquote>
<hr>
<h2 id="9-차원과-관련된-자주-하는-실수-체크리스트">9) 차원과 관련된 <strong>자주 하는 실수 체크리스트</strong></h2>
<ul>
<li><p>⛔ <strong>모델 바꿨는데 ES <code>dims</code> 안 바꿈</strong> → 색인 에러</p>
</li>
<li><p>⛔ <strong>임베딩 정규화 없이 cosine</strong> → 스코어 뒤틀림</p>
</li>
<li><p>⛔ <strong>메타데이터 타입 충돌</strong>(문서마다 같은 키인데 숫자/문자 섞임) → 색인 실패</p>
</li>
<li><p>⛔ <strong>Hubness 무시</strong> → 일부 문서가 과도하게 상위에 노출</p>
<ul>
<li>↳ 완화: 정규화, 차원 축소, 거리 보정(상호근접도/Mutual Proximity) 등</li>
</ul>
</li>
</ul>
<hr>
<h2 id="10-코드-스니펫-모음">10) 코드 스니펫 모음</h2>
<h3 id="a-차원-자동-감지-→-es-매핑-자동-설정">(A) <strong>차원 자동 감지 → ES 매핑 자동 설정</strong></h3>
<pre><code class="language-python">from langchain_community.embeddings import HuggingFaceEmbeddings
from elasticsearch import Elasticsearch

model_name = &quot;snunlp/KR-SBERT-V40K-klueNLI-augSTS&quot;
emb = HuggingFaceEmbeddings(model_name=model_name)

probe = emb.embed_query(&quot;차원 확인&quot;)
dim = len(probe)  # 예: 768

es = Elasticsearch(&quot;http://localhost:9200&quot;)
index = &quot;my_index&quot;

if es.indices.exists(index=index):
    es.indices.delete(index=index)

es.indices.create(
    index=index,
    mappings={
        &quot;properties&quot;: {
            &quot;text&quot;: {&quot;type&quot;: &quot;text&quot;, &quot;analyzer&quot;: &quot;nori&quot;},
            &quot;embedding&quot;: {&quot;type&quot;: &quot;dense_vector&quot;, &quot;dims&quot;: dim}
        }
    }
)
print(&quot;dims =&quot;, dim)</code></pre>
<h3 id="b-l2-정규화-후-색인-cosine-안정화">(B) <strong>L2 정규화 후 색인</strong> (cosine 안정화)</h3>
<pre><code class="language-python">import numpy as np

def l2norm(v):
    v = np.asarray(v, dtype=np.float32)
    n = np.linalg.norm(v)
    return (v / n).tolist() if n else v.tolist()

vecs = [l2norm(v) for v in emb.embed_documents(texts)]
# vecs를 embedding으로 색인하면, dot == cosine</code></pre>
<h3 id="c-2단계-검색개념">(C) <strong>2단계 검색(개념)</strong></h3>
<pre><code class="language-text">[낮은 차원 / 양자화 인덱스] --Top200--&gt; [고차원 ES/FAISS] --Topk--&gt;
[Cross-Encoder Rerank(Optional)] --Topk--&gt;</code></pre>
<hr>
<h2 id="11-추천-선택지요약">11) 추천 선택지(요약)</h2>
<ul>
<li><p><strong>한국어 문단 중심 RAG</strong> + <strong>문서 수: 수만~수십만</strong> → <strong>768차원</strong> 무난</p>
</li>
<li><p><strong>문서 수: 수백만+</strong> &amp; <strong>지연 엄격</strong> → <strong>384~512 + 2단계 검색</strong></p>
</li>
<li><p><strong>메모리/비용 제한</strong> → 256~384 + <strong>양자화</strong> 고려</p>
</li>
<li><p>결과가 마음에 안 들면, <strong>차원만 바꾸지 말고</strong></p>
<ul>
<li>모델 변경(학습 데이터/도메인 적합성)</li>
<li>청크 전략(분량/오버랩/레이아웃)</li>
<li>리랭킹(크로스인코더)까지 함께 조정</li>
</ul>
</li>
</ul>
<hr>
<h2 id="마무리">마무리</h2>
<p>임베딩 차원은 “<strong>성능 vs 비용</strong>”의 손잡이입니다. <strong>데이터 크기, 지연 요구사항, 도메인 복잡성</strong>을 동시에 보고, 작은 실험으로 엘보 지점을 찾는 게 가장 빠른 길이에요.
필요하면, 현재 쓰는 인덱스 규모/응답 시간 목표 알려주면 <strong>권장 차원 + 인덱싱 전략</strong>까지 구체적으로 짜 드릴게!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[LangChain `SemanticChunker` 사용 시 `AttributeError` 해결 과정 (feat. Wrapper 클래스)]]></title>
            <link>https://velog.io/@mo_ongh/LangChain-SemanticChunker-%EC%82%AC%EC%9A%A9-%EC%8B%9C-AttributeError-%ED%95%B4%EA%B2%B0-%EA%B3%BC%EC%A0%95-feat.-Wrapper-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@mo_ongh/LangChain-SemanticChunker-%EC%82%AC%EC%9A%A9-%EC%8B%9C-AttributeError-%ED%95%B4%EA%B2%B0-%EA%B3%BC%EC%A0%95-feat.-Wrapper-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Sat, 30 Aug 2025 17:46:20 GMT</pubDate>
            <description><![CDATA[<h3 id="제목-langchain-semanticchunker-사용-시-attributeerror-해결-과정-feat-wrapper-클래스"><strong>제목: LangChain <code>SemanticChunker</code> 사용 시 <code>AttributeError</code> 해결 과정 (feat. Wrapper 클래스)</strong></h3>
<h3 id="태그-langchain-semanticchunker-sentencetransformer-attributeerror-huggingfaceembeddings"><strong>태그:</strong> <code>LangChain</code>, <code>SemanticChunker</code>, <code>SentenceTransformer</code>, <code>AttributeError</code>, <code>HuggingFaceEmbeddings</code></h3>
<hr>
<h3 id="1-들어가며-문제-상황-겪기"><strong>1. 들어가며: 문제 상황 겪기</strong></h3>
<p>최근 RAG(Retrieval-Augmented Generation) 파이프라인의 성능을 높이기 위해, LangChain에서 제공하는 <code>SemanticChunker</code>를 도입하는 과정에서 흥미로운 오류를 만났습니다.</p>
<p>의미 기반으로 텍스트를 분할하기 위해 <code>sentence-transformers</code> 라이브러리로 한국어 임베딩 모델을 불러와 <code>SemanticChunker</code>에 전달했는데, 아래와 같은 에러가 발생했습니다.</p>
<p><strong><code>AttributeError: &#39;SentenceTransformer&#39; object has no attribute &#39;embed_documents&#39;</code></strong></p>
<p>분명 임베딩 모델 객체를 넘겨줬는데, 왜 <code>embed_documents</code>라는 속성이 없다는 오류가 발생했을까요? 이 글에서는 이 문제의 원인을 분석하고, LangChain의 아키텍처를 이해하며 어떻게 해결했는지 그 과정을 공유하고자 합니다.</p>
<h3 id="2-오류-발생-코드"><strong>2. 오류 발생 코드</strong></h3>
<p>문제를 일으켰던 코드는 다음과 같습니다. <code>sentence-transformers</code>로 모델을 로드하여 <code>SemanticChunker</code>의 <code>embeddings</code> 인자로 바로 전달했습니다.</p>
<pre><code class="language-python">from sentence_transformers import SentenceTransformer
from langchain_experimental.text_splitter import SemanticChunker

# 1. sentence-transformers로 임베딩 모델 직접 로드
model_name = &quot;snunlp/KR-SBERT-V40K-klueNLI-augSTS&quot;
embedding_model = SentenceTransformer(model_name)

# 2. SemanticChunker에 그대로 전달
text_splitter = SemanticChunker(
    embeddings=embedding_model, #
    breakpoint_threshold_type=&quot;percentile&quot; 
)

# 3. 문서 생성 시도 -&gt; AttributeError 발생!
chunks = text_splitter.create_documents([full_text])</code></pre>
<h3 id="3-오류의-원인-분석-api-호환성-문제"><strong>3. 오류의 원인 분석: API 호환성 문제</strong></h3>
<p>결론부터 말하면, 이 문제는 **LangChain이 기대하는 &#39;표준 인터페이스&#39;**와 <strong><code>sentence-transformers</code> 라이브러리가 제공하는 객체의 인터페이스</strong>가 달라서 발생했습니다.</p>
<p>마치 전기 콘센트와 플러그의 모양이 맞지 않는 것과 같습니다.</p>
<blockquote>
<p>**<code>SemanticChunker</code> (콘센트)**는 LangChain 생태계의 부품으로, <code>embed_documents</code>라는 이름의 메소드(&#39;세모 모양 플러그&#39;)를 가진 임베딩 객체를 받도록 설계되어 있습니다.</p>
<p>**<code>SentenceTransformer</code> 객체 (전자제품)**는 <code>encode</code>라는 메소드(&#39;동그란 모양 플러그&#39;)를 통해 문장을 임베딩합니다.</p>
</blockquote>
<p><code>SemanticChunker</code>는 <code>embedding_model.embed_documents()</code>를 호출하려고 했지만, 실제 객체에는 <code>embed_documents</code>가 없고 <code>encode</code>만 있으니 <code>AttributeError</code>가 발생한 것입니다.</p>
<h3 id="4-해결-방법-langchain-래퍼wrapper-클래스-사용하기"><strong>4. 해결 방법: LangChain 래퍼(Wrapper) 클래스 사용하기</strong></h3>
<p>LangChain은 이런 문제를 해결하기 위해 외부 라이브러리를 LangChain 표준에 맞게 감싸주는 <strong>래퍼(Wrapper) 클래스</strong>를 제공합니다. <code>sentence-transformers</code>를 위한 래퍼가 바로 **<code>HuggingFaceEmbeddings</code>**입니다.</p>
<p><code>HuggingFaceEmbeddings</code>는 내부에 <code>SentenceTransformer</code> 모델을 품고, 외부에는 LangChain이 알아볼 수 있는 <code>embed_documents</code> 메소드를 노출시켜주는 <strong>&#39;모양 변환 어댑터&#39;</strong> 역할을 합니다.</p>
<h4 id="수정된-코드"><strong>수정된 코드</strong></h4>
<pre><code class="language-python"># langchain_community에서 어댑터 역할을 할 래퍼 클래스를 임포트
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_experimental.text_splitter import SemanticChunker

# 1. 사용할 모델 이름 정의
model_name = &quot;snunlp/KR-SBERT-V40K-klueNLI-augSTS&quot;

# 2. SentenceTransformer 대신 HuggingFaceEmbeddings 래퍼 사용
# 이제 embedding_model은 LangChain 표준을 따르는 객체가 됩니다.
embedding_model = HuggingFaceEmbeddings(model_name=model_name)

# 3. SemanticChunker에 호환되는 객체 전달
text_splitter = SemanticChunker(
    embeddings=embedding_model,
    breakpoint_threshold_type=&quot;percentile&quot; 
)

# 4. 정상적으로 실행됨!
chunks = text_splitter.create_documents([full_text])

print(&quot;성공적으로 청킹 완료!&quot;)</code></pre>
<h3 id="5-결론-및-핵심-요약"><strong>5. 결론 및 핵심 요약</strong></h3>
<p>이번 오류 해결 과정을 통해 다음과 같은 중요한 점을 배울 수 있었습니다.</p>
<blockquote>
<p><strong>LangChain과 같은 프레임워크는 단순히 기능의 집합이 아니라, 정해진 &#39;약속(Interface)&#39;에 따라 각 부품이 유기적으로 연결되는 시스템이다.</strong></p>
</blockquote>
<p>외부 라이브러리를 LangChain과 연동할 때는, 해당 라이브러리를 직접 사용하기보다 LangChain이 제공하는 <strong>래퍼 클래스가 있는지 먼저 확인</strong>하는 습관을 들이는 것이 좋습니다. 이 래퍼들이 바로 서로 다른 모양의 플러그와 콘센트를 연결해주는 고마운 &#39;어댑터&#39;이기 때문입니다.</p>
<p>혹시 저와 같은 <code>AttributeError</code>를 만나신 분들께 이 글이 도움이 되기를 바랍니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[LangChain - UnstructuredPDFLoader]]></title>
            <link>https://velog.io/@mo_ongh/LangChain-UnstructuredPDFLoader</link>
            <guid>https://velog.io/@mo_ongh/LangChain-UnstructuredPDFLoader</guid>
            <pubDate>Sat, 30 Aug 2025 17:45:49 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-python">loader = UnstructuredPDFLoader(pdf_path, mode=&quot;elements&quot;, strategy=&quot;hi_res&quot;)
</code></pre>
<p>model=&quot;elements&quot;</p>
<ul>
<li>PDF내 요소 단위(제목, 본문, 리스트, 표 등)로 잘게 나눠 각각을 별도 Document로 돌려줌.</li>
<li>model = &quot;single&quot; : PDF전체를 하나의 Document로 변환</li>
<li>model = &quot;paged&quot; : 페이지 단위로 Document로 변환</li>
</ul>
<p>strategy=&quot;hi_res&quot;</p>
<ul>
<li><p>고정밀(high-resolution)파이프라인을 사용</p>
</li>
<li><p>내부적으로 unstructured라이브러리의 레이아웃감지(딥러닝/컴퓨터비전) + OCR(스캔된 PDF,이미지)을 활용하여 제목/본문/표/리스트 등 블록 수준 구조를 인식.</p>
</li>
<li><p>장점 : 표/리스트/섹션 헤더처럼 문서 구조를 더 정확히 파악</p>
</li>
<li><p>단점 : 느림, 메모리/의존성 요구 높음.</p>
</li>
<li><p>결과적으로 정보 검색(rag)이나 질의응답에서 &quot;문단/표/리스트&quot;등 의미 단위로 청크가 나뉘어 성능이 좋아지는 경우가 많음.</p>
</li>
<li><p>strategy=&quot;fast&quot;
: fast: 텍스트 추출 위주(레이아웃 인식은 약함), 빠름</p>
</li>
<li><p>ocr_only
: 무조건 OCR(스캔 위주 문서에 유용, 일반 PDF엔 불리)</p>
</li>
</ul>
<pre><code class="language-python">documents = loader.load()</code></pre>
<ul>
<li>실제로 PDF를 읽어 List[Document]를 반환.</li>
<li>model=&quot;elements&quot; 이므로 각 요소마다 Document한 개<ul>
<li>doc.page_content : 해당 블록의 텍스트</li>
<li>doc.metadata : source(파일 경로), page_number, category, 등등</li>
</ul>
</li>
<li>스캔본/그림만 있는 PDF도 hi_res 덕분에 OCR로 텍스트를 최대한 뽑아냄</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[pickle]]></title>
            <link>https://velog.io/@mo_ongh/pickle</link>
            <guid>https://velog.io/@mo_ongh/pickle</guid>
            <pubDate>Sat, 30 Aug 2025 11:00:47 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-python">import pickle</code></pre>
<ul>
<li>파이썬 객체를 <strong>직렬화(serialize)</strong>/ <strong>역직렬화(deserialize)</strong> 하는 표준 모듈을 불러옵니다.</li>
<li>직렬화 = 메모리 속 객체를 바이트(byte) 형태로 변환해 파일 등에 저장할 수 있게 만드는 것.</li>
</ul>
<pre><code class="language-python"># 결과를 pickle 파일로 저장
with open(&#39;chunks_baseline.pkl&#39;, &#39;wb&#39;) as f:</code></pre>
<ul>
<li><p><code>&#39;chunks_baseline.pkl&#39;</code>이라는 파일을 <strong>쓰기 모드로(binary)</strong> 엽니다.</p>
<ul>
<li><code>&#39;wb&#39;</code>: write + binary (피클은 텍스트가 아니라 <strong>바이너리</strong>라서 b 필수)</li>
</ul>
</li>
<li><p><code>with ... as f:</code> 컨텍스트 매니저: 블록이 끝나면 <strong>자동으로 파일을 닫아줍니다</strong>(에러가 나도 안전하게 닫힘).</p>
</li>
</ul>
<pre><code class="language-python">    pickle.dump(chunks, f)</code></pre>
<ul>
<li><p>메모리에 있는 <code>chunks</code> 객체를 피클 형식으로 <strong>파일 f에 저장</strong>합니다.</p>
</li>
<li><p><code>chunks</code>는 미리 만들어져 있어야 합니다(없으면 <code>NameError</code>).</p>
</li>
<li><p>프로토콜은 기본값(파이썬 버전에 따라 달라짐)이 사용됩니다. 더 빠르고 작은 최신 포맷을 원하면:</p>
<pre><code class="language-python">pickle.dump(chunks, f, protocol=pickle.HIGHEST_PROTOCOL)</code></pre>
</li>
</ul>
<pre><code class="language-python">print(&quot;✅ &#39;chunks_baseline.pkl&#39; 파일로 저장 완료!&quot;)</code></pre>
<ul>
<li>저장이 끝났음을 콘솔에 출력.</li>
</ul>
<hr>
<h3 id="추가-팁">추가 팁</h3>
<p><strong>불러오는 방법(역직렬화)</strong></p>
<pre><code class="language-python">import pickle

with open(&#39;chunks_baseline.pkl&#39;, &#39;rb&#39;) as f:
    chunks_loaded = pickle.load(f)

print(type(chunks_loaded), len(chunks_loaded) if hasattr(chunks_loaded, &#39;__len__&#39;) else &#39;no len&#39;)</code></pre>
<p><strong>경로/위치</strong></p>
<ul>
<li><p>파일은 <strong>현재 작업 디렉토리</strong>에 저장됩니다. 위치가 헷갈리면:</p>
<pre><code class="language-python">import os
print(os.getcwd())</code></pre>
</li>
</ul>
<p><strong>보안 주의</strong></p>
<ul>
<li><strong>신뢰할 수 없는 소스에서 받은 .pkl을 <code>pickle.load</code>로 열지 마세요.</strong> 임의 코드가 실행될 수 있습니다.</li>
</ul>
<p><strong>용량이 큰 경우 압축 저장</strong></p>
<pre><code class="language-python">import gzip, pickle
with gzip.open(&#39;chunks_baseline.pkl.gz&#39;, &#39;wb&#39;) as f:
    pickle.dump(chunks, f, protocol=pickle.HIGHEST_PROTOCOL)

with gzip.open(&#39;chunks_baseline.pkl.gz&#39;, &#39;rb&#39;) as f:
    chunks_loaded = pickle.load(f)</code></pre>
<p><strong>호환성</strong></p>
<ul>
<li>피클은 <strong>파이썬 전용</strong> 포맷입니다(다른 언어와 호환 X, 사람이 읽기 어려움).</li>
<li>교차 언어/사람 가독성이 필요하면 JSON/CSV 등을 검토하세요(단, 복잡한 파이썬 객체는 JSON으로 바로 저장하기 어려울 수 있음).</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[1]]></title>
            <link>https://velog.io/@mo_ongh/1-iqqxukzm</link>
            <guid>https://velog.io/@mo_ongh/1-iqqxukzm</guid>
            <pubDate>Sat, 30 Aug 2025 06:28:08 GMT</pubDate>
            <description><![CDATA[<hr>
<h3 id="-docker-run-명령어-상세-설명">## <code>docker run</code> 명령어 상세 설명</h3>
<p>우선 전체 명령어는 다음과 같습니다.</p>
<pre><code class="language-bash">docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e &quot;discovery.type=single-node&quot; -e &quot;xpack.security.enabled=false&quot; docker.elastic.co/elasticsearch/elasticsearch:8.10.2</code></pre>
<hr>
<p>이 명령어를 구성 요소별로 나누어 보면 이렇습니다.</p>
<ul>
<li><p><strong><code>docker run</code></strong></p>
<ul>
<li>가장 기본이 되는 명령어로, Docker에게 &quot;새로운 컨테이너를 하나 만들고 실행해 줘&quot;라고 지시하는 역할을 합니다.</li>
</ul>
</li>
<li><p><strong><code>-d</code></strong> 또는 <code>--detach</code></p>
<ul>
<li>**&quot;Detached mode&quot;**의 약자입니다. 이 옵션을 사용하면 컨테이너가 <strong>백그라운드에서 실행</strong>됩니다. 만약 이 옵션을 빼면, 현재 사용 중인 터미널 창이 컨테이너의 로그를 계속 출력하게 되고, 터미널을 닫으면 컨테이너도 함께 종료됩니다. 개발 서버처럼 계속 켜둬야 하는 경우 필수적인 옵션입니다.</li>
</ul>
</li>
<li><p><strong><code>--name elasticsearch</code></strong></p>
<ul>
<li>실행되는 컨테이너에 <strong>&quot;elasticsearch&quot;라는 고유한 이름</strong>을 붙여줍니다. 이름을 지정해두면 나중에 <code>docker stop elasticsearch</code>나 <code>docker logs elasticsearch</code>처럼 이름으로 컨테이너를 제어하기가 매우 편리해집니다.</li>
</ul>
</li>
<li><p><strong><code>-p 9200:9200</code></strong></p>
<ul>
<li><strong>&quot;Port forwarding&quot; (포트 포워딩)</strong> 설정입니다. 콜론(<code>:</code>)을 기준으로 **<code>[내 컴퓨터의 포트]:[컨테이너 내부의 포트]</code>**를 의미합니다.</li>
<li>Elasticsearch 컨테이너는 기본적으로 <strong>내부 9200번 포트</strong>를 사용해 외부와 통신(REST API)합니다. 이 옵션은 내 컴퓨터(호스트 PC)의 <strong>9200번 포트</strong>로 들어오는 요청을 컨테이너 내부의 <strong>9200번 포트</strong>로 전달하라는 의미입니다. 그래서 우리가 <code>http://localhost:9200</code>으로 접속할 수 있는 것입니다.</li>
<li></li>
</ul>
</li>
<li><p><strong><code>-p 9300:9300</code></strong></p>
<ul>
<li>위와 같은 포트 포워딩 설정입니다. <strong>9300번 포트</strong>는 Elasticsearch 노드(컴퓨터)들끼리 서로 통신할 때 사용하는 <strong>내부 통신용 포트</strong>입니다. 지금은 노드가 하나뿐이라 사용하지는 않지만, 표준 설정에 포함되어 있습니다.</li>
</ul>
</li>
<li><p><strong><code>-e &quot;...&quot;</code></strong> 또는 <code>--env &quot;...&quot;</code></p>
<ul>
<li>**&quot;Environment variable&quot; (환경 변수)**를 설정하는 옵션입니다. 컨테이너 내부에서 실행되는 애플리케이션(여기서는 Elasticsearch)의 설정을 Docker 명령어로 직접 지정할 수 있게 해줍니다.</li>
<li><strong><code>&quot;discovery.type=single-node&quot;</code></strong>: Elasticsearch에게 &quot;너는 다른 노드를 찾을 필요 없이 혼자(단일 노드) 실행될 거야&quot;라고 알려주는 설정입니다. 이걸 설정하지 않으면 Elasticsearch가 클러스터를 구성하기 위해 다른 노드를 찾으려고 시도하다가 오류를 낼 수 있습니다.</li>
<li><strong><code>&quot;xpack.security.enabled=false&quot;</code></strong>: Elasticsearch 8.x 버전부터 기본으로 활성화된 보안 기능(사용자 인증 등)을 비활성화하는 설정입니다. 개발 환경에서는 보안 기능이 없어야 번거로운 인증 절차 없이 바로 접속하고 테스트할 수 있어 편리합니다.</li>
</ul>
</li>
<li><p><strong><code>docker.elastic.co/elasticsearch/elasticsearch:8.10.2</code></strong></p>
<ul>
<li>실행할 <strong>Docker 이미지의 전체 이름</strong>입니다.</li>
<li><code>docker.elastic.co/elasticsearch/elasticsearch</code>는 이미지의 이름이고, <code>:8.10.2</code>는 **버전 태그(tag)**입니다. 버전을 명시해주면 항상 동일한 환경에서 컨테이너를 실행할 수 있어 안정적인 개발이 가능합니다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Docker]]></title>
            <link>https://velog.io/@mo_ongh/Docker</link>
            <guid>https://velog.io/@mo_ongh/Docker</guid>
            <pubDate>Thu, 28 Aug 2025 15:01:44 GMT</pubDate>
            <description><![CDATA[<pre><code>docker-compose build --no-cache</code></pre><p>레시피(Dockerfile)를 보고,
재료(--no-cache)를 아끼지 말고,
처음부터 정직하게 요리(build)해줘.</p>
<hr>
<p>docker-compose
: docker-compose.yml이라는 설계도를 읽어서 여러 Docker 컨테이너를 한 번에 관리</p>
<p>build
: 이미지를 만드는 명령어
docker-compose.yml 파일에서 
build: . 이라고 지정된 서비스(elasticsearch)를 찾아,
그 서비스의 레시피인 Dockerfile을 보고 이미지를 만듬</p>
<p>—no-cache
: Cache를 사용하지 말라는 옵션
Docker는 빌드 속도를 높이기 위해 이전에 만들었던 중간 과정들을 ‘캐시’로 저장해둠.
하지만 가끔 이 캐시 때문에 변경사항이 적용되지 않는 문제가 생기는데, 
—no-cache 옵션을 붙이면 이전에 기억해 둔 것들을 모두 무시하고, 
Dockerfile의 모든 단계를 처음부터 끝까지 깨끗하게 다시 실행함.</p>
<hr>
<pre><code>docker-compose up -d</code></pre><p>설계도(Docker-compose.yml)를 보고,
만들어진 이미지들을 사용해서 건물(컨테이너)을 짓고,
백그라운드에서 조용히 운영(-d)시작해줘</p>
<hr>
<p>up
: 컨테이너(Container)를 생성하고 실행
build 명령어로 만들어 둔 이미지를 가져다가 실제 작동하는 프로그램인 컨테이너를 만듬.</p>
<p>-d
: &#39;detached&#39;모드
이 옵션을 붙이면 터미널에서 컨테이너의 실행 로그가 계속 보이지 않고, 백그라운드에서 조용히 실해됨.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git 명령어 모음]]></title>
            <link>https://velog.io/@mo_ongh/Git-%EB%AA%85%EB%A0%B9%EC%96%B4-%EB%AA%A8%EC%9D%8C</link>
            <guid>https://velog.io/@mo_ongh/Git-%EB%AA%85%EB%A0%B9%EC%96%B4-%EB%AA%A8%EC%9D%8C</guid>
            <pubDate>Sat, 02 Aug 2025 22:21:56 GMT</pubDate>
            <description><![CDATA[<h1 id="git-명령어-빠른-참조---치트시트">Git 명령어 빠른 참조 - 치트시트</h1>
<h2 id="🚀-기본-작업-흐름">🚀 기본 작업 흐름</h2>
<h3 id="프로젝트-시작">프로젝트 시작</h3>
<pre><code class="language-bash"># 원격 저장소 클론
git clone https://github.com/username/repository.git

# 디렉토리 이동
cd repository-name</code></pre>
<h3 id="새-브랜치-생성-및-작업">새 브랜치 생성 및 작업</h3>
<pre><code class="language-bash"># 새 브랜치 생성 + 전환
git checkout -b branch-name

# 또는 (Git 2.23+)
git switch -c branch-name</code></pre>
<h3 id="작업-저장-및-업로드">작업 저장 및 업로드</h3>
<pre><code class="language-bash"># 변경사항 추가
git add .

# 커밋
git commit -m &quot;커밋 메시지&quot;

# 원격 저장소에 푸시
git push origin branch-name</code></pre>
<hr>
<h2 id="🔄-동기화-merge-후-필수">🔄 동기화 (Merge 후 필수!)</h2>
<h3 id="4단계-동기화">4단계 동기화</h3>
<pre><code class="language-bash">git checkout main                 # main 브랜치로 전환
git pull origin main             # 최신 main 가져오기
git checkout study/01-project-setup  # 작업 브랜치로 복귀
git pull origin main             # 작업 브랜치도 최신화</code></pre>
<hr>
<h2 id="📋-상태-확인">📋 상태 확인</h2>
<h3 id="현재-상태-확인">현재 상태 확인</h3>
<pre><code class="language-bash">git status                       # 현재 변경사항 확인
git branch                       # 로컬 브랜치 목록
git branch -r                    # 원격 브랜치 목록
git log --oneline -5             # 최근 5개 커밋 확인</code></pre>
<h3 id="변경사항-확인">변경사항 확인</h3>
<pre><code class="language-bash">git diff                         # 현재 변경사항 확인
git diff --staged                # 스테이지된 변경사항 확인
git log --oneline --graph        # 커밋 그래프 확인</code></pre>
<hr>
<h2 id="🌿-브랜치-관리">🌿 브랜치 관리</h2>
<h3 id="브랜치-생성전환">브랜치 생성/전환</h3>
<pre><code class="language-bash">git checkout -b new-branch       # 새 브랜치 생성 + 전환
git checkout existing-branch     # 기존 브랜치로 전환
git switch branch-name           # 브랜치 전환 (Git 2.23+)</code></pre>
<h3 id="브랜치-삭제">브랜치 삭제</h3>
<pre><code class="language-bash">git branch -d branch-name        # 로컬 브랜치 삭제
git push origin -d branch-name   # 원격 브랜치 삭제</code></pre>
<hr>
<h2 id="💾-커밋-관련">💾 커밋 관련</h2>
<h3 id="기본-커밋">기본 커밋</h3>
<pre><code class="language-bash">git add .                        # 모든 변경사항 스테이지
git add filename                 # 특정 파일만 스테이지
git commit -m &quot;메시지&quot;           # 커밋
git commit -am &quot;메시지&quot;          # 추가 + 커밋 (신규 파일 제외)</code></pre>
<h3 id="커밋-수정">커밋 수정</h3>
<pre><code class="language-bash">git commit --amend -m &quot;새 메시지&quot;  # 마지막 커밋 메시지 수정
git reset HEAD~1                 # 마지막 커밋 취소 (변경사항 유지)
git reset --hard HEAD~1          # 마지막 커밋 완전 삭제</code></pre>
<hr>
<h2 id="📤-원격-저장소">📤 원격 저장소</h2>
<h3 id="푸시풀">푸시/풀</h3>
<pre><code class="language-bash">git push origin branch-name      # 브랜치 푸시
git push origin main             # main 브랜치 푸시
git pull origin main             # main 브랜치 풀
git fetch origin                 # 정보만 가져오기 (머지 안함)</code></pre>
<h3 id="원격-저장소-관리">원격 저장소 관리</h3>
<pre><code class="language-bash">git remote -v                    # 원격 저장소 목록
git remote add origin url        # 원격 저장소 추가</code></pre>
<hr>
<h2 id="🔍-검색-및-이력">🔍 검색 및 이력</h2>
<h3 id="로그-확인">로그 확인</h3>
<pre><code class="language-bash">git log                          # 전체 커밋 로그
git log --oneline                # 한 줄로 요약
git log --oneline -10            # 최근 10개만
git log --graph --all            # 그래프로 모든 브랜치</code></pre>
<h3 id="파일-추적">파일 추적</h3>
<pre><code class="language-bash">git log filename                 # 특정 파일 변경 이력
git blame filename               # 각 줄의 작성자 확인
git show commit-hash             # 특정 커밋 상세 정보</code></pre>
<hr>
<h2 id="🛠️-우리-프로젝트-전용-명령어">🛠️ 우리 프로젝트 전용 명령어</h2>
<h3 id="phase-작업-시작">Phase 작업 시작</h3>
<pre><code class="language-bash">cd /Users/moon/Desktop/study-insupanda
git status
git checkout main
git pull origin main
git checkout study/01-project-setup
git pull origin main</code></pre>
<h3 id="phase-작업-완료">Phase 작업 완료</h3>
<pre><code class="language-bash">git add .
git commit -m &quot;docs: Phase X.Y [작업내용] 완료&quot;
git push origin study/01-project-setup</code></pre>
<h3 id="새로운-개별-브랜치-phase-13부터">새로운 개별 브랜치 (Phase 1.3부터)</h3>
<pre><code class="language-bash">git checkout main
git pull origin main
git checkout -b phase1-3-env-config
# 작업 진행
git add .
git commit -m &quot;docs: Phase 1.3 환경설정 파일 분석 완료&quot;
git push origin phase1-3-env-config</code></pre>
<hr>
<h2 id="📝-커밋-메시지-템플릿">📝 커밋 메시지 템플릿</h2>
<h3 id="제목-형식">제목 형식</h3>
<pre><code class="language-bash"># 학습 프로젝트용
git commit -m &quot;docs: Phase X.Y [작업내용] 완료&quot;
git commit -m &quot;study: [학습내용] 정리 완료&quot;
git commit -m &quot;analysis: [분석내용] 완료&quot;

# 일반 프로젝트용
git commit -m &quot;feat: 새로운 기능 추가&quot;
git commit -m &quot;fix: 버그 수정&quot;
git commit -m &quot;refactor: 코드 리팩토링&quot;</code></pre>
<hr>
<h2 id="⚠️-문제-해결">⚠️ 문제 해결</h2>
<h3 id="충돌-해결">충돌 해결</h3>
<pre><code class="language-bash"># 충돌 발생 시
git status                       # 충돌 파일 확인
# 파일 수동 편집 후
git add .
git commit -m &quot;resolve: merge conflict 해결&quot;</code></pre>
<h3 id="실수했을-때">실수했을 때</h3>
<pre><code class="language-bash">git reset HEAD filename          # 스테이지 취소
git checkout -- filename        # 파일 변경사항 취소
git reflog                       # 참조 로그 확인 (복구용)</code></pre>
<h3 id="강제-동기화-주의">강제 동기화 (주의!)</h3>
<pre><code class="language-bash">git fetch origin
git reset --hard origin/main     # 로컬을 원격과 완전 동일하게</code></pre>
<hr>
<h2 id="🎯-자주-사용하는-조합-명령어">🎯 자주 사용하는 조합 명령어</h2>
<h3 id="작업-시작할-때">작업 시작할 때</h3>
<pre><code class="language-bash">git status &amp;&amp; git pull origin main</code></pre>
<h3 id="작업-완료할-때">작업 완료할 때</h3>
<pre><code class="language-bash">git add . &amp;&amp; git commit -m &quot;메시지&quot; &amp;&amp; git push origin branch-name</code></pre>
<h3 id="브랜치-정리할-때">브랜치 정리할 때</h3>
<pre><code class="language-bash">git branch -d old-branch &amp;&amp; git push origin -d old-branch</code></pre>
<hr>
<h2 id="💡-유용한-별칭-설정">💡 유용한 별칭 설정</h2>
<h3 id="별칭-등록">별칭 등록</h3>
<pre><code class="language-bash">git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.cm commit
git config --global alias.ps push
git config --global alias.pl pull
git config --global alias.lg &quot;log --oneline --graph&quot;</code></pre>
<h3 id="별칭-사용">별칭 사용</h3>
<pre><code class="language-bash">git st              # git status
git co main         # git checkout main
git cm &quot;메시지&quot;      # git commit -m &quot;메시지&quot;
git lg              # 예쁜 로그</code></pre>
<hr>
<h2 id="🚨-비상시-명령어">🚨 비상시 명령어</h2>
<h3 id="작업-임시-저장">작업 임시 저장</h3>
<pre><code class="language-bash">git stash                        # 현재 작업 임시 저장
git stash pop                    # 임시 저장된 작업 복구
git stash list                   # 저장된 작업 목록</code></pre>
<h3 id="브랜치-복구">브랜치 복구</h3>
<pre><code class="language-bash">git reflog                       # 모든 참조 로그 확인
git checkout -b 브랜치명 커밋해시  # 특정 지점에서 브랜치 생성</code></pre>
<hr>
<h2 id="📱-github-cli-선택사항">📱 GitHub CLI (선택사항)</h2>
<h3 id="pr-생성-cli">PR 생성 (CLI)</h3>
<pre><code class="language-bash">gh pr create --title &quot;제목&quot; --body &quot;내용&quot;
gh pr list                       # PR 목록
gh pr view                       # PR 상세 보기</code></pre>
<hr>
<h2 id="🔥-실전-시나리오별-명령어">🔥 실전 시나리오별 명령어</h2>
<h3 id="시나리오-1-새로운-phase-시작">시나리오 1: 새로운 Phase 시작</h3>
<pre><code class="language-bash">git checkout main
git pull origin main
git checkout -b phase2-1-config</code></pre>
<h3 id="시나리오-2-작업-중-main-업데이트됨">시나리오 2: 작업 중 main 업데이트됨</h3>
<pre><code class="language-bash">git stash                        # 현재 작업 임시 저장
git checkout main
git pull origin main
git checkout my-branch
git pull origin main             # 최신 main 반영
git stash pop                    # 작업 복구</code></pre>
<h3 id="시나리오-3-pr-머지-후-정리">시나리오 3: PR 머지 후 정리</h3>
<pre><code class="language-bash">git checkout main
git pull origin main
git branch -d merged-branch      # 로컬 브랜치 삭제
git push origin -d merged-branch # 원격 브랜치 삭제</code></pre>
<hr>
<h2 id="📋-체크리스트">📋 체크리스트</h2>
<h3 id="작업-시작-전">작업 시작 전</h3>
<ul>
<li><input disabled="" type="checkbox"> <code>git status</code> 현재 상태 확인</li>
<li><input disabled="" type="checkbox"> <code>git pull origin main</code> 최신 상태 동기화</li>
<li><input disabled="" type="checkbox"> 올바른 브랜치에 있는지 확인</li>
</ul>
<h3 id="작업-완료-후">작업 완료 후</h3>
<ul>
<li><input disabled="" type="checkbox"> <code>git add .</code> 변경사항 스테이지</li>
<li><input disabled="" type="checkbox"> 의미있는 커밋 메시지 작성</li>
<li><input disabled="" type="checkbox"> <code>git push origin branch-name</code> 푸시</li>
<li><input disabled="" type="checkbox"> GitHub에서 PR 생성</li>
</ul>
<h3 id="pr-머지-후">PR 머지 후</h3>
<ul>
<li><input disabled="" type="checkbox"> 로컬 동기화 4단계 실행</li>
<li><input disabled="" type="checkbox"> 불필요한 브랜치 삭제</li>
<li><input disabled="" type="checkbox"> 다음 작업 브랜치 생성</li>
</ul>
<hr>
<p><strong>💡 TIP: 이 치트시트를 즐겨찾기하고 필요할 때마다 참고하세요!</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git 명령어]]></title>
            <link>https://velog.io/@mo_ongh/Git-%EB%AA%85%EB%A0%B9%EC%96%B4</link>
            <guid>https://velog.io/@mo_ongh/Git-%EB%AA%85%EB%A0%B9%EC%96%B4</guid>
            <pubDate>Sat, 02 Aug 2025 22:15:56 GMT</pubDate>
            <description><![CDATA[<h1 id="git--github-완전-정리---학습용-가이드">Git &amp; GitHub 완전 정리 - 학습용 가이드</h1>
<h2 id="📋-목차">📋 목차</h2>
<ol>
<li><a href="#git-%EA%B8%B0%EB%B3%B8-%EA%B0%9C%EB%85%90">Git 기본 개념</a></li>
<li><a href="#%EB%B8%8C%EB%9E%9C%EC%B9%98%EC%99%80-%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C%EC%9A%B0">브랜치와 워크플로우</a></li>
<li><a href="#pull-request-pr">Pull Request (PR)</a></li>
<li><a href="#merge%EC%9D%98-%EC%9D%B4%ED%95%B4">Merge의 이해</a></li>
<li><a href="#pr-vs-merge-%EC%B0%A8%EC%9D%B4%EC%A0%90">PR vs Merge 차이점</a></li>
<li><a href="#%EC%BB%A4%EB%B0%8B-%EB%A9%94%EC%8B%9C%EC%A7%80-%EC%9E%91%EC%84%B1-%EA%B7%9C%EC%B9%99">커밋 메시지 작성 규칙</a></li>
<li><a href="#git-%EB%AA%85%EB%A0%B9%EC%96%B4-%EC%8B%A4%EB%AC%B4-%ED%99%9C%EC%9A%A9">Git 명령어 실무 활용</a></li>
<li><a href="#%EC%8B%A4%EC%A0%9C-%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C%EC%9A%B0-%EC%98%88%EC%8B%9C">실제 워크플로우 예시</a></li>
</ol>
<hr>
<h2 id="git-기본-개념">Git 기본 개념</h2>
<h3 id="git이란">Git이란?</h3>
<ul>
<li><strong>버전 관리 시스템</strong>: 코드의 변화를 추적하고 관리</li>
<li><strong>분산 저장소</strong>: 로컬과 원격(GitHub)에 각각 저장</li>
<li><strong>협업 도구</strong>: 여러 사람이 동시에 작업 가능</li>
</ul>
<h3 id="핵심-용어">핵심 용어</h3>
<table>
<thead>
<tr>
<th>용어</th>
<th>의미</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Repository</strong></td>
<td>프로젝트 저장소</td>
<td><code>study-insupanda</code></td>
</tr>
<tr>
<td><strong>Commit</strong></td>
<td>변경사항 저장 단위</td>
<td><code>Phase 1.1 완료</code></td>
</tr>
<tr>
<td><strong>Branch</strong></td>
<td>작업 분기</td>
<td><code>study/01-project-setup</code></td>
</tr>
<tr>
<td><strong>Remote</strong></td>
<td>원격 저장소</td>
<td>GitHub의 repository</td>
</tr>
<tr>
<td><strong>Local</strong></td>
<td>로컬 저장소</td>
<td>내 컴퓨터의 repository</td>
</tr>
</tbody></table>
<hr>
<h2 id="브랜치와-워크플로우">브랜치와 워크플로우</h2>
<h3 id="브랜치란">브랜치란?</h3>
<pre><code>main:           A ← B ← C (안정된 버전)
                    ↘
feature:            D ← E ← F (새로운 작업)</code></pre><h3 id="브랜치-전략의-장점">브랜치 전략의 장점</h3>
<ul>
<li>✅ <strong>안전성</strong>: main 브랜치 보호</li>
<li>✅ <strong>병렬 작업</strong>: 동시에 여러 기능 개발</li>
<li>✅ <strong>롤백 용이</strong>: 문제 시 특정 브랜치만 제거</li>
</ul>
<h3 id="wbs-기반-브랜치-전략">WBS 기반 브랜치 전략</h3>
<pre><code class="language-bash"># Phase별 브랜치 생성
git checkout -b study/01-project-setup    # Phase 1 전체
git checkout -b phase1-3-env-config       # 개별 작업</code></pre>
<hr>
<h2 id="pull-request-pr">Pull Request (PR)</h2>
<h3 id="pr이란">PR이란?</h3>
<ul>
<li><strong>정의</strong>: &quot;내 변경사항을 검토해서 main에 반영해달라&quot;는 요청</li>
<li><strong>목적</strong>: 코드 리뷰, 품질 관리, 협업</li>
<li><strong>상태</strong>: 아직 main에 반영되지 않은 제안 상태</li>
</ul>
<h3 id="pr-생성-과정">PR 생성 과정</h3>
<pre><code class="language-bash"># 1. 작업 완료
git add .
git commit -m &quot;Phase 1.1-1.2: 분석 완료&quot;
git push origin study/01-project-setup

# 2. GitHub에서 PR 생성
# Compare &amp; pull request 버튼 클릭</code></pre>
<h3 id="pr-작성-표준-형식">PR 작성 표준 형식</h3>
<pre><code class="language-markdown">## 📋 작업 내용
- 구체적인 작업 1
- 구체적인 작업 2

## 🔍 변경 사항
- 추가된 파일
- 수정된 부분

## 📚 학습 성과
- 핵심 학습 내용 1
- 핵심 학습 내용 2

## 📈 진행 상황
- Phase X: Y% 완료
- 전체 프로젝트: Z% 완료</code></pre>
<hr>
<h2 id="merge의-이해">Merge의 이해</h2>
<h3 id="merge란">Merge란?</h3>
<ul>
<li><strong>정의</strong>: 브랜치의 변경사항을 main에 실제로 반영하는 작업</li>
<li><strong>결과</strong>: main 브랜치에 새로운 커밋 추가</li>
<li><strong>의미</strong>: 공식적인 완료 표시</li>
</ul>
<h3 id="merge-과정-시각화">Merge 과정 시각화</h3>
<pre><code># Merge 전
main:           A ← B ← C
feature:            ↘ D ← E

# Merge 후  
main:           A ← B ← C ← M (merge commit)
                        ↗ ↗
feature:            D ← E</code></pre><h3 id="merge-방법-3가지">Merge 방법 3가지</h3>
<h4 id="1-create-a-merge-commit-기본">1. Create a merge commit (기본)</h4>
<pre><code>main:     A ← B ← C ← M (merge commit)
                   ↗ ↗
feature:       D ← E</code></pre><ul>
<li>머지 기록 보존</li>
<li>브랜치 히스토리 유지</li>
</ul>
<h4 id="2-squash-and-merge-⭐-추천">2. Squash and merge ⭐ (추천)</h4>
<pre><code>main:     A ← B ← C ← S (압축된 하나의 커밋)
feature:       D ← E (원본 유지)</code></pre><ul>
<li>여러 커밋을 하나로 합침</li>
<li>깔끔한 히스토리</li>
</ul>
<h4 id="3-rebase-and-merge">3. Rebase and merge</h4>
<pre><code>main:     A ← B ← C ← D&#39; ← E&#39; (선형 배치)</code></pre><ul>
<li>선형적 히스토리</li>
<li>고급 사용법</li>
</ul>
<hr>
<h2 id="pr-vs-merge-차이점">PR vs Merge 차이점</h2>
<h3 id="핵심-차이점">핵심 차이점</h3>
<table>
<thead>
<tr>
<th>구분</th>
<th>PR (Pull Request)</th>
<th>Merge</th>
</tr>
</thead>
<tbody><tr>
<td><strong>목적</strong></td>
<td>검토 요청, 소통</td>
<td>실제 반영</td>
</tr>
<tr>
<td><strong>대상</strong></td>
<td>리뷰어, 팀원</td>
<td>Git 히스토리</td>
</tr>
<tr>
<td><strong>상태</strong></td>
<td>제안, 대기 중</td>
<td>완료, 반영됨</td>
</tr>
<tr>
<td><strong>시점</strong></td>
<td>작업 완료 시</td>
<td>승인 완료 시</td>
</tr>
</tbody></table>
<h3 id="기록-보존">기록 보존</h3>
<pre><code class="language-bash"># 둘 다 영구 보존됨!
GitHub → Pull requests → Closed     # PR 기록
GitHub → Commits                    # Merge 기록</code></pre>
<h3 id="제3자가-보는-정보">제3자가 보는 정보</h3>
<ul>
<li><strong>PR</strong>: 상세한 작업 과정, 토론, 리뷰 내용</li>
<li><strong>Commit</strong>: 간결한 변경사항, 실제 코드 diff</li>
</ul>
<hr>
<h2 id="커밋-메시지-작성-규칙">커밋 메시지 작성 규칙</h2>
<h3 id="표준-커밋-타입">표준 커밋 타입</h3>
<pre><code>feat: 새로운 기능 추가
fix: 버그 수정
docs: 문서 수정/추가
style: 코드 포맷팅
refactor: 코드 리팩토링
test: 테스트 추가/수정
chore: 기타 작업</code></pre><h3 id="학습-프로젝트용-타입">학습 프로젝트용 타입</h3>
<pre><code>docs: 문서 분석/작성
study: 학습 내용 정리
analysis: 코드/구조 분석
review: 검토 및 정리</code></pre><h3 id="제목-작성-규칙">제목 작성 규칙</h3>
<pre><code class="language-bash"># 좋은 예시
docs: Phase 1.1-1.2 프로젝트 설정 분석 완료
study: RAG 시스템 아키텍처 학습 정리

# 나쁜 예시
Update files                    # 너무 모호
Fix stuff                      # 구체적이지 않음
WIP                           # 완료되지 않은 상태</code></pre>
<h3 id="내용-작성-규칙">내용 작성 규칙</h3>
<pre><code># PR 내용 (상세함)
## 📋 작업 내용
## 🔍 변경 사항
## 📚 학습 성과
## 📈 진행 상황

# Merge 내용 (간결함)
간단한 요약

- 핵심 작업 1
- 핵심 작업 2
- 주요 결과</code></pre><hr>
<h2 id="git-명령어-실무-활용">Git 명령어 실무 활용</h2>
<h3 id="기본-워크플로우">기본 워크플로우</h3>
<pre><code class="language-bash"># 1. 프로젝트 클론
git clone https://github.com/username/repository.git

# 2. 새 브랜치 생성 및 전환
git checkout -b feature/new-branch

# 3. 작업 후 커밋
git add .
git commit -m &quot;feat: 새로운 기능 추가&quot;

# 4. 원격 저장소에 푸시
git push origin feature/new-branch</code></pre>
<h3 id="동기화-명령어-중요">동기화 명령어 (중요!)</h3>
<pre><code class="language-bash"># Merge 후 로컬 동기화
git checkout main              # main 브랜치로 전환
git pull origin main          # 최신 내용 가져오기
git checkout feature-branch   # 작업 브랜치로 복귀
git pull origin main          # 작업 브랜치도 최신화</code></pre>
<h3 id="브랜치-관리">브랜치 관리</h3>
<pre><code class="language-bash"># 브랜치 목록 확인
git branch                    # 로컬 브랜치
git branch -r                 # 원격 브랜치

# 브랜치 삭제
git branch -d branch-name     # 로컬 브랜치 삭제
git push origin -d branch-name # 원격 브랜치 삭제

# 브랜치 상태 확인
git status                    # 현재 상태
git log --oneline -5          # 최근 5개 커밋</code></pre>
<hr>
<h2 id="실제-워크플로우-예시">실제 워크플로우 예시</h2>
<h3 id="시나리오-phase-13-작업-시작">시나리오: Phase 1.3 작업 시작</h3>
<h4 id="1단계-환경-준비">1단계: 환경 준비</h4>
<pre><code class="language-bash">cd /Users/moon/Desktop/study-insupanda
git status                    # 현재 상태 확인</code></pre>
<h4 id="2단계-최신-상태로-동기화">2단계: 최신 상태로 동기화</h4>
<pre><code class="language-bash">git checkout main
git pull origin main
git checkout study/01-project-setup
git pull origin main</code></pre>
<h4 id="3단계-phase-13-작업">3단계: Phase 1.3 작업</h4>
<pre><code class="language-bash"># 파일 분석 및 학습
# 문서 작성</code></pre>
<h4 id="4단계-커밋-및-푸시">4단계: 커밋 및 푸시</h4>
<pre><code class="language-bash">git add .
git commit -m &quot;docs: Phase 1.3 환경설정 파일 분석 완료&quot;
git push origin study/01-project-setup</code></pre>
<h4 id="5단계-pr-생성">5단계: PR 생성</h4>
<pre><code class="language-markdown"># GitHub에서 PR 생성
제목: docs: Phase 1.3 환경설정 파일 분석 완료

내용:
## 📋 작업 내용
- .env 파일 구조 분석
- .gitignore 설정 분석
- Docker 관련 파일 탐색

## 🔍 변경 사항
- README.md 업데이트
- 환경설정 분석 문서 추가

## 📚 학습 성과
- 환경변수 관리 방식 이해
- Git 무시 패턴 학습

## 📈 진행 상황
- Phase 1: 100% 완료 (3/3)
- 전체 WBS: 10% 완료 (3/30)</code></pre>
<h4 id="6단계-merge-실행">6단계: Merge 실행</h4>
<pre><code>Commit message: docs: Phase 1.3 환경설정 파일 분석 완료

Extended description:
환경설정 파일 구조 및 역할 분석

- .env: 환경변수 관리 방식 파악
- .gitignore: 버전 관리 제외 패턴 학습
- Phase 1 완료: 프로젝트 설정 전체 이해</code></pre><hr>
<h2 id="브랜치-전략-비교">브랜치 전략 비교</h2>
<h3 id="전략-1-phase별-브랜치">전략 1: Phase별 브랜치</h3>
<pre><code class="language-bash">study/01-project-setup     → Phase 1 전체 (1.1, 1.2, 1.3)
study/02-config-utils      → Phase 2 전체
study/03-database          → Phase 3 전체</code></pre>
<p><strong>장점</strong>: 관련 작업 묶음, 관리 단순
<strong>단점</strong>: PR이 커질 수 있음</p>
<h3 id="전략-2-작업별-브랜치">전략 2: 작업별 브랜치</h3>
<pre><code class="language-bash">phase1-1-requirements      → 1.1만
phase1-2-pyproject        → 1.2만  
phase1-3-env-config       → 1.3만</code></pre>
<p><strong>장점</strong>: 작은 PR, 빠른 리뷰
<strong>단점</strong>: 브랜치 관리 복잡</p>
<h3 id="전략-3-하이브리드-추천">전략 3: 하이브리드 (추천)</h3>
<pre><code class="language-bash"># 첫 작업은 통합, 이후 개별
study/01-project-setup     → 1.1 + 1.2 (이미 완료)
phase1-3-env-config        → 1.3 개별
phase2-1-config-folder     → 2.1 개별</code></pre>
<hr>
<h2 id="문제-상황별-해결법">문제 상황별 해결법</h2>
<h3 id="1-merge-충돌-발생">1. Merge 충돌 발생</h3>
<pre><code class="language-bash"># 충돌 해결 후
git add .
git commit -m &quot;resolve: merge conflict 해결&quot;
git push origin branch-name</code></pre>
<h3 id="2-잘못된-커밋-수정">2. 잘못된 커밋 수정</h3>
<pre><code class="language-bash"># 마지막 커밋 메시지 수정
git commit --amend -m &quot;새로운 커밋 메시지&quot;

# 아직 푸시 안한 경우만 사용!</code></pre>
<h3 id="3-브랜치-삭제-후-복구">3. 브랜치 삭제 후 복구</h3>
<pre><code class="language-bash"># 삭제된 브랜치 복구
git reflog                          # 참조 로그 확인
git checkout -b 브랜치명 커밋해시     # 특정 커밋에서 브랜치 생성</code></pre>
<h3 id="4-원격과-로컬-불일치">4. 원격과 로컬 불일치</h3>
<pre><code class="language-bash"># 강제 동기화 (주의!)
git fetch origin
git reset --hard origin/main</code></pre>
<hr>
<h2 id="좋은-git-습관">좋은 Git 습관</h2>
<h3 id="✅-do-해야-할-것">✅ Do (해야 할 것)</h3>
<ul>
<li>자주 커밋하기 (의미 있는 단위로)</li>
<li>명확한 커밋 메시지 작성</li>
<li>작업 전 항상 동기화</li>
<li>브랜치 이름 규칙적으로 작성</li>
<li>PR에 충분한 설명 추가</li>
</ul>
<h3 id="❌-dont-하지-말-것">❌ Don&#39;t (하지 말 것)</h3>
<ul>
<li>main 브랜치에 직접 푸시</li>
<li>너무 큰 단위로 커밋</li>
<li>모호한 커밋 메시지</li>
<li>동기화 없이 작업 시작</li>
<li>테스트 없이 머지</li>
</ul>
<hr>
<h2 id="유용한-git-설정">유용한 Git 설정</h2>
<h3 id="글로벌-설정">글로벌 설정</h3>
<pre><code class="language-bash"># 사용자 정보 설정
git config --global user.name &quot;Your Name&quot;
git config --global user.email &quot;your.email@example.com&quot;

# 기본 에디터 설정
git config --global core.editor &quot;code --wait&quot;

# 줄바꿈 설정 (Windows)
git config --global core.autocrlf true</code></pre>
<h3 id="유용한-별칭">유용한 별칭</h3>
<pre><code class="language-bash"># 자주 사용하는 명령어 단축
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.cm commit
git config --global alias.lg &quot;log --oneline --graph --all&quot;</code></pre>
<hr>
<h2 id="마무리">마무리</h2>
<h3 id="핵심-기억사항">핵심 기억사항</h3>
<ol>
<li><strong>Git은 협업 도구</strong>: 혼자 써도 체계적 관리 가능</li>
<li><strong>브랜치 활용</strong>: 안전한 작업 환경 제공</li>
<li><strong>명확한 기록</strong>: 나중의 나를 위한 친절함</li>
<li><strong>표준 준수</strong>: 일관성 있는 패턴 유지</li>
</ol>
<h3 id="지속적-학습-포인트">지속적 학습 포인트</h3>
<ul>
<li>Git 고급 명령어 (rebase, cherry-pick 등)</li>
<li>GitHub Actions (CI/CD)</li>
<li>Git 훅 활용</li>
<li>대규모 프로젝트 브랜치 전략</li>
</ul>
<h3 id="참고-자료">참고 자료</h3>
<ul>
<li><a href="https://git-scm.com/book">Pro Git Book</a></li>
<li><a href="https://docs.github.com">GitHub Docs</a></li>
<li><a href="https://www.conventionalcommits.org">Conventional Commits</a></li>
</ul>
<hr>
<p><strong>이 가이드는 실제 프로젝트 경험을 바탕으로 작성되었습니다. 계속 업데이트하며 사용하세요! 🚀</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[# Phase 1.2: pyproject.toml 분석 학습 정리]]></title>
            <link>https://velog.io/@mo_ongh/Phase-1.2-pyproject.toml-%EB%B6%84%EC%84%9D-%ED%95%99%EC%8A%B5-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@mo_ongh/Phase-1.2-pyproject.toml-%EB%B6%84%EC%84%9D-%ED%95%99%EC%8A%B5-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sat, 02 Aug 2025 21:30:02 GMT</pubDate>
            <description><![CDATA[<h2 id="📋-학습-목표-달성-현황">📋 학습 목표 달성 현황</h2>
<ul>
<li>✅ 프로젝트 메타데이터 분석 완료</li>
<li>✅ 빌드 설정 이해 완료  </li>
<li>✅ Poetry 설정 파악 완료</li>
</ul>
<h2 id="🔍-pyprojecttoml-파일-분석">🔍 pyproject.toml 파일 분석</h2>
<h3 id="파일-기본-정보">파일 기본 정보</h3>
<ul>
<li><strong>위치</strong>: 프로젝트 루트 디렉토리</li>
<li><strong>크기</strong>: 매우 작음 (개발 도구 설정만 포함)</li>
<li><strong>특징</strong>: Poetry 미사용, 전통적인 pip 기반 프로젝트</li>
</ul>
<h3 id="파일-내용-구조">파일 내용 구조</h3>
<pre><code class="language-toml">[tool.black]
line-length = 120

[tool.isort]
profile = &quot;black&quot;
line_length = 120
src_paths = [&quot;src&quot;, &quot;.&quot;]

[tool.mypy]
ignore_missing_imports = true

[tool.mypy.simplejson]
ignore_missing_imports = true</code></pre>
<h2 id="🛠️-각-도구별-역할과-설정">🛠️ 각 도구별 역할과 설정</h2>
<h3 id="1-black-코드-포맷터">1. Black (코드 포맷터)</h3>
<ul>
<li><strong>목적</strong>: Python 코드 자동 포맷팅</li>
<li><strong>핵심 설정</strong>: <code>line-length = 120</code> (기본 88자 → 120자로 확장)</li>
<li><strong>특징</strong>: &quot;타협하지 않는 포맷터&quot;, 일관성 중시</li>
</ul>
<h3 id="2-isort-import-정렬">2. isort (Import 정렬)</h3>
<ul>
<li><strong>목적</strong>: import 문 자동 정렬 및 그룹화</li>
<li><strong>핵심 설정</strong>:<ul>
<li><code>profile = &quot;black&quot;</code>: Black과 호환성 보장</li>
<li><code>line_length = 120</code>: Black과 동일한 줄 길이</li>
<li><code>src_paths = [&quot;src&quot;, &quot;.&quot;]</code>: 소스 코드 경로 지정</li>
</ul>
</li>
</ul>
<h3 id="3-mypy-정적-타입-검사">3. mypy (정적 타입 검사)</h3>
<ul>
<li><strong>목적</strong>: 타입 힌트 검증으로 런타임 오류 예방</li>
<li><strong>핵심 설정</strong>: <code>ignore_missing_imports = true</code> (타입 스텁 없는 라이브러리 허용)</li>
<li><strong>특별 설정</strong>: simplejson 모듈 별도 예외 처리</li>
</ul>
<h2 id="💡-핵심-학습-내용">💡 핵심 학습 내용</h2>
<h3 id="pyprojecttoml의-존재-이유">pyproject.toml의 존재 이유</h3>
<ol>
<li><strong>과거 문제점</strong>: 설정 파일 분산 (setup.py, setup.cfg, .flake8, .isort.cfg 등)</li>
<li><strong>해결책</strong>: 하나의 파일로 모든 도구 설정 통합</li>
<li><strong>표준화</strong>: PEP 518에 의한 Python 커뮤니티 표준</li>
</ol>
<h3 id="중요한-오해-해결">중요한 오해 해결</h3>
<ul>
<li><strong>❌ 잘못된 이해</strong>: pyproject.toml만 있으면 자동으로 검사됨</li>
<li><strong>✅ 올바른 이해</strong>: 단순한 설정 파일, 별도 도구 설치 및 실행 필요</li>
</ul>
<h3 id="실제-동작-과정">실제 동작 과정</h3>
<ol>
<li><strong>도구 설치</strong>: <code>pip install black isort mypy</code></li>
<li><strong>수동 실행</strong>: <code>black .</code>, <code>isort .</code>, <code>mypy .</code></li>
<li><strong>자동화</strong>: pre-commit, IDE 설정, CI/CD 파이프라인</li>
</ol>
<h2 id="🔗-프로젝트-내-연관-파일들">🔗 프로젝트 내 연관 파일들</h2>
<h3 id="requirementstxt-연관성">requirements.txt 연관성</h3>
<pre><code class="language-txt">black==25.1.0      # 코드 포맷터
isort==6.0.1       # import 정렬
mypy==1.15.0       # 타입 검사
pre-commit==4.2.0  # Git 훅 자동화</code></pre>
<h3 id="pre-commit-configyaml-자동화">.pre-commit-config.yaml 자동화</h3>
<ul>
<li>Git 커밋 시 자동으로 black, isort, mypy 실행</li>
<li>pyproject.toml 설정을 읽어서 적용</li>
<li>코드 품질 자동 보장</li>
</ul>
<h2 id="📊-프로젝트-특징-분석">📊 프로젝트 특징 분석</h2>
<h3 id="의존성-관리-방식">의존성 관리 방식</h3>
<ul>
<li><strong>Poetry 미사용</strong>: 전통적인 pip + requirements.txt 방식</li>
<li><strong>점진적 개선</strong>: 개발 도구 설정만 pyproject.toml로 통합</li>
<li><strong>안정성 우선</strong>: 검증된 방식 유지</li>
</ul>
<h3 id="개발-워크플로우">개발 워크플로우</h3>
<pre><code>코드 작성 → mypy 타입 체크 → isort import 정렬 → black 포맷팅 → Git 커밋</code></pre><h3 id="팀-협업-장점">팀 협업 장점</h3>
<ul>
<li>모든 개발자가 동일한 코드 스타일 사용</li>
<li>설정 파일 하나로 일관성 보장</li>
<li>새 팀원 온보딩 시간 단축</li>
</ul>
<h2 id="🎯-주요-학습-포인트">🎯 주요 학습 포인트</h2>
<h3 id="기술적-개념">기술적 개념</h3>
<ul>
<li><strong>TOML 형식</strong>: 설정 파일 표준 형식</li>
<li><strong>정적 분석</strong>: 코드 실행 전 오류 검출</li>
<li><strong>코드 포맷팅</strong>: 가독성과 일관성 향상</li>
<li><strong>타입 힌팅</strong>: Python의 점진적 타이핑 시스템</li>
</ul>
<h3 id="실무-적용-가치">실무 적용 가치</h3>
<ul>
<li>코드 리뷰 시간 단축 (스타일 논쟁 제거)</li>
<li>버그 예방 (타입 체크로 오류 사전 발견)</li>
<li>유지보수성 향상 (일관된 코드 스타일)</li>
<li>자동화 지원 (CI/CD 파이프라인 통합)</li>
</ul>
<h2 id="🚀-다음-단계-준비">🚀 다음 단계 준비</h2>
<h3 id="phase-13-예고">Phase 1.3 예고</h3>
<ul>
<li>환경설정 파일들 분석 (.env, .gitignore 등)</li>
<li>Docker 관련 파일 탐색</li>
<li>프로젝트 전체 설정 체계 파악</li>
</ul>
<h3 id="연관-학습-포인트">연관 학습 포인트</h3>
<ul>
<li>Git 워크플로우와 코드 품질 도구 연동</li>
<li>IDE 설정과 개발 도구 통합</li>
<li>CI/CD 파이프라인에서의 자동화 적용</li>
</ul>
<h2 id="📝-wbs-진행-현황">📝 WBS 진행 현황</h2>
<ul>
<li><strong>Phase 1</strong>: 프로젝트 설정 및 환경 구성 (2/3 완료)</li>
<li><strong>다음 세션</strong>: Phase 1.3 - 환경설정 파일들 분석</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[# 🎓 세션 4: 로깅 시스템 구축 학습 정리]]></title>
            <link>https://velog.io/@mo_ongh/%EC%84%B8%EC%85%98-4-%EB%A1%9C%EA%B9%85-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EA%B5%AC%EC%B6%95-%ED%95%99%EC%8A%B5-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@mo_ongh/%EC%84%B8%EC%85%98-4-%EB%A1%9C%EA%B9%85-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EA%B5%AC%EC%B6%95-%ED%95%99%EC%8A%B5-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Fri, 01 Aug 2025 16:12:35 GMT</pubDate>
            <description><![CDATA[<h2 id="📋-세션-개요">📋 세션 개요</h2>
<ul>
<li><strong>주제</strong>: Python 로깅 시스템 구축 및 이해</li>
<li><strong>기준 코드</strong>: insupanda-rag의 <code>src/config/logger.py</code></li>
<li><strong>학습 방식</strong>: 직접 타이핑 + 상세 주석으로 개념 학습</li>
<li><strong>완성 결과</strong>: 콘솔과 파일에 동시 출력되는 로깅 시스템</li>
</ul>
<h2 id="🔍-핵심-개념-학습">🔍 핵심 개념 학습</h2>
<h3 id="1-로깅logging이란">1. 로깅(Logging)이란?</h3>
<ul>
<li><strong>정의</strong>: 프로그램 실행 중 발생하는 이벤트들을 기록하는 시스템</li>
<li><strong>비유</strong>: 프로그램의 &quot;일기장&quot; - 언제 무슨 일이 일어났는지 상세 기록</li>
<li><strong>필요성</strong>: 디버깅, 모니터링, 분석, 증거 보전</li>
</ul>
<h3 id="2-로깅-레벨-5단계">2. 로깅 레벨 5단계</h3>
<pre><code>DEBUG &lt; INFO &lt; WARNING &lt; ERROR &lt; CRITICAL</code></pre><ul>
<li><strong>DEBUG</strong>: 개발자용 상세 정보 (가장 자세함)</li>
<li><strong>INFO</strong>: 일반적인 정보 ← 우리 프로젝트에서 사용</li>
<li><strong>WARNING</strong>: 경고 메시지</li>
<li><strong>ERROR</strong>: 에러 발생</li>
<li><strong>CRITICAL</strong>: 치명적 오류 (가장 심각함)</li>
</ul>
<h3 id="3-핸들러handler-개념">3. 핸들러(Handler) 개념</h3>
<p>로그를 &quot;어디에&quot; 보낼지 결정하는 배달원 역할</p>
<h4 id="streamhandler">StreamHandler</h4>
<ul>
<li><strong>역할</strong>: 콘솔(터미널 화면)에 실시간 출력</li>
<li><strong>장점</strong>: 즉시 확인 가능, 개발 중 디버깅 용이</li>
<li><strong>단점</strong>: 프로그램 종료 시 사라짐</li>
</ul>
<h4 id="filehandler">FileHandler</h4>
<ul>
<li><strong>역할</strong>: 파일에 영구 저장</li>
<li><strong>장점</strong>: 영구 보관, 나중에 분석 가능</li>
<li><strong>설정</strong>: <code>(&quot;app.log&quot;, &quot;a&quot;, &quot;utf-8&quot;)</code><ul>
<li><code>&quot;app.log&quot;</code>: 파일명</li>
<li><code>&quot;a&quot;</code>: append 모드 (기존 내용에 추가)</li>
<li><code>&quot;utf-8&quot;</code>: 한글 지원 인코딩</li>
</ul>
</li>
</ul>
<h2 id="💻-실습-과정">💻 실습 과정</h2>
<h3 id="1-프로젝트-구조-확인">1. 프로젝트 구조 확인</h3>
<pre><code>insurance-rag-learning/
├── src/
│   ├── config/     ← 여기에 logger.py 생성
│   ├── db/
│   ├── models/
│   └── ...
├── tests/
└── README.md</code></pre><h3 id="2-loggerpy-핵심-코드">2. logger.py 핵심 코드</h3>
<pre><code class="language-python">import logging

def setup_logging() -&gt; None:
    logging.basicConfig(
        level=logging.INFO,  # INFO 이상만 기록
        format=&quot;%(asctime)s [%(levelname)s] %(name)s: %(message)s&quot;,
        handlers=[
            logging.StreamHandler(),  # 콘솔 출력
            logging.FileHandler(&quot;app.log&quot;, &quot;a&quot;, &quot;utf-8&quot;),  # 파일 저장
        ],
    )</code></pre>
<h3 id="3-테스트-코드-작성-및-실행">3. 테스트 코드 작성 및 실행</h3>
<ul>
<li><strong>파일</strong>: <code>test_logging.py</code></li>
<li><strong>테스트 내용</strong>: <ul>
<li>모든 로깅 레벨 테스트</li>
<li>다양한 모듈별 로깅 테스트</li>
<li>콘솔과 파일 동시 출력 확인</li>
</ul>
</li>
</ul>
<h2 id="✅-테스트-결과-분석">✅ 테스트 결과 분석</h2>
<h3 id="성공적인-동작-확인">성공적인 동작 확인</h3>
<ol>
<li><strong>DEBUG 필터링</strong> ✅ - INFO 레벨 설정으로 DEBUG 메시지 차단</li>
<li><strong>로거 이름 구분</strong> ✅ - <code>__main__</code>, <code>database</code>, <code>openai_api</code> 등 모듈별 구분</li>
<li><strong>시간 정확성</strong> ✅ - 밀리초 단위 정확한 타임스탬프</li>
<li><strong>동시 출력</strong> ✅ - 콘솔과 파일에 동일한 내용 기록</li>
<li><strong>Append 모드</strong> ✅ - 여러 번 실행해도 로그 누적 저장</li>
<li><strong>UTF-8 인코딩</strong> ✅ - 한글 깨짐 없이 완벽 저장</li>
</ol>
<h3 id="실제-테스트-출력-예시">실제 테스트 출력 예시</h3>
<pre><code>2025-08-02 01:06:51,021 [INFO] __main__: ℹ️ 프로그램이 정상적으로 시작되었습니다
2025-08-02 01:06:51,021 [WARNING] __main__: ⚠️ 이것은 경고 메시지입니다
2025-08-02 01:06:51,021 [ERROR] __main__: ❌ 에러가 발생했습니다
2025-08-02 01:06:51,021 [INFO] database: 💾 데이터베이스 연결 성공</code></pre><h2 id="🆚-기존-insupanda-rag와-비교">🆚 기존 insupanda-rag와 비교</h2>
<h3 id="공통점-잘-따라한-부분">공통점 (잘 따라한 부분)</h3>
<ul>
<li>✅ 동일한 로깅 레벨 (INFO)</li>
<li>✅ 동일한 포맷 구조</li>
<li>✅ 동일한 핸들러 조합</li>
<li>✅ 동일한 파일 설정</li>
</ul>
<h3 id="우리-버전의-장점">우리 버전의 장점</h3>
<ul>
<li><strong>상세한 주석</strong>: 각 라인의 목적과 동작 원리 명확히 설명</li>
<li><strong>구조화된 코드</strong>: <code>setup_logging()</code> 함수로 깔끔하게 정리</li>
<li><strong>학습 친화적</strong>: 초보자도 이해할 수 있는 상세한 설명</li>
</ul>
<h2 id="🎯-핵심-학습-포인트">🎯 핵심 학습 포인트</h2>
<h3 id="1-로깅-시스템의-3가지-핵심-기능">1. 로깅 시스템의 3가지 핵심 기능</h3>
<ol>
<li><strong>콘솔 출력</strong>: 실시간 모니터링</li>
<li><strong>파일 저장</strong>: 영구 보관 및 분석</li>
<li><strong>레벨 필터링</strong>: 필요한 정보만 선별 기록</li>
</ol>
<h3 id="2-append-모드의-중요성">2. Append 모드의 중요성</h3>
<ul>
<li><strong>&quot;a&quot; 모드</strong>: 기존 로그 보존하며 새 로그 추가</li>
<li><strong>&quot;w&quot; 모드</strong>: 기존 로그 삭제 후 새로 작성 (위험!)</li>
<li><strong>실제 증명</strong>: 두 번 실행했을 때 모든 로그가 누적 저장됨</li>
</ul>
<h3 id="3-로거-이름names의-가치">3. 로거 이름(%(name)s)의 가치</h3>
<ul>
<li><strong>문제 추적</strong>: 어느 모듈에서 발생한 로그인지 즉시 식별</li>
<li><strong>디버깅 효율성</strong>: 에러 발생 시 해당 부분만 집중 분석 가능</li>
<li><strong>시스템 모니터링</strong>: 각 구성 요소별 상태 개별 확인</li>
</ul>
<h2 id="🚀-다음-단계-예고">🚀 다음 단계 예고</h2>
<p>다음 세션에서는 <strong>환경 변수와 설정 관리</strong>를 다룰 예정입니다:</p>
<ul>
<li>Pydantic을 활용한 설정 관리</li>
<li>환경변수(.env) 활용법</li>
<li>개발/운영 환경 분리 방법</li>
</ul>
<h2 id="📝-학습-성과">📝 학습 성과</h2>
<ul>
<li>✅ 로깅의 핵심 개념 완전 이해</li>
<li>✅ Python logging 라이브러리 실습 완료</li>
<li>✅ 콘솔/파일 동시 출력 시스템 구축</li>
<li>✅ 기존 프로젝트 코드와 비교 분석 완료</li>
<li>✅ 실무에서 사용할 수 있는 로깅 시스템 습득</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[📚 Insurance RAG 학습 - 세션 3 완료 요약]]></title>
            <link>https://velog.io/@mo_ongh/Insurance-RAG-%ED%95%99%EC%8A%B5-%EC%84%B8%EC%85%98-3-%EC%99%84%EB%A3%8C-%EC%9A%94%EC%95%BD</link>
            <guid>https://velog.io/@mo_ongh/Insurance-RAG-%ED%95%99%EC%8A%B5-%EC%84%B8%EC%85%98-3-%EC%99%84%EB%A3%8C-%EC%9A%94%EC%95%BD</guid>
            <pubDate>Thu, 31 Jul 2025 20:43:47 GMT</pubDate>
            <description><![CDATA[<p>🎯 세션 3 주제: 환경변수와 설정 관리</p>
<p>📖 핵심 개념 학습
1️⃣ 환경변수 (Environment Variables)</p>
<p>정의: 운영체제에 저장되는 설정값
목적: 코드와 설정 분리로 보안성 향상
실생활 비유: 집 열쇠를 안전한 서랍에 보관하는 것</p>
<p>보안 레벨별 분류:</p>
<p>🔴 높은 보안: API 키, 비밀번호 → 절대 코드에 쓰지 않음
🟡 중간 보안: 호스트, 포트 → 기본값 제공하되 환경변수로 덮어쓰기 가능</p>
<p>2️⃣ Pydantic &amp; BaseSettings</p>
<p>Pydantic: 데이터 검증 자동화 라이브러리
BaseSettings: 환경변수 자동 매핑 + 타입 검증
동작원리: db_password → DB_PASSWORD 환경변수 자동 찾기</p>
<p>🔬 라이브러리 심화 분석
pathlib</p>
<p>용도: 현대적 파일 경로 처리
핵심 기능: Path(<strong>file</strong>).parent.parent.resolve() - 프로젝트 루트 찾기
장점: 직관적인 / 연산자 사용</p>
<p>typing</p>
<p>용도: 타입 힌트 제공
Optional[str]: str 또는 None 가능
장점: IDE 자동완성, 타입 에러 사전 발견</p>
<p>pydantic_settings</p>
<p>용도: 환경변수 자동 로딩 + 데이터 검증
BaseSettings 특징:</p>
<p>환경변수 이름 자동 변환 (snake_case → UPPER_CASE)
타입 자동 변환 (&quot;3306&quot; → 3306)
.env 파일 자동 로딩</p>
<p>💡 실무 인사이트
타입 선택 가이드라인</p>
<p>str: 호스트명, 비밀번호, 경로
int: 포트번호, 타임아웃, 개수 (숫자 계산 필요)
bool: 디버그 모드, 기능 활성화 여부</p>
<p>보안 베스트 프랙티스
python# ✅ 올바른 방식
db_host: str = &quot;localhost&quot;     # 공개 정보 → 기본값 제공
db_password: str               # 민감 정보 → 기본값 없음
Pydantic 우선순위</p>
<p>환경변수 값 (최우선)
.env 파일 값
코드의 기본값 (백업)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[📚 Insurance RAG 학습 세션 2 완료 보고서]]></title>
            <link>https://velog.io/@mo_ongh/Insurance-RAG-%ED%95%99%EC%8A%B5-%EC%84%B8%EC%85%98-2-%EC%99%84%EB%A3%8C-%EB%B3%B4%EA%B3%A0%EC%84%9C</link>
            <guid>https://velog.io/@mo_ongh/Insurance-RAG-%ED%95%99%EC%8A%B5-%EC%84%B8%EC%85%98-2-%EC%99%84%EB%A3%8C-%EB%B3%B4%EA%B3%A0%EC%84%9C</guid>
            <pubDate>Thu, 31 Jul 2025 19:40:40 GMT</pubDate>
            <description><![CDATA[<p>🎯 세션 개요</p>
<p>세션명: Insurance RAG 학습 지침 (세션2 수정완료판)
진행 방식: AI 가이드 &amp; 멘토링 + 깊이있는 개념 설명
기준 코드: /Users/moon/Desktop/insupanda-rag/ 구조 참조
학습 원칙: 기존 코드 참조 → 개념 설명 → 실습 안내 → 완료 확인</p>
<p>✅ 완료된 학습 내용
1단계: 프로젝트 구조 이해
개념 학습:</p>
<p>RAG(Retrieval-Augmented Generation): 검색 후 답변 생성 기술</p>
<p>도서관 사서처럼 관련 문서를 먼저 찾고 답변 생성
외운 내용보다 실제 문서 참조로 더 정확한 답변 제공</p>
<p>기존 코드 분석:
📁 insupanda-rag/src/
├── config/     # 설정 관리 (logger.py, settings.py)
├── db/         # 데이터베이스 (schema.py, sql_utils.py)<br>├── models/     # RAG 핵심 모듈 (임베딩, 검색, 답변생성)
├── modules/    # 메인 비즈니스 로직 (handler.py, user_state.py)
├── options/    # 타입 정의 (enums.py, insu_name.py)
├── prompts/    # AI 프롬프트 템플릿 (.jinja2 파일들)
├── services/   # 비즈니스 서비스 로직
└── util/       # 유틸리티 함수들
2단계: 프로젝트 기본 구조 생성
중요한 배움 - 명령어 효율성:</p>
<p>❌ 잘못된 방식: mkdir -p를 개별적으로 여러 번 사용
✅ 올바른 방식: mkdir -p src/{config,db,models,modules,options,prompts,services,util} tests</p>
<p>개념 학습:</p>
<p>mkdir -p: parent directories 옵션으로 중간 폴더까지 한 번에 생성
중괄호 {} 문법: 쉘에서 여러 이름을 한 번에 나열하는 방법</p>
<p>실행 명령어:
bashcd /Users/moon/Desktop
mkdir insurance-rag-learning
cd insurance-rag-learning
mkdir -p src/{config,db,models,modules,options,prompts,services,util} tests
3단계: Python 패키지 초기화
개념 학습:</p>
<p>Python 패키지: <strong>init</strong>.py 파일로 폴더를 Python이 인식할 수 있는 패키지로 변환
import 시스템: from src.config import settings 같은 코드 import 가능</p>
<p>기존 코드 참조:</p>
<p>insupanda-rag에 총 7개의 <strong>init</strong>.py 파일 확인
모든 주요 폴더에 패키지 초기화 파일 존재</p>
<p>실행 명령어:
bashtouch src/<strong>init</strong>.py src/config/<strong>init</strong>.py src/db/<strong>init</strong>.py src/models/<strong>init</strong>.py src/modules/<strong>init</strong>.py src/options/<strong>init</strong>.py src/prompts/<strong>init</strong>.py src/services/<strong>init</strong>.py src/util/<strong>init</strong>.py tests/<strong>init</strong>.py
문제 해결:</p>
<p>불필요한 src/api/ 폴더 발견 및 삭제
rm -rf src/api 명령어로 정리</p>
<p>4단계: 환경변수 설정 파일 (진행 중)
개념 학습:</p>
<p>환경변수: 프로그램 설정값을 코드 외부에 안전하게 저장
보안성: API 키, 비밀번호 등 민감 정보를 코드에 직접 노출하지 않음
유연성: 개발/테스트/운영 환경별로 다른 설정 사용 가능</p>
<p>기존 코드 참조:</p>
<p>src/.test.env 파일 발견
내용: DB_PASSWORD, OPENAI_API_KEY, UPSTAGE_API_KEY 설정</p>
<p>🔧 학습한 주요 기술 개념
Python 관련</p>
<p>Pydantic: 데이터 검증을 쉽게 해주는 라이브러리 (설정값 타입 자동 체크)
환경변수: 운영체제에 저장된 설정값 (민감 정보 별도 보관)
로깅: 프로그램 실행 중 일어나는 일들을 기록 (에러 찾기와 디버깅에 필수)</p>
<p>RAG 관련</p>
<p>임베딩: 텍스트를 숫자 벡터로 변환 (컴퓨터가 의미 이해 가능)
벡터 검색: 의미가 비슷한 문서를 찾는 기술 (키워드 검색보다 똑똑함)
프롬프트 템플릿: AI에게 질문하는 정해진 형식</p>
<p>터미널 명령어</p>
<p>mkdir -p: 폴더 생성 (중간 폴더도 함께 생성)
touch: 빈 파일 생성
rm -rf: 폴더와 내용 완전 삭제
find: 파일 검색</p>
<p>📊 생성된 프로젝트 구조
최종 폴더 구조
📁 insurance-rag-learning/
├── src/
│   ├── <strong>init</strong>.py
│   ├── config/
│   │   └── <strong>init</strong>.py
│   ├── db/
│   │   └── <strong>init</strong>.py
│   ├── models/
│   │   └── <strong>init</strong>.py
│   ├── modules/
│   │   └── <strong>init</strong>.py
│   ├── options/
│   │   └── <strong>init</strong>.py
│   ├── prompts/
│   │   └── <strong>init</strong>.py
│   ├── services/
│   │   └── <strong>init</strong>.py
│   └── util/
│       └── <strong>init</strong>.py
└── tests/
    └── <strong>init</strong>.py
생성된 파일 목록</p>
<p>총 10개의 <strong>init</strong>.py 파일
기존 insupanda-rag와 정확히 동일한 구조</p>
<p>🎓 중요한 학습 원칙
AI 역할</p>
<p>✅ 개념 설명 + 기존 코드 참조 + 실습 안내
✅ 모든 기술 용어 초보자용 설명 제공
❌ 직접 파일 생성이나 코드 작성 금지</p>
<p>학습자 역할</p>
<p>✅ 터미널 명령어 직접 실행
✅ Cursor에서 파일/코드 직접 작성
✅ 이해 안되는 개념 즉시 질문</p>
<p>효율성 원칙</p>
<p>명령어 설명 시 가장 효율적인 방법을 먼저 제시
프로 개발자가 사용하는 방식으로 바로 안내
비효율적 방법 → 수정하는 패턴 지양</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🏥 Insurance RAG 학습 - 세션 1 정리]]></title>
            <link>https://velog.io/@mo_ongh/Insurance-RAG-%ED%95%99%EC%8A%B5-%EC%84%B8%EC%85%98-1-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@mo_ongh/Insurance-RAG-%ED%95%99%EC%8A%B5-%EC%84%B8%EC%85%98-1-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Thu, 31 Jul 2025 11:20:50 GMT</pubDate>
            <description><![CDATA[<h1 id="🏥-insurance-rag-학습---세션-1-정리">🏥 Insurance RAG 학습 - 세션 1 정리</h1>
<blockquote>
<p><strong>학습 일자</strong>: 2025년 7월 31일<br><strong>학습 목표</strong>: 프로젝트 환경 설정 및 기본 구조 구축  </p>
</blockquote>
<h2 id="🎯-주요-학습-내용">🎯 주요 학습 내용</h2>
<h3 id="1-학습-폴더-생성">1. 학습 폴더 생성</h3>
<p><strong>개념</strong>: 기존 완성 프로젝트와 분리하여 단계별 학습 기록용<br><strong>실습 명령어</strong>: </p>
<pre><code class="language-bash">cd /Users/moon/Desktop
mkdir insurance-rag-learning
cd insurance-rag-learning</code></pre>
<h3 id="2-readmemd-작성">2. README.md 작성</h3>
<p><strong>개념</strong>: 프로젝트 개요 및 15세션 로드맵 기록용<br><strong>실습 명령어</strong>: </p>
<pre><code class="language-bash">touch README.md
# 텍스트 에디터로 15세션 로드맵과 기술스택 작성</code></pre>
<h3 id="3-프로젝트-구조-설계-⭐">3. 프로젝트 구조 설계 ⭐</h3>
<p><strong>프로젝트 구조</strong>:</p>
<pre><code>insurance-rag-learning/
├── src/                # 메인 소스코드
│   ├── config/        # 설정 파일들
│   ├── models/        # AI 모델 관련
│   ├── services/      # 비즈니스 로직
│   ├── utils/         # 유틸리티 함수들
│   └── api/           # API 엔드포인트
├── tests/             # 테스트 코드
├── docs/              # 문서
└── data/              # 데이터 파일들</code></pre><h3 id="4-효율적인-명령어-사용법-⭐">4. 효율적인 명령어 사용법 ⭐</h3>
<p><strong>기본 방법</strong>:</p>
<pre><code class="language-bash">mkdir src
mkdir tests
mkdir docs
mkdir data</code></pre>
<p><strong>효율적인 방법</strong>:</p>
<pre><code class="language-bash"># 여러 폴더를 한 번에 생성
mkdir src tests docs data

# 하위 폴더들도 한 번에 생성
mkdir src/config src/models src/services src/utils src/api</code></pre>
<p><strong>고급 방법 - 중괄호 확장</strong>:</p>
<pre><code class="language-bash"># -p 옵션으로 상위 폴더가 없어도 자동 생성
mkdir -p src/{config,models,services,utils,api}

# __init__.py 파일들을 한 번에 생성
touch {src,src/config,src/models,src/services,src/utils,src/api,tests}/__init__.py</code></pre>
<h3 id="5-python-패키지-구조-설정">5. Python 패키지 구조 설정</h3>
<p><strong>개념</strong>: <code>__init__.py</code> 파일로 Python 패키지 인식시키기<br><strong>실수 경험</strong>: <code>servies</code> → <code>services</code> 오타 발견 및 수정으로 디버깅 스킬 습득</p>
<h3 id="6-가상환경-설정">6. 가상환경 설정</h3>
<p><strong>개념</strong>: 프로젝트별 독립적인 Python 환경 구축<br><strong>실습 명령어</strong>:</p>
<pre><code class="language-bash"># 가상환경 생성
python -m venv venv

# 가상환경 활성화
source venv/bin/activate

# 활성화 확인
which python</code></pre>
<h2 id="🏆-세션-1-성과">🏆 세션 1 성과</h2>
<ul>
<li>✅ 학습 폴더 생성: <code>insurance-rag-learning</code></li>
<li>✅ README.md 작성: 15세션 로드맵 수립</li>
<li>✅ 프로젝트 구조 설계: Python 패키지 구조 완성</li>
<li>✅ 가상환경 설정: 격리된 개발 환경 구축</li>
<li>✅ 효율적인 명령어 학습: mkdir, touch 고급 활용법 습득</li>
</ul>
<h2 id="📝-학습-노트">📝 학습 노트</h2>
<h3 id="좋았던-점">좋았던 점</h3>
<ul>
<li>프로젝트 구조 설명 시 각 폴더 역할을 주석으로 명시</li>
<li>mkdir 기본 → 효율적 → 고급 방법 단계적 학습</li>
<li>실수(오타)를 통한 자연스러운 디버깅 스킴 습득</li>
</ul>
<h3 id="개선할-점">개선할 점</h3>
<ul>
<li>명령어 입력 전 철자 확인 습관 필요</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[SELECT
대장균의 크기에 따라 분류하기 2]]></title>
            <link>https://velog.io/@mo_ongh/SELECT%EB%8C%80%EC%9E%A5%EA%B7%A0%EC%9D%98-%ED%81%AC%EA%B8%B0%EC%97%90-%EB%94%B0%EB%9D%BC-%EB%B6%84%EB%A5%98%ED%95%98%EA%B8%B0-2</link>
            <guid>https://velog.io/@mo_ongh/SELECT%EB%8C%80%EC%9E%A5%EA%B7%A0%EC%9D%98-%ED%81%AC%EA%B8%B0%EC%97%90-%EB%94%B0%EB%9D%BC-%EB%B6%84%EB%A5%98%ED%95%98%EA%B8%B0-2</guid>
            <pubDate>Sun, 08 Jun 2025 18:42:42 GMT</pubDate>
            <description><![CDATA[<p>logo
코딩테스트 연습
SELECT
대장균의 크기에 따라 분류하기 2
도움말
컴파일 옵션
대장균의 크기에 따라 분류하기 2
문제 설명
대장균들은 일정 주기로 분화하며, 분화를 시작한 개체를 부모 개체, 분화가 되어 나온 개체를 자식 개체라고 합니다.
다음은 실험실에서 배양한 대장균들의 정보를 담은 ECOLI_DATA 테이블입니다. ECOLI_DATA 테이블의 구조는 다음과 같으며, ID, PARENT_ID, SIZE_OF_COLONY, DIFFERENTIATION_DATE, GENOTYPE 은 각각 대장균 개체의 ID, 부모 개체의 ID, 개체의 크기, 분화되어 나온 날짜, 개체의 형질을 나타냅니다.</p>
<p>Column name    Type    Nullable
ID    INTEGER    FALSE
PARENT_ID    INTEGER    TRUE
SIZE_OF_COLONY    INTEGER    FALSE
DIFFERENTIATION_DATE    DATE    FALSE
GENOTYPE    INTEGER    FALSE
최초의 대장균 개체의 PARENT_ID 는 NULL 값입니다.</p>
<p>문제
대장균 개체의 크기를 내름차순으로 정렬했을 때 상위 0% ~ 25% 를 &#39;CRITICAL&#39;, 26% ~ 50% 를 &#39;HIGH&#39;, 51% ~ 75% 를 &#39;MEDIUM&#39;, 76% ~ 100% 를 &#39;LOW&#39; 라고 분류합니다. 대장균 개체의 ID(ID) 와 분류된 이름(COLONY_NAME)을 출력하는 SQL 문을 작성해주세요. 이때 결과는 개체의 ID 에 대해 오름차순 정렬해주세요 . 단, 총 데이터의 수는 4의 배수이며 같은 사이즈의 대장균 개체가 서로 다른 이름으로 분류되는 경우는 없습니다.</p>
<p>예시
예를 들어 ECOLI_DATA 테이블이 다음과 같다면</p>
<p>ID    PARENT_ID    SIZE_OF_COLONY    DIFFERENTIATION_DATE    GENOTYPE
1    NULL    10    2019/01/01    5
2    NULL    2    2019/01/01    3
3    1    100    2020/01/01    4
4    2    16    2020/01/01    4
5    2    17    2020/01/01    6
6    4    101    2021/01/01    22
7    6    101    2022/01/01    23
8    6    1    2022/01/01    27
기준에 의해 분류된 대장균들의 ID는 다음과 같습니다.</p>
<p>CRITICAL (상위 0% ~ 25%) : ID 6, ID 7
HIGH (상위 26% ~ 50%) : ID 3, ID 5
MEDIUM (상위 51% ~ 75%) : ID 1, ID 4
LOW (상위 76% ~ 100%) : ID 2, ID 8</p>
<p>따라서 결과를 ID 에 대해 오름차순 정렬하면 다음과 같아야 합니다.</p>
<p>ID    COLONY_NAME
1    MEDIUM
2    LOW
3    HIGH
4    MEDIUM
5    HIGH
6    CRITICAL
7    CRITICAL
8    LOW</p>
<pre><code class="language-sql">SELECT 
    ID,
    CASE
        WHEN percentile &lt;= 0.25 THEN &#39;CRITICAL&#39;
        WHEN percentile &lt;= 0.50 THEN &#39;HIGH&#39;
        WHEN percentile &lt;= 0.75 THEN &#39;MEDIUM&#39;
        WHEN percentile &lt;= 100 THEN &#39;LOW&#39;
    END AS COLONY_NAME
FROM (
        SELECT 
            ID,
            PERCENT_RANK() OVER( ORDER BY size_of_colony DESC ) AS percentile
        FROM ecoli_data
    ) AS ranked
ORDER BY ID;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[GROUP BY
부서별 평균 연봉 조회하기]]></title>
            <link>https://velog.io/@mo_ongh/GROUP-BY%EB%B6%80%EC%84%9C%EB%B3%84-%ED%8F%89%EA%B7%A0-%EC%97%B0%EB%B4%89-%EC%A1%B0%ED%9A%8C%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mo_ongh/GROUP-BY%EB%B6%80%EC%84%9C%EB%B3%84-%ED%8F%89%EA%B7%A0-%EC%97%B0%EB%B4%89-%EC%A1%B0%ED%9A%8C%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 08 Jun 2025 17:24:38 GMT</pubDate>
            <description><![CDATA[<p>좋은 지적 감사합니다! 아래는 <strong>문제 설명 + 예시 데이터 + 기대 출력 결과까지 모두 포함한 원문 전체 내용</strong>입니다:</p>
<hr>
<h2 id="문제-설명">문제 설명</h2>
<p>HR_DEPARTMENT 테이블은 회사의 부서 정보를 담은 테이블입니다.
HR_DEPARTMENT 테이블의 구조는 다음과 같으며 DEPT_ID, DEPT_NAME_KR, DEPT_NAME_EN, LOCATION은 각각 부서 ID, 국문 부서명, 영문 부서명, 부서 위치를 의미합니다.</p>
<table>
<thead>
<tr>
<th>Column name</th>
<th>Type</th>
<th>Nullable</th>
</tr>
</thead>
<tbody><tr>
<td>DEPT_ID</td>
<td>VARCHAR</td>
<td>FALSE</td>
</tr>
<tr>
<td>DEPT_NAME_KR</td>
<td>VARCHAR</td>
<td>FALSE</td>
</tr>
<tr>
<td>DEPT_NAME_EN</td>
<td>VARCHAR</td>
<td>FALSE</td>
</tr>
<tr>
<td>LOCATION</td>
<td>VARCHAR</td>
<td>FALSE</td>
</tr>
</tbody></table>
<p>HR_EMPLOYEES 테이블은 회사의 사원 정보를 담은 테이블입니다.
HR_EMPLOYEES 테이블의 구조는 다음과 같으며 EMP_NO, EMP_NAME, DEPT_ID, POSITION, EMAIL, COMP_TEL, HIRE_DATE, SAL은 각각 사번, 성명, 부서 ID, 직책, 이메일, 전화번호, 입사일, 연봉을 의미합니다.</p>
<table>
<thead>
<tr>
<th>Column name</th>
<th>Type</th>
<th>Nullable</th>
</tr>
</thead>
<tbody><tr>
<td>EMP_NO</td>
<td>VARCHAR</td>
<td>FALSE</td>
</tr>
<tr>
<td>EMP_NAME</td>
<td>VARCHAR</td>
<td>FALSE</td>
</tr>
<tr>
<td>DEPT_ID</td>
<td>VARCHAR</td>
<td>FALSE</td>
</tr>
<tr>
<td>POSITION</td>
<td>VARCHAR</td>
<td>FALSE</td>
</tr>
<tr>
<td>EMAIL</td>
<td>VARCHAR</td>
<td>FALSE</td>
</tr>
<tr>
<td>COMP_TEL</td>
<td>VARCHAR</td>
<td>FALSE</td>
</tr>
<tr>
<td>HIRE_DATE</td>
<td>DATE</td>
<td>FALSE</td>
</tr>
<tr>
<td>SAL</td>
<td>NUMBER</td>
<td>FALSE</td>
</tr>
</tbody></table>
<hr>
<h2 id="문제">문제</h2>
<p>HR_DEPARTMENT와 HR_EMPLOYEES 테이블을 이용해 부서별 평균 연봉을 조회하려 합니다.
부서별로 부서 ID, 영문 부서명, 평균 연봉을 조회하는 SQL문을 작성해주세요.</p>
<ul>
<li>평균연봉은 소수점 첫째 자리에서 반올림하고 컬럼명은 <code>AVG_SAL</code>로 해주세요.</li>
<li>결과는 부서별 평균 연봉을 기준으로 <strong>내림차순 정렬</strong>해주세요.</li>
</ul>
<hr>
<h2 id="예시">예시</h2>
<h3 id="hr_department-테이블">HR_DEPARTMENT 테이블</h3>
<table>
<thead>
<tr>
<th>DEPT_ID</th>
<th>DEPT_NAME_KR</th>
<th>DEPT_NAME_EN</th>
<th>LOCATION</th>
</tr>
</thead>
<tbody><tr>
<td>D0005</td>
<td>재무팀</td>
<td>Finance</td>
<td>그렙타워 5층</td>
</tr>
<tr>
<td>D0006</td>
<td>구매팀</td>
<td>Purchasing</td>
<td>그렙타워 5층</td>
</tr>
<tr>
<td>D0007</td>
<td>마케팅팀</td>
<td>Marketing</td>
<td>그렙타워 6층</td>
</tr>
</tbody></table>
<h3 id="hr_employees-테이블">HR_EMPLOYEES 테이블</h3>
<table>
<thead>
<tr>
<th>EMP_NO</th>
<th>EMP_NAME</th>
<th>DEPT_ID</th>
<th>POSITION</th>
<th>EMAIL</th>
<th>COMP_TEL</th>
<th>HIRE_DATE</th>
<th>SAL</th>
</tr>
</thead>
<tbody><tr>
<td>2019003</td>
<td>한동희</td>
<td>D0005</td>
<td>팀장</td>
<td><a href="mailto:donghee_han@grep.com">donghee_han@grep.com</a></td>
<td>031-8000-1122</td>
<td>2019-03-01</td>
<td>57000000</td>
</tr>
<tr>
<td>2020032</td>
<td>한명지</td>
<td>D0005</td>
<td>팀원</td>
<td><a href="mailto:mungji_han@grep.com">mungji_han@grep.com</a></td>
<td>031-8000-1123</td>
<td>2020-03-01</td>
<td>52000000</td>
</tr>
<tr>
<td>2022003</td>
<td>김보라</td>
<td>D0005</td>
<td>팀원</td>
<td><a href="mailto:bora_kim@grep.com">bora_kim@grep.com</a></td>
<td>031-8000-1126</td>
<td>2022-03-01</td>
<td>47000000</td>
</tr>
<tr>
<td>2018005</td>
<td>이재정</td>
<td>D0006</td>
<td>팀장</td>
<td><a href="mailto:jaejung_lee@grep.com">jaejung_lee@grep.com</a></td>
<td>031-8000-1127</td>
<td>2018-03-01</td>
<td>60000000</td>
</tr>
<tr>
<td>2019032</td>
<td>윤성희</td>
<td>D0006</td>
<td>팀원</td>
<td><a href="mailto:sunghee_yoon@grep.com">sunghee_yoon@grep.com</a></td>
<td>031-8000-1128</td>
<td>2019-03-01</td>
<td>57000000</td>
</tr>
<tr>
<td>2020009</td>
<td>송영섭</td>
<td>D0006</td>
<td>팀원</td>
<td><a href="mailto:yungseop_song@grep.com">yungseop_song@grep.com</a></td>
<td>031-8000-1130</td>
<td>2020-03-01</td>
<td>51000000</td>
</tr>
<tr>
<td>2021006</td>
<td>이성주</td>
<td>D0006</td>
<td>팀원</td>
<td><a href="mailto:sungju_lee@grep.com">sungju_lee@grep.com</a></td>
<td>031-8000-1131</td>
<td>2021-03-01</td>
<td>49000000</td>
</tr>
<tr>
<td>2018004</td>
<td>이주리</td>
<td>D0007</td>
<td>팀장</td>
<td><a href="mailto:joori_lee@grep.com">joori_lee@grep.com</a></td>
<td>031-8000-1132</td>
<td>2018-03-01</td>
<td>61000000</td>
</tr>
<tr>
<td>2020012</td>
<td>김사랑</td>
<td>D0007</td>
<td>팀원</td>
<td><a href="mailto:sarang_kim@grep.com">sarang_kim@grep.com</a></td>
<td>031-8000-1133</td>
<td>2020-03-01</td>
<td>54000000</td>
</tr>
<tr>
<td>2021018</td>
<td>김히라</td>
<td>D0007</td>
<td>팀원</td>
<td><a href="mailto:heera_kim@grep.com">heera_kim@grep.com</a></td>
<td>031-8000-1136</td>
<td>2021-03-01</td>
<td>49000000</td>
</tr>
</tbody></table>
<hr>
<h2 id="출력-예시">출력 예시</h2>
<table>
<thead>
<tr>
<th>DEPT_ID</th>
<th>DEPT_NAME_EN</th>
<th>AVG_SAL</th>
</tr>
</thead>
<tbody><tr>
<td>D0007</td>
<td>Marketing</td>
<td>54666667</td>
</tr>
<tr>
<td>D0006</td>
<td>Purchasing</td>
<td>54250000</td>
</tr>
<tr>
<td>D0005</td>
<td>Finance</td>
<td>52000000</td>
</tr>
</tbody></table>
<hr>
<pre><code class="language-sql">SELECT 
    d.DEPT_ID AS DEPT_ID, 
    d.DEPT_NAME_EN AS DEPT_NAME_EN, 
    ROUND(AVG(SAL), 0) AS AVG_SAL
FROM hr_department d
    JOIN hr_employees e ON d.DEPT_ID = e.DEPT_ID
GROUP BY d.DEPT_ID, d.DEPT_NAME_EN
ORDER BY AVG(SAL) DESC;</code></pre>
<pre><code class="language-sql">SELECT 
    e.DEPT_ID AS DEPT_ID, 
    d.DEPT_NAME_EN AS DEPT_NAME_EN, 
    e.AVG_SAL AS AVG_SAL
FROM hr_department d JOIN (
        SELECT 
            dept_id, 
            ROUND(AVG(SAL), 0) AS AVG_SAL
        FROM hr_employees
        GROUP BY dept_id
        ) e ON d.dept_id = e.dept_id
ORDER BY e.avg_sal DESC;</code></pre>
]]></description>
        </item>
    </channel>
</rss>