<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>kaeul_1.log</title>
        <link>https://velog.io/</link>
        <description>안녕하세요. 2년차 머신러닝 엔지니어입니다.</description>
        <lastBuildDate>Sun, 18 Jan 2026 08:35:27 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>kaeul_1.log</title>
            <url>https://velog.velcdn.com/images/kaeul_1/profile/81106d39-31dd-40cc-8f10-a224a197c804/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. kaeul_1.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/kaeul_1" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[PyTorch] Tensor 연산할 때 t1**2가 빠를까? t1.pow(2)가 빠를까?]]></title>
            <link>https://velog.io/@kaeul_1/PyTorch-Tensor-%EC%97%B0%EC%82%B0%ED%95%A0-%EB%95%8C-t12%EA%B0%80-%EB%B9%A0%EB%A5%BC%EA%B9%8C-t1.pow2%EA%B0%80-%EB%B9%A0%EB%A5%BC%EA%B9%8C</link>
            <guid>https://velog.io/@kaeul_1/PyTorch-Tensor-%EC%97%B0%EC%82%B0%ED%95%A0-%EB%95%8C-t12%EA%B0%80-%EB%B9%A0%EB%A5%BC%EA%B9%8C-t1.pow2%EA%B0%80-%EB%B9%A0%EB%A5%BC%EA%B9%8C</guid>
            <pubDate>Sun, 18 Jan 2026 08:35:27 GMT</pubDate>
            <description><![CDATA[<p>PyTorch로 코딩을 하다 보면 같은 연산임에도 불구하고 측정할 때마다 속도가 다르게 나오거나, 특정 방식이 미세하게 더 빠를 때가 있다. 
이번글에서는<code>**2</code> 연산자와 <code>.pow(2)</code> 메서드 사이의 속도 차이가 발생하는 근본적인 이유를 정리하려고 한다.</p>
<hr>
<h2 id="문제상황">문제상황</h2>
<p>pytorch에서 텐서에 대해 제곱을 계산할때, 
<code>**2</code>과 <code>.pow(2)</code>중 어떤것이 더 빠른지 궁금해서 간단한 실험을 준비했다.</p>
<ul>
<li>환경 : colab T4</li>
</ul>
<pre><code class="language-python">t1 = torch.arange(start = 0, end = 1000, step = 0.001)
t1 = t1.to(device=&quot;cuda&quot;)

start_time = time.time()
print(t1**2)
end_time = time.time()
print(f&quot;t1**2 : {(end_time - start_time)*1000}ms&quot;)

start_time = time.time()
print(t1.pow(2))
end_time = time.time()
print(f&quot;t1.pow(2): {(end_time - start_time)*1000}ms&quot;)

start_time = time.time()
print(t1.pow(2))
end_time = time.time()
print(f&quot;t1.pow(2): {(end_time - start_time)*1000}ms&quot;)

start_time = time.time()
print(t1**2)
end_time = time.time()
print(f&quot;t1**2 : {(end_time - start_time)*1000}ms&quot;)
</code></pre>
<pre><code class="language-text">tensor([0.0000e+00, 1.9881e-02, 7.9524e-02,  ..., 1.9881e+10, 1.9881e+10,
        1.9881e+10], device=&#39;cuda:0&#39;)
t1**2 : 1.4524459838867188ms
tensor([0.0000e+00, 1.9881e-02, 7.9524e-02,  ..., 1.9881e+10, 1.9881e+10,
        1.9881e+10], device=&#39;cuda:0&#39;)
t1.pow(2): 0.904083251953125ms
tensor([0.0000e+00, 1.9881e-02, 7.9524e-02,  ..., 1.9881e+10, 1.9881e+10,
        1.9881e+10], device=&#39;cuda:0&#39;)
t1.pow(2): 0.8094310760498047ms
tensor([0.0000e+00, 1.9881e-02, 7.9524e-02,  ..., 1.9881e+10, 1.9881e+10,
        1.9881e+10], device=&#39;cuda:0&#39;)
t1**2 : 0.7979869842529297ms</code></pre>
<p>왜 수학적으로는 동일한 연산임에도 불구하고 시간차이가 나타나는 걸까?</p>
<hr>
<h3 id="1-cuda-warm-up--synchronization">1. CUDA Warm-up &amp; Synchronization</h3>
<p>GPU 연산을 처음 시작할 때 가장 많이 겪는 현상이다.</p>
<ul>
<li><strong>Warm-up:</strong> GPU는 첫 연산 시 컨텍스트 초기화, 커널 로드 등의 준비 시간이 필요하다. 따라서 코드 상에서 먼저 실행되는 연산이 이 &quot;준비 시간&quot;을 독박 쓰게 되어 훨씬 느려 보일 수 있다.</li>
<li><strong>비동기 실행:</strong> GPU 연산은 CPU에서 명령만 내리고 따로 돌아간다. <code>print()</code>를 통해 결과를 확인하려 하면, CPU는 GPU가 연산을 끝내고 데이터를 보내줄 때까지 기다려야 하므로, 이 대기 시간이 측정값에 포함된다.</li>
</ul>
<p>이를 반영하여 아래처럼 코드를 짰다.</p>
<pre><code class="language-python"># Warm-up (미리 한번 실행해서 GPU를 깨워둠)
_ = t1**2 
torch.cuda.synchronize() # GPU 작업이 끝날 때까지 대기

# t1**2 측정
start = time.time()
res1 = t1**2
torch.cuda.synchronize() # 연산이 완전히 끝날 때까지 기다린 후 시간 측정
print(f&quot;t1**2: {(time.time() - start)*1000:.4f}ms&quot;)

# t1.pow(2) 측정
start = time.time()
res2 = t1.pow(2)
torch.cuda.synchronize()
print(f&quot;t1.pow(2): {(time.time() - start)*1000:.4f}ms&quot;)

# t1.pow(2) 측정
start = time.time()
res2 = t1.pow(2)
torch.cuda.synchronize()
print(f&quot;t1.pow(2): {(time.time() - start)*1000:.4f}ms&quot;)

# t1**2 측정
start = time.time()
res1 = t1**2
torch.cuda.synchronize()
print(f&quot;t1**2: {(time.time() - start)*1000:.4f}ms&quot;)</code></pre>
<pre><code class="language-text">t1**2: 0.0567ms
t1.pow(2): 0.0527ms
t1.pow(2): 0.0515ms
t1**2: 0.0520ms</code></pre>
<p>이번에는 아까처럼 눈에 띄는 정도의 시간차는 보이지 않아졌다. 그럼에도 불구하고 미세한 시간차이가 나는 이유가 무엇일까?</p>
<h3 id="2-파이썬-인터프리터의-오버헤드">2. 파이썬 인터프리터의 오버헤드</h3>
<p>Warm-up을 제외하더라도 마이크로초($\mu s$) 단위의 미세한 차이가 지속된다면, 이는 파이썬의 처리 경로 차이 때문이다.</p>
<ul>
<li><code>t1**2</code> (연산자 오버로딩):<ol>
<li>파이썬 인터프리터가 <code>**</code> 연산자 인식.</li>
<li>객체의 <code>__pow__</code> 매직 메서드를 찾는 과정을 거침.</li>
<li>최종적으로 PyTorch의 C++ 백엔드 호출.</li>
</ol>
</li>
<li><code>t1.pow(2)</code> (메서드 직접 호출):<ol>
<li>객체에 정의된 <code>pow</code> 메서드를 직접 호출.</li>
<li>연산자 해석 단계를 건너뛰므로 <strong>함수 호출 오버헤드(Function Call Overhead)</strong>가 더 적다.</li>
</ol>
</li>
</ul>
<h3 id="3-커널-런칭kernel-launch의-효율성">3. 커널 런칭(Kernel Launch)의 효율성</h3>
<p>GPU 연산 속도는 &#39;계산 시간&#39;보다 &#39;명령 전달 시간&#39;에 좌우되기도 한다.</p>
<ul>
<li><code>t1.pow(2)</code>는 PyTorch의 C++ API로 진입하는 경로가 더 직접적이다.</li>
<li>CPU가 GPU에게 &quot;이 연산을 실행해!&quot;라고 명령을 전달하는 과정이 아주 미세하게 더 효율적일 수 있다.</li>
</ul>
<h3 id="4-시스템-노이즈와-캐싱">4. 시스템 노이즈와 캐싱</h3>
<p>측정 시마다 값이 튀는 것은 컴퓨터의 하드웨어 상황 때문이다. CPU 스케줄링이나 명령어 캐시 상태에 따라 <code>0.01ms</code> 정도의 오차는 언제든 발생할 수 있으며, 두 번째 실행부터는 이미 캐시에 로드된 정보를 사용하기 때문에 더 빨라지기도 한다.</p>
<hr>
<h3 id="결론-무엇을-써야-할까">결론: 무엇을 써야 할까?</h3>
<table>
<thead>
<tr>
<th align="left">항목</th>
<th align="left"><code>t1**2</code></th>
<th align="left"><code>t1.pow(2)</code></th>
</tr>
</thead>
<tbody><tr>
<td align="left"><strong>내부 구현</strong></td>
<td align="left">연산자 오버로딩</td>
<td align="left">C++ API 직접 호출</td>
</tr>
<tr>
<td align="left"><strong>속도</strong></td>
<td align="left">미세하게 느릴 수 있음</td>
<td align="left"><strong>미세하게 빠를 수 있음</strong></td>
</tr>
<tr>
<td align="left"><strong>추천 용도</strong></td>
<td align="left">직관적인 수학 수식 표현</td>
<td align="left">일관된 함수형 프로그래밍 스타일</td>
</tr>
</tbody></table>
<p><strong>결론적으로, 성능 차이는 실무에서 무시해도 될 만큼 미미해보인다.</strong> 
이런경우, 성능 최적화보다는 팀의 컨벤션이나 코드의 가독성을 우선시하여 선택하는 것이 좋다. 
만약 정확한 성능 비교를 원한다면 반드시 <code>torch.cuda.synchronize()</code>를 사용하여 GPU의 작업이 끝날 때까지 기다린 후 시간을 측정해야 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] with문 이해하기]]></title>
            <link>https://velog.io/@kaeul_1/Python-with%EB%AC%B8-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@kaeul_1/Python-with%EB%AC%B8-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 17 Jan 2026 13:32:26 GMT</pubDate>
            <description><![CDATA[<h2 id="with-문이란">With 문이란?</h2>
<p>파이썬을 공부하다보면 다음과 같은 코드를 목격하게 된다.</p>
<pre><code class="language-python">with open(&quot;./corpus.txt&quot;, &quot;r&quot;, encoding=&quot;utf-8&quot;) as fd:
  corpus = fd.readlines()</code></pre>
<p>대충 해석해보자면 <code>with</code> 다음에 오는 <code>open(&quot;./corpus.txt&quot;, &quot;r&quot;, encoding=&quot;utf-8&quot;)</code>을 <code>fd</code>로 정의하는것으로 보인다.
그렇다면 왜 굳이 <code>with as</code>를 써준걸까?</p>
<p>이에 대한 구체적이니 이유는 다음 블로그에서 찾을 수 있었다.</p>
<blockquote>
<p><a href="https://projooni.tistory.com/entry/Python-with%EC%A0%88-%EB%AC%B8%EB%B2%95%EC%9D%98-%EC%9D%B4%ED%95%B4#google_vignette">Python with절 문법의 이해</a></p>
</blockquote>
<p>위 블로그의 내용을 요약하자면, 
리소스를 특정 구간에만 주고 싶은데 코드를 중복해서(<code>try</code>/<code>except</code>/<code>finally</code>)쓰기 보다는 
<strong><code>with</code>을 써서 해당 블록안에서만 리소스를 주고 나가면 해제한다.</strong></p>
<p>그렇다면 주피터 노트북의 다른 셀에서 fd를 실행시키면 어떻게 나올까?</p>
<pre><code class="language-python">fd</code></pre>
<pre><code class="language-bash">&lt;_io.TextIOWrapper name=&#39;./corpus.txt&#39; mode=&#39;r&#39; encoding=&#39;utf-8&#39;&gt;</code></pre>
<p>분명 with 블록 안에서만 리소스를 준다고 했는데 어떻게 된걸까?</p>
<h2 id="계속-참조하고-있는-변수">계속 참조하고 있는 변수</h2>
<p><code>with open(...) as fd</code> 구문은 <code>fd</code> 객체에 대해서 해당 <code>with</code>문을 벗어난 후에 자동으로 닫히도록 보장해준다. 
즉 File Handle인 <code>fd</code>가 참조하던 실제 파일 리소스는 운영체제에 반환되어 닫히는건 맞다.
하지만 <code>fd</code>라는 변수 자체는 여전히 전역 스코프에 남아있다. 
파이썬은 변수가 선언된 스코프 내에서 존재하므로, <code>fd</code>는 해당 <code>TextIoWrapper</code> 객체를 계속 참조하고 있는 것이다. </p>
<p>실제로 닫혔는지 다음 코드로 실험해봤다.</p>
<pre><code class="language-python">fd.read()</code></pre>
<pre><code class="language-bash">---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/tmp/ipython-input-28972991.py in &lt;cell line: 0&gt;()
----&gt; 1 fd.read()

ValueError: I/O operation on closed file.</code></pre>
<p>이로써, <code>fd</code>가 정상적으로 닫힌 파일을 계속 참조하고 있다는것을 알 수 있다.</p>
<h2 id="정리">정리</h2>
<ul>
<li>with문은 블록 안에서만 리소스를 할당하고 싶을때 사용한다.</li>
<li>with문을 나올때 해당 리소스는 자동으로 닫긴다.</li>
<li>다만, 블록 바깥에서도 해당 리소스를 가리키던 변수는 남아있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Agno로 에이전트 구축하기]]></title>
            <link>https://velog.io/@kaeul_1/Agno%EB%A1%9C-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@kaeul_1/Agno%EB%A1%9C-%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 20 Nov 2025 03:02:13 GMT</pubDate>
            <description><![CDATA[<p>DEVOCEAN OpenLab 2025 발표 </p>
<hr>
<p><img src="https://velog.velcdn.com/images/kaeul_1/post/37bbf79c-81ac-4233-89c8-0ff27d2994b6/image.jpg" alt=""></p>
<h2 id="1-introduction">1. Introduction</h2>
<p>안녕하세요!</p>
<p>DEVOCEAN OpenLab 2025의 <strong>“멀티모달 기반 AI 챗봇 기술 연구 &amp; 개발”</strong> 스터디에 참여 중인 <strong>가을</strong>입니다.</p>
<p>이번 포스팅에서는 최근 AI 트렌드로 주목받는 <strong>AI Agent</strong>와 <strong>Agno 프레임워크</strong>를 활용해 상담형 에이전트를 실습한 내용 공유하려 합니다.</p>
<p>이 글에서는 다음 내용을 다룹니다.</p>
<ul>
<li>Agent란 무엇인가</li>
<li>Agno의 구조와 주요 개념</li>
<li>간단한 Simple Agent 실습</li>
<li>Agno 기반 B tv 상담 Agent 실습</li>
</ul>
<hr>
<h2 id="2-agent란">2. Agent란?</h2>
<h3 id="21-agentic-ai-vs-ai-agent">2.1. Agentic AI vs AI Agent</h3>
<p>요즘 자주 등장하는 “에이전트(Agent)”는 단순히 모델을 호출하는 시스템이 아닙니다.</p>
<p>Agent는 <strong>모델이 실행 흐름을 스스로 제어하며 추론, 행동, 응답을 결정하는 자율적 AI 프로그램</strong>을 의미합니다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>Agentic AI</th>
<th>AI Agent</th>
</tr>
</thead>
<tbody><tr>
<td>개념</td>
<td>모델이 능동적으로 계획·추론·행동·피드백을 수행하는 패러다임</td>
<td>그 개념을 실제 시스템에 구현한 인스턴스</td>
</tr>
<tr>
<td>특징</td>
<td>LLM 기반의 자율성, 도구 사용, 멀티스텝 추론</td>
<td>특정 도메인(예: 상담, 분석, 추천)에 특화된 구조</td>
</tr>
<tr>
<td>예시</td>
<td>OpenAI o1-preview, AutoGPT, LangGraph Agents</td>
<td>Btv 상담 Agent, 문서 분석 Agent 등</td>
</tr>
</tbody></table>
<p>즉, Agent는 “지시를 수행하는 AI”가 아니라 “스스로 생각하고 실행하는 AI”라고 할 수 있습니다.</p>
<hr>
<h2 id="3-agno란">3. Agno란?</h2>
<p><img src="https://velog.velcdn.com/images/kaeul_1/post/bd08709b-cf65-4d25-9474-fad8d313da39/image.png" alt=""></p>
<p>Agno는 <strong>Agent Orchestration에 특화된 Python 프레임워크</strong>입니다.</p>
<p>단일 에이전트부터 복수의 팀 단위 워크플로까지 모두 구성할 수 있으며, FastAPI 기반 런타임과 UI를 함께 제공합니다.</p>
<blockquote>
<p>공식 문서 Link</p>
<ul>
<li>GitHub: <a href="https://github.com/agno-agi/agno">https://github.com/agno-agi/agno</a></li>
<li>Docs: <a href="https://docs.agno.com/introduction">https://docs.agno.com/introduction</a></li>
<li>UI: <a href="https://os.agno.com/">https://os.agno.com</a></li>
</ul>
</blockquote>
<h3 id="31-agno의-핵심-특징">3.1. Agno의 핵심 특징</h3>
<ol>
<li><strong>Pre-built FastAPI Runtime</strong><ul>
<li><code>AgentOS</code>는 즉시 실행 가능한 FastAPI 앱 형태로, Agent, Team, Workflow를 곧바로 실행할 수 있습니다.</li>
</ul>
</li>
<li><strong>Integrated UI</strong><ul>
<li><code>AgentOS UI</code>를 통해 런타임에 직접 연결되어 시스템 테스트, 모니터링, 관리가 가능합니다.</li>
</ul>
</li>
<li><strong>Privacy by Design</strong><ul>
<li>모든 데이터 처리를 클라우드 내부에서 수행하여 개인 정보 보호를 보장합니다.</li>
</ul>
</li>
<li><strong>성능</strong><ul>
<li>공식 벤치마크에 따르면 타 프레임워크 대비 처리 속도와 응답 일관성이 우수합니다.<ul>
<li>가장 보편적으로 사용되는 Langgraph와 비교했을때, 
Agno대비 Langgraph가 529배 느리고, 24배 메모리를 더 사용한다고 합니다.<ul>
<li>ref. <a href="https://docs.agno.com/introduction/performance">https://docs.agno.com/introduction/performance</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<hr>
<h2 id="4-agno의-주요-개념">4. Agno의 주요 개념</h2>
<table>
<thead>
<tr>
<th>구성요소</th>
<th>역할</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Memory</strong></td>
<td>과거 대화를 기억하고 학습하여 반응 품질 향상</td>
</tr>
<tr>
<td><strong>Storage</strong></td>
<td>세션 상태를 DB에 저장하여 상태 기반 상호작용 지원</td>
</tr>
<tr>
<td><strong>Knowledge</strong></td>
<td>벡터DB 기반 도메인 지식 검색 (Agentic RAG / Search)</td>
</tr>
<tr>
<td><strong>Reasoning</strong></td>
<td>응답 전 사고·분석을 수행하여 신뢰성 강화</td>
</tr>
</tbody></table>
<h3 id="41-agent-구조">4.1. Agent 구조</h3>
<ul>
<li><strong>Model</strong> : 사고(Reason), 행동(Act), 응답(Respond) 결정</li>
<li><strong>Instructions</strong> : 에이전트의 행동 지침</li>
<li><strong>Tools</strong> : 외부 시스템과 상호작용하는 실행 도구</li>
</ul>
<h3 id="42-team--workflow">4.2. Team &amp; Workflow</h3>
<ul>
<li><strong>Team</strong> : 여러 Agent 혹은 하위 Team의 집합으로, 복잡한 문제를 분담 처리</li>
<li><strong>Workflow</strong> : 결정적 실행 제어를 통해 일관된 자동화를 지원</li>
</ul>
<hr>
<h2 id="5-simple-agent-실습">5. Simple Agent 실습</h2>
<p>위에서 배운 Agno를 활용하여 아주 간단하게 에이전트를 구축해보겠습니다.</p>
<p>한 개의 Python 파일만으로 기본 구조를 완성할 수 있습니다.</p>
<p>우선 저는 무료로 호출할 수 있는 Gemini API(2025.10.15일 기준)를 이용해서 구축했습니다.</p>
<h3 id="51-환경-설정">5.1. 환경 설정</h3>
<ol>
<li><p><code>.env</code> 파일에 Gemini API 키를 등록</p>
<pre><code class="language-bash"> GEMINI_API_KEY=your_key_here</code></pre>
</li>
<li><p>Python 코드</p>
<pre><code class="language-python"> from dotenv import load_dotenv
 load_dotenv()  # .env 파일 로드

 from agno.agent import Agent
 from agno.db.sqlite import SqliteDb
 from agno.models.google import Gemini
 from agno.os import AgentOS

 # ************* 에이전트 생성 *************
 agno_agent = Agent(
     name=&quot;Agno 실험 에이전트&quot;,
     model=Gemini(id=&quot;gemini-2.0-flash&quot;),
     # 데이터베이스 추가
     db=SqliteDb(db_file=&quot;agno_os.db&quot;),
     # 이전 대화 기록을 컨텍스트에 추가
     add_history_to_context=True,
     instructions=[
         &quot;당신은 친절한 AI 어시스턴트입니다.&quot;,
         &quot;한국어로 대답해주세요.&quot;
     ],
     markdown=True,
 )

 # ************* AgentOS 생성 *************
 agent_os = AgentOS(agents=[agno_agent])
 # FastAPI 앱 가져오기
 app = agent_os.get_app()

 # ************* AgentOS 실행 *************
 if __name__ == &quot;__main__&quot;:
     # 서버 실행: http://localhost:7777
     # AgentOS UI는 https://os.agno.com 에서 접속 가능
     agent_os.serve(app=&quot;agent_os_server:app&quot;, reload=True)</code></pre>
</li>
<li><p>Terminal </p>
<pre><code class="language-bash"> python main.py</code></pre>
</li>
</ol>
<p>이후 Agent UI에서 실시간 테스트가 가능합니다.</p>
<ol>
<li><p><a href="https://os.agno.com/">**https://os.agno.com/</a>** 접속</p>
</li>
<li><p>Local, endpoint url, name 설정 후 Update 버튼 클릭</p>
<p> <img src="https://velog.velcdn.com/images/kaeul_1/post/e094bcb5-f10b-40e5-bb22-e06f08137fdb/image.png" alt=""></p>
</li>
</ol>
<ol start="3">
<li><p>Chat에서 실험할 수 있습니다.
 <img src="https://velog.velcdn.com/images/kaeul_1/post/6a508092-62a0-410f-8ee1-72aaf0794092/image.png" alt=""></p>
<p> <small style="color:gray">Agno에 대해 Gemini API 기반 Agent에게 물어봤을때, 
 검색 툴을 연결하지않아 이상한 대답을 하는 것을 확인할 수 있습니다.</small></p>
</li>
</ol>
<blockquote>
<p><strong>Tip.</strong> 
Agno 객체는 기본적으로 OpenAI API를 사용합니다.
다른 모델(Gemini, Claude 등)을 사용하려면 반드시 명시해야 합니다.</p>
</blockquote>
<hr>
<h2 id="6-b-tv-상담-agent-구축-실습">6. B tv 상담 Agent 구축 실습</h2>
<p>Agno는 Agnet orchestration에 특화된 Framework인 만큼, 이에 대해 성능을 확인해보려고 합니다.</p>
<h3 id="61-실험-구조">6.1. 실험 구조</h3>
<ul>
<li>*<em>실험 1) 단일 Agent *</em></li>
<li>*<em>실험 2) Team *</em><ol>
<li>문서 검색 Agent : PDF 내 정보 검색</li>
<li>기술 해설 Agent : 검색된 내용 정리</li>
<li>품질 검증 Agent : 답변 타당성 점검</li>
<li>Team leader Agent</li>
</ol>
</li>
</ul>
<h3 id="62-공통-설정">6.2. 공통 설정</h3>
<p>Knowledge에는 <strong>‘B tv  통합서비스 이용가이드.pdf’</strong> 문서를 이용하여 단순 <code>PDFReader</code>로 읽고 임베딩하여 상담이 가능하도록 구성했습니다.</p>
<pre><code class="language-bash">from dotenv import load_dotenv
load_dotenv()

from agno.agent import Agent
from agno.knowledge import Knowledge
from agno.vectordb.lancedb import LanceDb
from agno.knowledge.embedder.google import GeminiEmbedder
from agno.knowledge.reader.pdf_reader import PDFReader
from agno.knowledge.chunking.fixed import FixedSizeChunking
from agno.models.google import Gemini
from agno.os import AgentOS
from agno.db.sqlite import SqliteDb

# ************* LanceDB로 로컬 Vector DB 설정 *************
vector_db = LanceDb(
    table_name=&quot;service_guide&quot;,
    uri=&quot;./lancedb&quot;,
    embedder=GeminiEmbedder()
)

# ************* Knowledge 생성 및 PDF 추가 *************
knowledge = Knowledge(vector_db=vector_db)

knowledge.add_content(
            path=&quot;통합서비스_이용가이드.pdf&quot;,
            reader=PDFReader(
                chunking_strategy=FixedSizeChunking(
                    chunk_size=1000,  # 93자 → 1000자로 증가
                    overlap=200       # 청크 간 오버랩으로 맥락 유지
                )
            ),
            metadata={&quot;type&quot;: &quot;guide&quot;, &quot;category&quot;: &quot;service&quot;}
        )
</code></pre>
<p>그리고 동일하게 <strong>“AI 스피커형 셋톱박스의 불빛 색 별 의미를 알려줘”</strong> 라는 질문을 입력했습니다.</p>
<p>해당 질문에 대한 정답페이지 아래 이미지의 왼쪽입니다.</p>
<p><img src="https://velog.velcdn.com/images/kaeul_1/post/fe9fa184-7e52-42e4-b9c8-bf81fa37d0f2/image.jpg" alt=""></p>
<p>그리고 이에 해당하는 chunck는 다음과 같습니다.</p>
<pre><code class="language-bash">--- Chunk 3 ---
ID: cb9912d390c043c9e1fbfa7769421df2
파일명: 통합서비스_이용가이드.pdf
메타데이터: {&#39;page&#39;: 4, &#39;chunk&#39;: 1, &#39;chunk_size&#39;: 999, &#39;type&#39;: &#39;guide&#39;, &#39;category&#39;: &#39;service&#39;}
내용: 6 Smart 3, UHD 4 셋톱박스 윗면 뒷면 셋톱박스의 동작 상태에 따라 불빛이 들어와요. B tv 채널을 변경할 수 있어요. 상태 알림 LED 채널채널 마이크(MIC) 입력 랜 포트 HDMI 포트 USB  포트 전원 연결 포트 마이크를 연결할 수 있어요. 랜 케이블을 이용해 SK브로드밴드 인터넷을 연결해요. HDMI 케이블을 이용해 TV와 연결해요. USB 메모리를 연결할 수 있어요.(USB 2.0 , USB 3.0 ) 전원 어댑터를 연결해요. 흰색 불빛 : 나타남 B tv 시청 중일 때 초록색 불빛 : 나타남 B tv 전원이 꺼졌을 때(B tv 대기모드) 흰색 불빛 : 깜박임 B tv 전원이 켜질 때 / 시스템을 시작할 때 빨간색 불빛 : 깜박임 네트워크 오류가 발생했을 때 전원을 켜고 서비스를 시작하면 초록색과 파란색 불빛이 들어와요. “아리아”라고 말하면, 사용자의 위치에 따라 파란색 불빛이 들어와요. ※ 빔 포밍(Beam Forming) 기술을 이용해, 소리가 나는 위치를 실시간으로 인지하고, 사용자의 위치에 따라 불빛이 함께 움직여요. 사용자의 음성을 인식하는 동안에는 파란색 불빛이 좌우로  동작을 반복해요. 사용자의 요청을 처리하는 동안에는 파란색 불빛이 좌우로 크게 들어와요. 사용자의 요청에 따라 응답할 때는 파란색 불빛이 천천히 깜박거려요. 마이크가 꺼지면 “아리아”라 고 불러도 음성을 인식할 수 없어요. 주황색 불빛이 좌우로 크기가 줄어들어요. ※ 마이크를 다시 켜려면, 셋톱박스 뒷면에 있는 [마이크 OFF] 버튼을 다시 눌러 마이크를 켜 주세요. 혹은 B tv 홈 화면에서 [MY ▶ 설정 ▶ NUGU 설정 ▶ 음성인식 사용설정]을 선택한 후, ‘사용함’으로 설정을 변경해 주세요. 음량의 크기에 따라 흰색 불빛이 들어와요. 음량이 0이 되거나 ‘조용히’ 모드일  때는 중앙에 흰색 불빛이 들어와요. ※ 음량은 총 32단계로 조절할 수 있으며, 불빛의 밝기와 위치로 음량의 크기를 확인할 수 있어요. 중앙에 주황색 불빛이 들어와요. 불빛이 오랫동안        
Vector 차원: 1536

--- Chunk 4 ---
ID: a82e137ee4afd86163e02cdadf062fba
파일명: 통합서비스_이용가이드.pdf
메타데이터: {&#39;page&#39;: 4, &#39;chunk&#39;: 2, &#39;chunk_size&#39;: 363, &#39;type&#39;: &#39;guide&#39;, &#39;category&#39;: &#39;service&#39;}
내용:  ▶ NUGU 설정 ▶ 음성인식 사용설정]을 선택한 후, ‘사용함’으로 설정을 변경해 주세요. 음량의 크기에 따라 흰색 불빛이 들어와요. 음량이 0이 되거나 ‘조용히’ 모드일 때는 중앙에 흰색 불빛이 들어와요. ※ 음량은 총 32단계로 조절할 수 있으며, 불빛의 밝기와 위치로 음량의 크기를 확인할 수 있어요. 중앙에 주황색 불빛이 들어와요. 불빛이 오랫동안 나타나면, 고객센터로 문 의해 주세요.(고객센터 106) 서비스를 시작할 때 음성인식 기능을 사용할 때 마이크가 꺼졌을 때 음량을 조절할 때 시스템 오류가 발생했을 때 상태별 알림 안내 AI 스피커형 셋톱박스 5 ※ B tv pop 이용 고객의 경우, Smart 3 셋톱박스만 설치 가능해요.
Vector 차원: 1536</code></pre>
<p>단순한 <code>PDFReader</code> 와 <code>FixedSizeChunking</code>을 이용했기 때문에,
잘 나눠지지는 않은  것을 확인할 수 있었습니다. </p>
<p>특히, 정답페이지의 왼쪽과 오른쪽 방면의 내용이 섞인 것을 확인할 수 있었습니다.</p>
<p>기본 세팅으로 Agent들의 성능을 확인하고 싶었기에 실험은 이대로 진행했습니다.</p>
<h3 id="63-실험-1-단일-agent">6.3. 실험 1) 단일 Agent</h3>
<p><strong>code</strong></p>
<pre><code class="language-bash"># ************* Gemini 모델로 상담사 에이전트 생성 *************
agent = Agent(
    name=&quot;통합서비스 고객지원 챗봇&quot;,
    model=Gemini(id=&quot;gemini-2.0-flash&quot;),
    knowledge=knowledge,
    search_knowledge=True,
    db=SqliteDb(db_file=&quot;rag_chatbot.db&quot;),
    add_history_to_context=True,
    instructions=[
        &quot;당신은 통합서비스 고객지원 챗봇입니다.&quot;,
        &quot;제공된 매뉴얼을 기반으로 정확하게 답변하세요.&quot;,
        &quot;문서에 없는 내용은 추측하지 말고 정중하게 안내하세요.&quot;,
    ],
    markdown=True,
)

# ************* AgentOS로 UI 제공 *************
agent_os = AgentOS(agents=[agent])
app = agent_os.get_app()

if __name__ == &quot;__main__&quot;:
    agent_os.serve(app=&quot;agent_rag_chatbot:app&quot;, reload=True)</code></pre>
<p><strong>결과</strong></p>
<p><img src="https://velog.velcdn.com/images/kaeul_1/post/e6cc8d51-eb06-4cd9-b008-6067d3dc4b3b/image.png" alt=""></p>
<p>chunck 분할이 제대로 안되었던 점을 감안하면, 간결히 정리되어 나오는 것을 볼 수 있습니다. </p>
<h3 id="64-실험-2-team">6.4. 실험 2) Team</h3>
<p>여기서는 총 3개의 하위 Agent와 Team Learder Agent를 사용했습니다.</p>
<ol>
<li><strong>문서 검색 Agent</strong> : PDF 내 정보 검색</li>
<li><strong>기술 해설 Agent</strong> : 검색된 내용 정리</li>
<li><strong>품질 검증 Agent</strong> : 답변 타당성 점검</li>
<li><strong>Team Leader Agent</strong> : 통합서비스 전문 상담팀 리더(1~3을 통솔)</li>
</ol>
<p><strong>code</strong></p>
<pre><code class="language-bash"># 1. 문서 검색 전문가
search_expert = Agent(
    name=&quot;문서검색전문가&quot;,
    role=&quot;매뉴얼에서 관련 정보를 찾는 전문가&quot;,
    model=Gemini(id=&quot;gemini-2.0-flash&quot;),
    knowledge=knowledge,
    search_knowledge=True,
    instructions=[
        &quot;당신은 문서 검색 전문가입니다.&quot;,
        &quot;고객 질문을 분석하여 핵심 키워드를 파악하세요.&quot;,
        &quot;매뉴얼에서 관련된 모든 정보를 철저히 검색하세요.&quot;,
        &quot;특히 표, 목록, 단계별 설명 등을 주의 깊게 찾으세요.&quot;,
        &quot;찾은 정보를 구조화하여 다른 팀원에게 전달하세요.&quot;,
    ],
    markdown=True,
)</code></pre>
<pre><code class="language-bash"># 2. 기술 해설 전문가
technical_expert = Agent(
    name=&quot;기술해설전문가&quot;,
    role=&quot;기술 내용을 쉽게 설명하는 전문가&quot;,
    model=Gemini(id=&quot;gemini-2.0-flash&quot;),
    knowledge=knowledge,
    search_knowledge=True,
    instructions=[
        &quot;당신은 기술 해설 전문가입니다.&quot;,
        &quot;검색된 기술 정보를 고객이 이해하기 쉽게 설명하세요.&quot;,
        &quot;전문 용어는 쉬운 말로 풀어서 설명하세요.&quot;,
        &quot;단계, 절차, 색상 등 구체적 정보는 정확히 전달하세요.&quot;,
        &quot;예시나 비유를 활용하여 이해를 돕세요.&quot;,
    ],
    markdown=True,
)</code></pre>
<pre><code class="language-bash"># 3. 품질 검증 전문가
quality_checker = Agent(
    name=&quot;품질검증전문가&quot;,
    role=&quot;답변의 정확성을 검증하는 전문가&quot;,
    model=Gemini(id=&quot;gemini-2.0-flash&quot;),
    knowledge=knowledge,
    search_knowledge=True,
    instructions=[
        &quot;당신은 품질 검증 전문가입니다.&quot;,
        &quot;팀원들이 제공한 답변이 문서 내용과 일치하는지 확인하세요.&quot;,
        &quot;누락된 중요 정보가 있는지 점검하세요.&quot;,
        &quot;최종 답변이 고객 질문에 완전히 답하는지 확인하세요.&quot;,
        &quot;필요시 추가 검색이나 보완을 요청하세요.&quot;,
    ],
    markdown=True,
)</code></pre>
<pre><code class="language-bash"># ************* 상담 팀 구성 *************
support_team = Team(
    name=&quot;통합서비스 전문 상담팀&quot;,
    model=Gemini(id=&quot;gemini-2.0-flash&quot;),  # 팀 리더 모델
    members=[search_expert, technical_expert, quality_checker],
    db=SqliteDb(db_file=&quot;rag_team.db&quot;),
    add_history_to_context=True,
    instructions=[
        &quot;당신은 통합서비스 고객지원팀의 리더입니다.&quot;,
        &quot;팀원들과 협력하여 고객 질문에 정확하고 완전한 답변을 제공하세요.&quot;,
        &quot;&quot;,
        &quot;작업 순서:&quot;,
        &quot;1. 문서검색전문가가 관련 정보를 찾습니다.&quot;,
        &quot;2. 기술해설전문가가 내용을 이해하기 쉽게 정리합니다.&quot;,
        &quot;3. 품질검증전문가가 답변을 검증하고 보완합니다.&quot;,
        &quot;4. 최종 답변을 고객에게 친절하게 전달합니다.&quot;,
        &quot;&quot;,
        &quot;품질 기준:&quot;,
        &quot;- 문서에 근거한 정확한 정보&quot;,
        &quot;- 명확하고 이해하기 쉬운 설명&quot;,
        &quot;- 고객 질문에 완전히 답변&quot;,
        &quot;- 친절하고 전문적인 톤&quot;,
    ],
    markdown=True,
)</code></pre>
<pre><code class="language-bash"># ************* AgentOS로 UI 제공 *************
agent_os = AgentOS(teams=[support_team])
app = agent_os.get_app()

if __name__ == &quot;__main__&quot;:
    agent_os.serve(app=&quot;agent_rag_team:app&quot;, reload=True)</code></pre>
<p><strong>결과</strong></p>
<ol>
<li><p>Team내 소통</p>
<p> <img src="https://velog.velcdn.com/images/kaeul_1/post/97679163-9d3c-48a9-9656-09865822802d/image.png" alt=""></p>
</li>
</ol>
<pre><code>![](https://velog.velcdn.com/images/kaeul_1/post/6a847535-0ece-4357-a958-08230c533c2e/image.png)


![](https://velog.velcdn.com/images/kaeul_1/post/78ad5706-7757-481a-a44a-14ce702680f8/image.png)</code></pre><ol start="2">
<li><p>최종 응답</p>
<p> <img src="https://velog.velcdn.com/images/kaeul_1/post/9351d59d-2536-4d89-a1af-44db0546ebac/image.png" alt=""></p>
</li>
</ol>
<p>실험 1) 단일 Agent때의 답변과 비교했을때,</p>
<p>더 구체적이고 명료하게 작성된 것을 확인할 수 있었습니다.</p>
<hr>
<h2 id="7-느낀-점">7. 느낀 점</h2>
<p>직접 실습해 본 결과, Agno는 다음과 같은 장점이 있었습니다.</p>
<ol>
<li>빠르고 직관적인 Agent 구축 가능</li>
<li>UI에서 바로 채팅 테스트 가능</li>
<li>MCP(Multi-Context Protocol) 제공 → Cursor 등 개발 환경과 통합 용이</li>
<li>FastAPI처럼 외부 API 연동이 쉬움</li>
<li>JSON 형태의 응답 및 LLM 평가(LLM-as-a-Judge 등) 기능 지원</li>
</ol>
<p>무엇보다 “<strong>에이전트 개발이 이렇게 단순해질 수 있다</strong>”는 점이 인상적이었습니다.</p>
<p>향후에는 멀티모달 입력과 MCP 연동 기능까지 활용해볼 계획입니다.</p>
<p>읽어주셔서 감사합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[왜 SSE로 통신할 때 JSON String이 오지?]]></title>
            <link>https://velog.io/@kaeul_1/%EC%99%9C-SSE%EB%A1%9C-%ED%86%B5%EC%8B%A0%ED%95%A0-%EB%95%8C-JSON-String%EC%9D%B4-%EC%98%A4%EC%A7%80</link>
            <guid>https://velog.io/@kaeul_1/%EC%99%9C-SSE%EB%A1%9C-%ED%86%B5%EC%8B%A0%ED%95%A0-%EB%95%8C-JSON-String%EC%9D%B4-%EC%98%A4%EC%A7%80</guid>
            <pubDate>Wed, 16 Jul 2025 16:34:24 GMT</pubDate>
            <description><![CDATA[<h1 id="introduction">Introduction</h1>
<p>오늘은 저번에 구현해놓은 AI서버의 채팅 기능과, BE간의 채팅 통신(SSE ; Server-Sent Events)을 테스트했다.
우리 팀의 BE인 rick.lee랑 진행중에 알게 된 사실을 공유한다.</p>
<h2 id="background">Background</h2>
<p>BE(Spring boot)쪽에서 ai요청에 대해 JSON으로 파싱하는 코드를 작성해서 사용중이었음.</p>
<h2 id="problem-definition">Problem definition</h2>
<p>그런데 AI쪽에서 SSE로 보내준 데이터가 JSON형식이 아니어서 에러가 난다는 BE 로그를 발견.</p>
<p>AI쪽 코드를 확인해 보니 아래와 같았음.</p>
<pre><code class="language-python"># kaeul/22-tenten-ai/services/bot_chats_service.py

# ...
                stream_data = {
                    &quot;stream_id&quot;: stream_id,
                    &quot;message&quot;: token + &quot; &quot;, # 각 단어 뒤에 공백을 붙여서 전송
                    &quot;timestamp&quot;: datetime.now().strftime(&#39;%Y-%m-%dT%H:%M:%S&#39;)
                }
                # stream_data 딕셔너리를 JSON 문자열로 변환하여 전송
                await sse_manager.broadcast(f&quot;event: stream\ndata: {json.dumps(stream_data, ensure_ascii=False)}\n\n&quot;)
# ...
</code></pre>
<p>서버가 클라이언트(BE 서버)로 이벤트를 보낼때, Python dictionary를 <code>json.dumps()</code>를 사용해 <strong>JSON String</strong>로 변환한 뒤 보내고 있었음.</p>
<p>따라서 클라이언트는 <code>data</code>필드에 포함된 내용을 <strong>JSON으로 파싱</strong> 해서 사용해야함.
실제로 클라이언트가 받는 raw data의 형식은 아래의 예제와 같음.</p>
<pre><code class="language-bash">event: stream
data: {&quot;stream_id&quot;: &quot;some-stream-id&quot;, &quot;message&quot;: &quot;안녕하세요 &quot;, &quot;timestamp&quot;: &quot;2024-07-17T12:34:56&quot;}

event: stream
data: {&quot;stream_id&quot;: &quot;some-stream-id&quot;, &quot;message&quot;: &quot;반갑습니다 &quot;, &quot;timestamp&quot;: &quot;2024-07-17T12:34:57&quot;}

event: done
data: {&quot;stream_id&quot;: &quot;some-stream-id&quot;, &quot;message&quot;: null, &quot;timestamp&quot;: &quot;2024-07-17T12:34:58&quot;}</code></pre>
<hr>
<h1 id="study">Study</h1>
<h2 id="json과-json-string의-차이점">JSON과 JSON String의 차이점</h2>
<h3 id="1-json">1. JSON</h3>
<ul>
<li>데이터 구조(Structure)나 형식(Format)을 의미함.<ul>
<li>key-value 쌍으로 이루어져있고, 계층을 가질 수 있음</li>
</ul>
</li>
<li>Python의 <code>딕셔너리(dict)</code>나 JavaScript의 <code>객체(Object)</code>처럼 메모리에 존재하는 실제 데이터 덩어리임.</li>
<li>따라서, <code>data[&#39;user_id&#39;]</code>와 같이 특정 키를 이용해 값에 바로 접근 가능</li>
</ul>
<pre><code class="language-python"># 이것은 &#39;JSON 데이터 구조&#39;에 해당하는 파이썬 딕셔너리입니다.
data_dict = {
    &quot;stream_id&quot;: &quot;test-123&quot;,
    &quot;user_id&quot;: 1,
    &quot;message&quot;: &quot;안녕하세요&quot;
}

# 딕셔너리이므로 키로 값에 접근할 수 있습니다.
print(data_dict[&#39;user_id&#39;])  # 출력: 1
print(type(data_dict))       # 출력: &lt;class &#39;dict&#39;&gt;</code></pre>
<h3 id="2-json-string">2. JSON String</h3>
<ul>
<li>위에서 설명한 데이터 구조를 전송하거나, 저장하기 위해 하나의 긴 <code>문자열(String)</code>으로 변환한 결과물</li>
<li>네트워크를 통해 데이터를 보내거나, 파일에 데이터를 쓸 때는 메모리에 있는 데이터 구조를 직접 보낼 수 없기 때문에 이런 텍스트 형태로 변환하는 것임.</li>
<li>이 과정을 <code>직렬화(Serialization)</code>이라고 한다.</li>
<li>JSON String은 그냥 긴 텍스트이기 때문에, <code>json_string[&#39;user_id&#39;]</code>와 같이 키로 값에 접근 할 수 없음. 그래서 이 문자열을 다시 데이터 구조로 변환(Parsing)하는 <code>역직렬화</code>해야함.</li>
</ul>
<pre><code class="language-python">import json

data_dict = {
    &quot;stream_id&quot;: &quot;test-123&quot;,
    &quot;user_id&quot;: 1,
    &quot;message&quot;: &quot;안녕하세요&quot;
}

# 딕셔너리(데이터 구조)를 JSON 문자열(텍스트)로 변환 (직렬화)
json_string = json.dumps(data_dict, ensure_ascii=False)

print(json_string)       # 출력: &#39;{&quot;stream_id&quot;: &quot;test-123&quot;, &quot;user_id&quot;: 1, &quot;message&quot;: &quot;안녕하세요&quot;}&#39;
print(type(json_string)) # 출력: &lt;class &#39;str&#39;&gt;

# 문자열이므로 이렇게 접근하면 에러가 발생합니다!
# json_string[&#39;user_id&#39;]  # TypeError 발생

# 사용하려면 다시 딕셔너리로 변환해야 합니다 (역직렬화).
parsed_dict = json.loads(json_string)
print(parsed_dict[&#39;user_id&#39;]) # 출력: 1</code></pre>
<h2 id="왜-sse를-사용할-때-json-string-형식으로-데이터를-전송해야하는가">왜 SSE를 사용할 때, JSON String 형식으로 데이터를 전송해야하는가?</h2>
<p><strong>요약</strong></p>
<blockquote>
<ul>
<li>네트워크는 메모리에 있는 데이터 구조(객체, 딕셔너리 등)를 직접 실어서 보낼 수 없다. </li>
<li>네트워크는 오직 바이트(byte)의 흐름, 즉 텍스트 같은 순차적인 데이터만 전송 할 수 있다</li>
</ul>
</blockquote>
<h3 id="이유">이유</h3>
<ol>
<li><strong>전송의 한계 :</strong>
서버의 메모리에 있는 파이썬 딕셔너리 객체는 서버 컴퓨터에서만 의미가 있는 데이터 덩어리다. 
이 데이터 구조를 네트워크 케이블을 통해 클라이언트 컴퓨터로 그대로 &#39;밀어 넣을&#39;방법은 없다.
네트워크는 이런 복잡한 구조가 아닌, 순차적인 바이트 스트림만 전송할 수 있다.</li>
<li>** 표준화의 필요성 :**
설령 보낼 수 있다고 해도, 파이썬의 딕셔너리를 자바스크립트나 자바가 직접 이해할 수 없다. 각 언어는 데이터를 메모리에 저장하는 방식이 다르기 때문. 그래서 모든 언어가 공통적으로 이해할 수 있는 &#39;표준 글자 형식&#39;이 필요한데, 그것이 바로 JSON String이다.</li>
<li><strong>직렬화 (Serialization) :</strong>
그래서 서버는 전송 전에 자신의 딕셔너리를 <code>json.dumps()</code>를 통해 JSON String으로 변환.</li>
<li><strong>역직렬화 (Deserialization) :</strong>
클라이언트는 이 JSON String을 받은 뒤, <code>JSON.parse()</code>같이 각각의 언어에 맞는 객체로 재조립함.</li>
</ol>
<h2 id="그렇다면-왜-http-통신에서는-json형식으로-가는-걸까">그렇다면 왜 HTTP 통신에서는 JSON형식으로 가는 걸까?</h2>
<p><strong>요약</strong></p>
<blockquote>
<p>편리한 도구들이 중간 과정을 자동으로 처리해주기 때문에 마치 JSON 형식이 그대로 가는 것 처럼 보일 뿐. 데이터 구조 자체가 네트워크를 통해 전송되지 않는다.</p>
</blockquote>
<h3 id="왜-그렇게-보일까--content-type-헤더">왜 그렇게 보일까? : <code>Content-Type</code> 헤더</h3>
<p>일반 HTTP통신이 SSE와 다른 점은 <strong>&quot;이 데이터는 JSON String이니, 받으면 JSON 객체로 해석해주세요&quot;</strong> 라는 Header를 붙여서 보낸다는 것. 이 Header가 <code>Content-Type : application/json</code> header다. </p>
<h4 id="http-통신-과정을-살펴보자">HTTP 통신 과정을 살펴보자</h4>
<blockquote>
<p>서버에서 <code>{&quot;status&quot;:&quot;ok&quot;}</code>라는 응답을 보낸다고 가정.</p>
</blockquote>
<p><strong>[서버]</strong></p>
<ol>
<li><p>데이터 준비 : 먼저 파이썬 딕셔너리 형태의 데이터를 만든다.</p>
<pre><code class="language-python"> response_data = {&quot;status&quot;: &quot;ok&quot;}</code></pre>
</li>
<li><p>JSON String으로 변환(직렬화)</p>
<pre><code class="language-python"> json_string = &#39;{&quot;status&quot;: &quot;ok&quot;}&#39;</code></pre>
</li>
<li><p>HTTP 응답 생성 : 이 JSON Stringdmf HTTP 응답 본문(Body)에 싣는다. 그리고 Header를 붙인다.</p>
<pre><code class="language-text"> HTTP/1.1 200 OK
 Content-Type: application/json  &lt;-- &quot;JSON 이 들어있어요!&quot; 라는 표시
 Content-Length: 15

 {&quot;status&quot;: &quot;ok&quot;} &lt;-- 실제 내용(JSON String)</code></pre>
</li>
</ol>
<p><strong>[네트워크]</strong></p>
<p>Postman, 웹브라우저 같은 HTTP 클라이언트 도구들은 위의 응답을 받으면 다음과 같이 행동합니다.</p>
<ol>
<li>응답 확인 :
가장 먼저 <code>Content-Type</code> 헤더를 확인.</li>
<li>자동 변환 (역직렬화) :
<code>Content-Type</code> 헤더 내용을 기반으로, 응답 본문에 있던 <code>{&quot;status&quot;: &quot;ok&quot;}</code>라는 순수 String을 자동으로 자바스크립트의 객체나 파이썬의 딕셔너리로 변환(Parsing)해줌. </li>
<li>개발자에게 전달 :
그리고 최종적으로 변환된 객체를 개발자에게 보여준다.</li>
</ol>
<p>-&gt; 이 자동 변환 과정때문에 개발자는 마치 서버가 처음부터 JSON 객체를 보내준 것처럼 느끼게 됨.</p>
<h3 id="http와-sse의-content-type-헤더-차이점">HTTP와 SSE의 <code>Content-Type</code> 헤더 차이점</h3>
<ul>
<li>일반 HTTP 통신 : <code>Content-Type: application/json</code></li>
<li>SSE 통신 : <code>Content-Type: text/event-stream</code><ul>
<li>정해진 형식(<code>event : , data :</code>)에 따라 텍스트가 계속 스트리밍 된다. <code>data</code> 필드에 있는 내용이 JSON String인지는 클라이언트 측에서 직접 해석하고 파싱해야한다.</li>
</ul>
</li>
</ul>
<hr>
<p>스트리밍 기능을 구현하다보니, 생각치도 못했던 부분을 알게되어서 좋다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[KakaoBase를 소개합니다]]></title>
            <link>https://velog.io/@kaeul_1/KakaoBase%EB%A5%BC-%EC%86%8C%EA%B0%9C%ED%95%A9%EB%8B%88%EB%8B%A4</link>
            <guid>https://velog.io/@kaeul_1/KakaoBase%EB%A5%BC-%EC%86%8C%EA%B0%9C%ED%95%A9%EB%8B%88%EB%8B%A4</guid>
            <pubDate>Sun, 13 Jul 2025 04:03:28 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>카카오테크 부트캠프 수강생들을 위한 온라인 커뮤니티 서비스 - KakaoBase</p>
</blockquote>
<p><strong>Links</strong></p>
<ul>
<li>Service [현재 운영 중지] : <a href="https://www.kakaobase.com/">https://www.kakaobase.com/</a></li>
<li>Disquiet : <a href="https://disquiet.io/product/kakao-base">https://disquiet.io/product/kakao-base</a></li>
<li>GitHub <ul>
<li>wiki repo : <a href="https://github.com/100-hours-a-week/22-tenten-wiki/wiki">https://github.com/100-hours-a-week/22-tenten-wiki/wiki</a></li>
<li>AI repo : <a href="https://github.com/100-hours-a-week/22-tenten-ai">https://github.com/100-hours-a-week/22-tenten-ai</a></li>
</ul>
</li>
</ul>
<hr>
<p>안녕하세요.
KakaoBase 서비스를 운영하는 tenten의 AI팀에 속해있는 astra.ka 입니다.</p>
<p>이번 포스트에서는
저희가 2025년 3월 31일부터 시작했던 프로젝트인, <code>KakaoBase</code>에 대해 소개드리려고 합니다.</p>
<hr>
<h3 id="왜-만들었을까">왜 만들었을까?</h3>
<p>기존에 카카오테크 부트캠프에서 사용하던 Discord나 Zep이 있는데, 왜 카카오테크 부트캠프 수강생들을 위한 온라인 커뮤니티가 필요할까요?</p>
<p> Discord나 Zep은 아무래도 수업/공지 중심이라 자유롭게 수다 떨기엔 눈치가 보였어요.</p>
<p>게다가 “기수 상관없이” 소통할 공간이 있으면 프로젝트를 진행하거나 취업 준비할 때 훨씬 유용할 것 같더라고요.</p>
<p>그래서 저희는,</p>
<blockquote>
<p>카카오 테크 부트캠프 수강생만의 문화와 연대감을 만들어갈 수 있는 곳</p>
</blockquote>
<p>을 만들자는 생각으로 KakaoBase를 시작했습니다.</p>
<hr>
<h3 id="뭐가-되냐면요">뭐가 되냐면요</h3>
<p>KakaoBase는 다음과 같은 주요 기능으로 구성되어있습니다.</p>
<ol>
<li><strong>Post</strong> : 자유롭게 글을 작성하고 좋아요/댓글로 소통</li>
<li><strong>Alarm</strong> : 내 활동(좋아요, 댓글 등)에 대한 알림 제공</li>
<li><strong>[AI] Social Bot - roro</strong> : 게시물·댓글·채팅으로 대화하는 소셜봇</li>
<li><strong>[AI] 유튜브 영상 요약</strong> : 긴 유튜브 영상의 링크를 올리면 자동 요약</li>
</ol>
<hr>
<h3 id="어떻게-만들었나">어떻게 만들었나</h3>
<p>저희는 개발할 때 애자일 방식을 썼습니다.
프로젝트 기간인 18주동안 2주마다 스프린트를 돌리고, 4주마다 배포하는 식으로 총 3번 배포까지 진행했어요.</p>
<p>그리고 매일 아침에는 데일리 스크럼으로 상태를 공유했고, 주마다 타운홀·PL·PM 미팅을 하면서 진행상황을 공유하고 운영 중 이슈에 대처했습니다.</p>
<hr>
<h3 id="성과-요약">성과 요약</h3>
<p>서비스는 3개월 동안 운영됐는데요,</p>
<p>덕분에 Disquiet 주간 1위도 찍어봤고 🎉</p>
<p>처음 타겟유저였던 <code>카카오테크 부트캠프 2기 수강생</code>중 총 89.9%인 124명의 수강생이 KakaoBase에 가입해서 실제로 써줬습니다!</p>
<hr>
<h3 id="회고">회고</h3>
<p>솔직히… 쉽지 않았습니다 😂
매일 야근에 주말도 반납하고, 새벽까지 디스코드 붙잡고 있었거든요.</p>
<p>근데 그만큼 많이 배웠습니다.</p>
<ul>
<li>기술 선택 근거를 팀원들에게 설득하는 방법</li>
<li>AI뿐만 아니라 클라우드랑 풀스택 기본기도 꼭 필요하다는 점</li>
<li>서비스는 단순히 배포가 끝이 아니라, 운영까지 고려해야 한다는 점</li>
</ul>
<p><img src="https://velog.velcdn.com/images/kaeul_1/post/da4238fc-471a-4a7c-9be7-493ebcbe91b8/image.png" alt=""></p>
<figcaption style="text-align:center; font-size:15px; color:#808080; margin-top:40px">
    우리 팀은 4일 연속 교육장에서 제일 마지막까지 남아 개발하다가, 매번 문 닫고 나온 기록이 있습니다…😂
  </figcaption>

<p>무엇보다 같이 고생한 팀원들한테는 진짜 고맙다는 말밖에 못 하겠네요.
교육장에서 마지막까지 남아있던 게 한두 번이 아니었어요.
그런데 분명 같이 문 닫고 나가고, 집에 보냈는데 디스코드 켜고 개발 얘기하는 걸 보면서 “와, 진짜 대단하다”라는 존경심이 들었어요.</p>
<p>덕분에 이 프로젝트는 제게 단순한 개발 경험을 넘어, 정말 재미있고 값진 시간이 되었습니다.</p>
<hr>
<p>다음 글에서는 KakaoBase를 만들면서 겪었던 구체적인 기술적 도전과 해결 과정을 풀어보겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[fastapi, uvicorn, event loop]]></title>
            <link>https://velog.io/@kaeul_1/fastapi-uvicorn-event-loop</link>
            <guid>https://velog.io/@kaeul_1/fastapi-uvicorn-event-loop</guid>
            <pubDate>Sun, 13 Jul 2025 03:25:52 GMT</pubDate>
            <description><![CDATA[<p>이번에 카카오베이스에서 채팅기능을 구현하는데, 아무리 생각해도 응답속도가 너무 느릴것같아서 고민이었다...</p>
<h3 id="background-현재-모델-서빙-구조">Background (현재 모델 서빙 구조)</h3>
<p>게다가 지금 현재 구조가 </p>
<pre><code>base llm + lora1(유튜브 요약)
         + lora2(소셜봇) </code></pre><p>위와 같은 multi adapter라서.. </p>
<h3 id="problem-definition">Problem definition</h3>
<p>만약에 유튜브영상 2시간짜리 넣으면, 해당 inference가 진행되는동안 채팅기능이 마비될 것으로 예상된다... ㅠ</p>
<h3 id="study">Study</h3>
<p>그래서 같은 카카오베이스팀에서 BE를 맡고 계신 rick.lee랑, 카카오테크 부트캠프 ai과정을 같이 듣고계신 simon.lee한테 많이 여쭤봐서 해당 내용을 기록한다.</p>
<p><code>20250712 밤 - rick</code>
spring boot자체에는 이벤트 루프가 없다. fastapi는 자동으로 지원해주는것 같다.
이벤트 루프는 round queue같은건데, 들어오는 순서대로 일을 처리해준다. </p>
<p><code>20250713 낮 - simon</code>
fastapi에 있는 이벤트 루프 == python 자체에 있는 이벤트 루프</p>
<pre><code>fastapi
    | 
uvicorn
    |
이벤트루프</code></pre><p>요런느낌이랬음. 그래서 각 요청(a,b,c)마다 3초씩 걸린다고 가정했을때, </p>
<p>[잘못 생각한 시나리오]
a요청  : 0<del>3초에 생성 및 응답 / 이벤트 루프 [b요청, c요청]
b요청 : 3</del>6초에 생성 및 응답 / 이벤트 루프 [c요청]
c요청 : 6~9초에 생성 및 응답 / 이벤트 루프 []</p>
<p>[실제 돌아가는 방법]
a 요청 : 0<del>3초에 생성하고, 응답을 이벤트루프에 넣기 / 이벤트 루프 [b요청, c요청, a응답]
b요청 : 3</del>6초에 생성하고,  응답을 이벤트루프에 넣기 / 이벤트 루프  [c요청, a응답, b응답]
c요청 : 6~9초에 생성하고,  응답을 이벤트루프에 넣기 / 이벤트 루프  [a응답, b응답, c응답]
9초쯤에 abc응답을 우다다 반환</p>
<p>그리고 fastapi에서 uvicorn의 worker를 n개로 설정하면 이벤트루프가 n개 생성되고 각각의 이벤트 루프위에 uvicorn과 fastapi가 있는거</p>
<h3 id="conclusion">Conclusion</h3>
<blockquote>
<p>결론 : uvicorn의 worker 수를 늘려야한다.</p>
</blockquote>
<h3 id="limitation">Limitation</h3>
<p>그럼에도 불구하고 문제점이 있다.</p>
<p>우리 ai 서버는 현재 다음과 같은 구조로 되어있음.</p>
<ol>
<li>Hugging Face에 model정보 가져오기(lora도 가져오기)</li>
<li>모델을 vllm으로 띄우기 (따로 server 안띄우고 GCP 내부에서 실행)</li>
</ol>
<p>결국 모델을 worker수인 n개만큼 띄우게 되는건데, OOM(메모리 부족 현상)이 발생할 가능성이 높아보임. </p>
<h3 id="future-work">Future work</h3>
<blockquote>
<p>oom이 발생하지 않는 적정선의 worker수인 n을 찾아야한다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[카카오테크 부트캠프 2기 생성형AI - 엄청 늦은 합격후기 ✌️ ]]></title>
            <link>https://velog.io/@kaeul_1/%EC%B9%B4%EC%B9%B4%EC%98%A4%ED%85%8C%ED%81%AC-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-2%EA%B8%B0-%EC%83%9D%EC%84%B1%ED%98%95AI-%EC%97%84%EC%B2%AD-%EB%8A%A6%EC%9D%80-%ED%95%A9%EA%B2%A9%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@kaeul_1/%EC%B9%B4%EC%B9%B4%EC%98%A4%ED%85%8C%ED%81%AC-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-2%EA%B8%B0-%EC%83%9D%EC%84%B1%ED%98%95AI-%EC%97%84%EC%B2%AD-%EB%8A%A6%EC%9D%80-%ED%95%A9%EA%B2%A9%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Sat, 24 May 2025 11:19:53 GMT</pubDate>
            <description><![CDATA[<p>엄청엄청 늦은 합격후기를 공유합니당</p>
<p><img src="https://velog.velcdn.com/images/kaeul_1/post/de7f6217-ce54-4297-b271-12d2969f7ef2/image.png" alt=""></p>
<p>올해 1월, <a href="https://ktb.goorm.io/pangyo/ai">카카오테크 부트캠프(줄여서 카부캠, KTB) 2기 생성형 AI 과정</a>에 합격했다.</p>
<p>8월에 졸업하고나서 고향에 내려가서 혼자서 취업준비하다가 매일 일어나서 이력서 쓰고 포폴쓰고...
이대로 가다간 공부한 걸 다 까먹게 생겼다!!! 라는 생각이 들어서 지원하게 되었다.</p>
<p>석사했을때는 거의 머신러닝을 다뤄서, generative ai에 관심이 있었는데 딱 과정명이 명확하게 <code>생성형 AI</code>라고 적혀있어서 더 매력적이었다. </p>
<p>그리고 풀스택/클라우드/인공지능이 팀을 이뤄서 4개월짜리 프로젝트를 한다는 것도 가점!</p>
<p>그러면 어떻게 합격했는지 기억나는대로 공유해보겠다</p>
<img src="https://velog.velcdn.com/images/kaeul_1/post/4a23c7ef-94d2-4746-b3a0-e59a9a03c8b2/image.png" width="50%">

<hr>
<h2 id="지원서-평가">지원서 평가</h2>
<p><code>3배수 인원 선발</code></p>
<h4 id="선택-주요업무-내용">(선택) 주요업무 내용</h4>
<p>-&gt; 이거는 석사 하는동안 연구했던 내용에 대해서 작성했다. 기존에 써놓은 이력서 형태로 넣었음.</p>
<h4 id="선택-기타-경력사항">(선택) 기타 경력사항</h4>
<p>-&gt; 그냥 석사 기간 동안 퍼블리시했던 모든 논문을 리스트업했음.</p>
<h4 id="카카오테크-부트캠프-지원-동기를-작성해주세요-공란-포함-최대-500자">카카오테크 부트캠프 지원 동기를 작성해주세요. (공란 포함 최대 500자)</h4>
<p>-&gt; 카카오라는 기업을 조사한 내용과, 카카오부트캠프에서 내가 이루고 싶은것을 적었음.</p>
<h4 id="본-과정을-통해-6개월-후-자신의-성장할-모습을-설명해주세요-공란-포함-최대-500자">본 과정을 통해 6개월 후 자신의 성장할 모습을 설명해주세요. (공란 포함 최대 500자)</h4>
<p>-&gt; 실제 서비스를 만들어보고 싶다는 식으로 적음.</p>
<h4 id="좋아하는-서비스를-소개하고-개선이-필요한-점과-이를-바탕으로-만들어-보고-싶은-프로젝트를-작성해딱-주세요-공란-포함-최대-500자-">좋아하는 서비스를 소개하고, 개선이 필요한 점과 이를 바탕으로 만들어 보고 싶은 프로젝트를 작성해딱 주세요. (공란 포함 최대 500자) *</h4>
<p>-&gt; 솔직히 이 문항을 가장 오랫동안 고민했다. 이것때문에 제출못할뻔함..ㅎㅎ
딱 일상에서 접근할 수 있는 포인트를 집어서 유저 입장에서 개선이 필요한 점을 작성했다. 그리고 이를 어떻게 ai로 구현할 수 있을지를 간단하게 적었다. 마지막으로 아이디어 내다가 내가 스스로 폐기했던 것들도 한줄로 적어서 내긴했다.</p>
<h4 id="팀프로젝트-수행경험에-대해-나의-역할을-중심으로-설명해주세요-공란-포함-최대-500자">(팀)프로젝트 수행경험에 대해 &#39;나의 역할&#39;을 중심으로 설명해주세요. (공란 포함 최대 500자)</h4>
<p>-&gt; 이거는 연구할때 데이터세트 수집하면서 발생한 내용을 작성했다.</p>
<h4 id="결과">결과</h4>
<img src="https://velog.velcdn.com/images/kaeul_1/post/5cf3037b-62fd-4738-9639-1c11c6b1c61c/image.png" width="70%">


<p>히히</p>
<hr>
<h2 id="코딩테스트-전형">코딩테스트 전형</h2>
<p><code>2배수 인원 선발</code></p>
<img src="https://velog.velcdn.com/images/kaeul_1/post/8227a332-0420-4ad4-9937-e01a3e7f0983/image.png" width="70%">

<p>이건 솔직히 기억안남..
하지만 딱 하나 기억나는건 있다</p>
<p>카카오라서 당연히 프로그래머스일줄 알았다.
그리고 평소에 코딩테스트 공부도 프로그래머스로만 햇구...</p>
<p>그런데 입력방식은 백준임</p>
<p>있는기억 없는 기억 다 끄집어내서 겨우 <code>input()</code>을 알아냈다. 
진짜 장함. 몇년동안 안쓴거를 어떻게 기억해낸거지</p>
<p>한 3~4문제 정도 나왔던걸로 기억한다.</p>
<hr>
<h2 id="온라인-면접-및-인성평가">온라인 면접 및 인성평가</h2>
<p><code>코딩테스트 합격자 대상 진행</code></p>
<img src="https://velog.velcdn.com/images/kaeul_1/post/e81d9cb1-f751-4adc-8387-2b7a8c655be2/image.png" width="70%">

<p>면접날에 개인사정때문에 서울로 올라가야만 하는 상황이라.... 
인생최초로 혼자서 공간대여해서 면접봤다ㅋㅋㅋ</p>
<p>질문은 평범..?</p>
<p>생성형 ai랑 프로젝트 어떤거 했었는지 같은 질문들을 받았다.
그리고 면접때 처음으로 들은 말이 있었는데 <code>R&amp;R</code>이었다.
그때는 면접 내공이 부족해서 모르는 단어있으면 어쭤보면 되는데, 우물쭈물 어버버 거렸던 기억..ㅋㅋㅋ</p>
<p>나중에 찾아보니 </p>
<blockquote>
<p>R&amp;R : Role and Responsibillity 
조직 또는 팀 내에서 개인이 맡은 역할과 그에 따른 책임</p>
</blockquote>
<p>이런 뜻이었더라 허허
그냥 줄이지말고 얘기해달라고...!!!</p>
<p>이때 yohan.kim 이랑 같이 면접봤었다.
그때도 대답잘한다~ 라고 생각했었는데, ktb에 합격한거 보고 속으로 반가웠다</p>
<hr>
<h2 id="결과-및-후기">결과 및 후기</h2>
<img src="https://velog.velcdn.com/images/kaeul_1/post/41563721-c1c0-4b22-80af-09ae08d750dd/image.png" width="70%">

<p>헤헤</p>
<p>솔직히 면접 보고 나서, 떨어질수도 있겠다..? 라고 생각했는데 붙어서 엄청 기분좋았다</p>
<p>이 다음에 입과 신청서를 작성했어야했는데,
카테부안에서 쓸 영어 이름을 적으라기에, 이름을 뭐로하면 좋을지 엄청엄청엄청 고민했었던 기억이있다ㅋㅋㅋㅋ</p>
<p>처음에는 평범하게 noah로 하려다가 말았는데, 선택안하길 잘했다 (들어와보니 noah만 8명임)</p>
<img src="https://velog.velcdn.com/images/kaeul_1/post/31cdf26a-1347-46df-88ed-130eaab505d9/image.png" width="50%">

<p>내가 선택한 이름은 <code>astra.ka</code>였는데, astra는 라틴어로 별이라는 뜻이다.
더 정확히는</p>
<blockquote>
<p><em>Per Aspera Ad astra</em>
역경과 고난을 넘어서 별을 향하여</p>
</blockquote>
<p>라는 라틴어 속담에서 따왔다</p>
<p>사람은 이름을 따라간다니깐..! 지금은 고생하더라도 나중에 원하는 바를 이룰수 있었으면 하는 소망때문에 이렇게 지었다
<del>그런데지금고생너무심하게하는것같기도하고</del></p>
<h3 id="단점">단점</h3>
<p>팀프로젝트 시작하면서 오프라인 수업으로 전환되면서, 판교에 있는 오피스로 가야하는데...
지방사람으로써 정말정말 큰 허들이었다...
솔직히 매일왔다갔다 충주-판교 통학이 자신이 없어서 겨우 자취시작함</p>
<p>그리고 여기와서 가장 충격적이었던것
-&gt; 팀프로젝트 클라우드 비용 지원 4달에 100만원...
이걸로 인공지능 뭘 해야한단말인가.. 프로젝트 시작할때 엄청 머리아팠던 기억이 있다.
그래도 colab pro plus를 지원해줘서 그나마 다행이었음.</p>
<h3 id="장점">장점</h3>
<p>그럼에도 불구하고 지금 거의 4개월동안 부캠한 결과 만족도는 매우 높다!</p>
<p>복수전공하고나서부터 공부하면서 계속 모르는것을 편하게 물어볼 사람들이 필요했는데 없었다..
모르는걸 물어보면 아는사람이 있어서 그거에 대한 대답을 해줘야하는데, 서로 모르는느낌?
그런데 여기서는 다같이 공부하는 입장이니까, 편하게 물어보고 편하게 대답해주고, 정확히 모르겠으면 강사님붙잡고 여쭤볼수도 있고..!
개발이나 인공지능에 대해서 뿐만 아니라, 소통방법이나 공부하는 접근법 등 서로에게 인사이트도 얻고 너무 좋은것 같다. </p>
<p>그리고 뭔가를 할때 열심히 몰두해서 하는 사람을 만나기 정말 힘든데, 여기는 그런사람들이 많이 모여있어서 더 동기부여되는 느낌</p>
<p>신청할까말까 고민하는 사람 있으면 추천하고 싶은 정도</p>
<img src="https://velog.velcdn.com/images/kaeul_1/post/94f7f6e1-34ea-4d3a-a38c-d00e122c9a48/image.png" width="50%">
오피스에있는 코딩하는 춘식이로 마무리]]></description>
        </item>
        <item>
            <title><![CDATA[Python  부동소수점]]></title>
            <link>https://velog.io/@kaeul_1/Python-%EB%B6%80%EB%8F%99%EC%86%8C%EC%88%98%EC%A0%90</link>
            <guid>https://velog.io/@kaeul_1/Python-%EB%B6%80%EB%8F%99%EC%86%8C%EC%88%98%EC%A0%90</guid>
            <pubDate>Sat, 24 May 2025 09:07:23 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/19532">백준 19532번</a> 문제를 풀다가 발견한 이슈를 정리합니다.</p>
<hr>
<h2 id="백준-19532번">백준 19532번</h2>
<h4 id="수학은-비대면강의입니다">수학은 비대면강의입니다</h4>
<p>브론즈 II, 시간 제한 1초(추가 시간 없음)</p>
<h4 id="문제">문제</h4>
<p>수현이는 4차 산업혁명 시대에 살고 있는 중학생이다. 코로나 19로 인해, 수현이는 버추얼 학교로 버추얼 출석해 버추얼 강의를 듣고 있다. 수현이의 버추얼 선생님은 문자가 2개인 연립방정식을 해결하는 방법에 대해 강의하고, 다음과 같은 문제를 숙제로 냈다.</p>
<p>다음 연립방정식에서n$x$와 $y$의 값을 계산하시오.</p>
<p><img src="https://velog.velcdn.com/images/kaeul_1/post/f580c1e6-74e0-4cf6-9c68-cc79eed3baa6/image.png" alt=""></p>
<p>4차 산업혁명 시대에 숙제나 하고 앉아있는 것보다 버추얼 친구들을 만나러 가는 게 더 가치있는 일이라고 생각했던 수현이는 이런 연립방정식을 풀 시간이 없었다. 다행히도, 버추얼 강의의 숙제 제출은 인터넷 창의 빈 칸에 수들을 입력하는 식이다. 각 칸에는 $-999$ 이상 $999$ 이하의 정수만 입력할 수 있다. 수현이가 버추얼 친구들을 만나러 버추얼 세계로 떠날 수 있게 도와주자.</p>
<h4 id="입력">입력</h4>
<p>정수 $a$, $b$, $c$, $d$, $e$, $f$가 공백으로 구분되어 차례대로 주어진다. ($-999 \leq a,b,c,d,e,f \leq 999$) 문제에서 언급한 방정식을 만족하는 $\left(x,y\right)$가 유일하게 존재하고, 이 때 $x$와 $y$가 각각 $-999$ 이상 $999$ 이하의 정수인 경우만 입력으로 주어짐이 보장된다.</p>
<h4 id="출력">출력</h4>
<p>문제의 답인 $x$와 $y$를 공백으로 구분해 출력한다.</p>
<h4 id="예제">예제</h4>
<p>입력 1</p>
<pre><code>1 3 -1 4 1 7</code></pre><p>출력 1</p>
<pre><code>2 -1</code></pre><p>입력 2</p>
<pre><code>2 5 8 3 -4 -11</code></pre><p>출력 2</p>
<pre><code>-1 2</code></pre><hr>
<h2 id="처음-풀이-방식">처음 풀이 방식</h2>
<p>이 문제를 처음 봤을때는
ㅋㅋ 쉽네 하고 아래와 같이 풀었다.</p>
<pre><code class="language-python">a, b, c, d, e, f = map(int, input().split(&#39; &#39;))

y = int((c/a - f/d)/(b/a-e/d))
x = int(c/a - (b/a)*y)

print(x, y)
</code></pre>
<p>그런데 결과가.. 2%에서 틀렸다고 뜸
어째서?
<img src="https://velog.velcdn.com/images/kaeul_1/post/4d106579-dcbe-409b-b4ac-c1e6b648ba77/image.png" width="30%"></p>
<p>그래서 반례를 열심히 찾아봤다.</p>
<p><img src="https://velog.velcdn.com/images/kaeul_1/post/3907468f-8047-401b-b91b-fc2ee02e388a/image.png" alt=""></p>
<p>내 코드에서도 1 1 3 7 6 1을 입력하면 -16 19으로 틀리게 출력하는 것을 알게됨.
아니 부동소수점 오차이거먼데 옛날에 들었던것 같은디</p>
<hr>
<h2 id="부동소수점이란">부동소수점이란?</h2>
<p><em>ref :</em> <a href="https://ko.wikipedia.org/wiki/%EB%B6%80%EB%8F%99%EC%86%8C%EC%88%98%EC%A0%90">https://ko.wikipedia.org/wiki/%EB%B6%80%EB%8F%99%EC%86%8C%EC%88%98%EC%A0%90</a></p>
<blockquote>
<p> 실수를 컴퓨터상에서 근사하여 표현할 때 소수점의 위치를 고정하지 않고 그 위치를 나타내는 수를 따로 적는 것으로, 유효숫자를 나타내는 가수(假數)와 소수점의 위치를 풀이하는 지수(指數)로 나누어 표현한다. </p>
</blockquote>
<h3 id="부동소수점-표기-방식-ieee-745">부동소수점 표기 방식 (IEEE 745)</h3>
<p><em>ref :</em> <a href="https://ko.wikipedia.org/wiki/IEEE_754">https://ko.wikipedia.org/wiki/IEEE_754</a></p>
<p><img src="https://velog.velcdn.com/images/kaeul_1/post/b4514304-7117-4972-962f-ef714fa3ad5a/image.png" alt=""></p>
<p><strong>예시</strong>
−118.625(십진법)를 IEEE 754(32비트 단정밀도)로 표현해 보자.</p>
<ul>
<li>음수이므로, 부호부는 1이 된다.</li>
<li>그 다음, 절댓값을 이진법으로 나타내면 1110110.101(2)이 된다.</li>
<li>소수점을 왼쪽으로 이동시켜, 왼쪽에는 1만 남게 만든다. 예를 들면 1110110.101(2)=1.110110101(2)×2⁶ 과 같다. 이것을 정규화된 부동소수점 수라고 한다.</li>
<li>가수부는 소수점의 오른쪽 부분으로, 부족한 비트 수 부분만큼 0으로 채워 23비트로 만든다. 결과는 11011010100000000000000 이 된다.</li>
<li>지수는 6이므로, Bias를 더해야 한다. 32비트 IEEE 754 형식에서는 Bias는 127이므로 6+127 = 133이 된다. 이진법으로 변환하면 10000101(2)이 된다.
이 결과를 정리해서 표시하면 다음과 같다.</li>
</ul>
<p>부동소수점 표기 방식을 자세히 살펴보면, 2진수로 소숫점을 나타내는 것을 확인할 수 있다.
당연히 컴퓨터는 2진수를 사용하니까~라고 생각하면서 넘겼었는데,
사람은 <code>10진수</code>를 사용하는게 문제였다.</p>
<h2 id="부동-소수점-산술-문제점">부동 소수점 산술 문제점</h2>
<p><em>ref :</em> <a href="https://docs.python.org/ko/3.13/tutorial/floatingpoint.html">https://docs.python.org/ko/3.13/tutorial/floatingpoint.html</a></p>
<p>오늘날 대부분 기계에서, float는 이진 분수로 근사 되는 데, 최상위 비트로부터 시작하는 53비트를 분자로 사용하고, 2의 거듭제곱 수를 분모로 사용합니다. 1/10의 경우, 이진 분수는 <code>3602879701896397 / 2 ** 55</code> 인데, 실제 값 1/10과 거의 같지만 정확히 같지는 않습니다.</p>
<p>많은 사용자는 값이 표시되는 방식 때문에 근사를 인식하지 못합니다. 파이썬은 기계에 저장된 이진 근삿값의 진짜 십진 값에 대한 십진 근삿값을 인쇄할 뿐입니다. 대부분 기계에서, 만약 파이썬이 0.1로 저장된 이진 근삿값의 진짜 십진 값을 출력한다면 다음과 같이 표시해야 합니다:</p>
<pre><code class="language-python">&gt;&gt;&gt; 0.1
0.1000000000000000055511151231257827021181583404541015625</code></pre>
<p>이것은 대부분 사람이 유용하다고 생각하는 것보다 많은 숫자이므로, 파이썬은 반올림된 값을 대신 표시하여 숫자를 다룰만하게 만듭니다:</p>
<pre><code class="language-python">&gt;&gt;&gt; 1 / 10
0.1</code></pre>
<p>인쇄된 결과가 정확히 1/10인 것처럼 보여도, 실제 저장된 값은 가장 가까운 표현 가능한 이진 소수임을 기억하세요.</p>
<p>하나의 환상은 다른 환상을 낳을 수 있습니다. 예를 들어, 0.1은 정확히 1/10이 아니므로, 0.1의 세 개를 합한 것 역시 정확히 0.3이 아닙니다:</p>
<pre><code class="language-python">&gt;&gt;&gt; 0.1 + 0.1 + 0.1 == 0.3
False</code></pre>
<p>또한, 0.1은 1/10의 정확한 값에 더 가까워질 수 없고, 0.3도 3/10의 정확한 값에 더 가까워질 수 없으므로, round() 함수로 미리 반올림하는 것은 도움이 되지 않습니다:</p>
<pre><code class="language-python">&gt;&gt;&gt; round(0.1, 1) + round(0.1, 1) + round(0.1, 1) == round(0.3, 1)
False</code></pre>
<p>숫자를 의도한 정확한 값에 더 가깝게 만들 수는 없지만, math.isclose() 함수는 부정확한 값을 비교할 때 유용할 수 있습니다:</p>
<pre><code class="language-python">&gt;&gt;&gt; math.isclose(0.1 + 0.1 + 0.1, 0.3)
True</code></pre>
<hr>
<h2 id="해결방법">해결방법</h2>
<p>사람은 10진수로 사용해서 자연스럽게 딱 떨어지는 소숫점을 기대한 방면, 컴퓨터는 2진수를 사용하기때문에 10진수로 떨어지는 소숫점을 정확하기 표현하기 어려움
=&gt; 이 문제로 인해 백준 19532번에서 틀린것!</p>
<p>정말로 그런지 코드에서 <code>int</code>를 빼고 확인해보자</p>
<p>code :</p>
<pre><code class="language-python">a, b, c, d, e, f = map(int, input().split(&#39; &#39;))

y = ((c/a - f/d)/(b/a-e/d))
x = (c/a - (b/a)*y)

print(x, y)</code></pre>
<p>input:</p>
<pre><code>1 1 3 7 6 1</code></pre><p>expected output:</p>
<pre><code>-17 20</code></pre><p>received output:</p>
<pre><code>-16.999999999999993 19.999999999999993</code></pre><blockquote>
<ol>
<li>중간에 실수 나누기를 사용하면서 <strong>부동소숫점 연산 근사 오차</strong> 발생</li>
<li>이를 <code>int</code>를 붙여서 단순 절사해서 문제였던 것!</li>
<li>그리고 이런식으로 풀면, <code>a==0 or b==0</code> 인경우 <code>ZeroDivisionError</code>가 발생할 수 있다.</li>
</ol>
</blockquote>
<p>이를 고려해서 코드를 고쳤다.</p>
<p>code :</p>
<pre><code class="language-python">a, b, c, d, e, f = map(int, input().split(&#39; &#39;))

y = int((c*d - a*f)/(b*d-a*e))
x = int((c*e-b*f)/(a*e-b*d))

print(x, y)</code></pre>
<p><strong>해설</strong> :</p>
<ul>
<li>중간에 $a$나 $d$로 먼저 나누지 않고 분자와 분모를 모두 정수로 계산. </li>
<li>문제 조건 상 해 $x$, $y$는 무조건 정수이므로 분자 / 분모가 반드시 딱 떨어지는 정수가 되기 때문에 부동소수점 오차 없이 정확히 계산됨.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/kaeul_1/post/058ea739-030a-4f78-b0d8-ae3b71e0157b/image.png" alt=""></p>
<p>통과! 🥳</p>
<hr>
<h2 id="후기">후기</h2>
<p>처음에는 가볍게 접근했다가 머리 끙끙 싸맸다... 
그래도 푸니까 뿌듯!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MongoDB와 colab 연결하기]]></title>
            <link>https://velog.io/@kaeul_1/MongoDB%EC%99%80-colab-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@kaeul_1/MongoDB%EC%99%80-colab-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 29 Mar 2025 16:50:28 GMT</pubDate>
            <description><![CDATA[<ol>
<li>mongodb atlas 들어가기
링크 : <a href="https://www.mongodb.com/ko-kr/lp/cloud/atlas/try4?utm_source=google&amp;utm_campaign=search_gs_pl_evergreen_atlas_core_prosp-brand_gic-null_apac-kr_ps-all_desktop_kor_lead&amp;utm_term=%EB%AA%BD%EA%B3%A0%EB%94%94%EB%B9%84&amp;utm_medium=cpc_paid_search&amp;utm_ad=p&amp;utm_ad_campaign_id=20378068775&amp;adgroup=154980292201&amp;cq_cmp=20378068775&amp;gad_source=1&amp;gclid=Cj0KCQjwhYS_BhD2ARIsAJTMMQaoljP-mRVT1RmnXRrgZ7NbplkMFHODn6FH--wTBVMnH8Onfg5-zPMaAqxQEALw_wcB">mongodb</a>
무료로 시작하기 클릭
<img src="https://velog.velcdn.com/images/kaeul_1/post/0002d846-aa3d-41b4-9e62-ca771ae14367/image.png" alt=""></li>
</ol>
<ol start="2">
<li><p>등록하기
구글 계정으로 등록 클릭
<img src="https://velog.velcdn.com/images/kaeul_1/post/ef9463e7-1711-4abd-9ae1-3076a8138501/image.png" alt=""></p>
</li>
<li><p>atlas 메인 화면 진입 &gt; 중간에 <code>+Create</code> 클릭
<img src="https://velog.velcdn.com/images/kaeul_1/post/bad7eb5b-c13f-4175-9ce1-16209ae51f58/image.png" alt=""></p>
</li>
<li><p>Free 버전 &gt; <code>Create Deployment</code>
<img src="https://velog.velcdn.com/images/kaeul_1/post/387d1273-cf1e-4a5c-95f2-7d8800446ac5/image.png" alt=""></p>
</li>
<li><p>username, password 설정
<img src="https://velog.velcdn.com/images/kaeul_1/post/176fc8e7-1c66-4693-9ca0-b1c467b46b46/image.png" alt=""></p>
</li>
<li><p>drivers &gt; driver : <code>python</code> 선택 &gt; Done.
<img src="https://velog.velcdn.com/images/kaeul_1/post/c3728ce1-ddfe-4da4-9468-9facff4c770b/image.png" alt=""> 
<img src="https://velog.velcdn.com/images/kaeul_1/post/119e0ed6-ff9a-42b0-b2ec-2bff7b307c44/image.png" alt=""></p>
</li>
<li><p>cluster 설정 완료!
<img src="https://velog.velcdn.com/images/kaeul_1/post/1307247c-13ba-4449-b943-d36ad5d2fe14/image.png" alt=""></p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Velog-Highlighter 만들기 (결과 : 실패)]]></title>
            <link>https://velog.io/@kaeul_1/Velog-Highlighter-%EB%A7%8C%EB%93%A4%EA%B8%B0-%EA%B2%B0%EA%B3%BC-%EC%8B%A4%ED%8C%A8</link>
            <guid>https://velog.io/@kaeul_1/Velog-Highlighter-%EB%A7%8C%EB%93%A4%EA%B8%B0-%EA%B2%B0%EA%B3%BC-%EC%8B%A4%ED%8C%A8</guid>
            <pubDate>Tue, 07 Jan 2025 02:54:37 GMT</pubDate>
            <description><![CDATA[<p>안녕하세요! 가을입니다.
이번에 간단한 토이 프로젝트를 진행하면서 있었던 일을 기록하고 싶어서 남깁니당</p>
<p><img src="https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white" alt="GitHub"></p>
<hr>
<h2 id="아이디어">아이디어</h2>
<p>Velog를 처음 쓰는 초보자로써, 다음과 같은 생각이 들었습니다.</p>
<blockquote>
<p>왜 *<em>글자의 색을 바꾸거나, 글자의 배경색을 바꾸기 위한 *</em> 기능이 없는가?</p>
</blockquote>
<p>현재 velog에서 글자 색을 바꾸거나, 글자의 배경색을 바꾸기 위해서는 아래와 같이 입력해야 합니다.</p>
<pre><code class="language-html">&lt;span style=&#39;background-color: #ffdce0; color: red;&#39;&gt;안녕하세요&lt;/span&gt;</code></pre>
<p>-&gt; 결과 : <span style='background-color: #ffdce0; color: red;'>안녕하세요</span></p>
<p>불편~</p>
<p>이번에 경신스(경제신문스크랩)을 진행하면서, 
계속 빨간색과 파란색으로 칠해야하는데 일일이 <code>&lt;span&gt;</code>을 작성하는게 귀찮았다..ㅋㅋ</p>
<p>velog의 깃허브에 요청하자니, 너무 오래 걸릴것 같고..</p>
<p>그래서 내가 생각한 대안은 바로 </p>
<blockquote>
<p>&quot;구글 확장 프로그램으로 velog용 하이라이터 만들기&quot;</p>
</blockquote>
<p>였다.</p>
<hr>
<h2 id="진행">진행</h2>
<ol>
<li>우선 구글 확장 프로그램을 만드는 방법에 대해 공부했다.<ul>
<li>공식페이지 : 맞춤 Chrome 앱 및 확장 프로그램 만들기 및 게시하기
<a href="https://support.google.com/chrome/a/answer/2714278?hl=ko">https://support.google.com/chrome/a/answer/2714278?hl=ko</a></li>
<li>대충 확인해 보니, 간단한 javascript와 html, css로 구성되어 있었다.</li>
</ul>
</li>
<li>구현 방향<ol>
<li>마크다운에 글을 쓰기</li>
<li>원하는 부분에 마우스로 블록처리</li>
<li>확장프로그램 클릭해서 원하는 글자 색, 배경 색 선택</li>
<li>마우스로 블록처리 된 곳 앞 뒤로 <code>&lt;span&gt;</code>태그 붙어서 나오기!</li>
</ol>
</li>
</ol>
<hr>
<h2 id="issue-발생">issue 발생</h2>
<p>간단하게 확장프로그램을 로컬에서 띄우는 것 까지는 성공했다.
UI는 너무 못생겼지만, 우선 기능이 중요하니까..</p>
<p><img src="https://velog.velcdn.com/images/kaeul_1/post/b3efd8b5-a5bd-40d3-97fd-d11513178314/image.gif" alt=""></p>
<ul>
<li>왼쪽에 &#39;블록처리&#39;된 곳에 변하지 않는 모습..🥲</li>
</ul>
<p>이를 해결하기 위해 gpt랑 열심히 토론한 결과.. </p>
<hr>
<h2 id="issue-해결-시도-및-결과">issue 해결 시도 및 결과</h2>
<p>아래는 내가 시도했던 방법과 결과들이다.</p>
<h3 id="✅-방법-1-rangeinsertnode를-사용해-dom-조작">✅ 방법 1: range.insertNode()를 사용해 DOM 조작</h3>
<ul>
<li>내용: 선택된 텍스트 앞뒤로 HTML 태그(<span>)를 직접 삽입.</li>
<li>결과: 콘솔 로그에는 HTML 태그가 정상적으로 표시되었지만, Velog 글쓰기 페이지에서는 적용되지 않음.</li>
<li>문제: React의 가상 DOM과 충돌하여 Velog 에디터가 변경 사항을 감지하지 못함.</li>
</ul>
<h3 id="✅-방법-2-react-이벤트-트리거">✅ 방법 2: React 이벤트 트리거</h3>
<ul>
<li>내용: HTML 태그 삽입 후, input 및 change 이벤트를 트리거하여 React가 변경 사항을 감지하도록 시도.</li>
<li>결과: 콘솔에서는 이벤트 트리거가 성공했다고 표시되었으나, Velog 에디터에 반영되지 않음.</li>
<li>문제: React의 내부 상태가 제대로 업데이트되지 않음.</li>
</ul>
<h3 id="✅-방법-3-codemirror-인스턴스에-직접-접근">✅ 방법 3: CodeMirror 인스턴스에 직접 접근</h3>
<ul>
<li>내용: Velog 에디터가 사용하는 CodeMirror 라이브러리에 접근하여 텍스트를 수정.</li>
<li>결과: .cm-content 요소를 찾지 못해 실패.</li>
<li>문제: Velog 에디터의 DOM 구조가 복잡하여 직접적인 접근이 어려움.</li>
</ul>
<h3 id="✅-방법-4-shadow-dom-접근">✅ 방법 4: Shadow DOM 접근</h3>
<ul>
<li>내용: Velog 글쓰기 페이지에서 textarea의 Shadow DOM에 접근하여 텍스트 삽입 시도.</li>
<li>결과: ShadowRoot를 찾을 수 없음 오류 발생.</li>
<li>문제: Velog 에디터는 Shadow DOM을 사용하지 않음.</li>
</ul>
<h3 id="✅-방법-5-mutationobserver-사용">✅ 방법 5: MutationObserver 사용</h3>
<ul>
<li>내용: MutationObserver를 사용하여 Velog 에디터가 동적으로 렌더링되는 시점을 탐지하고 텍스트 삽입 시도.</li>
<li>결과: MutationObserver로 DOM 변경을 감지했으나, Velog 에디터가 변경 사항을 무시함.</li>
<li>문제: CodeMirror 인스턴스를 찾을 수 없었고, React 상태가 제대로 업데이트되지 않음.</li>
</ul>
<h3 id="✅-방법-6-markdown-상태-직접-조작">✅ 방법 6: Markdown 상태 직접 조작</h3>
<ul>
<li>내용: <strong>.CodeMirror textarea</strong>에 접근하여 Markdown 텍스트를 수정.</li>
<li>결과: 콘솔에는 텍스트가 수정되었으나, Velog 에디터에는 반영되지 않음.</li>
<li>문제: Velog 에디터가 내부 상태를 다시 렌더링하면서 수정 사항을 덮어씀.</li>
</ul>
<h3 id="✅-방법-7-html-엔티티-코드-변환-후-삽입">✅ 방법 7: HTML 엔티티 코드 변환 후 삽입</h3>
<ul>
<li>내용: HTML 태그를 엔티티 코드로 변환하여 삽입.</li>
<li>결과: 콘솔 로그에는 정상적으로 변환된 HTML 태그가 출력되었으나, Velog 글쓰기 페이지에는 적용되지 않음.</li>
<li>문제: Velog 에디터가 HTML 태그를 Markdown 문법으로 처리하지 않음.</li>
</ul>
<h3 id="🔴-요약-모든-방법-실패">🔴 요약: 모든 방법 실패</h3>
<table>
<thead>
<tr>
<th><strong>시도한 방법</strong></th>
<th><strong>결과</strong></th>
<th><strong>문제</strong></th>
</tr>
</thead>
<tbody><tr>
<td><code>range.insertNode()</code> 사용</td>
<td>실패</td>
<td>React 가상 DOM과 충돌</td>
</tr>
<tr>
<td>React 이벤트 트리거</td>
<td>실패</td>
<td>React 상태 업데이트 불가</td>
</tr>
<tr>
<td>CodeMirror 인스턴스 접근</td>
<td>실패</td>
<td><code>.cm-content</code>를 찾을 수 없음</td>
</tr>
<tr>
<td>Shadow DOM 접근</td>
<td>실패</td>
<td>ShadowRoot가 없음</td>
</tr>
<tr>
<td>MutationObserver 사용</td>
<td>실패</td>
<td>Velog 에디터가 변경 사항 무시</td>
</tr>
<tr>
<td>Markdown 상태 직접 조작</td>
<td>실패</td>
<td>에디터 내부 상태 덮어쓰기 발생</td>
</tr>
<tr>
<td>HTML 엔티티 코드 변환 후 삽입</td>
<td>실패</td>
<td>HTML 태그를 엔티티로 변환</td>
</tr>
<tr>
<td></br></td>
<td></td>
<td></td>
</tr>
</tbody></table>
<h3 id="결론">결론</h3>
<p>결국 해결하지 못했다!
으아아
12시에 착수하여 새벽 4시 30분에 겨우 멈췄다...😭😭😭
우선은 해당프로젝트는 킵해놓고, 다음에 시간나면 다시 가동하는걸로...ㅠㅠ</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[LG Aimers 6기 시작]]></title>
            <link>https://velog.io/@kaeul_1/LG-Aimers-6%EA%B8%B0-%EC%8B%9C%EC%9E%91</link>
            <guid>https://velog.io/@kaeul_1/LG-Aimers-6%EA%B8%B0-%EC%8B%9C%EC%9E%91</guid>
            <pubDate>Tue, 07 Jan 2025 01:49:52 GMT</pubDate>
            <description><![CDATA[<p>참여하기 전에 썼어야 했는데..ㅋㅋ
정신이 없어서 뒤늦게 쓰는 LG Aimers 6기 참여 과정.</p>
<p>우선, 친구를 통해 <a href="https://www.lgaimers.ai/">LG Aimers</a>에 대해 알게됐음.</p>
<h3 id="lg-aimers란">LG Aimers란?</h3>
<p>LG AI 연구원, DACON, 한경닷컴, 대한상공회의소, kef 한국경영자총협회, 고용노동부가 함께하는 <strong>온라인 학습 + 해커톤</strong>이다. </p>
<p>다른 곳에 비해 장점은, 해커톤에서 <strong>실제 LG가 가지고 있는 데이터를 이용할 수 있다</strong>는 점!</p>
<h3 id="프로그램-일정">프로그램 일정</h3>
<p><img src="https://velog.velcdn.com/images/kaeul_1/post/6fddfb4e-58d4-4e8b-9b38-453c9477bf02/image.png" alt=""></p>
<p>우선 한 달 동안 온라인 교육을 받은 뒤, 다음 한 달 동안 해커톤에 도전한다. 
여기서 해커톤 상위 팀만 다음 오프라인 해커톤에 참가할 자격을 얻게 된다.</p>
<p>오프라인 해커톤은 보통 온라인 해커톤에서 데이터를 추가로 공개하고, 모델을 고도화하는 작업을 진행하는 것 같다.</p>
<h3 id="신청방법">신청방법</h3>
<p>신청방법은 다른 곳과 다르게 정말로 간단한 개인정보만을 입력하면된다. 이력서같은것두 필요없음.
(여기서 신청방법이 너무 간단해서 깜짝놀람)</p>
<h3 id="다짐">다짐</h3>
<p>온라인학습으로 공부 재활좀 하고, 해커톤에서 상위팀에 들어보자!
아자자자자자!!!</p>
<img src="https://velog.velcdn.com/images/kaeul_1/post/18f1bc87-281d-4ecd-bf89-8cc12ed48138/image.png" width="50%" display="block" margin="auto">

]]></description>
        </item>
        <item>
            <title><![CDATA[Module 2 : Machine Learning 개론 Part 1.]]></title>
            <link>https://velog.io/@kaeul_1/Module-2-Machine-Learning-%EA%B0%9C%EB%A1%A0-Part-1</link>
            <guid>https://velog.io/@kaeul_1/Module-2-Machine-Learning-%EA%B0%9C%EB%A1%A0-Part-1</guid>
            <pubDate>Mon, 06 Jan 2025 08:53:09 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>LG Ai</strong>mers 6기 수강중.
서울대학교 컴퓨터공학부 김건희 교수님 강의를 들으며 정리한 글입니다.</p>
</blockquote>
<h1 id="part-1-introduction-to-machine-learning">Part 1. Introduction to Machine Learning</h1>
<hr>
<h2 id="machine-learningml">Machine Learning(ML)</h2>
<ul>
<li>범위 : Artificial Intelligence(AI) &gt; Machine Learning(ML) &gt; Deep Learning(DL)<ul>
<li>DL : 기계학습 중 신경망, 신경망 중에 아주 layer가 많은 특별한 분야.</li>
<li>ML 정의<ul>
<li>Herbert Simon : 경험을 통해서 그 성능을 높이는 시스템에 의한 모든 프로세스 = 학습(Learning)</li>
<li>Arthur Samuel : 직접적으로 프로그래밍하지 않고, 컴퓨터가 스스로 배울 수 있는 능력을 다루는 학문</li>
<li>Tom Mitchell : T에 대해서 E를 기반으로해서 P를 개선하는 것.<ul>
<li>T : Task ex) classification, regression, detection ...</li>
<li>P : Performance Measure ex) error rate, accuracy, likelihood, margin ...</li>
<li>E : Experience ex) data</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="generalization">Generalization</h2>
<ul>
<li>ML의 목표 : generalization(일반화) -&gt; 모든 경우에 대응하고 싶다.</li>
<li>generalization 정의 :<ul>
<li>수많은 예제 중 공통적 특징을 파악해서 보편적인 주장이나 개념으로 추상화하는 것.</li>
</ul>
</li>
</ul>
<hr>
<h2 id="no-free-lunch-theorem-for-ml">No Free Lunch Theorem for ML</h2>
<ul>
<li>어떤 기계학습 알고리즘도, 다른 기계학습 알고리즘보다 항상 좋다고는 할 수 없다.<ul>
<li>옆팀에서 해당 모델이 잘 먹힌다고해서, 내 데이터세트에 잘 먹힌다는 보장 X</li>
</ul>
</li>
<li>새로운 테스크, 새로운 데이터를 이용할 때 마다 최적의 알고리즘을 찾아야 한다.</li>
</ul>
<hr>
<h2 id="types-of-learning">Types of Learning</h2>
<h3 id="supervised-learning감독학습-지도학습">Supervised learning(감독학습, 지도학습)</h3>
<ul>
<li>Input에 대한 Output(정답)을 쌍으로 명시적으로 가르쳐줌.</li>
<li>대표적인 Task : classification, regression</li>
</ul>
<h3 id="unsupervised-learning비감독학습-비지도-학습">Unsupervised learning(비감독학습, 비지도 학습)</h3>
<ul>
<li>학습데이터가 x(input)만 있음.</li>
<li>대표적인 Task : Clustering, Anomaly Detection, Density Estimation</li>
</ul>
<h3 id="semi-supervised-learning">Semi-supervised learning</h3>
<ul>
<li>몇몇 학습데이터는 x,y줌. 몇몇은 x만. (몇몇개만 labeling하는거)</li>
<li>2개의 시나리오<ul>
<li>LU learning : 몇몇 x,y, 몇몇 x</li>
<li>PU learning : One-class Classification(특정 class에 대해서만 label 준 경우)</li>
</ul>
</li>
<li>semi-supervised learning이 도움이 되는 경우<ul>
<li>unlabeled data : label있는 데이터를 기반으로 soft한 label을 얻는다.</li>
<li>-&gt; 더 섬세한 decision boundary를 얻는다. (정확도 up!)</li>
</ul>
</li>
</ul>
<h3 id="reinforcement-learning강화학습">Reinforcement learning(강화학습)</h3>
<ul>
<li>모델에게 사전에 주어지는 것 : Dataset X, 환경 O</li>
<li>모델(agent)가 환경(state)과 interaction하면서 학습하는 과정.</li>
<li>agent 학습 과정 :
state주어짐 -&gt; action 취함 -&gt; environment가 얼마나 좋은 action이었는지 reward 줌</li>
<li>but. 많은 경우에는 state 주어짐-&gt;action 취함 -&gt; state약간 변함 -&gt; action 취함 이럼(reward가 매우 딜레이가 됨). <ul>
<li>그래서 매우 어려운 학습 방법 (시간, 난이도 훨씬 높다.)</li>
</ul>
</li>
</ul>
<hr>
<h2 id="references">References</h2>
<p>교수님이 추천하는 machine learning 책</p>
<ol>
<li>처음 공부하는 사람<ul>
<li>An Introduction to Statistical Learning<ul>
<li>(Python 버전도 있음)</li>
</ul>
</li>
<li>가볍게 시작하는 통계학습 - R로 실습하는</li>
</ul>
</li>
<li>좀 아는 사람 (사진이 너무 조만해서 잘 안보여요..ㅠㅠ)<ul>
<li>The Elements of Statistical Learning</li>
<li>Machine Learning</li>
<li>Information Theory, Inference, and Learning Algorithms.</li>
<li>Convex Optimization</li>
</ul>
</li>
</ol>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[Module 1 : AI 윤리 Part 3.]]></title>
            <link>https://velog.io/@kaeul_1/Module-1-AI-%EC%9C%A4%EB%A6%AC-Part-3</link>
            <guid>https://velog.io/@kaeul_1/Module-1-AI-%EC%9C%A4%EB%A6%AC-Part-3</guid>
            <pubDate>Sat, 04 Jan 2025 14:19:52 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>LG Ai</strong>mers 6기 수강중.
KAIST 전산학부 차미영 교수님 강의를 들으며 정리한 글입니다.</p>
</blockquote>
<h2 id="part-3-세계적인-데이터-과학자가-되는-방법">Part 3. 세계적인 데이터 과학자가 되는 방법</h2>
<hr>
<h3 id="becoming-a-world-class-data-scientist">Becoming a world-class data scientist</h3>
<ul>
<li>항상 데이터에 대해 <code>호기심</code>을 가져야한다.</li>
<li>이종(heterogeneous) 데이터의 결합은 혁신을 가져옴. <ul>
<li>서울시의 야간버스노선 개선 </li>
</ul>
</li>
<li><blockquote>
<p>통신사와 협업. </p>
</blockquote>
</li>
<li><blockquote>
<p>새로운 노선을 고객들이 많이 이용할지 위치정보로 확인.</p>
</blockquote>
<ul>
<li>각자의 페북 네트워크로 커플 이별 예측</li>
<li>위성영상 딥러닝 분석으로 빈곤지역 예측 및 녹지 계산</li>
</ul>
</li>
<li>세계적인 데이터 과학자는 어떻게 일할까?<ul>
<li>실리콘밸리에서 배운 Tip<ul>
<li>진정한 과학자가 되려면 과학자에 대한 환상을 접고, 
데이터에 푹 빠져서 매일 꾸준히 조금씩 성과를 내는 데일리 루틴이 비결.</li>
<li>변화가 곧 생존이다.</li>
<li>페북스타일 목표 정하는 법<ul>
<li>50%만 달성 가능성이 있는 목표 세우기. -&gt; 이러면 50%보다 더 많이 하게되니까 빠르게 성장할 수 있음.</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[Module 1 : AI 윤리 Part 2.]]></title>
            <link>https://velog.io/@kaeul_1/Module-1-AI-%EC%9C%A4%EB%A6%AC-Part-2</link>
            <guid>https://velog.io/@kaeul_1/Module-1-AI-%EC%9C%A4%EB%A6%AC-Part-2</guid>
            <pubDate>Sat, 04 Jan 2025 11:58:10 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>LG Ai</strong>mers 6기 수강중.
KAIST 전산학부 차미영 교수님 강의를 들으며 정리한 글입니다.</p>
</blockquote>
<h2 id="part-2-ai-ethics">Part 2. AI Ethics</h2>
<hr>
<h3 id="ai-and-creativity">AI and Creativity</h3>
<ul>
<li>다양한 분야에서 AI가 창작을 하고 있음</li>
</ul>
<hr>
<h3 id="ai-art-in-action">AI Art in Action</h3>
<ul>
<li>인공지능이 그리고, 3D 프린터로 뽑아 액자에 담아 고액에 판매<ul>
<li>AI 예술 작품은 학습데이터 기반인데, 창작성(originality)이 있는가?</li>
<li>저작권은 누구에게로? : 학습데이터vs프로그래머vs기획자<ul>
<li>여기서는 학습데이터, 무료로 알고리즘을 공개한 프로그래머에게 한푼도 안감</li>
<li>그럼 나중에는 누구에게 저작권을 줘야하는가?</li>
</ul>
</li>
</ul>
</li>
<li>NFT(Non-Fungible Token, 대체 불가능한 토큰)의 시대<ul>
<li>: 블록체인 기술을 적용한 디지털 토큰<ul>
<li>출처 : <a href="https://www.eventx.io/ko/blog/nft-%EB%9C%BB">https://www.eventx.io/ko/blog/nft-%EB%9C%BB</a></li>
</ul>
</li>
<li>NFT 유행으로 인해 더욱 비싼 가격으로 AI 작품들 거래중.<ul>
<li>최초 시민권을 받은 로봇인 소피아가 그린 그림도 고액에 판매됨.</li>
</ul>
</li>
<li>누구나 쉽게 저작권도 없는 작품을 만들 수 있어서 문제</li>
</ul>
</li>
</ul>
<hr>
<h3 id="copyright-issues">Copyright issues</h3>
<ul>
<li>학습에 사용된 데이터와 관련된 issue<ul>
<li>해당 데이터가 학습에 얼만큼 기여를 했는가?</li>
<li>데이터의 원 제작자가 누구인가? </li>
</ul>
</li>
<li>AI를 창작자로 볼 수 있는 법적 제도 없음.<ul>
<li>사람만 창작자로 볼 수 있다고 규정되어있음.</li>
</ul>
</li>
<li>현존하는 예술가의 스타일을 따라한 예술 작품을 만들 경우 상업적 피해를 준다.</li>
<li>창작된 작품이 인간의 윤리적 규범을 따르지 않을 수 있다.<ul>
<li>ex) 폭력, 차별 유발</li>
</ul>
</li>
<li>법인 : 법적 권리를 가지는 주체<ul>
<li>꼭 사람일 필요 X (정부, NGO, 자연, 회사 등 가능) -&gt; 하지만 AI는 X</li>
<li>인공지능을 법인으로 인정하자(EU, 2017년) -&gt; 찬성vs반대 논란!</li>
<li>동물의 저작권<ul>
<li>원숭이가 찍은 셀피<ul>
<li>법적 다툼 결과 : 여기서 사람이 찍은거라 카메라 주인이 저작권을 인정할 수 없음, 
그리고 원숭이는 사람이 아니므로 원숭이에게 저작권을 인정해줄수 없음.</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="ai-contriguted-harm">AI contriguted harm</h3>
<ul>
<li>아시모프의 로봇 3원칙<ol>
<li>로봇은 인간을 다치게 해선 안되며, 인간이 해를 입는 걸 방관해서도 안된다.</li>
<li>법칙 1에 위배되지 않는 한 로봇은 인간의 명령에 복종한다.</li>
<li>법칙 1과 2에 위배되지 않는 한 로봇은 스스로를 보호해야 한다.</li>
</ol>
</li>
<li><blockquote>
<p>언제나 예외 상황이 있기 때문에, 어떤 원칙도 로봇에게 안정적으로 부여 X</p>
</blockquote>
</li>
<li>자율주행 uber로 사고 발생. 보행자 사망<ul>
<li>운전자 : 앞 안보고 모니터 보고있었음.</li>
<li>보행자 : 야밤에 무단횡단 자전거 끌고가기 -&gt; 학습 데이터에 없는 상황</li>
<li>해당사건에 우버는 형사적 책임X 판결남.(2018년)</li>
</ul>
</li>
<li>The Moral Machine experiment(MIT) : 트롤리 문제 다룸.<ul>
<li>게임을 통해 230개국 수만명 대상으로 데이터 수집함.</li>
</ul>
</li>
<li><blockquote>
<p>문제는 AI 개발 과정에서 이러한 논의 없이, 이미 상용화 되는 서비스들이 존재한다는 점.</p>
</blockquote>
</li>
</ul>
<hr>
<h3 id="summary">summary</h3>
<ul>
<li>인간의 창조적 활동 영역으로 들어온 인공지능</li>
<li>AI 시대 지식재산, 법인격, 처벌 그리고 윤리의 문제 부각</li>
</ul>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[Module 1 : AI 윤리 Part 1.]]></title>
            <link>https://velog.io/@kaeul_1/Module-1-AI-%EC%9C%A4%EB%A6%AC</link>
            <guid>https://velog.io/@kaeul_1/Module-1-AI-%EC%9C%A4%EB%A6%AC</guid>
            <pubDate>Sat, 04 Jan 2025 08:53:30 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>LG Ai</strong>mers 6기 수강중.
KAIST 전산학부 차미영 교수님 강의를 들으며 정리한 글입니다.</p>
</blockquote>
<h2 id="part-1-데이터-분석과-ai학습에서-유의할-점">Part 1. 데이터 분석과 AI학습에서 유의할 점</h2>
<hr>
<h3 id="데이터를-잘-해석하고-있는가">데이터를 잘 해석하고 있는가?</h3>
<ul>
<li>상관관계와 인과관계는 다르다.</li>
<li>ex) A와 B가 서로 정비례하게 나올수 있음. <pre><code>하지만 A(B)가 많으면 무조건 B(A)라는 건 아님</code></pre></li>
</ul>
<hr>
<h3 id="데이터-전처리와-분석방법은-적절한가">데이터 전처리와 분석방법은 적절한가?</h3>
<ul>
<li>error bar 사용하기</li>
<li>적합한 통계 테스트 찾기</li>
<li>아웃라이어 제거하기</li>
<li>데이터 정규화</li>
<li>EDA(Exploratory Data Analysis) <ul>
<li>정의 : 수집한 데이터가 들어왔을 때, 이를 다양한 각도에서 관찰하고 이해하는 과정<ul>
<li>출처 : <a href="https://eda-ai-lab.tistory.com/13">https://eda-ai-lab.tistory.com/13</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="학습에-쓰는-데이터가-충분한가">학습에 쓰는 데이터가 충분한가?</h3>
<ul>
<li>Appropirate-fitting인가? (Under-fitting, Over-fitting X)</li>
<li>training, test 데이터는 달라야한다.</li>
</ul>
<hr>
<h3 id="black-box-algorithm">Black Box Algorithm</h3>
<ul>
<li>성능만 중요함 X, <code>설명력</code>도 높아야한다.<ul>
<li>사후 설명력(post-hoc explainablility) <ul>
<li>ex) Grad-CAM</li>
<li>One pixel attack : 픽셀 하나만 바뀌었는데 결과가 달라짐. -&gt; 모델이 얼마나 <code>민감</code>한지 고려해야함.</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="handling-the-web-data">Handling the Web Data</h3>
<ul>
<li>Spiral of silence<ul>
<li>: 한명이 큰소리로 극단적의견냄 &gt; 내 의견은 반대지만 다수가 아닌가보다 &gt; 조용히함 &gt; 큰소리낸 한명이 더 부각됨 
  =&gt;  편향현상</li>
<li>인터넷 상의 의견이 <code>대표성</code> 있는 의견이 아닐 수 있다.</li>
<li>소셜 링크를 통한 빠른 정보 전파, 봇의 참여, 극단화 현상 주의</li>
</ul>
</li>
<li>Infodemic(인포데믹) : <code>사실정보</code>와 더불어 오정보의 양이 늘어서, 어떤게 사실인지 구분이 어려워지는 정보 과부화 현상</li>
<li>데이터 사용과 서비스 개발에 사용자 어려움을 반영해야된다.<ul>
<li>잊혀질 권리 -&gt; 정보가 자동 복제되니까 삭제는 힘들지만, 검색은 안되는식으로 권리를 보장할 수 있음.</li>
</ul>
</li>
</ul>
<hr>
<h3 id="윤리에-대한-법적-제도">윤리에 대한 법적 제도</h3>
<ul>
<li>GDPR (EU)<ul>
<li>정의 : 개인정보 보호, 과다광고에 노출 혹은 혐오 표현 규제하는 플랫폼 단속 법</li>
<li>EU에 있는 제도, 하지만 인터넷으로 연결되니 우리도 알아야함.</li>
</ul>
</li>
<li>Digital Services Act (EU)<ul>
<li>네티즌의 성별, 인종, 종교 등에 기반한 알고리즘으로 개인화 추천 광고를 노출하지 않음</li>
<li>어린이 대상 개인화 추천 광고는 전면 금지</li>
<li>디지털서비스 사업자는 혐오 발언, 아동 학대, 테러 선동 등 불법 콘텐츠 유통도 막아야함.</li>
</ul>
</li>
</ul>
<hr>
<h3 id="ai-and-ethical-decisions">AI and Ethical Decisions</h3>
<ul>
<li>COMPAS(Correctional Offender Management Profiling for Alternative Sanctions) (미국 법)<ul>
<li>피고의 미래 범죄 위험을 점수로 예측하는 Software Tool -&gt; 판사가 결정내릴 때 참고하는 점수</li>
<li>2017년 기준 미국 12개(캘리포니아 주, 뉴욕주, 워싱턴 ...) 기타권할권 법원에서 사용 중<ul>
<li>인종차별적 예측해버림...</li>
</ul>
</li>
</ul>
</li>
<li>아마존 -&gt; AI 기반 채용시스템 -&gt; 기존 직원들 남성 대다수 -&gt; 성차별적 예측.. -&gt; 폐기!</li>
</ul>
<hr>
<h3 id="summary">summary</h3>
<ul>
<li>데이터의 확보, 전처리, 분석, 해석의 전 과정이 중요</li>
<li>알고리즘의 설명력, 편향, 신뢰의 문제에 주의</li>
</ul>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[velog 꿀팁]]></title>
            <link>https://velog.io/@kaeul_1/velog-%EA%BF%80%ED%8C%81</link>
            <guid>https://velog.io/@kaeul_1/velog-%EA%BF%80%ED%8C%81</guid>
            <pubDate>Mon, 23 Dec 2024 16:37:00 GMT</pubDate>
            <description><![CDATA[<p>내가 보려고 만든 꿀팁</p>
<h3 id="글씨-변형-하이라이트">글씨 변형 (하이라이트)</h3>
<p>: <a href="https://velog.io/@euisuk-chung/%EA%BF%80%ED%8C%81-Velog-%EA%B8%80%EC%94%A8%EB%A5%BC-%EB%82%B4-%EB%A7%88%EC%9D%8C%EB%8C%80%EB%A1%9C-%EC%83%89%EC%83%81-%ED%98%95%EA%B4%91%ED%8E%9C">https://velog.io/@euisuk-chung/꿀팁-Velog-글씨를-내-마음대로-색상-형광펜</a></p>
<ul>
<li>여기서 내가 많이쓸것들:<ul>
<li><span style='background-color: #ffdce0; color: red;'>안녕하세요</span>: 
<code>&lt;span style=&#39;background-color: #ffdce0; color: red;&#39;&gt;안녕하세요&lt;/span&gt;</code><ul>
<li><span style='background-color: #d1ebf9; color: blue;'>안녕하세요</span>: 
<code>&lt;span style=&#39;background-color: #d1ebf9; color: blue;&#39;&gt;안녕하세요&lt;/span&gt;</code></li>
<li><span style='background-color: #f5f0ff; color: purple;'>안녕하세요</span>: 
<code>&lt;span style=&#39;background-color: #f5f0ff; color: purple;&#39;&gt;안녕하세요&lt;/span&gt;</code></li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[✍️Hello, world!]]></title>
            <link>https://velog.io/@kaeul_1/Hello-world</link>
            <guid>https://velog.io/@kaeul_1/Hello-world</guid>
            <pubDate>Mon, 23 Dec 2024 16:27:38 GMT</pubDate>
            <description><![CDATA[<h3 id="자기소개">자기소개</h3>
<p>안녕하세요. 가을입니다!</p>
<p>간단히 제 소개를 하자면,
컴퓨터과학전공으로 석사학위를 가지고 있습니다.
머신러닝의 전반적인 분야에 대해 관심이 있으나, 
특별히 꼽자면 관심분야는 <strong>MultiModal</strong>과 <strong>Computer Vision</strong>입니다.</p>
<h3 id="향후-계획">향후 계획</h3>
<p>앞으로 이 블로그에 </p>
<ul>
<li>머신러닝과 관련된 논문을 리뷰하거나</li>
<li>토이 프로젝트에 대한 진행상황</li>
<li>부트캠프나 스터디모임과 관련된 내용</li>
</ul>
<p>을 공유하려고 합니다. 
히히✌️
<img src="https://velog.velcdn.com/images/kaeul_1/post/3be5b432-1fbe-4574-b100-382c9a1e6ef5/image.png" width="50%"></p>
]]></description>
        </item>
    </channel>
</rss>