<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>In Hyuk Portfolio Homepage |</title><link>https://inhyuk2000.github.io/</link><atom:link href="https://inhyuk2000.github.io/index.xml" rel="self" type="application/rss+xml"/><description>In Hyuk Portfolio Homepage</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Wed, 02 Sep 2026 00:00:00 +0900</lastBuildDate><image><url>https://inhyuk2000.github.io/media/icon_hu_eee4a95885829ab2.png</url><title>In Hyuk Portfolio Homepage</title><link>https://inhyuk2000.github.io/</link></image><item><title>CS 지식의 정석</title><link>https://inhyuk2000.github.io/blog/study/cs-%EC%A7%80%EC%8B%9D%EC%9D%98-%EC%A0%95%EC%84%9D/</link><pubDate>Wed, 02 Sep 2026 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/blog/study/cs-%EC%A7%80%EC%8B%9D%EC%9D%98-%EC%A0%95%EC%84%9D/</guid><description>
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-blue-100 dark:bg-blue-900 border-blue-500"
data-callout="note"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-blue-600 dark:text-blue-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m16.862 4.487l1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8l.8-2.685a4.5 4.5 0 0 1 1.13-1.897zm0 0L19.5 7.125"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;CS 강의는 &lt;code&gt;네트워크&lt;/code&gt; - &lt;code&gt;자료구조&lt;/code&gt; - &lt;code&gt;운영체제&lt;/code&gt; - &lt;code&gt;데이터베이스&lt;/code&gt; - &lt;code&gt;개발자 필수지식&lt;/code&gt; 순으로 공부하자.&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-red-100 dark:bg-red-900 border-red-500"
data-callout="caution"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-red-600 dark:text-red-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0zM12 15.75h.007v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;강의 내용을 전부 필기하기 보다는, &lt;code&gt;AI Engineer&lt;/code&gt; 직군에 필요한 질문들 위주로 정리하자.&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="네트워크"&gt;네트워크&lt;/h3&gt;
&lt;h4 id="q1-네트워크에-대해-아는-것이-있나요"&gt;Q1. 네트워크에 대해 아는 것이 있나요?&lt;/h4&gt;
&lt;p&gt;네트워크에서는 TCP/IP 기반 통신과 HTTP 통신에 대한 기본적인 내용을 알고 있습니다. TCP와 UDP는 전송 계층 프로토콜입니다. TCP는 연결 지향 방식으로 데이터의 순서와 전달을 보장하기 위해 &lt;code&gt;Sequence Number&lt;/code&gt;, &lt;code&gt;ACK&lt;/code&gt;, &lt;code&gt;재전송&lt;/code&gt; 같은 매커니즘을 사용합니다. 반면에 UDP는 비연결형으로 전달이나 순서를 보장하지 않는 대신 오버헤드가 작다는 특징이 있습니다.
애플리케이션 계층에서는 &lt;code&gt;HTTP&lt;/code&gt;/&lt;code&gt;HTTPS&lt;/code&gt;가 있고, 프로젝트에서 &lt;code&gt;REST API&lt;/code&gt;를 구현하면서 클라이언트와 서버 간 &lt;code&gt;Request&lt;/code&gt;/&lt;code&gt;Response&lt;/code&gt; 방식으로 통신하는 경험을 했습니다.&lt;/p&gt;
&lt;h4 id="q2-osi-7-layer에-대해서는-아시나요"&gt;Q2. `OSI 7 Layer에 대해서는 아시나요?&lt;/h4&gt;
&lt;p&gt;네. &lt;code&gt;OSI 7 Layer&lt;/code&gt;는 네트워크 통신 과정을 7개의 계층으로 나눈 모델입니다. 아래부터 &lt;code&gt;Physical&lt;/code&gt;, &lt;code&gt;DataLink&lt;/code&gt;, &lt;code&gt;Network&lt;/code&gt;, &lt;code&gt;Transport&lt;/code&gt;, &lt;code&gt;Session&lt;/code&gt;, &lt;code&gt;Presentation&lt;/code&gt;, &lt;code&gt;Application&lt;/code&gt; 계층으로 구성됩니다. 대표적으로 &lt;code&gt;Network&lt;/code&gt; 계층인 3계층에서는 &lt;code&gt;IP&lt;/code&gt;를 통해 목적지까지 데이터를 전달하고, &lt;code&gt;Transport&lt;/code&gt; 계층인 4계층에서는 &lt;code&gt;TCP&lt;/code&gt;와 &lt;code&gt;UDP&lt;/code&gt;를 통해 프로세스 간 데이터 전송을 담당합니다. &lt;code&gt;Application&lt;/code&gt; 계층인 7계층에는 &lt;code&gt;HTTP&lt;/code&gt;나 &lt;code&gt;DNS&lt;/code&gt;처럼 애플리케이션에서 사용하는 프로토콜이 있습니다.&lt;/p&gt;
&lt;h4 id="q3-자료구조나-알고리즘에-대해-아는-것이-있나요"&gt;Q3. 자료구조나 알고리즘에 대해 아는 것이 있나요?&lt;/h4&gt;
&lt;p&gt;네. 자료구조는 데이터를 효율적으로 저장하고 접근하기 위한 구조로 알고 있습니다. 대표적으로 &lt;code&gt;Array&lt;/code&gt;, &lt;code&gt;Linked List&lt;/code&gt;, &lt;code&gt;Stack&lt;/code&gt;, &lt;code&gt;Queue&lt;/code&gt;, &lt;code&gt;Hash Table&lt;/code&gt;, &lt;code&gt;Tree&lt;/code&gt;, &lt;code&gt;Graph&lt;/code&gt; 등이 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Python&lt;/code&gt;에서는 &lt;code&gt;List&lt;/code&gt;와 &lt;code&gt;Dictionary&lt;/code&gt;를 많이 사용했습니다. &lt;code&gt;List&lt;/code&gt;는 동적 배열 기반이라 인덱스를 이용한 조회는 &lt;code&gt;O(1)&lt;/code&gt; 이지만, 중간에 데이터를 삽입하거나 삭제하는 경우는 &lt;code&gt;O(n)&lt;/code&gt; 이 걸릴 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Dictionary&lt;/code&gt;는 &lt;code&gt;Hash Table&lt;/code&gt; 기반의 &lt;code&gt;Key-Value&lt;/code&gt; 자료구조이고, 일반적으로 조회, 삽입, 삭제가 평균 &lt;code&gt;O(1)&lt;/code&gt; 입니다.&lt;/p&gt;
&lt;p&gt;알고리즘에서는 정렬, 탐색, &lt;code&gt;BFS&lt;/code&gt;/&lt;code&gt;DFS&lt;/code&gt; 등을 알고 있으며, 문제에 맞는 알고리즘을 선택할 때는 데이터의 특성과 크기, 시간복잡도와 공간복잡도를 고려합니다.&lt;/p&gt;
&lt;h4 id="q4-어떤-알고리즘을-사용하는-것이-더-좋은지-어떻게-판단하나요"&gt;Q4. 어떤 알고리즘을 사용하는 것이 더 좋은지 어떻게 판단하나요?&lt;/h4&gt;
&lt;p&gt;알고리즘을 선택할 때는 먼저 입력 데이터의 크기와 특성을 확인하고, &lt;code&gt;Big-O&lt;/code&gt; 표기법을 통해 시간복잡도와 공간복잡도를 비교합니다.&lt;/p&gt;
&lt;p&gt;예를 들어 데이터가 많다면 &lt;code&gt;O(n^2)&lt;/code&gt; 알고리즘보다 &lt;code&gt;O(nlogn)&lt;/code&gt; 알고리즘이 일반적으로 확장성 측면에서 유리합니다.&lt;/p&gt;
&lt;p&gt;다만 &lt;code&gt;Big-O&lt;/code&gt;가 더 좋다고 해서 항상 최적의 알고리즘인 것은 아니기 때문에, 실제 데이터의 크기나 메모리 사용량, 평균 및 최악의 시간복잡도, 구현 복잡도 등을 함께 고려해서 선택합니다.&lt;/p&gt;</description></item><item><title>최종 버전 확정 및 초안 배포</title><link>https://inhyuk2000.github.io/blog/notillm/%EA%B0%9C%EB%B0%9C_0821/</link><pubDate>Fri, 21 Aug 2026 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/blog/notillm/%EA%B0%9C%EB%B0%9C_0821/</guid><description>&lt;h2 id="version-03-architecture"&gt;Version 03 Architecture&lt;/h2&gt;
&lt;div class="mermaid"&gt;flowchart TD
START([사용자 입력&lt;br/&gt;prompt + pending + pendingOriginal&lt;br/&gt;+ installedApps]) --&gt; P{pending=true&lt;br/&gt;AND pendingOriginal?}
P --&gt;|Yes| PR[Pending Resolver&lt;br/&gt;gpt-4o-mini&lt;br/&gt;LangChain]
P --&gt;|No| IC[Intent Classifier&lt;br/&gt;ST + LogisticRegression&lt;br/&gt;또는 heuristic&lt;br/&gt;LLM 없음]
PR --&gt; A{5액션}
A --&gt;|CANCEL| C1([END&lt;br/&gt;ok=false&lt;br/&gt;failReason=cancelled&lt;br/&gt;needsSupplement=false])
A --&gt;|UNRESOLVED| C2([END&lt;br/&gt;ok=false&lt;br/&gt;needsSupplement=true&lt;br/&gt;pending 유지])
A --&gt;|CONTINUE / UPDATE| M[이전 명령 + 이번 입력&lt;br/&gt;merge prompt]
A --&gt;|NEW_REQUEST| N[이번 prompt만]
IC --&gt;|reject&lt;br/&gt;잡담| R([END&lt;br/&gt;ok=false&lt;br/&gt;failReason=chitchat&lt;br/&gt;dialogIntent=reject&lt;br/&gt;LLM 0회])
IC --&gt;|extract| E
M --&gt; E[LLM Extractor&lt;br/&gt;gpt-4o&lt;br/&gt;function calling]
N --&gt; E
E --&gt; V[Rule Validator&lt;br/&gt;코드]
V --&gt;|incomplete| ASK([END&lt;br/&gt;ok=false&lt;br/&gt;needsSupplement=true&lt;br/&gt;재질문 / pending])
V --&gt;|complete| MAP[App Mapper&lt;br/&gt;embedding cosine&lt;br/&gt;name → packageName]
MAP --&gt;|미매칭| U([END&lt;br/&gt;ok=false&lt;br/&gt;app_unresolved])
MAP --&gt;|성공| OK([END&lt;br/&gt;ok=true&lt;br/&gt;규칙 저장])
&lt;/div&gt;
&lt;h3 id="docker"&gt;Docker&lt;/h3&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;앱 + 라이브러리 + 실행 방법을 상자에 넣어, 어디든 같은 방식으로 돌리게 하는 도구임.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;현재 V3는 &lt;code&gt;sentence-transformers&lt;/code&gt;와 같은 것들로 인해 &lt;span class="high-mark"&gt;&lt;strong&gt;의존성이 무거워&lt;/strong&gt;&lt;/span&gt;
, EC2에 수동 pip보다는 &lt;strong&gt;Docker로 묶는 것&lt;/strong&gt;이 좋다고 결정함.&lt;/p&gt;
&lt;p&gt;우선 &lt;code&gt;Docker&lt;/code&gt; + &lt;code&gt;AWS ECR&lt;/code&gt; + &lt;code&gt;App Runner&lt;/code&gt;를 활용해서, 1차적으로 배포를 먼저 진행함.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이후 &lt;strong&gt;부하 테스트&lt;/strong&gt; 진행 후, 수정 사항 반영 후 재배포할 예정임.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="aws-app-runner-운영-종료-이슈"&gt;AWS App Runner 운영 종료 이슈&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;이로 인해, &lt;strong&gt;Amazon Elastic Container Service로 배포&lt;/strong&gt;를 진행함. (Tokyo)&lt;/li&gt;
&lt;li&gt;배포 이후, &lt;code&gt;/health&lt;/code&gt; 확인 완료&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ok&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;promptEngine&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;v3&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="중간-점검"&gt;중간 점검&lt;/h2&gt;
&lt;h3 id="notillm-관련"&gt;NotiLLM 관련&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;전체 소스코드에 주석 남기면서 과정을 하나하나 다시 뜯어보는 과정&lt;/strong&gt;이 필요함&lt;/li&gt;
&lt;li&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;부하 테스트&lt;/strong&gt;&lt;/span&gt;
반드시 진행할 것.&lt;/li&gt;
&lt;li&gt;아직, &lt;strong&gt;눈에 띄는 인사이트를 기반으로 한 발전 과정이 안보임&lt;/strong&gt;. 너무 뻔하고 흔한 과정들로 발전시킨 것 같아, 해당 과정에 대한 고민도 필요할 것 같음.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="기타"&gt;기타&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;포스터 홀 개선 및 추가&lt;/strong&gt;할 것.&lt;/li&gt;
&lt;li&gt;코딩테스트 및 서류 및 면접 준비&lt;/li&gt;
&lt;li&gt;통계 및 머신러닝 관련 공부도 지속적으로 진행.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Version 간 결과 비교/분석</title><link>https://inhyuk2000.github.io/blog/notillm/%EA%B8%B0%ED%9A%8D_0820/</link><pubDate>Thu, 20 Aug 2026 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/blog/notillm/%EA%B8%B0%ED%9A%8D_0820/</guid><description>&lt;p&gt;&lt;strong&gt;LangGraph를 사용하기 이전(전부 4o모델) vs 모델 분기 비교 실험&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="결과"&gt;결과&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th style="text-align: right"&gt;Baseline&lt;/th&gt;
&lt;th style="text-align: right"&gt;Routing V2&lt;/th&gt;
&lt;th style="text-align: right"&gt;Change (%)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Runs&lt;/td&gt;
&lt;td style="text-align: right"&gt;85.0000&lt;/td&gt;
&lt;td style="text-align: right"&gt;85.0000&lt;/td&gt;
&lt;td style="text-align: right"&gt;0.0000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total Cost ($)&lt;/td&gt;
&lt;td style="text-align: right"&gt;&lt;strong&gt;0.8520&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;&lt;strong&gt;0.7277&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;-14.5903&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Avg Cost ($)&lt;/td&gt;
&lt;td style="text-align: right"&gt;0.0100&lt;/td&gt;
&lt;td style="text-align: right"&gt;0.0086&lt;/td&gt;
&lt;td style="text-align: right"&gt;-14.5903&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mean Latency (s)&lt;/td&gt;
&lt;td style="text-align: right"&gt;4.6433&lt;/td&gt;
&lt;td style="text-align: right"&gt;7.5294&lt;/td&gt;
&lt;td style="text-align: right"&gt;+62.1563&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P50 Latency (s)&lt;/td&gt;
&lt;td style="text-align: right"&gt;4.2594&lt;/td&gt;
&lt;td style="text-align: right"&gt;7.3486&lt;/td&gt;
&lt;td style="text-align: right"&gt;+72.5282&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P95 Latency (s)&lt;/td&gt;
&lt;td style="text-align: right"&gt;&lt;strong&gt;7.2314&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;&lt;strong&gt;9.9255&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;+37.2561&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P99 Latency (s)&lt;/td&gt;
&lt;td style="text-align: right"&gt;9.4063&lt;/td&gt;
&lt;td style="text-align: right"&gt;13.0560&lt;/td&gt;
&lt;td style="text-align: right"&gt;+38.8006&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;LLM-based routing은 비용을 감소시켰지만 sequential LLM calls로 P95 latency가 너무 증가하는 문제점이 생겼다. &lt;strong&gt;Total Cost와 Latency의 문제를 둘 다 잡는 다른 방법&lt;/strong&gt;에 대한 고민이 필요해보였다..&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;LLM Router 까지 두어서 &lt;strong&gt;LLM 모델을 두 번 처리하는 게 문제&lt;/strong&gt;였기에, &lt;span class="high-mark"&gt;&lt;strong&gt;LLM Router를 제거하고 lightweight intent classifier로 대체&lt;/strong&gt;&lt;/span&gt;
하려고 함.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;기존 &lt;code&gt;LLM Router&lt;/code&gt; 대신 &lt;code&gt;sentenceTransformer&lt;/code&gt; + &lt;code&gt;LogisticRegression&lt;/code&gt; 기반 classifier로 구현하고자 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="v1-vs-v2-vs-v3"&gt;&lt;code&gt;v1&lt;/code&gt; vs &lt;code&gt;v2&lt;/code&gt; vs &lt;code&gt;v3&lt;/code&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th style="text-align: right"&gt;V1 Baseline&lt;/th&gt;
&lt;th style="text-align: right"&gt;V2 LLM Router&lt;/th&gt;
&lt;th style="text-align: right"&gt;V3 Classifier&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Runs&lt;/td&gt;
&lt;td style="text-align: right"&gt;85&lt;/td&gt;
&lt;td style="text-align: right"&gt;85&lt;/td&gt;
&lt;td style="text-align: right"&gt;85&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total Cost ($)&lt;/td&gt;
&lt;td style="text-align: right"&gt;0.8557&lt;/td&gt;
&lt;td style="text-align: right"&gt;0.7401&lt;/td&gt;
&lt;td style="text-align: right"&gt;&lt;strong&gt;0.7224&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Avg Cost / Run ($)&lt;/td&gt;
&lt;td style="text-align: right"&gt;0.0101&lt;/td&gt;
&lt;td style="text-align: right"&gt;0.0087&lt;/td&gt;
&lt;td style="text-align: right"&gt;&lt;strong&gt;0.0085&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mean Latency (s)&lt;/td&gt;
&lt;td style="text-align: right"&gt;4.1386&lt;/td&gt;
&lt;td style="text-align: right"&gt;6.2194&lt;/td&gt;
&lt;td style="text-align: right"&gt;&lt;strong&gt;3.3433&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P50 Latency (s)&lt;/td&gt;
&lt;td style="text-align: right"&gt;&lt;strong&gt;3.1119&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;5.4087&lt;/td&gt;
&lt;td style="text-align: right"&gt;3.1164&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P95 Latency (s)&lt;/td&gt;
&lt;td style="text-align: right"&gt;7.4149&lt;/td&gt;
&lt;td style="text-align: right"&gt;11.0379&lt;/td&gt;
&lt;td style="text-align: right"&gt;&lt;strong&gt;7.0132&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P99 Latency (s)&lt;/td&gt;
&lt;td style="text-align: right"&gt;12.9387&lt;/td&gt;
&lt;td style="text-align: right"&gt;11.9233&lt;/td&gt;
&lt;td style="text-align: right"&gt;&lt;strong&gt;8.7200&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Calls&lt;/td&gt;
&lt;td style="text-align: right"&gt;85&lt;/td&gt;
&lt;td style="text-align: right"&gt;85&lt;/td&gt;
&lt;td style="text-align: right"&gt;&lt;strong&gt;67&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Call Rate (%)&lt;/td&gt;
&lt;td style="text-align: right"&gt;100.00&lt;/td&gt;
&lt;td style="text-align: right"&gt;100.00&lt;/td&gt;
&lt;td style="text-align: right"&gt;&lt;strong&gt;78.82&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extract Rule Correctness&lt;/td&gt;
&lt;td style="text-align: right"&gt;0.8941&lt;/td&gt;
&lt;td style="text-align: right"&gt;&lt;strong&gt;0.9048&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;0.9024&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extract Rule Correctness (if routed)&lt;/td&gt;
&lt;td style="text-align: right"&gt;-&lt;/td&gt;
&lt;td style="text-align: right"&gt;&lt;strong&gt;0.9048&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;0.8780&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Route Correctness&lt;/td&gt;
&lt;td style="text-align: right"&gt;-&lt;/td&gt;
&lt;td style="text-align: right"&gt;&lt;strong&gt;1.0000&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;0.9756&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;V3는 V1 대비 비용 15.58%, 평균 Latency 19.22% 감소했고, LLM API 호출도 21.18% 절감함.&lt;/li&gt;
&lt;li&gt;정확도는 V1 0.8941 → V3 0.9024로 유지·소폭 개선되어, 성능 저하 없이 비용과 응답 속도를 함께 개선함.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>LangGraph 도입 검토 및 데이터셋 설계</title><link>https://inhyuk2000.github.io/blog/notillm/%EA%B8%B0%ED%9A%8D_0817/</link><pubDate>Mon, 17 Aug 2026 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/blog/notillm/%EA%B8%B0%ED%9A%8D_0817/</guid><description>&lt;h2 id="langgraph-도입하는-게-맞을까"&gt;&lt;code&gt;LangGraph&lt;/code&gt; 도입하는 게 맞을까?&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;LangGraph&lt;/code&gt;를 &lt;span class="high-mark"&gt;&lt;strong&gt;비용 최적화&lt;/strong&gt;&lt;/span&gt;
를 위해 도입하는 게 좋을 거 같음.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;현재 &lt;code&gt;version&lt;/code&gt;은 ChatGPT 4o 모델을 활용해 사용자 자연어 처리를 함.
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;현재 얼마의 비용이 청구되는 지에 대한 정확한 판단이 필요함. &lt;span class="high-mark"&gt;&lt;strong&gt;문제 설정 필요&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;하지만 사용자 명령이 만약 &lt;strong&gt;안녕&lt;/strong&gt;, &lt;strong&gt;ㅎ2&lt;/strong&gt;, &lt;strong&gt;ㅎㅎ&lt;/strong&gt; 라면? &lt;span class="high-mark"&gt;&lt;strong&gt;굳이 모든 명령들을 전부 &lt;code&gt;4o&lt;/code&gt; 모델로 처리할 필요가 있을까??&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;사용자의 명령을 &lt;code&gt;중요도 낮음&lt;/code&gt;, &lt;code&gt;약간 중요&lt;/code&gt;, &lt;code&gt;매우 중요&lt;/code&gt; 등으로 나눠서, 이에 맞는 수준의 모델로 라우팅해주는 게 좋을 거 같음. &lt;span class="high-mark"&gt;&lt;strong&gt;나중에 구현할 기능&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="version-01"&gt;Version 01.&lt;/h3&gt;
&lt;div class="mermaid"&gt;flowchart TD
START([사용자 입력&lt;br/&gt;prompt + pending 플래그]) --&gt; R{의도 라우터&lt;br/&gt;gpt-4o-mini}
R --&gt;|잡담 / 인사 / ㅎㅎ| S[단순 응답&lt;br/&gt;gpt-4o-mini&lt;br/&gt;tool 없음]
S --&gt; END1([END&lt;br/&gt;채팅 응답만])
R --&gt;|알림 규칙 관련| P{pending?}
P --&gt;|false| E[규칙 추출&lt;br/&gt;gpt-4o&lt;br/&gt;extract_notification_rule]
P --&gt;|true| C[재질문 후속 분류&lt;br/&gt;gpt-4o-mini]
C --&gt;|supplement&lt;br/&gt;보충| M[이전 명령 + 보충&lt;br/&gt;합친 prompt]
C --&gt;|new_command&lt;br/&gt;새 명령| N[이번 prompt만]
M --&gt; E
N --&gt; E
E --&gt;|tool 성공| OK[confirm 문장&lt;br/&gt;gpt-4o]
E --&gt;|정보 부족| ASK[재질문 메시지&lt;br/&gt;ok=false]
OK --&gt; END2([END&lt;br/&gt;규칙 저장])
ASK --&gt; END3([END&lt;br/&gt;앱이 pending 유지])
&lt;/div&gt;
&lt;h3 id="version-02"&gt;Version 02.&lt;/h3&gt;
&lt;div class="mermaid"&gt;flowchart TD
START([사용자 입력&lt;br/&gt;prompt + pending + pendingOriginal]) --&gt; ENTRY{pending=true&lt;br/&gt;AND pendingOriginal 있음?}
ENTRY --&gt;|Yes| RP[resolve_pending]
ENTRY --&gt;|No| R[의도 라우터&lt;br/&gt;gpt-4o-mini&lt;br/&gt;route_intent]
R --&gt;|chitchat&lt;br/&gt;잡담/인사/ㅎㅎ| S[단순 응답&lt;br/&gt;gpt-4o-mini&lt;br/&gt;tool 없음]
S --&gt; END1([END&lt;br/&gt;ok=false&lt;br/&gt;failReason=chitchat&lt;br/&gt;needsSupplement=false])
R --&gt;|extract&lt;br/&gt;알림 규칙 관련| RP
RP --&gt; C{pending 분류?&lt;br/&gt;gpt-4o-mini}
C --&gt;|pending 아님| N[이번 prompt만]
C --&gt;|supplement&lt;br/&gt;보충| M[이전 명령 + 보충&lt;br/&gt;합친 prompt]
C --&gt;|new_command&lt;br/&gt;새 명령| N
M --&gt; E[규칙 추출&lt;br/&gt;gpt-4o&lt;br/&gt;function calling]
N --&gt; E
E --&gt;|성공| OK[confirm 문장&lt;br/&gt;gpt-4o]
E --&gt;|정보 부족| ASK[재질문&lt;br/&gt;ok=false&lt;br/&gt;needsSupplement=true]
E --&gt;|충돌/앱 미해결 등| FAIL[실패&lt;br/&gt;ok=false&lt;br/&gt;needsSupplement=false]
OK --&gt; END2([END&lt;br/&gt;규칙 저장])
ASK --&gt; END3([END&lt;br/&gt;앱이 pending 유지])
FAIL --&gt; END4([END&lt;br/&gt;pending 해제])
&lt;/div&gt;
&lt;h3 id="langgraph-도입-시-routing-버전을-추가-확인-사항"&gt;LangGraph 도입 시 (&lt;code&gt;Routing 버전&lt;/code&gt;을 추가), 확인 사항&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;A버전에 비해 B버전에서, &lt;strong&gt;정확도&lt;/strong&gt;가 많이 떨어지지 않는지&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;비용 및 속도&lt;/strong&gt;가 얼마나 줄어드는지&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="evaluation-dataset-구성-기준"&gt;Evaluation Dataset 구성 기준&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Evaluation Dataset&lt;/code&gt;이 특정 유형에 편중되지 않도록, 주요 평가 축을 &lt;code&gt;intent&lt;/code&gt;, &lt;code&gt;time&lt;/code&gt;, &lt;code&gt;target&lt;/code&gt;으로 나누고 각 카테고리 별 최소 케이스 수를 정의했습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;전체 Dataset: &lt;strong&gt;85 cases&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;주요 카테고리 별 최소 5 cases 이상&lt;/strong&gt; 확보&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ok=true&lt;/code&gt; 케이스에서는 &lt;code&gt;time&lt;/code&gt;, &lt;code&gt;target&lt;/code&gt; 세부 유형이 모두 포함되도록 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="coverage-확인"&gt;Coverage 확인&lt;/h3&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-blue-100 dark:bg-blue-900 border-blue-500"
data-callout="note"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-blue-600 dark:text-blue-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m16.862 4.487l1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8l.8-2.685a4.5 4.5 0 0 1 1.13-1.897zm0 0L19.5 7.125"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;모든 주요 카테고리에서 최소 5개 이상의 평가 케이스를 확보하여, 특정 입력 유형이 Dataset에서 완전히 누락되는 것을 방지했습니다.&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;축&lt;/th&gt;
&lt;th&gt;값&lt;/th&gt;
&lt;th style="text-align: right"&gt;개수&lt;/th&gt;
&lt;th style="text-align: right"&gt;기준&lt;/th&gt;
&lt;th style="text-align: center"&gt;상태&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A. intent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mute&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;44&lt;/td&gt;
&lt;td style="text-align: right"&gt;≥5&lt;/td&gt;
&lt;td style="text-align: center"&gt;OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A. intent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;allow&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;14&lt;/td&gt;
&lt;td style="text-align: right"&gt;≥5&lt;/td&gt;
&lt;td style="text-align: center"&gt;OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A. intent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;reject&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;27&lt;/td&gt;
&lt;td style="text-align: right"&gt;≥5&lt;/td&gt;
&lt;td style="text-align: center"&gt;OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;B. time (ok=true 58건)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;duration&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;38&lt;/td&gt;
&lt;td style="text-align: right"&gt;≥5&lt;/td&gt;
&lt;td style="text-align: center"&gt;OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;B. time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;until_absolute&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;5&lt;/td&gt;
&lt;td style="text-align: right"&gt;≥5&lt;/td&gt;
&lt;td style="text-align: center"&gt;OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;B. time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;relative_delay&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;5&lt;/td&gt;
&lt;td style="text-align: right"&gt;≥5&lt;/td&gt;
&lt;td style="text-align: center"&gt;OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;B. time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;daily&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;5&lt;/td&gt;
&lt;td style="text-align: right"&gt;≥5&lt;/td&gt;
&lt;td style="text-align: center"&gt;OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;B. time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;weekly&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;5&lt;/td&gt;
&lt;td style="text-align: right"&gt;≥5&lt;/td&gt;
&lt;td style="text-align: center"&gt;OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;C. target (ok=true 58건)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;all&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;11&lt;/td&gt;
&lt;td style="text-align: right"&gt;≥5&lt;/td&gt;
&lt;td style="text-align: center"&gt;OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;C. target&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;single_app&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;29&lt;/td&gt;
&lt;td style="text-align: right"&gt;≥5&lt;/td&gt;
&lt;td style="text-align: center"&gt;OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;C. target&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;multi_app&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;5&lt;/td&gt;
&lt;td style="text-align: right"&gt;≥5&lt;/td&gt;
&lt;td style="text-align: center"&gt;OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;C. target&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;content&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;6&lt;/td&gt;
&lt;td style="text-align: right"&gt;≥5&lt;/td&gt;
&lt;td style="text-align: center"&gt;OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;C. target&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app_and_content&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;7&lt;/td&gt;
&lt;td style="text-align: right"&gt;≥5&lt;/td&gt;
&lt;td style="text-align: center"&gt;OK&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;LangGraph 도입해야 한다면 내 프로젝트 서비스를 최적화시켜줄 수 있는 최적의 참조 논문은..?&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Reasoning&lt;/code&gt;과 &lt;code&gt;Action&lt;/code&gt;을 번갈아 수행하면서 외부 환경 / 도구와 상호작용하는 구조&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;같은 LLM이 &lt;code&gt;Generator&lt;/code&gt;, &lt;code&gt;Feedback Provider&lt;/code&gt;, &lt;code&gt;Refiner&lt;/code&gt; 역할을 수행하면서 반복적으로 결과 개선&lt;/li&gt;
&lt;li&gt;별도의 &lt;code&gt;Supervised Training&lt;/code&gt;이나 &lt;code&gt;RL&lt;/code&gt; 없이도 &lt;strong&gt;여러 task에서 one-shot generation보다 성능 개선&lt;/strong&gt; 보고&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;자연어 &lt;code&gt;reflection&lt;/code&gt; 형태로 &lt;code&gt;memory&lt;/code&gt;에 저장&lt;/strong&gt;하고 다음 &lt;code&gt;attempt&lt;/code&gt;에 활용하는 구조&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LangGraph&lt;/code&gt;에서 &lt;code&gt;state&lt;/code&gt; / &lt;code&gt;memory&lt;/code&gt; / &lt;code&gt;retry loop&lt;/code&gt;를 설계할 때 굉장히 자연스럽게 연결&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="4"&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;틀린 모델이 자기 답을 평가&lt;/strong&gt;하면 틀릴 수 있음.&lt;/li&gt;
&lt;li&gt;검색엔진, 코드 실행기 같은 &lt;strong&gt;외부 도구의 피드백을 사용해 검증&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="5"&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;여러 &lt;code&gt;reasoning candidate&lt;/code&gt;를 만들고 평가하면서 &lt;code&gt;search&lt;/code&gt; / &lt;code&gt;branching&lt;/code&gt; / &lt;code&gt;backtracking&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="6"&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;전체 문제를 먼저 작은 &lt;code&gt;subtask&lt;/code&gt;로 나눈 뒤 실행&lt;/li&gt;
&lt;li&gt;특히 &lt;code&gt;Zero-shot CoT&lt;/code&gt;에서 발생하는 &lt;code&gt;missing-step&lt;/code&gt; 등의 문제를 해결하려는 접근&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="7"&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;reasoning&lt;/code&gt;과 &lt;code&gt;tool observation&lt;/code&gt;을 &lt;strong&gt;분리&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="8"&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Tool Calling&lt;/code&gt;의 중요한 초기 연구&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LLM이 언제 어떤 API를 사용할지를 결정&lt;/strong&gt;하는 것 자체를 연구한 논문&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="9"&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;같은 여러 &lt;code&gt;Agent&lt;/code&gt; 간 &lt;code&gt;interaction&lt;/code&gt;을 일반화한 프레임워크 연구&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LLM&lt;/code&gt;, &lt;code&gt;human input&lt;/code&gt;, &lt;code&gt;tool&lt;/code&gt;을 조합한 &lt;code&gt;customizable/conversable agen&lt;/code&gt;t를 구성하고 다양한 &lt;code&gt;conversation pattern&lt;/code&gt;을 정의&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>사용자 재질문 처리 전략</title><link>https://inhyuk2000.github.io/blog/notillm/%EA%B8%B0%ED%9A%8D_0816/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/blog/notillm/%EA%B8%B0%ED%9A%8D_0816/</guid><description>&lt;p&gt;&lt;strong&gt;pending flag를 활용해 재질문 처리용 LLM 추가&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="backendapppendingpy-추가"&gt;backend/app/pending.py 추가&lt;/h2&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;Sequence Diagram&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이전 대화에서 사용자 질문 의도 파악 불가로 &lt;u&gt;재질문&lt;/u&gt; + &lt;u&gt;사용자 보충 질문 추가&lt;/u&gt;하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="mermaid"&gt;sequenceDiagram
participant U as 사용자
participant App as Android PromptEngine
participant API as FastAPI handle
participant C as gpt-4o-mini 분류
participant E as gpt-4o 추출
U-&gt;&gt;App: 카톡만 받아줘
App-&gt;&gt;API: pending=false
API-&gt;&gt;E: extract
E--&gt;&gt;API: ok=false + 재질문
API--&gt;&gt;App: ok=false
App-&gt;&gt;App: pendingOriginal 저장
U-&gt;&gt;App: 1시간
App-&gt;&gt;API: pending=true + pendingOriginal
API-&gt;&gt;C: 이전+이번 분류
C--&gt;&gt;API: supplement
API-&gt;&gt;E: 합친 prompt로 extract
E--&gt;&gt;API: ok=true + 규칙
API--&gt;&gt;App: ok=true
App-&gt;&gt;App: 규칙 저장, pending clear
&lt;/div&gt;
&lt;h3 id="classify_pending_turn-함수"&gt;&lt;code&gt;classify_pending_turn&lt;/code&gt; 함수&lt;/h3&gt;
&lt;p&gt;재질문 대기 중일 때, &lt;span class="high-mark"&gt;&lt;strong&gt;이번 입력이 보충인지 새 명령인지 LLM으로 판별&lt;/strong&gt;&lt;/span&gt;
한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pending_original&lt;/code&gt;: 재질문 전 사용자 명령&lt;/li&gt;
&lt;li&gt;&lt;code&gt;current_prompt&lt;/code&gt;: 재질문 후 사용자 입력&lt;/li&gt;
&lt;li&gt;&lt;code&gt;supplement&lt;/code&gt;: 이전 명령에 대한 보충 (예: 1시간)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;new_command&lt;/code&gt;: 이전과 무관한 새 규칙&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="resolve_extract_prompt-함수"&gt;&lt;code&gt;resolve_extract_prompt&lt;/code&gt; 함수&lt;/h3&gt;
&lt;p&gt;handle 앞에서 &lt;span class="high-mark"&gt;&lt;strong&gt;추출용 prompt 문자열을 만드는 진입점&lt;/strong&gt;&lt;/span&gt;
역할을 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;prompt&lt;/code&gt;: 이번 사용자 입력&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pending&lt;/code&gt;: 앱이 보낸 재질문 대기 여부&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pending_original&lt;/code&gt;: 재질문 전 원문&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(extract_prompt, classification)&lt;/code&gt;: 추출 LLM에 넣을 문장 + 분류 결과 [None: 분류 안함]&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-blue-100 dark:bg-blue-900 border-blue-500"
data-callout="todo"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-blue-600 dark:text-blue-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12.75L11.25 15L15 9.75M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;추가 재질문 (Pending 처리) LLM이 실 기기에서 동작하는 지에 대한 테스트 진행 필요&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>파이썬을 활용한 머신러닝 딥러닝 입문</title><link>https://inhyuk2000.github.io/blog/study/%ED%8C%8C%EC%9D%B4%EC%8D%AC%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EB%94%A5%EB%9F%AC%EB%8B%9D-%EC%9E%85%EB%AC%B8/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/blog/study/%ED%8C%8C%EC%9D%B4%EC%8D%AC%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EB%94%A5%EB%9F%AC%EB%8B%9D-%EC%9E%85%EB%AC%B8/</guid><description>&lt;h2 id="머신러닝-종류"&gt;머신러닝 종류&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;지도 학습 : &lt;code&gt;Data의 정답을 이는 경우&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;분류 (Classification)&lt;/li&gt;
&lt;li&gt;회귀 (Regression)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;비지도 학습 : &lt;code&gt;Data의 정답을 모르는 경우&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;강화 학습 : 분류나 예측이 아닌 행동을 결정 &lt;code&gt;의사결정&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;지도 학습 : &lt;code&gt;Label(정답)&lt;/code&gt;을 아는 경우
&lt;ul&gt;
&lt;li&gt;Model에 학습시켜 새로운 Data에 대한 Output 예측&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;비지도 학습 : &lt;code&gt;Training Data&lt;/code&gt;에 &lt;code&gt;Label(정답)&lt;/code&gt;이 없음
&lt;ul&gt;
&lt;li&gt;Data의 패턴을 인식해 군집화 및 특징 추출 &lt;code&gt;사람이 결과 해석&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="머신러닝에-사용되는-파이썬-라이브러리"&gt;머신러닝에 사용되는 파이썬 라이브러리&lt;/h2&gt;
&lt;h3 id="scikit-learn"&gt;Scikit-Learn&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;전통적 ML Tools:
&lt;ul&gt;
&lt;li&gt;벤치마크용 데이터셋 예제&lt;/li&gt;
&lt;li&gt;데이터 전처리 함수들&lt;/li&gt;
&lt;li&gt;지도 / 비지도 Model&lt;/li&gt;
&lt;li&gt;모형 평가 및 선택&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="딥러닝에-사용되는-파이썬-라이브러리"&gt;딥러닝에 사용되는 파이썬 라이브러리&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Scikit-Learn&lt;/code&gt;, &lt;code&gt;Tensorflow&lt;/code&gt;, &lt;code&gt;Keras&lt;/code&gt; (Tensorflow에 대한 High-Level API. 더 쉽게 쓰기 위함), &lt;code&gt;Pytorch&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>통계 분석 마스터 클래스</title><link>https://inhyuk2000.github.io/blog/study/%ED%86%B5%EA%B3%84-%EB%B6%84%EC%84%9D-%EB%A7%88%EC%8A%A4%ED%84%B0-%ED%81%B4%EB%9E%98%EC%8A%A4/</link><pubDate>Sat, 15 Aug 2026 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/blog/study/%ED%86%B5%EA%B3%84-%EB%B6%84%EC%84%9D-%EB%A7%88%EC%8A%A4%ED%84%B0-%ED%81%B4%EB%9E%98%EC%8A%A4/</guid><description>&lt;h2 id="통계분석-마스터-클래스-배울-내용-소개"&gt;통계분석 마스터 클래스 배울 내용 소개&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;통계 분석&lt;/code&gt;을 통해 &lt;code&gt;가정&lt;/code&gt;을 객관적으로 &lt;code&gt;검증&lt;/code&gt;할 수 있음.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;의사결정 Framework (PPDAC)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;P: Problem. Business Question&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;통계: 피어슨 통계&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;기술 통계.
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Data Modeling. Data 확보. 데이터 &lt;code&gt;분석 / 요약&lt;/code&gt;을 통해 &lt;span class="high-mark"&gt;&lt;strong&gt;인사이트를 뽑기 위한 방법&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;값&lt;/code&gt;으로 요약. &lt;code&gt;시각화&lt;/code&gt;로 요약.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;확률론.
&lt;ul&gt;
&lt;li&gt;표본을 바탕으로 모집단을 설명하기 위한 방법들.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;추론 통계.
&lt;ul&gt;
&lt;li&gt;ex. &lt;code&gt;T-test&lt;/code&gt; (&lt;code&gt;t-검정&lt;/code&gt;. 2개의 집단.), &lt;code&gt;카이검정&lt;/code&gt;, &lt;code&gt;Anova&lt;/code&gt;, &lt;code&gt;회귀분석&lt;/code&gt;, &lt;code&gt;로지스틱 회귀분석&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="직관적-의사결정과-데이터-기반-의사결정"&gt;직관적 의사결정과 데이터 기반 의사결정&lt;/h2&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;직관적 의사 결정&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;고객의 욕구, 경쟁자 전략, 기술 변화 등 관련 정보의 획득과 최적 대안 도출이 실제 경영상황에서는 완벽하게 얻어내기 힘든 경우가 많음&lt;/li&gt;
&lt;li&gt;사이몬의 &lt;code&gt;관리적 의사결정 모형&lt;/code&gt;: 완벽한 합리성보다는 제한된 합리성 하에서의 의사결정&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- &gt; [!Note] 작성 예정. [PST1001] 부터 수강 시작. --&gt;</description></item><item><title>baseline_v1_auto_map Evaluation 및 개선</title><link>https://inhyuk2000.github.io/blog/notillm/%EA%B8%B0%ED%9A%8D_0814/</link><pubDate>Fri, 14 Aug 2026 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/blog/notillm/%EA%B8%B0%ED%9A%8D_0814/</guid><description>&lt;p&gt;&lt;strong&gt;Evaluation에서 확인된 부분을 기반으로 코드 수정&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
&lt;figure &gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;&lt;img src="./image.png" alt="LangSmith" loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/figure&gt;
LangSmith를 기반으로 53문항의 테스트를 진행했고, 개선 수행.&lt;/p&gt;
&lt;p&gt;
에서는 여러 앱의 메타데이터도 같이 넣어서, context기반 cosine 유사도 계산 방식을 추천했으나, 메타데이터를 불러올 적절한 방법을 찾지 못함.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;앱 관련 시스템 정보에는 메타데이터가 존재하지 않았음. 전부 &lt;code&gt;null&lt;/code&gt; 필드.&lt;/li&gt;
&lt;li&gt;Google Play Store에서 API 형태로 앱의 Description을 가져오는 것도 생각해 보았으나, 서비스가 너무 무거워질 것으로 예상되어 &lt;span class="high-mark"&gt;&lt;strong&gt;유의어 사전을 만드는 방식을 채택함.&lt;/strong&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="코드-개선-전-baseline-테스트-결과"&gt;코드 개선 전, Baseline 테스트 결과&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;총 53개 테스트 데이터&lt;/li&gt;
&lt;li&gt;정답률 : &lt;span class="high-mark"&gt;&lt;strong&gt;0.87&lt;/strong&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="error-case-1"&gt;Error Case 1.&lt;/h2&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-green-100 dark:bg-green-900 border-green-500"
data-callout="success"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-green-600 dark:text-green-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12.75L11.25 15L15 9.75M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;&amp;ldquo;카톡 2분만 받지마&amp;rdquo;&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;output
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;ok&amp;rdquo;: false&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ground truth
&lt;ul&gt;
&lt;li&gt;현재 시간부터 2분동안 카톡을 받지 않도록 설정함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;피드백
&lt;ul&gt;
&lt;li&gt;시스템 프롬프트에 현재 시간이 정의되어 있지 않으면 현재 시간 부터라는 내용을 추가해 넣어줘야 할 거 같음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="error-case-2"&gt;Error Case 2.&lt;/h2&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-green-100 dark:bg-green-900 border-green-500"
data-callout="success"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-green-600 dark:text-green-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12.75L11.25 15L15 9.75M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;&amp;ldquo;지금부터 1시간 문자만 받아줘&amp;rdquo;&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;output
&lt;ul&gt;
&lt;li&gt;문자 앱이 아닌 com.samsung.android.mdecservice 다른 앱의 cosine 유사도가 가장 높았고, 이 마저도 0.5 이하여서 ok=false 반환.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ground truth
&lt;ul&gt;
&lt;li&gt;packages에 &amp;ldquo;com.samsung.android.messaging&amp;quot;이 담겨야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;피드백
&lt;ul&gt;
&lt;li&gt;Cosine 유사도 판단 오류. &amp;ldquo;문자&amp;quot;와 &amp;ldquo;메시지&amp;quot;의 코사인 유사도가 낮게 나옴.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="error-case-3"&gt;Error Case 3.&lt;/h2&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-orange-100 dark:bg-orange-900 border-orange-500"
data-callout="warning"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-orange-600 dark:text-orange-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0zM12 15.75h.007v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;&amp;ldquo;지금부터 2시간 문자 스팸 알림 받지마&amp;rdquo;&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;output
&lt;ul&gt;
&lt;li&gt;name 필드는 비어있고, content=[&amp;ldquo;문자&amp;rdquo;, &amp;ldquo;스팸&amp;rdquo;]&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ground truth
&lt;ul&gt;
&lt;li&gt;name=&amp;ldquo;메시지&amp;rdquo;, content=&amp;ldquo;스팸&amp;rdquo; 이 담겨야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;피드백
&lt;ul&gt;
&lt;li&gt;스팸이 name인지 앞서 나온 &amp;ldquo;문자&amp;quot;에 대한 &amp;ldquo;스팸&amp;quot;인지 확인할 수 있어야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="error-case-4"&gt;Error Case 4.&lt;/h2&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-green-100 dark:bg-green-900 border-green-500"
data-callout="success"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-green-600 dark:text-green-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12.75L11.25 15L15 9.75M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;&amp;ldquo;지금부터 2시간 문자에서 &amp;lsquo;스팸&amp;rsquo;이라는 단어가 들어간 알림 받지마&amp;rdquo;&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;output
&lt;ul&gt;
&lt;li&gt;문자 앱이 아닌 com.samsung.android.mdecservice 다른 앱의 cosine 유사도가 가장 높았고, 이 마저도 0.5 이하여서 ok=false 반환.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ground truth
&lt;ul&gt;
&lt;li&gt;packages에 &amp;ldquo;com.samsung.android.messaging&amp;quot;이 담겨야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;피드백
&lt;ul&gt;
&lt;li&gt;Cosine 유사도 판단 오류. &amp;ldquo;문자&amp;quot;와 &amp;ldquo;메시지&amp;quot;의 코사인 유사도가 낮게 나옴.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="error-case-5"&gt;Error Case 5.&lt;/h2&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-green-100 dark:bg-green-900 border-green-500"
data-callout="success"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-green-600 dark:text-green-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12.75L11.25 15L15 9.75M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;&amp;ldquo;지금부터 2시간 플레이스토어 업데이트 알림 받지마&amp;rdquo;&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;output
&lt;ul&gt;
&lt;li&gt;com.android.vending 앱이 아닌 com.samsung.android.smartsuggestions 다른 앱의 cosine 유사도가 가장 높았음. 즉, 잘못된 앱의 이름을 설정함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ground truth
&lt;ul&gt;
&lt;li&gt;packages에 &amp;ldquo;com.android.vending&amp;quot;이 담겨야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;피드백
&lt;ul&gt;
&lt;li&gt;Cosine 유사도 판단 오류.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="error-case-5-제외-케이스"&gt;Error Case 5. [제외 케이스]&lt;/h2&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-orange-100 dark:bg-orange-900 border-orange-500"
data-callout="warning"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-orange-600 dark:text-orange-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0zM12 15.75h.007v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;&amp;ldquo;지금부터 12시간 카톡 홍보, 프로모션이나 카드 알림은 띄우지마&amp;rdquo;&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;output
&lt;ul&gt;
&lt;li&gt;name=&amp;ldquo;카카오톡&amp;rdquo;, content=&amp;ldquo;홍보, 프로모션, 카드&amp;rdquo; 가 들어감.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ground truth
&lt;ul&gt;
&lt;li&gt;현재 구조로는 해결이 불가능. ok=false&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;피드백
&lt;ul&gt;
&lt;li&gt;아직 해결 불가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="error-case-6"&gt;Error Case 6.&lt;/h2&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-orange-100 dark:bg-orange-900 border-orange-500"
data-callout="warning"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-orange-600 dark:text-orange-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0zM12 15.75h.007v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;&amp;ldquo;지금부터 5분 카톡 메세지 알림 받지마&amp;rdquo;&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;output
&lt;ul&gt;
&lt;li&gt;name=&amp;ldquo;카카오톡&amp;rdquo;, content=&amp;ldquo;메세지&amp;rdquo; 가 들어감.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ground truth
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;카톡 메세지&amp;rdquo; 라고 말을 해도, 사실상 &amp;ldquo;카톡&amp;quot;을 의미하는 것이므로, name=&amp;ldquo;카카오톡&amp;rdquo; 이고 content는 비워야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;피드백
&lt;ul&gt;
&lt;li&gt;추출 오류.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;문제점&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;다른 기기에서도 전화/문자하기&amp;rdquo;(&amp;ldquo;com.samsung.android.mdecservice&amp;rdquo;) 와 &amp;ldquo;메시지&amp;rdquo;(&amp;ldquo;com.samsung.android.messaging&amp;rdquo;)가 있을 때, &amp;ldquo;문자&amp;quot;라는 단어가 &amp;ldquo;메시지&amp;quot;에 매핑되도록 하려면 어떻게 해야 하나?&lt;/li&gt;
&lt;li&gt;&amp;ldquo;퍼스널 데이터 인텔리전스&amp;rdquo;(&amp;ldquo;com.samsung.android.smartsuggestions&amp;rdquo;) 와 &amp;ldquo;Play 스토어&amp;rdquo;(&amp;ldquo;com.android.vending&amp;rdquo;)가 있을 때, &amp;ldquo;플레이스토어&amp;quot;라는 단어가 &amp;ldquo;Play 스토어&amp;quot;에 매핑되도록 하려면 어떻게 해야 하나?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;나의 해결책&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;처음에는
사이트에서 관련 메타데이터를 찾을 수 있는 방법을 고민함.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;하지만 &lt;span class="high-mark"&gt;&lt;strong&gt;해당 필드가 전부 비어있는 값으로 나와 사용할 수 없었음.&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;따라서 &lt;span class="high-mark"&gt;&lt;strong&gt;유의어 사전&lt;/strong&gt;&lt;/span&gt;
을 만드는 방법을 채택함.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;LLM이 뽑은 **앱 이름(name, &amp;ldquo;문자&amp;rdquo;)**으로 찾음&lt;/li&gt;
&lt;li&gt;유의어 사전에 그 그룹 단어를 [&amp;ldquo;문자&amp;rdquo;, &amp;ldquo;메시지&amp;rdquo;, &amp;ldquo;SMS&amp;rdquo;, &amp;hellip;] 로 확장&lt;/li&gt;
&lt;li&gt;(확장된 각 단어) X (설치 앱 각 라벨) : Cosine&lt;/li&gt;
&lt;li&gt;각 앱마다 그 중 가장 높은 점수로 대표&lt;/li&gt;
&lt;li&gt;전 앱 중 최고 + Threshold 로 최종 package 결정&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;시스템 프롬프트 &lt;strong&gt;few-shot learning&lt;/strong&gt; 추가&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;N분(만/동안/간) …&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;처럼&lt;/span&gt; &lt;span class="n"&gt;기간만&lt;/span&gt; &lt;span class="n"&gt;있고&lt;/span&gt; &lt;span class="n"&gt;시작&lt;/span&gt; &lt;span class="n"&gt;시각이&lt;/span&gt; &lt;span class="n"&gt;없으면&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;지금부터&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;delivery&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;현재&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expires&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;현재&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;N분&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;예&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;카톡 2분만 받지마&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;카톡 5분동안 받지마&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;모두&lt;/span&gt; &lt;span class="n"&gt;현재부터&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="코드-개선-이후"&gt;코드 개선 이후&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;정답률 : &lt;span class="high-mark"&gt;&lt;strong&gt;0.91&lt;/strong&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-orange-100 dark:bg-orange-900 border-orange-500"
data-callout="warning"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-orange-600 dark:text-orange-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0zM12 15.75h.007v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;&amp;ldquo;매일 밤 10시부터 새벽 4시까지 조용히&amp;rdquo;&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-orange-100 dark:bg-orange-900 border-orange-500"
data-callout="warning"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-orange-600 dark:text-orange-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0zM12 15.75h.007v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;&amp;ldquo;매일 밤 10시부터 아침 6시까지 모든 알림 받지마&amp;rdquo;&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;주기성 명령의 경우 delivery와 expires 시간 계산에서 예측값과 실제값이 다르게 나옴. &lt;span class="high-mark"&gt;&lt;strong&gt;하지만 이것이 결과에는 영향을 주지 않음&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;프롬프트 변경을 통해 해결함.
&lt;ul&gt;
&lt;li&gt;구간 전: 다음 회차&lt;/li&gt;
&lt;li&gt;구간 안: 진행 중 회차&lt;/li&gt;
&lt;li&gt;구간 끝남: 다음 밤 회차&lt;/li&gt;
&lt;li&gt;지난 회차 금지. &lt;code&gt;overrnight&lt;/code&gt;면 &lt;code&gt;expires = delivery + 1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Coding Test</title><link>https://inhyuk2000.github.io/blog/coding-test/practice_0814/</link><pubDate>Fri, 14 Aug 2026 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/blog/coding-test/practice_0814/</guid><description>&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;프로그래머스&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-purple-100 dark:bg-purple-900 border-purple-500"
data-callout="important"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-purple-600 dark:text-purple-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m9-.75a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9 3.75h.008v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;[해시] 전화번호 목록&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="접근-방법"&gt;접근 방법&lt;/h3&gt;
&lt;p&gt;시간복잡도가 지금은 O(N^2)라서 O(NlongN)으로 가는 방법에 대해서 고민 필요.&lt;/p&gt;
&lt;h3 id="풀이-전략"&gt;풀이 전략&lt;/h3&gt;
&lt;p&gt;ㅇㅇㅇ&lt;/p&gt;
&lt;h3 id="관련-이론-정리"&gt;관련 이론 정리&lt;/h3&gt;
&lt;p&gt;ㅇㅇㅇ&lt;/p&gt;
&lt;hr&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-purple-100 dark:bg-purple-900 border-purple-500"
data-callout="important"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-purple-600 dark:text-purple-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m9-.75a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9 3.75h.008v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;[해시] 의상&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="접근-방법-1"&gt;접근 방법&lt;/h3&gt;
&lt;p&gt;ㅇㅇㅇ&lt;/p&gt;
&lt;h3 id="풀이-전략-1"&gt;풀이 전략&lt;/h3&gt;
&lt;p&gt;ㅇㅇㅇ&lt;/p&gt;
&lt;h3 id="관련-이론-정리-1"&gt;관련 이론 정리&lt;/h3&gt;
&lt;p&gt;ㅇㅇㅇ&lt;/p&gt;
&lt;hr&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-purple-100 dark:bg-purple-900 border-purple-500"
data-callout="important"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-purple-600 dark:text-purple-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m9-.75a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9 3.75h.008v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;[해시] 베스트앨범&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="접근-방법-2"&gt;접근 방법&lt;/h3&gt;
&lt;p&gt;ㅇㅇㅇ&lt;/p&gt;
&lt;h3 id="풀이-전략-2"&gt;풀이 전략&lt;/h3&gt;
&lt;p&gt;ㅇㅇㅇ&lt;/p&gt;
&lt;h3 id="관련-이론-정리-2"&gt;관련 이론 정리&lt;/h3&gt;
&lt;p&gt;ㅇㅇㅇ&lt;/p&gt;</description></item><item><title>LangSmith를 활용한 Evaluation 설계</title><link>https://inhyuk2000.github.io/blog/notillm/%EA%B8%B0%ED%9A%8D_0812/</link><pubDate>Wed, 12 Aug 2026 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/blog/notillm/%EA%B8%B0%ED%9A%8D_0812/</guid><description>&lt;p&gt;&lt;strong&gt;Phoenix 기반 DeepLearningAI의 강의 코드를 참조해, 동일한 로직을 LangSmith로 구현함&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="evaluation-설명"&gt;Evaluation 설명&lt;/h2&gt;
&lt;p&gt;기존 시스템은 Kotlin 기반 Android 앱 내부의 PromptEngine.kt에서 자연어 입력을 LLM에 전달하고, Function Calling 결과를 바탕으로 알림 규칙을 생성하는 구조였다.&lt;/p&gt;
&lt;p&gt;하지만 Android 플랫폼 로직과 LLM Extraction 로직이 하나의 코드에 강하게 결합되어 있어, &lt;span class="high-mark"&gt;&lt;strong&gt;LLM 성능만 독립적으로 평가하거나 Prompt 변경에 따른 성능 변화를 반복적으로 검증하기 어려운 구조&lt;/strong&gt;&lt;/span&gt;
였다.&lt;/p&gt;
&lt;p&gt;이에 기존 PromptEngine.kt에서 수행하던 자연어 조건 추출 로직을 분리하여, &lt;span class="high-mark"&gt;&lt;strong&gt;FastAPI + LangChain 기반의 AI Backend&lt;/strong&gt;&lt;/span&gt;
로 이전하였다.&lt;/p&gt;
&lt;p&gt;이를 통해 Android 앱은 사용자 입력을 AI Backend로 전달하고 결과를 받아 실제 알림 규칙으로 저장하는 역할에 집중하고, AI Backend에서는 LLM 호출, Function Calling, 결과 후처리 및 Evaluation을 독립적으로 수행할 수 있도록 구조를 분리하였다.&lt;/p&gt;
&lt;h3 id="fastapi-기반-ai-backend-부분-설명"&gt;FastAPI 기반 AI Backend 부분 설명&lt;/h3&gt;
&lt;p&gt;FastAPI 기반 AI Backend의 핵심 로직은 크게 &lt;span class="high-mark"&gt;&lt;strong&gt;다음 4단계&lt;/strong&gt;&lt;/span&gt;
로 구성하였다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;시스템 프롬프트 few shot learning 관련 코드&lt;/li&gt;
&lt;li&gt;현재 시간을 지정해 function calling용 Tool Schema 리스트를 return 해주는 코드&lt;/li&gt;
&lt;li&gt;LLM의 추론으로 반환된 Function Calling 결과를 내 서비스에서 사용하기 쉽도록 후처리하는 코드&lt;/li&gt;
&lt;li&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;메인 처리 로직&lt;/strong&gt;&lt;/span&gt;
: (사용자 프롬프트, 현재 시간) 입력 -&amp;gt; (targetFixed, condition 포함한 Response Json) 반환&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;AI Backend 코드에 대한 Kotlin 연결부 : FastAPI LLM 서버에 요청하고 결과를 기존 Android 규칙 시스템에 연결&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="langsmith를-활용한-llm-실행-추적"&gt;LangSmith를 활용한 LLM 실행 추적&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;LangSmith를 활용해서 &lt;span class="high-mark"&gt;&lt;strong&gt;현재 LangChain 기반 LLM Function Calling을 추적&lt;/strong&gt;&lt;/span&gt;
했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;figure &gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;&lt;img src="./image.png" alt="LangSmith 결과화면" loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;code&gt;handle&lt;/code&gt; 함수안의 두 &lt;code&gt;ChatOpenAI.invoke&lt;/code&gt; 함수를 자동으로 추적하고 있는 것을 확인할 수 있었다!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="code-based-evaluation-설계-과정"&gt;Code-based Evaluation 설계 과정&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;evals&lt;/code&gt; 폴더 생성 후, 평가에 사용할 샘플 5개 &lt;strong&gt;JSON 데이터셋(input, output)&lt;/strong&gt; 생성&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dataset_upload.py&lt;/code&gt; : Jsonl 확장자 파일에서 정의한 데이터셋을 &lt;strong&gt;LangSmith Dataset&lt;/strong&gt;에 업로드&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System Few Shot&lt;/code&gt; 부분도 전체적으로 어떻게 프롬프팅 했는지 점검해봐야 함.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;evaluators.py&lt;/code&gt; 파일과 &lt;code&gt;run_experiment.py&lt;/code&gt; 파일 생성해서 LangSmith 기반 테스트 진행함. (정답률 : 100%, 샘플 5개 적용)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="evaluatorspy-코드에-대해서"&gt;Evaluators.py 코드에 대해서..&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract_rule_correctness&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reference_outputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; ExtractRule JSON 정답 일치도 (binary code metric).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; LangSmith evaluate()가 Example마다 호출:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; outputs ← Target(handle) 반환값
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; reference_outputs ← Dataset example.outputs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; Returns:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; key/score 형태 dict — UI 지표명과 0~1 점수
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; comment — 필드별 pass/fail (디버깅용)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; delivery/expires 는 currentTime이 고정이므로 ISO 문자열 exact match.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pred&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;exp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reference_outputs&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# ok (성공/실패) — router 성격&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ok&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pred&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ok&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ok&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 정답이 실패면 구조 필드 없음 → ok만 채점&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 예: &amp;#34;카톡만 받아줘&amp;#34; (시간 없음) → ok=false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ok&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;extract_rule_correctness&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;score&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ok&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;comment&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 성공 정답 → targetFixed / condition 필드 비교&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 정답에 있는 키만 검사 (부분 reference 허용)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pred&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;targetFixed&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;et&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;targetFixed&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pred&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;condition&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;condition&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;mute&amp;#34;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;et&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;mute&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;mute&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;et&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;mute&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;et&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_as_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;_as_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;et&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;content&amp;#34;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;et&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_as_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;_as_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;et&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;recurrence&amp;#34;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;recurrence&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;recurrence&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;recurrence&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;delivery&amp;#34;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;delivery&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;delivery&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;_abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;delivery&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;expires&amp;#34;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;expires&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;expires&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;_abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;expires&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;passed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;checks&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;extract_rule_correctness&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;score&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;passed&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;comment&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LangSmith&lt;/code&gt;에서 &lt;code&gt;Target(handle)&lt;/code&gt; 반환값과 &lt;code&gt;Dataset example.outputs&lt;/code&gt; 의 결과값을 비교해 &lt;code&gt;0, 1&lt;/code&gt; 점(binary)으로 수치화함.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;handle&lt;/code&gt; 함수의 결과값 JSON 필드는 예상과 정확하게 나와야 하기 때문에, &lt;span class="high-mark"&gt;&lt;strong&gt;Code Based Evaluation&lt;/strong&gt;&lt;/span&gt;
을 진행함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="dataset-생성"&gt;Dataset 생성&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;예전 학부연구생 생활하면서, 같은 연구실 동기들에게 받은 32개의 예시에는 &lt;code&gt;ok=False&lt;/code&gt;가 너무 많아 평가가 편향될 것으로 예상되어, 10개로 줄였다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ok = True&lt;/code&gt; 는 40개 / &lt;code&gt;ok = False&lt;/code&gt; 는 10개로 개수를 맞춰 테스트를 진행할 예정이다.&lt;/li&gt;
&lt;li&gt;본 Evaluation에서는 사용자 자연어 요청으로부터 앱, 콘텐츠, 알림 허용/차단 및 시간 조건을 구조화된 JSON으로 정확하게 추출하는지를 검증하며, &lt;span class="high-mark"&gt;&lt;strong&gt;콘텐츠의 의미적 분류 정확도는 평가 범위에서 제외&lt;/strong&gt;&lt;/span&gt;
한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;figure &gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;&lt;img src="./image2.png" alt="LangSmith 결과화면" loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;의미적 분류 정확도는 현재 오류로 검증하지 않았지만, &lt;strong&gt;개선 사항&lt;/strong&gt;임.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;extra_rule_correctness&lt;/code&gt; = 0.76 : 왜 이 테스트 결과값이 나왔는지 점검 해봐야 한다.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Coding Test</title><link>https://inhyuk2000.github.io/blog/coding-test/practice_0811/</link><pubDate>Tue, 11 Aug 2026 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/blog/coding-test/practice_0811/</guid><description>&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;프로그래머스&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-purple-100 dark:bg-purple-900 border-purple-500"
data-callout="important"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-purple-600 dark:text-purple-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m9-.75a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9 3.75h.008v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;[Step1] 최소직사각형&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="분류"&gt;분류&lt;/h3&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;그리디&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 id="접근-방법"&gt;접근 방법&lt;/h3&gt;
&lt;p&gt;Max(가로), Max(세로)로 생각했지만, 명함을 눕혀 사이즈를 조정할 수 있음.
그러면 모든 명함을 한 방향으로 통일해서 정렬하고, 그 안에서 제일 큰 가로와 세로 길이를 측정하면 한 번에 해결할 수 있음.&lt;/p&gt;
&lt;h3 id="풀이-전략"&gt;풀이 전략&lt;/h3&gt;
&lt;p&gt;각 명함의 방향을 정규화해서 한 번 순회하는 풀이이다.
&lt;span class="high-mark"&gt;&lt;strong&gt;회전 가능한 데이터를 일정한 기준으로 정규화한 뒤 최댓값을 구한다.&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 id="관련-이론-정리"&gt;관련 이론 정리&lt;/h3&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-purple-100 dark:bg-purple-900 border-purple-500"
data-callout="important"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-purple-600 dark:text-purple-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m9-.75a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9 3.75h.008v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;[Step2] 주차 요금 계산&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="분류-1"&gt;분류&lt;/h3&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;구현&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 id="접근-방법-및-풀이-전략"&gt;접근 방법 및 풀이 전략&lt;/h3&gt;
&lt;p&gt;차량별로 Dictionary 자료구조를 활용해서 입 • 출차 기록을 모으고, 각 차량의 누적 주차 시간을 계산하여 요금을 한 번만 계산한다.&lt;/p&gt;
&lt;h3 id="내-코드"&gt;내 코드&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;math&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fees&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;def_min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;def_pri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unit_min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unit_pri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fees&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;car_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;car_num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_in_out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minute&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;:&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 데이터 삽입&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;car_num&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;car_dict&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;car_dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;car_num&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minute&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;is_in_out&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;car_dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;car_num&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minute&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;is_in_out&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;car_dict&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# 홀수개인 경우&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;car_dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;OUT&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;car_sort_keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;car_dict&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;car_dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;car_sort_key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;car_sort_keys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;period_min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;car_dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;car_sort_key&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;car_out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;car_dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;car_sort_key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;car_in&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;car_dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;car_sort_key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;period_min&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;car_out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;car_out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;car_in&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;car_in&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;period_min&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;def_min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;def_pri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;def_pri&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;period_min&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;def_min&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;unit_min&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;unit_pri&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="잘-작성된-class-기반-코드"&gt;잘 작성된 Class 기반 코드&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;math&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ceil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Parking&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fees&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fees&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fees&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_flag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inout&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_flag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;inout&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;IN&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_flag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;str2int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str2int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calc_fee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_flag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;23:59&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;out&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;add_t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fees&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fees&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add_t&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fees&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fees&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;add_t&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fees&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;str2int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fees&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;recordsDict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;Parking&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fees&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;rcd&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;car&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rcd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;recordsDict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;car&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;calc_fee&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;recordsDict&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;())]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="알아두면-좋을-개념"&gt;알아두면 좋을 개념&lt;/h3&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;from collections import defaultdict&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;파이썬의 일반 dict와 거의 같은데, &lt;span class="high-mark"&gt;&lt;strong&gt;존재하지 않는 key에 접근했을 때 기본값을 자동으로 만들어주는 딕셔너리&lt;/strong&gt;&lt;/span&gt;
이다.&lt;/dd&gt;
&lt;/dl&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;다음번에 Dictionary 자료구조를 이용해야 할 때, 한 번 활용&lt;/strong&gt;&lt;/span&gt;
해보자.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-purple-100 dark:bg-purple-900 border-purple-500"
data-callout="important"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-purple-600 dark:text-purple-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m9-.75a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9 3.75h.008v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;[Step3] k진수에서 소수 개수 구하기&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="분류-2"&gt;분류&lt;/h3&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;구현&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 id="접근-방법-및-풀이-전략-1"&gt;접근 방법 및 풀이 전략&lt;/h3&gt;
&lt;p&gt;문제에서 요구하는 과정을 순서대로 구현하는 &lt;strong&gt;구현 문제&lt;/strong&gt;로 접근하였다. 주어진 숫자를 &lt;code&gt;k진수&lt;/code&gt;로 변환한 뒤, &lt;code&gt;0&lt;/code&gt;을 기준으로 분리하고 각 숫자가 소수인지 판별하여 개수를 계산하였다.&lt;/p&gt;
&lt;h4 id="진법-변환"&gt;진법 변환&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parseTen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&gt;[::&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;문자열의 각 문자를 하나씩 뒤에서부터 카운팅하기 위해서는 &lt;code&gt;el[::-1]&lt;/code&gt;을 활용해 역순으로 찾아야 한다.&lt;/li&gt;
&lt;li&gt;index는 몇 제곱인지를 나타내므로 &lt;code&gt;10 ** index&lt;/code&gt;으로 나타내야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="소수-판별"&gt;소수 판별&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;isPrime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;처음에는 소수의 개수를 세줄때, &lt;code&gt;range(2, int(num))&lt;/code&gt; 으로 세어서 시간 초과가 발생하였다.&lt;/li&gt;
&lt;li&gt;소수 판별 시에는, &lt;span class="high-mark"&gt;&lt;strong&gt;[제곱근 + 1]&lt;/strong&gt;&lt;/span&gt;
개 만큼만 카운팅해주면 된다는 것을 기억하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-purple-100 dark:bg-purple-900 border-purple-500"
data-callout="important"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-purple-600 dark:text-purple-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m9-.75a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9 3.75h.008v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;[해시] 완주하지 못한 선수&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;part_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;part_dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;comp&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;part_dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;comp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;part_dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;comp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;part_dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;comp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;part_dict&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;())[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="접근-방법-1"&gt;접근 방법&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;defaultdict&lt;/code&gt;를 사용해 존재하지 않는 키에 접근할 경우, 자동 생성하도록 만들었다. 그 자동으로 생성할 때의 값을 뭘로 설정할 지를 &lt;code&gt;defaultdict&lt;/code&gt;의 인자로 넣어준다.&lt;/p&gt;
&lt;h3 id="풀이-전략-1"&gt;풀이 전략&lt;/h3&gt;
&lt;p&gt;문제 자체는 어렵지 않으나, 통과하기 위해서는 최적화를 통해 시간 단축이 필요하다. 따라서 list 사용해 이중 순회하는 것이 아니라 Dictionary를 사용해 O(1)의 시간복잡도로 조회 및 수정이 이루어지도록 설계했다.&lt;/p&gt;
&lt;hr&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-purple-100 dark:bg-purple-900 border-purple-500"
data-callout="important"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-purple-600 dark:text-purple-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m9-.75a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9 3.75h.008v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;[해시] 폰켓몬&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="접근-방법-및-풀이-전략-2"&gt;접근 방법 및 풀이 전략&lt;/h3&gt;
&lt;p&gt;마찬가지로 &lt;code&gt;defaultdict&lt;/code&gt; 함수를 사용해서 처음 빈 Dict의 경우 자동 생성이 되도록 작성했다. 해당 문제는 &lt;code&gt;(전체 총 개수) // 2&lt;/code&gt;와 &lt;code&gt;중복 제거한 개수&lt;/code&gt;를 비교하는 문항이다.&lt;/p&gt;</description></item><item><title>Study Schedule</title><link>https://inhyuk2000.github.io/blog/schedule/study-schedule/</link><pubDate>Tue, 11 Aug 2026 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/blog/schedule/study-schedule/</guid><description>&lt;h2 id="프로젝트-관련-발전-방향"&gt;프로젝트 관련 발전 방향&lt;/h2&gt;
&lt;p&gt;기존 프로젝트들은 시스템 구현과 실험까지는 진행했지만, 앞으로는 &lt;span class="high-mark"&gt;&lt;strong&gt;결과의 신뢰성을 정량적으로 검증하고 실제 서비스 환경에서 안정적으로 동작하는지 확인하는 과정&lt;/strong&gt;&lt;/span&gt;
을 더욱 보완할 필요가 있어 보인다.&lt;/p&gt;
&lt;p&gt;또한 이미 해왔던 프로젝트들을 &lt;strong&gt;이론적으로 보완하는 전략&lt;/strong&gt;이 필요해보인다.&lt;/p&gt;
&lt;p&gt;단순히 새로운 기술을 추가하기보다는 &lt;strong&gt;Baseline 설정 → Evaluation Dataset 구축 → 자동 평가 → Error Analysis → 구조 개선 → 재평가 → Reliability 강화 → 실제 사용자 검증&lt;/strong&gt;의 흐름으로 기존 프로젝트를 발전시키고자 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;멀티 에이전트 환각 탐지 및 교정&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;기존 실험 결과에 대한 정량적 검증 보완&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;평가 데이터셋 확대 및 Ground Truth 기준 명확화&lt;/li&gt;
&lt;li&gt;Hallucination Detection / Correction 성능을 측정할 수 있는 평가 지표 설계&lt;/li&gt;
&lt;li&gt;모델 조합 및 토론 전략별 성능 비교&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;Error Analysis를 통한 실패 유형 및 원인 분석&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;어떤 문제 유형에서 토론이 효과적인지 분석&lt;/li&gt;
&lt;li&gt;두 모델이 모두 오답인 경우, 한 모델만 오답인 경우 등 조건별 성능 비교&lt;/li&gt;
&lt;li&gt;잘못된 의견을 수용하거나 기존 정답을 오히려 수정하는 실패 사례 분석&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ablation Study 및 통계적 검증&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;토론 유무, 모델 조합, 토론 횟수 등에 따른 성능 차이 분석&lt;/li&gt;
&lt;li&gt;개선 결과가 실제로 유의미한 차이인지 통계적으로 검증&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;향후 RAG, Tool Use, Memory 등을 결합한 멀티 에이전트 구조로 확장 가능성 검토&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;자연어 기반 알림 전송 제어 시스템 개발&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;현재 시스템의 Baseline 구조와 성능 고정&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;현재 알림 관리자와 조건 추출자의 동작 구조 정리&lt;/li&gt;
&lt;li&gt;기존 Function Calling 기반 시스템의 성능을 이후 개선의 비교 기준으로 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Evaluation Dataset 구축&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;실제 사용자가 입력할 수 있는 다양한 자연어 요청 수집&lt;/li&gt;
&lt;li&gt;각 자연어 입력에 대응하는 JSON Ground Truth 직접 정의&lt;/li&gt;
&lt;li&gt;시간, 위치, 활동, 반복 조건 등 필드별 테스트 케이스 구성&lt;/li&gt;
&lt;li&gt;JSON 스키마를 구성하는 각 필드가 실제 서비스에 필요한 정보인지 재검토&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;자동 Evaluation Pipeline 구현&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;자연어 입력 → 조건 추출 → JSON 결과 생성 과정을 자동화&lt;/li&gt;
&lt;li&gt;Exact Match, Field-level Accuracy 등 평가 지표 설계&lt;/li&gt;
&lt;li&gt;시간 표현이나 동의어처럼 표현은 다르지만 의미가 동일한 결과의 평가 방식 고민&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;Error Analysis를 통한 알림 관리자·조건 추출자 로직 개선&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;현재 사용하는 구현 방식이 서비스 성능 측면에서 갖는 약점 분석&lt;/li&gt;
&lt;li&gt;시간, 위치, 활동, 반복 조건 등 필드별 오류 유형 분류&lt;/li&gt;
&lt;li&gt;Prompt 문제인지, JSON Schema 문제인지, 시스템 구조 문제인지 원인 분석&lt;/li&gt;
&lt;li&gt;분석 결과를 바탕으로 Prompt 및 구조 개선 후 v2 시스템 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;자연어 파싱 과정에서 오류 발생 시 대처 방안 설계&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JSON Schema Validation&lt;/li&gt;
&lt;li&gt;잘못된 결과에 대한 Retry&lt;/li&gt;
&lt;li&gt;조건 누락이나 해석 불가능한 요청에 대한 Fallback&lt;/li&gt;
&lt;li&gt;사용자에게 추가 정보를 요청해야 하는 경우에 대한 처리 방식 설계&lt;/li&gt;
&lt;li&gt;반복적인 실패나 무한 Retry를 방지하는 정책 고민&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LangGraph 도입 검토&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;조건 추출 → 검증 → 재추론 → 알림 생성 과정을 State 기반 Workflow로 관리&lt;/li&gt;
&lt;li&gt;Node / Edge / State 구조를 활용한 Agent Workflow 구현 가능성 검토&lt;/li&gt;
&lt;li&gt;단순히 기술을 적용하는 것보다 기존 구조 대비 실제 장점이 있는지 비교&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;v1과 개선된 v2 시스템 성능 비교 및 통계적 검증&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;동일 Evaluation Dataset을 활용해 개선 전후 성능 비교&lt;/li&gt;
&lt;li&gt;전체 정확도뿐만 아니라 Field별 성능 변화 분석&lt;/li&gt;
&lt;li&gt;개선 폭이 실제로 의미 있는 차이인지 통계적으로 검증&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reliability 강화&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Validation / Retry / Fallback 로직 적용&lt;/li&gt;
&lt;li&gt;API 오류, 네트워크 오류, LLM 응답 오류 등에 대한 예외 처리&lt;/li&gt;
&lt;li&gt;실제 서비스 환경에서 실패하더라도 안전하게 동작할 수 있는 구조 설계&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;실제 사용자 테스트 및 서비스 운영 경험 확보&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;테스트 사용자에게 앱 배포&lt;/li&gt;
&lt;li&gt;Firebase Analytics를 통한 실제 사용 패턴 확인&lt;/li&gt;
&lt;li&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;Firebase NotiLLM_Crashlytics&lt;/strong&gt;&lt;/span&gt;
를 통한 Crash 및 Error 분석&lt;/li&gt;
&lt;li&gt;실제 사용자 환경에서 발생한 문제를 기반으로 반복적인 개선&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;사용자 실험 및 Product 효과 검증&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;자연어 기반 알림 제어 기능이 실제로 사용자의 알림 관리 부담을 줄이는지 확인&lt;/li&gt;
&lt;li&gt;필요할 경우 기존 방식과 개선된 방식 간 사용자 실험 또는 A/B Test 진행&lt;/li&gt;
&lt;li&gt;모델 정확도뿐만 아니라 실제 사용자 경험 측면의 효과까지 검증&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;7호선 급행열차 최적 정차역 제안&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;데이터 분석과 관련한 추가적인 공부&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;계층적 클러스터링&lt;/li&gt;
&lt;li&gt;다중공선성 및 VIF&lt;/li&gt;
&lt;li&gt;PCA&lt;/li&gt;
&lt;li&gt;회귀분석&lt;/li&gt;
&lt;li&gt;p-value 및 가설검정&lt;/li&gt;
&lt;li&gt;머신러닝 / 딥러닝 기본 개념 복습&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;분석 결과를 설명하고 검증할 수 있는 통계적 기반 강화&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;단순히 모델을 적용하는 것에서 끝내지 않고 해당 방법을 선택한 이유 이해&lt;/li&gt;
&lt;li&gt;변수 선택과 모델링 과정의 통계적 타당성 검토&lt;/li&gt;
&lt;li&gt;결과의 해석 가능성과 신뢰성을 설명할 수 있도록 보완&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;그 외&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;최신 Generative AI 기술 학습&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Agentic AI&lt;/li&gt;
&lt;li&gt;Tool Use / Function Calling&lt;/li&gt;
&lt;li&gt;RAG&lt;/li&gt;
&lt;li&gt;Memory&lt;/li&gt;
&lt;li&gt;Multimodal Agent&lt;/li&gt;
&lt;li&gt;Multi-Agent System&lt;/li&gt;
&lt;li&gt;LLM Evaluation&lt;/li&gt;
&lt;li&gt;최신 논문 및 실제 서비스 Architecture 참고&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;AI 도구를 활용한 개발 방식 학습&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ChatGPT / Cursor 등을 적극적으로 활용해 구현 속도를 높이되, 생성된 코드를 그대로 사용하는 데 그치지 않기&lt;/li&gt;
&lt;li&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;왜&lt;/strong&gt;&lt;/span&gt;
해당 구조와 평가 방법을 선택했는지 직접 설명할 수 있는 수준까지 이해&lt;/li&gt;
&lt;li&gt;구현 자체보다 문제 정의, 설계, 평가 지표 선정, Error Analysis 및 결과 해석 능력을 중심으로 학습&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;코딩테스트&lt;/strong&gt;&lt;/span&gt;
꾸준히 준비&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;COMMON&lt;/strong&gt; 코몬 서비스 활용해서 &lt;strong&gt;하루에 4문제씩 풀이&lt;/strong&gt;하고, &lt;strong&gt;풀이 정리&lt;/strong&gt; 및 &lt;strong&gt;관련 개념 정리&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;추가 참조 자료&lt;/strong&gt;&lt;/span&gt;
는 계속 웹사이트에 공유하고 수강&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>전체 NotiLLM Schedule 및 Architecture 설계</title><link>https://inhyuk2000.github.io/blog/notillm/%EA%B8%B0%ED%9A%8D/</link><pubDate>Tue, 11 Aug 2026 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/blog/notillm/%EA%B8%B0%ED%9A%8D/</guid><description>&lt;h2 id="schedule"&gt;Schedule&lt;/h2&gt;
&lt;p&gt;단순히 기능을 추가하는 방식이 아니라, &lt;strong&gt;측정 가능한 기준을 세우고 반복적으로 개선하는 과정&lt;/strong&gt;을 중심으로 프로젝트를 진행했습니다.&lt;/p&gt;
&lt;p&gt;아래와 같이 단순한 LLM 기능 구현을 넘어, &lt;code&gt;Evaluation&lt;/code&gt; - &lt;code&gt;Optimization&lt;/code&gt; - &lt;code&gt;Validation&lt;/code&gt; - &lt;code&gt;Production&lt;/code&gt; 으로 이어지는 AI Engineering 전 과정을 경험하는 것을 목표로 합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align:center;"&gt;순서&lt;/th&gt;
&lt;th&gt;할 일&lt;/th&gt;
&lt;th&gt;핵심 산출물&lt;/th&gt;
&lt;th&gt;키우는 역량&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style="background-color: rgba(81, 255, 0, 0.18);"&gt;
&lt;td style="text-align:center;"&gt;&lt;small&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;현재 시스템 Baseline 고정&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;v1 구조/성능 기준&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;System Design&lt;/small&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="background-color: rgba(81, 255, 0, 0.18);"&gt;
&lt;td style="text-align:center;"&gt;&lt;small&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;Evaluation Dataset 구축&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;Ground Truth Dataset&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;LLM Evaluation&lt;/small&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="background-color: rgba(81, 255, 0, 0.18);"&gt;
&lt;td style="text-align:center;"&gt;&lt;small&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;자동 Evaluation 구현&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;평가 코드 + 지표&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;AI Engineering&lt;/small&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="background-color: rgba(81, 255, 0, 0.18);"&gt;
&lt;td style="text-align:center;"&gt;&lt;small&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;Error Analysis&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;실패 유형/원인&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;Problem Solving&lt;/small&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="background-color: rgba(255, 215, 0, 0.18);"&gt;
&lt;td style="text-align:center;"&gt;&lt;small&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;구조/Prompt 개선&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;v2&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;LLM Engineering&lt;/small&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="background-color: rgba(255, 0, 0, 0.18);"&gt;
&lt;td style="text-align:center;"&gt;&lt;small&gt;&lt;strong&gt;6&lt;/strong&gt;&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;LangGraph 도입 검토&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;Stateful Agent&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;Agent Engineering&lt;/small&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="background-color: rgba(255, 215, 0, 0.18);"&gt;
&lt;td style="text-align:center;"&gt;&lt;small&gt;&lt;strong&gt;7&lt;/strong&gt;&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;재평가 + 통계 검증&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;v1 vs v2 결과&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;Experimentation&lt;/small&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="background-color: rgba(255, 0, 0, 0.18);"&gt;
&lt;td style="text-align:center;"&gt;&lt;small&gt;&lt;strong&gt;8&lt;/strong&gt;&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;Reliability 강화&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;Retry/Fallback/Validation&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;Production AI&lt;/small&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style="background-color: rgba(255, 215, 0, 0.18);"&gt;
&lt;td style="text-align:center;"&gt;&lt;small&gt;&lt;strong&gt;9&lt;/strong&gt;&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;실제 사용자 배포&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;테스트 사용자&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;Product Engineering&lt;/small&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;&lt;small&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;Analytics/Crashlytics 분석&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;실사용 데이터&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;Product Analytics&lt;/small&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;&lt;small&gt;&lt;strong&gt;11&lt;/strong&gt;&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;사용자 실험/A-B Test&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;Product 효과 검증&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;Experiment Design&lt;/small&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align:center;"&gt;&lt;small&gt;&lt;strong&gt;12&lt;/strong&gt;&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;최종 포트폴리오 정리&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;GitHub/Portfolio&lt;/small&gt;&lt;/td&gt;
&lt;td&gt;&lt;small&gt;취업&lt;/small&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;본격적인 &lt;code&gt;Evaluation&lt;/code&gt;을 진행하기에 앞서서, 전체 &lt;code&gt;Architecture&lt;/code&gt;를 먼저 설계해 어느 부분을 평가할 지에 대한 계획을 수립했습니다.&lt;/p&gt;
&lt;h2 id="baseline-ver1-architecture"&gt;Baseline Ver.1 Architecture&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;Mermaid&lt;/strong&gt;&lt;/span&gt;
목적 : Evaluation 시, &lt;span class="high-mark"&gt;&lt;strong&gt;어느 Component에서 문제가 발생하는지 특정&lt;/strong&gt;&lt;/span&gt;
하기 위함&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ChatGPT-4o&lt;/code&gt; 모델로 &lt;code&gt;Function Calling&lt;/code&gt; 전체 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="mermaid"&gt;flowchart TB
user((User))
router["Router&lt;br/&gt;GPT-4o w/&lt;br/&gt;function calling"]
user --&gt;|chat command| router
router --&gt;|reply| user
parse[Parse User Intent]
choose[Choose mute / allow tool]
router --&gt; parse --&gt; choose
cond["extract_notification_condition&lt;br/&gt;(time / recurrence)"]
mute["extract_mute_target&lt;br/&gt;(name / content)"]
allow["extract_allow_target&lt;br/&gt;(name / content)"]
choose --&gt;|function call| cond
choose --&gt;|function call| mute
choose --&gt;|function call| allow
c1[Infer delivery / expires]
c2[Set recurrence / window]
m1[Extract mute apps / keywords]
m2[Normalize app names]
a1[Extract mute apps / keywords]
a2[Normalize app names]
cond --&gt; c1 --&gt; c2
mute --&gt; m1 --&gt; m2
allow --&gt; a1 --&gt; a2
c2 -.-&gt;|tool result| router
m2 -.-&gt;|tool result| router
a2 -.-&gt;|tool result| router
merge["PromptEngine Merge&lt;br/&gt;(target + condition)"]
inj[Inject mute flag]
build[Build target JSON]
cm[ContextManager]
mapPkg[Map app name to package]
validate[Validate delivery before expires]
save[Save rule to SQLite]
db[(SQLite)]
router --&gt;|two JSONs| merge
merge --&gt; inj --&gt; build --&gt; cm --&gt; mapPkg --&gt; validate --&gt; save
save --&gt;|Persist mode / apps / window| db
classDef userNode fill:#7eb8da,stroke:#4a90b8,color:#fff
classDef routerNode fill:#e8a0a0,stroke:#c07070,color:#222
classDef stepRed fill:#fff5f5,stroke:#c07070,color:#b33
classDef toolNode fill:#90c9a0,stroke:#5a9a6a,color:#222
classDef stepGreen fill:#f3faf5,stroke:#5a9a6a,color:#2a7a3a
classDef dbNode fill:#a8d5b5,stroke:#5a9a6a,color:#222
class user userNode
class router routerNode
class parse,choose,c1,c2,m1,m2,a1,a2 stepRed
class cond,mute,allow toolNode
class merge,cm stepGreen
class inj,build,mapPkg,validate,save stepGreen
class db dbNode
&lt;/div&gt;
&lt;h2 id="평가-방식"&gt;평가 방식&lt;/h2&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-yellow-100 dark:bg-yellow-900 border-yellow-500"
data-callout="question"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-yellow-700 dark:text-yellow-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9.879 7.519c1.172-1.025 3.071-1.025 4.243 0c1.171 1.025 1.171 2.687 0 3.712q-.308.268-.67.442c-.746.361-1.452.999-1.452 1.827v.75M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9 5.25h.008v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;각 Tools (&lt;code&gt;extract_notification_condition&lt;/code&gt;, &lt;code&gt;extract_mute_target&lt;/code&gt;, &lt;code&gt;extract_allow_target&lt;/code&gt;) 에 따라 &lt;strong&gt;어떤 평가 방식&lt;/strong&gt;을 사용해야 할까?&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;지금 평가 대상이 &lt;strong&gt;자유로운 자연어 답변이 아니라 스키마가 정해진 구조화된 JSON&lt;/strong&gt;이고, 이미 &lt;strong&gt;Ground Truth&lt;/strong&gt;를 만들 수 있다. 그래서 굳이 또 다른 LLM의 주관적 판단을 끼워 넣을 필요가 없다고 판단했습니다.&lt;/p&gt;
&lt;h3 id="평가-방식-선정"&gt;평가 방식 선정&lt;/h3&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-blue-100 dark:bg-blue-900 border-blue-500"
data-callout="check"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-blue-600 dark:text-blue-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m4.5 12.75l6 6l9-13.5"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;&lt;code&gt;Code-based evals&lt;/code&gt; 선정&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Function Calling&lt;/code&gt;의 출력이 정해진 &lt;code&gt;JSON Schema&lt;/code&gt;를 따르는 &lt;strong&gt;구조화된 데이터&lt;/strong&gt;이므로, 각 필드를 &lt;code&gt;Ground Truth&lt;/code&gt;와 직접 비교하는 &lt;span class="high-mark"&gt;&lt;strong&gt;Code-based Eval 방식&lt;/strong&gt;&lt;/span&gt;
을 사용하기로 결정했습니다.&lt;/p&gt;
&lt;h3 id="function-calling이-현재-출력하는-json-필드"&gt;Function Calling이 현재 출력하는 JSON 필드&lt;/h3&gt;
&lt;div class="schema-tool-grid"&gt;
&lt;!-- LEFT : 50% WIDTH / 100% HEIGHT --&gt;
&lt;div class="schema-tool-panel"&gt;
&lt;div class="schema-tool-label"&gt;
extract_notification_condition
&lt;/div&gt;
&lt;pre class="schema-tool-pre"&gt;&lt;code&gt;{
"name": "extract_notification_condition",
"parameters": {
"type": "object",
"additionalProperties": false,
"properties": {
"delivery": {
"type": "object",
"additionalProperties": false,
"properties": {
"absolute": { "type": "string" }
},
"required": ["absolute"]
},
"activity": {
"type": ["string", "null"]
},
"location": {
"type": ["string", "null"]
},
"expires": {
"type": "object",
"additionalProperties": false,
"properties": {
"absolute": { "type": "string" }
},
"required": ["absolute"]
},
"recurrence": {
"type": "string",
"enum": ["none", "daily", "weekly"]
},
"days_of_week": {
"type": "array",
"items": {
"type": "integer"
}
},
"window_start": {
"type": ["string", "null"]
},
"window_end": {
"type": ["string", "null"]
}
},
"required": [
"delivery",
"activity",
"location",
"expires",
"recurrence",
"days_of_week",
"window_start",
"window_end"
]
}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- RIGHT : 50% WIDTH --&gt;
&lt;div class="schema-tool-stack"&gt;
&lt;!-- RIGHT TOP : 50% HEIGHT --&gt;
&lt;div class="schema-tool-panel"&gt;
&lt;div class="schema-tool-label"&gt;
extract_mute_target
&lt;/div&gt;
&lt;pre class="schema-tool-pre"&gt;&lt;code&gt;{
"name": "extract_mute_target",
"parameters": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "array",
"items": {
"type": ["string", "null"]
}
},
"content": {
"type": "array",
"items": {
"type": ["string", "null"]
}
}
},
"required": [
"name",
"content"
]
}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- RIGHT BOTTOM : 50% HEIGHT --&gt;
&lt;div class="schema-tool-panel"&gt;
&lt;div class="schema-tool-label"&gt;
extract_allow_target
&lt;/div&gt;
&lt;pre class="schema-tool-pre"&gt;&lt;code&gt;{
"name": "extract_allow_target",
"parameters": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "array",
"items": {
"type": ["string", "null"]
}
},
"content": {
"type": "array",
"items": {
"type": ["string", "null"]
}
}
},
"required": [
"name",
"content"
]
}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>NotiLLM_Crashlytics</title><link>https://inhyuk2000.github.io/blog/notillm/crashlytics/</link><pubDate>Wed, 05 Aug 2026 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/blog/notillm/crashlytics/</guid><description>&lt;h2 id="firebase-crashlytics-연동"&gt;Firebase Crashlytics 연동&lt;/h2&gt;
&lt;h3 id="목적"&gt;목적&lt;/h3&gt;
&lt;p&gt;앱이 강제 종료되거나 예외가 발생했을 때, 사용자가 로그를 보내지 않아도 Firebase Console에서 비정상 종료 보고서를 확인할 수 있도록 했다.&lt;/p&gt;
&lt;h3 id="사전-조건"&gt;사전 조건&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;최소 요구&lt;/th&gt;
&lt;th&gt;본 프로젝트&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gradle&lt;/td&gt;
&lt;td&gt;8.0&lt;/td&gt;
&lt;td&gt;8.13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Android Gradle Plugin&lt;/td&gt;
&lt;td&gt;8.1.0&lt;/td&gt;
&lt;td&gt;8.11.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google services 플러그인&lt;/td&gt;
&lt;td&gt;4.4.1&lt;/td&gt;
&lt;td&gt;4.4.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;app/google-services.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;필요&lt;/td&gt;
&lt;td&gt;사용 중&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="코드-변경-요약"&gt;코드 변경 요약&lt;/h3&gt;
&lt;h4 id="1-프로젝트-수준-buildgradlekts"&gt;1. 프로젝트 수준 (&lt;code&gt;build.gradle.kts&lt;/code&gt;)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Crashlytics Gradle 플러그인 추가&lt;br&gt;
&lt;code&gt;id(&amp;quot;com.google.firebase.crashlytics&amp;quot;) version &amp;quot;3.0.3&amp;quot; apply false&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-앱-모듈-appbuildgradlekts"&gt;2. 앱 모듈 (&lt;code&gt;app/build.gradle.kts&lt;/code&gt;)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;google-services.json&lt;/code&gt;이 있을 때 플러그인 적용
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;com.google.gms.google-services&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;com.google.firebase.crashlytics&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Firebase 의존성 추가 (BoM 사용, 버전 미지정)
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;firebase-crashlytics&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;firebase-analytics&lt;/code&gt; (탐색경로 로그용)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-테스트-비정상-종료-ui"&gt;3. 테스트 비정상 종료 UI&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;위치: 프로필 화면 (&lt;code&gt;ProfileScreen&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;debug 빌드에서만 &lt;strong&gt;Test Crash&lt;/strong&gt; 버튼 표시&lt;/li&gt;
&lt;li&gt;동작: &lt;code&gt;throw RuntimeException(&amp;quot;Test Crash&amp;quot;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="검증-절차"&gt;검증 절차&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Firebase Console → &lt;strong&gt;Crashlytics&lt;/strong&gt; 사용 설정&lt;/li&gt;
&lt;li&gt;(권장) 프로젝트 설정 → 통합에서 &lt;strong&gt;Google Analytics&lt;/strong&gt; 사용 설정&lt;/li&gt;
&lt;li&gt;앱 빌드 후 설치·실행&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로필&lt;/strong&gt; → &lt;strong&gt;Test Crash&lt;/strong&gt; 탭 → 앱 강제 종료&lt;/li&gt;
&lt;li&gt;앱을 &lt;strong&gt;다시 실행&lt;/strong&gt; (이때 보고서 전송)&lt;/li&gt;
&lt;li&gt;Firebase Console → Crashlytics에서 &lt;code&gt;Test Crash&lt;/code&gt; 확인
&lt;ul&gt;
&lt;li&gt;반영까지 수 분 소요될 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="참고"&gt;참고&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Test Crash 버튼은 &lt;code&gt;BuildConfig.DEBUG&lt;/code&gt;일 때만 보이므로 release에는 노출되지 않음&lt;/li&gt;
&lt;li&gt;확인 완료 후 테스트 버튼 코드는 제거해도 됨&lt;/li&gt;
&lt;li&gt;Crashlytics는 크래시/ANR 등 &lt;strong&gt;비정상 종료&lt;/strong&gt;용이며, LLM 실패·규칙 생성 실패 등 &lt;strong&gt;비즈니스 로그&lt;/strong&gt;는 Realtime Database 원격 로그로 별도 설계 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="느낀점"&gt;느낀점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;가까운 지인에게 테스트를 부탁하면서 연령층 별로 생각보다 입력하는 메시지의 느낌이 다르다는 것을 느꼈다. &amp;ldquo;받지마/받아줘&amp;rdquo; 보다는 &amp;ldquo;보류&amp;quot;라는 단어를 사용하는 케이스가 있었다. 또한 &amp;ldquo;카카오톡 메시지&amp;quot;라는 말을 &amp;ldquo;카카오톡&amp;rdquo; 앱의 &amp;ldquo;메시지&amp;rdquo; 키워드로 잘못 등록하는 케이스도 존재했다. 해당 케이스에 대해서는 어떻게 컨트롤하고 제어 조건으로 설정하기 위해 프롬프팅해줘야 할 지 고민이 필요해 보였다.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>NotiLLM : LLM 기반 자연어 알림 전송 제어</title><link>https://inhyuk2000.github.io/projects/notillm/</link><pubDate>Tue, 04 Aug 2026 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/projects/notillm/</guid><description>
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-orange-100 dark:bg-orange-900 border-orange-500"
data-callout="warning"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-orange-600 dark:text-orange-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0zM12 15.75h.007v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;해당 서비스는 연구실의 아이디어를 기반으로 서비스화한 것으로, 관련 저작권은 연구실에 있습니다.&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-purple-100 dark:bg-purple-900 border-purple-500"
data-callout="important"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-purple-600 dark:text-purple-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m9-.75a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9 3.75h.008v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;정리예정 진행중입니다.&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="요약"&gt;요약&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 이름&lt;/strong&gt;: NotiLLM&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 기간&lt;/strong&gt;: 2026.07 ~ (진행중)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 설명&lt;/strong&gt;: LLM Agent를 실서비스로 배포하고, 수집된 사용자 데이터를 기반으로 데이터 분석&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 목적&lt;/strong&gt;: 수집된 데이터를 분석해 추가 아이디어 확장&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="problem"&gt;Problem&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;기존 수동제어 기반 방식은 사용자의 직접 설정을 필요로 하므로, &lt;strong&gt;사용자 부담이 증가&lt;/strong&gt;하고 사용성이 떨어집니다.&lt;/li&gt;
&lt;li&gt;반대로 ML 기반 알림 수신 타이밍 예측 방식들은 정확성을 높이기 위한 연구들이 많이 진행되고 있지만, 근본적으로 사용자의 비언어적 신호를 기반으로 하기에 &lt;strong&gt;예측이 부정확&lt;/strong&gt;합니다.&lt;/li&gt;
&lt;li&gt;따라서 본 연구는 수동 제어 방식의 불편함과 모델 기반 방식의 부정확성을 둘 다 잡고 해결하기 위해, &lt;strong&gt;LLM 기반 사용자 제어&lt;/strong&gt;를 진행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-blue-100 dark:bg-blue-900 border-blue-500"
data-callout="note"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-blue-600 dark:text-blue-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m16.862 4.487l1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8l.8-2.685a4.5 4.5 0 0 1 1.13-1.897zm0 0L19.5 7.125"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;본 서비스는 연구실의 아이디어를 실제 서비스로 확장하고, 배포 및 운영 경험을 바탕으로 후속 연구 및 서비스 고도화를 진행하기 위한 목적으로 개발되었습니다.&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;figure &gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;
&lt;img alt="Architecture"
srcset="https://inhyuk2000.github.io/projects/notillm/img/chat-screen_hu_c521ae42cf5fbdb9.webp 320w, https://inhyuk2000.github.io/projects/notillm/img/chat-screen_hu_41301439f970b9a2.webp 480w, https://inhyuk2000.github.io/projects/notillm/img/chat-screen_hu_8af69f2d87435f76.webp 760w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 90vw, (max-width: 1024px) 80vw, 760px"
src="https://inhyuk2000.github.io/projects/notillm/img/chat-screen_hu_c521ae42cf5fbdb9.webp"
width="760"
height="648"
loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id="서비스-디자인"&gt;서비스 디자인&lt;/h3&gt;
&lt;p&gt;Figma를 활용해 실제 서비스에 가까운 수준으로 UI/UX를 디자인했습니다. 화면을 구성할 때는 사용성을 고려해 버튼과 텍스트의 배치를 설계하고, 사용자에게 어떤 정보를 효과적으로 제공할지 중점적으로 고민했습니다. &lt;span class="high-mark"&gt;&lt;strong&gt;[1] 특히 알림 피로가 얼마나 줄어들었는지 사용자가 직접 확인할 수 있도록 차단된 알림의 실시간 통계 기능을 추가&lt;/strong&gt;&lt;/span&gt;
했습니다. 또한 필요한 경우 &lt;span class="high-mark"&gt;&lt;strong&gt;[2] 모든 알림을 한 번에 확인할 수 있는 버튼을 제공&lt;/strong&gt;&lt;/span&gt;
하고, 홈 화면 하단에서는 &lt;span class="high-mark"&gt;&lt;strong&gt;[3] 수신된 알림을 앱별로 요약&lt;/strong&gt;&lt;/span&gt;
해 확인할 수 있도록 구성했습니다.&lt;/p&gt;
&lt;h3 id="시스템-설계-확장"&gt;시스템 설계 확장&lt;/h3&gt;
&lt;p&gt;Function Calling을 통해 사용자의 자연어를 JSON 구조로 변환할 때는 기본 동작을 &amp;ldquo;알림을 허용(받아줘 Default)&amp;ldquo;으로 할지, &amp;ldquo;알림을 차단(받지마 Default)&amp;ldquo;으로 할지 설계 방향을 결정해야 했습니다. &lt;strong&gt;연구를 진행하면서 한 가지 방식만 적용할 경우 예상하지 못한 반례가 발생한다는 점을 확인&lt;/strong&gt;했습니다. 이를 해결하기 위해 두 가지 기본 동작을 모두 지원하도록 Function Calling을 설계하여 다양한 명령을 유연하게 처리할 수 있도록 확장했습니다. 그 결과 &lt;span class="high-mark"&gt;&lt;strong&gt;기존에는 처리하기 어려웠던 &amp;ldquo;매일&amp;rdquo;, &amp;ldquo;평일만&amp;rdquo;, &amp;ldquo;주말만&amp;quot;과 같은 반복 · 주기성 명령까지 안정적으로 지원&lt;/strong&gt;&lt;/span&gt;
할 수 있었습니다.&lt;/p&gt;
&lt;h3 id="느낀점"&gt;느낀점&lt;/h3&gt;
&lt;p&gt;테스트를 진행하며 다양한 사용자층을 확보하는 것이 중요하다는 점을 느꼈습니다. 현재는 테스트 사용자가 가까운 지인들로 한정되어 있어 충분히 의미 있는 인사이트를 도출하지는 못했지만, &lt;span class="high-mark"&gt;&lt;strong&gt;연령대에 따라 사용하는 표현과 언어 습관에 차이가 있다는 점을 확인&lt;/strong&gt;&lt;/span&gt;
할 수 있었습니다. 이를 통해 Function Calling 프롬프트를 제 언어 습관과 표현 방식을 중심으로 설계했다는 한계를 깨달았으며, 향후에는 다양한 사용자 표현을 수집하고 반영해 자연어 명령에 대한 처리 범위를 확장해야 한다고 판단했습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Questions? Leave a comment below or reach out on
!&lt;/p&gt;</description></item><item><title>LLM을 활용한 자연어 기반 알림 전송 제어 시스템 개발</title><link>https://inhyuk2000.github.io/projects/a-natural-language-based-notification-delivery-control-system-using-llm/</link><pubDate>Tue, 15 Jul 2025 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/projects/a-natural-language-based-notification-delivery-control-system-using-llm/</guid><description>&lt;h4 id="-paper"&gt;📄 Paper&lt;/h4&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;KSC 2025 Paper Accept&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;📑
&lt;/p&gt;
&lt;h4 id="-poster"&gt;🖼️ Poster&lt;/h4&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;KCC 2025 Conference Poster&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;📄
&lt;/p&gt;
&lt;h3 id="요약"&gt;요약&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 이름&lt;/strong&gt;: LLM을 활용한 자연어 기반 알림 전송 제어 시스템 개발&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 기간&lt;/strong&gt;: 2025.07 ~ 2025.11&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 설명&lt;/strong&gt;: 사용자의 자연어 명령에서 알림 수신 조건과 대상을 추출하고, 조건에 맞는 알림만 선별적으로 전송하는 LLM 기반 모바일 알림 제어 시스템&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 목적&lt;/strong&gt;: 복잡한 수동 설정 과정과 머신러닝 기반 자동 예측의 부정확성을 개선하여 사용자가 자연어만으로 원하는 알림 수신 조건을 설정할 수 있도록 지원&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;데이터 출처&lt;/strong&gt;: 사용자 7명으로부터 수집한 자연어 명령 시나리오 24개&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;주요 설계 대상&lt;/strong&gt;: 시간·장소·활동을 나타내는 조건 필드와 앱·키워드를 나타내는 대상 필드&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 성과&lt;/strong&gt;: KSC 2025 논문 발표 및 Paper Accept&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;code&gt;연구 시작 배경&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;알림을 일일히 &lt;strong&gt;수동으로 설정&lt;/strong&gt;하기 어렵다.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;현재 알림 시스템은 시간/앱/내용/패턴 등의 &lt;strong&gt;컨텍스트&lt;/strong&gt;를 충분히 고려하지 못한다.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이로 인해, &lt;strong&gt;사용자가 에이전트에게 알림 커스터마이징을 요청했을 때, 자동으로 커스터마이징 해주는 기능&lt;/strong&gt;을 핵심 아이디어로 도출함.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;구현 가능성 기술 조사&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Google Assistant&lt;/code&gt;, &lt;code&gt;Bixby&lt;/code&gt;, &lt;code&gt;Gemini&lt;/code&gt; 의 기존 음성 에이전트로 구현 가능성 조사
&lt;ul&gt;
&lt;li&gt;단순 앱 실행이 아니라 &lt;strong&gt;앱 내부의 특정 알림 제어 기능까지 자연어로 실행할 수 있는지&lt;/strong&gt; 조사함.&lt;/li&gt;
&lt;li&gt;Google Assistant의 App Actions, Shortcut / Bixby Capsule / Gemini 연동 가능성을 각각 확인함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-yellow-100 dark:bg-yellow-900 border-yellow-500"
data-callout="question"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-yellow-700 dark:text-yellow-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9.879 7.519c1.172-1.025 3.071-1.025 4.243 0c1.171 1.025 1.171 2.687 0 3.712q-.308.268-.67.442c-.746.361-1.452.999-1.452 1.827v.75M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9 5.25h.008v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;하지만 &lt;strong&gt;Google Assistant&lt;/strong&gt; 는 &lt;code&gt;App Actions&lt;/code&gt;, &lt;code&gt;Shortcut&lt;/code&gt; 중심으로 미리 정의된 액션에 매핑해야 하는 제약이 있고, 테스트 도구도 &lt;code&gt;Google Console&lt;/code&gt;에 너무 의존하고 있었음. &lt;strong&gt;Gemini&lt;/strong&gt;는 앱을 열어주는 수준이 아니라 앱 내부 알림 데이터를 자유롭게 제어하는 수준이 불가능했음. 마지막으로 &lt;strong&gt;Bixby Capsule&lt;/strong&gt;은 그나마 가능성이 있어시 실제 프로토타입까지 만들어 보았지만, 사용자의 자유로운 명령에 대응하기 위한 &lt;code&gt;goal&lt;/code&gt;, &lt;code&gt;intent&lt;/code&gt;, &lt;code&gt;training&lt;/code&gt; 등 사전 정의 작업이 필요했음.&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;결국 위 세가지 방식들은 전부 기각하고, &lt;code&gt;LLM Function Calling&lt;/code&gt; 기술을 기반으로 직접 구현하기로 결정.&lt;/p&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-blue-100 dark:bg-blue-900 border-blue-500"
data-callout="note"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-blue-600 dark:text-blue-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m16.862 4.487l1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8l.8-2.685a4.5 4.5 0 0 1 1.13-1.897zm0 0L19.5 7.125"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;LLM Function Calling&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;포폴에 작성된 내용&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;사용자 수집 데이터 기반 자료구조 설계 (JSON Schema)&lt;/li&gt;
&lt;li&gt;시스템 구조 설계 (알림 관리자, 조건 추출자)&lt;/li&gt;
&lt;li&gt;개발&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;포폴 이후 NotiLLM 개인 프로젝트 발전&lt;/code&gt; &lt;span class="high-mark"&gt;&lt;strong&gt;진행중&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;목표: &lt;strong&gt;LLM 시스템 Evaluation&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;LangChain&lt;/code&gt; 및 &lt;code&gt;LangGraph&lt;/code&gt;를 활용해 Version 개선&lt;/strong&gt;, &lt;strong&gt;부하 테스트&lt;/strong&gt;, &lt;strong&gt;배포&lt;/strong&gt;, &lt;strong&gt;사용자 피드백&lt;/strong&gt; 진행해 연구를 개선하는 것.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="자료구조-시나리오-설계-과정"&gt;자료구조 시나리오 설계 과정&lt;/h3&gt;
&lt;p&gt;사용자의 자연어를 Function Calling 기능을 활용해 JSON 구조로 변환해야겠다고 결정했을 때, 두 가지 조건을 결정해야 했습니다. 따라서 &lt;span class="high-mark"&gt;&lt;strong&gt;&amp;ldquo;알림을 언제 보내줘야 하지?&amp;rdquo;&lt;/strong&gt;&lt;/span&gt;
, &lt;span class="high-mark"&gt;&lt;strong&gt;&amp;ldquo;어떤 유형의 알림을 보내줘야 하지?&amp;rdquo;&lt;/strong&gt;&lt;/span&gt;
와 같은 결정을 내리기 위해서, 저는 8명의 참여자들로부터 총 24개의 질문 시나리오를 받고, 이를 바탕으로 가능한 JSON 구조를 설계했습니다.&lt;/p&gt;
&lt;h4 id="json-schema-설계"&gt;JSON Schema 설계&lt;/h4&gt;
&lt;p&gt;참여자들의 자연어 명령을 분석한 결과, 알림 제어에 필요한 정보는 크게 &lt;strong&gt;알림 대상(Notification Target)&lt;/strong&gt; 과 &lt;strong&gt;알림 조건(Notification Condition)&lt;/strong&gt; 으로 구분할 수 있었습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Notification Target&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;앱 이름을 기반으로 알림을 필터링&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;content&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;알림 제목 및 본문의 키워드를 기반으로 알림을 필터링&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Notification Condition&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;time.relative&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;현재 시점을 기준으로 한 상대 시간 (예: 5분 후)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;time.absolute&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;특정 절대 시간 (예: 오후 3시)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;activity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;사용자의 현재 활동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;location&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;사용자의 현재 위치&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;이를 바탕으로 다음과 같은 JSON 구조를 설계했습니다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;extract_notification_target&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;extract_notification_condition&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;relative&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;absolute&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;activity&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;location&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="작동-시스템-설계"&gt;작동 시스템 설계&lt;/h3&gt;
&lt;p&gt;이후 사용자의 자연어 명령을 위와 같이 JSON 자료구조로 변환하는 &lt;span class="high-mark"&gt;&lt;strong&gt;NotificationParser&lt;/strong&gt;&lt;/span&gt;
와 데이터베이스에 저장된 알림 내용들과 조건 목록들을 모니터링하는 &lt;span class="high-mark"&gt;&lt;strong&gt;ContextManager&lt;/strong&gt;&lt;/span&gt;
를 두 핵심 기능으로 삼아 개발을 진행했습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="트러블슈팅-과정"&gt;트러블슈팅 과정&lt;/h3&gt;
&lt;p&gt;해당 기능을 구현한 뒤 실제 환경에서 테스트하는 과정에서 예상치 못한 문제가 발생했습니다. 2025년 4월 One UI 7 업데이트 이후 &lt;strong&gt;알림에 표시되는 앱 아이콘이 시스템에 의해 임의로 변경&lt;/strong&gt;되었으며, 삼성의 내부 프레임워크가 공개되어 있지 않아 코드 수정만으로는 기존과 동일한 smallIcon을 가져올 수 없었습니다.&lt;/p&gt;
&lt;p&gt;약 2개월간 다양한 해결 방법을 검토했지만, 최종적으로 애플리케이션 코드 수준에서는 해결하기 어렵다는 결론에 도달했습니다. 이에 &lt;span class="high-mark"&gt;&lt;strong&gt;시스템 설정에서 알림 표시 방식을 이전 버전과 유사하게 변경하는 방법을 사용자에게 안내하는 방식으로 우회책을 마련&lt;/strong&gt;&lt;/span&gt;
했습니다. 이를 통해 개발 과정에서는 코드 개선뿐만 아니라 플랫폼의 제약을 파악하고, 제한된 환경 안에서 사용자 경험을 보완할 수 있는 현실적인 대안을 찾는 것 역시 중요하다는 점을 배웠습니다.&lt;/p&gt;
&lt;h3 id="프로젝트를-진행하며-느낀점"&gt;프로젝트를 진행하며 느낀점&lt;/h3&gt;
&lt;p&gt;알림 관련 문제 상황을 제가 제일 관심이 많이 있는 LLM 모델과 결합하다가 나온 연구 주제입니다. 선배분의 아이디어 기획 능력으로 초반 아이디어 구체화 부분은 수월하게 진행되었지만, 이후 자료구조 설계와 사용자 조사, 그리고 개발 및 논문 작성까지 주도적으로 작성하게 되어서 힘들었지만 많이 배우고 성장할 수 있는 뜻깊은 시간이었습니다. 문제 분석 - 기획 - 해결 아이디어 탐색 - 개발 - 논문 작성 까지의 일련의 흐름을 거치니, 논문과 프로젝트의 퀄리티를 좌지우지하는 중요한 과정은 개발이 아닌 &lt;span class="high-mark"&gt;&lt;strong&gt;문제 분석과 기획&lt;/strong&gt;&lt;/span&gt;
임을 다시 한 번 느꼈습니다. 또한 개발을 진행하는 과정에서 Android 버전이 바뀌어 아이콘이 깨지는 문제를 한동안 해결하느라 고생했던 것 같습니다. 이러한 예상치 못했던 문제에 대한 &lt;span class="high-mark"&gt;&lt;strong&gt;트러블슈팅 과정&lt;/strong&gt;&lt;/span&gt;
역시 저를 더 성장하게 해준 계기가 되었던 것 같습니다.&lt;/p&gt;</description></item><item><title>다중 언어 모델 기반 멀티 에이전트 챗봇 토론 프레임워크를 통한 환각 탐지 및 교정</title><link>https://inhyuk2000.github.io/projects/a-multi-agent-debate-framework-of-multiple-language-models-for-hallucination-detection-correction/</link><pubDate>Tue, 15 Jul 2025 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/projects/a-multi-agent-debate-framework-of-multiple-language-models-for-hallucination-detection-correction/</guid><description>&lt;h4 id="-paper"&gt;📄 Paper&lt;/h4&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;다중 언어 모델 기반 멀티 에이전트 챗봇 토론 프레임워크를 통한 환각 탐지 및 교정&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;📑
&lt;/p&gt;
&lt;h4 id="-poster"&gt;🖼️ Poster&lt;/h4&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;KCC 2025 Conference Poster&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;📄
&lt;/p&gt;
&lt;h4 id="-award"&gt;🏆 Award&lt;/h4&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;KCC 2025 Best Poster Award (최우수상)&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;🏅
&lt;/p&gt;
&lt;br/&gt;
&lt;h3 id="요약"&gt;요약&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 이름&lt;/strong&gt; : 다중 언어 모델 기반 멀티 에이전트 챗봇 토론 프레임워크를 통한 환각 탐지 및 교정&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 기간&lt;/strong&gt; : 2025.03 ~ 2025.07&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 설명&lt;/strong&gt; : 서로 다른 LLM이 독립적으로 생성한 답변을 비교하고, 답변이 일치하지 않을 경우 토론을 통해 상호 검증하는 멀티 에이전트 프레임워크&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 목적&lt;/strong&gt; : 단일 모델의 학습 데이터 편향과 자체 검증 기능 부족으로 발생하는 환각 문제를 완화하고 답변의 정확성과 논리적 일관성을 향상&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;검증 데이터&lt;/strong&gt; : 2025학년도 대학수학능력시험 전 문항&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;주요 분석 대상&lt;/strong&gt; : 모델 간 답변이 달랐던 수능 66문항&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 성과&lt;/strong&gt; : KCC 2025 논문 발표 및 Best Poster Award 수상&lt;/li&gt;
&lt;/ul&gt;
&lt;br/&gt;
&lt;h3 id="llm-api를-활용"&gt;LLM API를 활용&lt;/h3&gt;
&lt;p&gt;해당 연구는 LLM의 내부 구조나 핵심 처리 로직을 직접 수정하는 방식으로 진행한 연구는 아닙니다. 연구의 핵심 가설은 &lt;span class="high-mark"&gt;&lt;strong&gt;서로 다른 학습 데이터와 추론 특성을 가진 LLM 간의 토론이 답변의 오류를 발견하고 교정하는 데 유의미할 것&lt;/strong&gt;&lt;/span&gt;
이라는 점이었습니다.&lt;/p&gt;
&lt;p&gt;이를 검증하기 위해 유사한 수준의 지식 및 추론 성능을 가진 ChatGPT와 Gemini 모델을 선정하고, 각 모델의 API를 활용해 멀티 에이전트 토론 시스템을 구축했습니다. 각 모델이 독립적으로 답변을 생성한 뒤, 상대 모델의 답변과 반박 내용을 다음 요청의 Context에 포함해 재추론하도록 설계함으로써 두 모델이 반복적으로 의견을 검토하고 답변을 수정할 수 있도록 구현했습니다.&lt;/p&gt;
&lt;h3 id="구현-및-검증-과정"&gt;구현 및 검증 과정&lt;/h3&gt;
&lt;p&gt;해당 연구에서 핵심으로 하고 있던 아이디어를 생각해봤을 때, &lt;span class="high-mark"&gt;&lt;strong&gt;결론 역시 유의미할 것이라고 판단되어 프레임워크 개발을 우선적으로 진행&lt;/strong&gt;&lt;/span&gt;
했습니다. 이후 환각 발생 여부를 정확히 판단하기 위해 수능문항을 데이터셋으로 선정하게 되었고 일주일에 걸쳐 검증 및 결과 분석을 진행했습니다.&lt;/p&gt;
&lt;p&gt;연구를 진행하는 과정에서 &lt;span class="high-mark"&gt;&lt;strong&gt;연구 방법론에 대한 근본적인 의문&lt;/strong&gt;&lt;/span&gt;
도 들었습니다. 이번 연구는 가설과 부합하는 유의미한 결과를 얻어 논문 게재와 학술대회 입상으로 이어졌지만, &lt;strong&gt;만약 기대했던 결과가 나타나지 않았다면 연구 전체를 처음부터 다시 설계해야 하는지 고민&lt;/strong&gt;하게 되었습니다.&lt;/p&gt;
&lt;p&gt;해당 고민을 연구실 세미나에서 교수님께 질문하며 논의했지만, 예상과 다른 결과가 나오는 상황을 사전에 완전히 방지할 수 있는 명확한 해답은 찾지 못했습니다.&lt;/p&gt;
&lt;h3 id="논문-합격-후-발표-포스터-제작"&gt;논문 합격 후 발표 포스터 제작&lt;/h3&gt;
&lt;p&gt;발표 포스터를 제작할 때는 KHUDA 프로젝트를 진행하며 접했던 다른 학우들의 다양한 포스터와 발표 자료가 큰 도움이 되었습니다. 여러 디자인 사례를 참고한 경험을 바탕으로 완성도 높은 포스터의 특징을 파악할 수 있었고, &lt;strong&gt;핵심 내용을 한눈에 전달하기 위한 정보 배치와 시각적 구성 방식을 실제 제작 과정에 적용&lt;/strong&gt;할 수 있었습니다.&lt;/p&gt;
&lt;h3 id="프로젝트를-진행하며-느낀점"&gt;프로젝트를 진행하며 느낀점&lt;/h3&gt;
&lt;p&gt;일상 속에서 문제를 발견하고 이를 해결하기 위한 실용적인 연구를 수행하는 과정은 매우 흥미로웠으며, 이는 제가 컴퓨터공학으로 전과한 근본적인 이유와도 맞닿아 있었습니다. 다만 막연한 문제의식을 구체적인 연구 문제로 발전시키고, 기존 연구와의 명확한 차별점을 만드는 과정은 생각보다 훨씬 어려웠습니다. 이로 인해 기획 단계에 많은 시간을 투자하며 연구 주제를 처음부터 다시 검토하고 수정하는 과정을 여러 차례 반복했습니다.&lt;/p&gt;
&lt;p&gt;이 과정에서 &lt;strong&gt;XMind를 활용해 아이디어와 관련 문제를 구조화하고, 연구 주제를 더 깊이 탐색하는 훈련을 지속&lt;/strong&gt;했습니다. 그 결과 &lt;span class="high-mark"&gt;&lt;strong&gt;문제를 구체화하고 연구 방향을 설계하는 역량을 키울 수 있었으며, 연구의 완성도를 결정하는 데 기획 단계가 얼마나 중요한지도 깊이 체감&lt;/strong&gt;&lt;/span&gt;
했습니다.&lt;/p&gt;
&lt;p&gt;첫 연구를 논문으로 발전시키고 &lt;strong&gt;최우수상&lt;/strong&gt;이라는 값진 성과까지 얻을 수 있었지만, 이는 저 혼자만의 노력으로 만들어진 결과는 아니었습니다. 연구 방향을 지도해주신 교수님과 논문 작성 과정에서 도움을 주신 선배의 조언과 협력이 있었기에 가능했던 결과였으며, 이를 통해 좋은 연구는 개인의 역량뿐 아니라 팀원들 간의 지속적인 논의와 협업, 그리고 내가 틀림을 인정할 수 있는 능력을 통해 완성된다는 점도 배울 수 있었습니다.&lt;/p&gt;</description></item><item><title>딥러닝 해석을 위한 계층적 다중 뉴런 프레임워크 모델 개발</title><link>https://inhyuk2000.github.io/projects/a-hierarchical-interpretation-framework-based-on-multi-neuron-activation-patterns/</link><pubDate>Tue, 15 Jul 2025 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/projects/a-hierarchical-interpretation-framework-based-on-multi-neuron-activation-patterns/</guid><description>&lt;h4 id="-paper"&gt;📄 Paper&lt;/h4&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;딥러닝 해석을 위한 계층적 다중 뉴런 프레임워크 모델 개발&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;📑
&lt;/p&gt;
&lt;h4 id="-poster"&gt;🖼️ Poster&lt;/h4&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;KCC 2025 Conference Poster&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;📄
&lt;/p&gt;
&lt;h4 id="-award"&gt;🏆 Award&lt;/h4&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;KCC 2025 Encouragement Award (장려상)&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;🏅
&lt;/p&gt;
&lt;br/&gt;
&lt;h3 id="설명"&gt;설명&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 이름&lt;/strong&gt;: 딥러닝 해석을 위한 계층적 다중 뉴런 프레임워크 모델 개발&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 기간&lt;/strong&gt;: 2025.03 ~ 2025.07&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 설명&lt;/strong&gt;: 사전 라벨이 없는 이미지 데이터를 의미 단위로 계층화하고, 각 이미지 그룹에 공통으로 반응하는 다중 뉴런을 추출해 딥러닝 모델의 내부 의미 구조를 자연어로 설명하는 자동 해석 프레임워크&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 목적&lt;/strong&gt;: 단일 뉴런 중심 해석 방식의 한계를 보완하고, 딥러닝 모델 내부에서 여러 뉴런이 함께 형성하는 복잡한 개념 구조를 계층적으로 분석&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;분석 모델&lt;/strong&gt;: ResNet-18&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;데이터 출처&lt;/strong&gt;: Unsplash Lite Dataset&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;분석 데이터&lt;/strong&gt;: 약 25,000장의 무라벨 고해상도 자연 이미지&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;주요 분석 대상&lt;/strong&gt;: 이미지 의미 계층, 공통 활성 뉴런 그룹, 상·하위 계층 간 차이 뉴런&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 성과&lt;/strong&gt;: KCC 2025 논문 발표 및 Encouragement Award 수상&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-yellow-100 dark:bg-yellow-900 border-yellow-500"
data-callout="question"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-yellow-700 dark:text-yellow-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9.879 7.519c1.172-1.025 3.071-1.025 4.243 0c1.171 1.025 1.171 2.687 0 3.712q-.308.268-.67.442c-.746.361-1.452.999-1.452 1.827v.75M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9 5.25h.008v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;&lt;code&gt;ResNet-18&lt;/code&gt;이 이미지를 볼 때 내부의 여러 뉴런들이 어떤 개념을 함께 표현하고 있는지를 자동으로 찾아서 자연어로 설명해보자. 즉, 기존에는 주로 뉴런 하나씩 해석했다면, 우리는 &lt;strong&gt;여러 뉴런을 그룹으로 묶고 그 관계를 계층적으로 해석&lt;/strong&gt;하려고 함.&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="문제-정의"&gt;문제 정의&lt;/h2&gt;
&lt;p&gt;&lt;u&gt;딥러닝의 블랙박스 문제&lt;/u&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;단일 뉴런 기반&lt;/strong&gt; &lt;code&gt;XAI&lt;/code&gt; 기존 연구 :
&lt;/li&gt;
&lt;li&gt;하나의 개념 표현에 여러 뉴런이 협력하기 때문에, 단일 뉴런 분석으로는 이런 &lt;strong&gt;협동적 표현&lt;/strong&gt;을 고려하기 어려움&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;따라서 뉴런 하나씩 해석하지 말고, 같은 개념에 함께 반응하는 뉴런 그룹을 찾아서 해석하자.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="그런데-어떤-이미지로-뉴런의-의미를-알아내지"&gt;그런데 어떤 이미지로 뉴런의 의미를 알아내지?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;기존 연구들은 사람이 정한 라벨이 있는 데이터셋을 이용하는 경우가 많음.
&lt;ul&gt;
&lt;li&gt;즉, &lt;strong&gt;결국 사람이 미리 정한 개념 안에서만 모델을 분석하게 될 수 있는 문제가 있음.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;이를 피하기 위해 아예 라벨이 없는 &lt;code&gt;Unsplash&lt;/code&gt; 이미지 &lt;strong&gt;25000장&lt;/strong&gt;을 사용함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="그럼-라벨이-없으면-비슷한-이미지를-어떻게-묶지"&gt;그럼 라벨이 없으면 비슷한 이미지를 어떻게 묶지?&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;BLIP&lt;/code&gt; : 이미지 &lt;strong&gt;25000장&lt;/strong&gt;을 &lt;code&gt;BLIP&lt;/code&gt;에 하나씩 넣어서 이미지 설명을 자동 생성함.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ex. &lt;em&gt;이미지 A. 폭포 + 바위&lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;BLIP&lt;/code&gt;: &lt;em&gt;A waterfall located in a rocky environment.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;이 &lt;code&gt;BLIP&lt;/code&gt; 캡션을 이후 &lt;code&gt;의미 기반 클러스터링&lt;/code&gt;의 &lt;strong&gt;입력&lt;/strong&gt;으로 사용함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="비슷한-의미의-이미지들을-자동으로-묶음"&gt;비슷한 의미의 이미지들을 자동으로 묶음.&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;FINCH&lt;/code&gt; : 클러스터 개수를 사람이 미리 지정하지 않아도 되고, 반복적인 병합을 통해 계층적인 클러스터 구조 생성.&lt;/p&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-blue-100 dark:bg-blue-900 border-blue-500"
data-callout="note"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-blue-600 dark:text-blue-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m16.862 4.487l1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8l.8-2.685a4.5 4.5 0 0 1 1.13-1.897zm0 0L19.5 7.125"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;결과적으로 이미지들이 총 6개의 Level 계층 구조로 구성됨.&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="chatgpt를-활용해-한-클러스터의-모들-설명에-대한-대표-캡션을-생성함"&gt;ChatGPT를 활용해 한 클러스터의 모들 설명에 대한 대표 캡션을 생성함.&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ex. &lt;strong&gt;클러스터 A.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;A waterfall in a forest&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;A waterfall surrounded by rocks&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;A waterfall in a natural environment&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ChatGPT&lt;/code&gt; 기반 &lt;strong&gt;대표 캡션&lt;/strong&gt; 생성&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;A waterfall located in a rocky environment.&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="이미지들을-resnet-18에-넣음"&gt;이미지들을 ResNet-18에 넣음.&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Cluser A.&lt;/code&gt; : &lt;code&gt;A waterfall located in a rocky environment.&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;이 클러스터 내 이미지 100장을 &lt;code&gt;ResNet-18&lt;/code&gt;에 넣어서, 어떤 뉴런들이 &lt;strong&gt;강하게 활성화&lt;/strong&gt;되는 지를 기록함.&lt;/li&gt;
&lt;li&gt;활성화 값이 전체 뉴런 중 &lt;code&gt;상위 10%&lt;/code&gt;에 들어가는 뉴런 추출 = &lt;code&gt;활성화 뉴런&lt;/code&gt; 정의&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;공통 활성 뉴런 그룹 찾음.&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;클러스터의 &lt;strong&gt;절반 이상의 이미지에서 공통적으로 활성화되는 뉴런&lt;/strong&gt;을 해당 클러스터의 &lt;strong&gt;대표 뉴런 그룹으로 선정&lt;/strong&gt;함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="계층적-뉴런-해석"&gt;계층적 뉴런 해석&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ex. &lt;code&gt;Level 1.&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;숲속 폭포&lt;/code&gt; - &lt;code&gt;[10, 32, 81, 100]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;협곡 폭포&lt;/code&gt; - &lt;code&gt;[10, 32, 81, 150]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;바위 폭포&lt;/code&gt; - &lt;code&gt;[10, 32, 81, 200]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;공통 뉴런은 &lt;code&gt;[10, 32, 81]&lt;/code&gt; 이므로, 이를 &lt;strong&gt;상위 Level의 뉴런 그룹&lt;/strong&gt;으로 해석&lt;/p&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;차이 뉴런 정의&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[100]&lt;/code&gt;: &lt;code&gt;숲속&lt;/code&gt; 의미.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[150]&lt;/code&gt;: &lt;code&gt;협곡&lt;/code&gt; 의미.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[200]&lt;/code&gt;: &lt;code&gt;바위&lt;/code&gt; 의미.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-blue-100 dark:bg-blue-900 border-blue-500"
data-callout="note"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-blue-600 dark:text-blue-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m16.862 4.487l1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8l.8-2.685a4.5 4.5 0 0 1 1.13-1.897zm0 0L19.5 7.125"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;&lt;code&gt;ResNet-18&lt;/code&gt; 내부의 뉴런들을 단일 뉴런이 아니라 &lt;code&gt;여러 뉴런이 함께 표현하는 의미&lt;/code&gt; + &lt;code&gt;상하위 의미 관계&lt;/code&gt;로 설명하는 프레임워크를 구현함.&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h3 id="프로젝트를-진행하며-느낀점"&gt;프로젝트를 진행하며 느낀점&lt;/h3&gt;
&lt;p&gt;여러 프로젝트를 진행하며 &lt;span class="high-mark"&gt;&lt;strong&gt;직접 사용해보기 전에는 실제 문제를 발견하기 어렵다&lt;/strong&gt;&lt;/span&gt;
는 생각을 갖게 되었습니다. 이에 뉴런 해석과 관련된 기존 논문의 GitHub 코드를 직접 설치하고 실행해보며, 기존 방법의 한계와 개선이 필요한 지점을 파악하고자 했습니다.&lt;/p&gt;
&lt;p&gt;이전 프로젝트에서 연구 기획을 여러 차례 수정했던 경험을 바탕으로, 이번 프로젝트에서는 문제를 정의하고 새로운 연구 방향을 구체화하는 과정에 특히 많은 노력을 기울였습니다. 이후 딥러닝 프로젝트 담당 교수님과 주기적으로 회의를 진행하며 연구 방향을 지속적으로 점검하고 수정했고, 그 과정에서 새로운 접근을 설계하기 위한 인사이트를 얻을 수 있었습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;최종적으로 단일 뉴런을 중심으로 의미를 해석하는 기존 방식에서 벗어나, 여러 뉴런의 공통 활성화 패턴을 하나의 집합으로 구성해 해석에 활용하는 아이디어를 제안&lt;/strong&gt;했습니다. 이를 바탕으로 연구를 성공적으로 마무리하고 KCC 2025 학술대회에 논문을 제출했으며, 감사하게도 장려상을 수상했습니다. 직접 문제를 발견하고 연구 방향을 설계하기 위해 기울였던 노력이 성과로 이어졌다는 점에서 큰 보람을 느낄 수 있었습니다.&lt;/p&gt;</description></item><item><title>멀티 모델을 활용한 RAG Generation 단계 환각 탐지</title><link>https://inhyuk2000.github.io/projects/a-multi-llm-cross-verification-framework-for-attribution-hallucination-detection-in-rag-generation/</link><pubDate>Tue, 15 Jul 2025 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/projects/a-multi-llm-cross-verification-framework-for-attribution-hallucination-detection-in-rag-generation/</guid><description>&lt;h4 id="-paper"&gt;📄 Paper&lt;/h4&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;멀티 모델을 활용한 RAG Generation 단계 환각 탐지&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;📑
&lt;/p&gt;
&lt;h4 id="-ppt"&gt;🖼️ PPT&lt;/h4&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;Graduation Project PPT&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;📄
&lt;/p&gt;
&lt;h3 id="요약"&gt;요약&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 이름&lt;/strong&gt;: 멀티 모델을 활용한 RAG Generation 단계 환각 탐지&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;영문 제목&lt;/strong&gt;: A Multi-LLM Cross-Verification Framework for Attribution Hallucination Detection in RAG Generation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 기간&lt;/strong&gt;: 2025.03 ~ 2025.07&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 설명&lt;/strong&gt;: 동일한 RAG 검색 문서를 기반으로 ChatGPT와 LLaMA가 독립적으로 답변을 생성하고, 유사도가 낮을 때 문서 인용 기반 상호 평가·토론을 수행하는 Generation 단계 환각 탐지 시스템&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 목적&lt;/strong&gt;: RAG Generation 단계에서 발생하는 환각을 단일 모델 검증의 한계를 넘어, 서로 다른 LLM의 답변 다양성으로 탐지하고 교정&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;검증 데이터&lt;/strong&gt;: TruthfulQA 중 Source가 Wikipedia인 질문 50문항&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;비교 모델&lt;/strong&gt;: ChatGPT-3.5-turbo, Groq 기반 llama-4-maverick-17b-128e-instruct&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;주요 검증 대상&lt;/strong&gt;: 최종 답변, 원본 문서 인용 문장, 근거가 답변을 지지하는 이유&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;주요 성과&lt;/strong&gt;: 한 모델만 오답인 문항에서 토론을 통해 약 절반을 정답으로 교정 (GPT만 오답 3문항 중 1문항, LLaMA만 오답 13문항 중 7문항)&lt;/li&gt;
&lt;/ul&gt;
&lt;br/&gt;
&lt;h3 id="연구를-시작하게-된-배경"&gt;연구를 시작하게 된 배경&lt;/h3&gt;
&lt;p&gt;기존 LLM의 환각을 개선하기 위해 RAG 기법이 도입되었지만, RAG를 활용한 LLM에서도 환각 문제는 여전히 남아 있었습니다.&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;SUFFICIENT CONTEXT: A NEW LENS ON RETRIEVAL AUGMENTED GENERATION SYSTEMS (2025) 논문 일부 발췌&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;RAG로 추가 맥락을 주더라도 AI의 자신감이 올라가는 것과 정확성이 항상 비례하지는 않았습니다.&lt;/li&gt;
&lt;li&gt;ChatGPT 4o, Gemini 1.5 Pro, Gemma 27B처럼 모델이 다르면 학습 데이터 차이로 환각률도 다르게 나타났습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;따라서 본 연구에서는 &lt;span class="high-mark"&gt;&lt;strong&gt;서로 다른 언어 모델의 답변 다양성을 Generation 단계 환각 개선에 활용&lt;/strong&gt;&lt;/span&gt;
하고자 했습니다. RAG 파이프라인 중에서도 Query Rewriting과 Generation에서 환각이 자주 발생하는데, Generation은 LLM 사용이 필수이므로 이 단계에 집중해 멀티 에이전트 구조로 분기했습니다.&lt;/p&gt;
&lt;h3 id="시스템-아키텍처"&gt;시스템 아키텍처&lt;/h3&gt;
&lt;p&gt;
&lt;figure &gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;
&lt;img alt="Architecture"
srcset="https://inhyuk2000.github.io/projects/a-multi-llm-cross-verification-framework-for-attribution-hallucination-detection-in-rag-generation/img/architecture_hu_491d715c65ecc5a.webp 320w, https://inhyuk2000.github.io/projects/a-multi-llm-cross-verification-framework-for-attribution-hallucination-detection-in-rag-generation/img/architecture_hu_886f383c93590605.webp 480w, https://inhyuk2000.github.io/projects/a-multi-llm-cross-verification-framework-for-attribution-hallucination-detection-in-rag-generation/img/architecture_hu_d2cbbb04f0d4c118.webp 760w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 90vw, (max-width: 1024px) 80vw, 760px"
src="https://inhyuk2000.github.io/projects/a-multi-llm-cross-verification-framework-for-attribution-hallucination-detection-in-rag-generation/img/architecture_hu_491d715c65ecc5a.webp"
width="760"
height="428"
loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Query Rewriting&lt;/strong&gt;: 추가 LLM(&lt;code&gt;gpt-5.2-2025-12-11&lt;/code&gt;, temp=0)으로 검색 쿼리 생성&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generation 1 / 2&lt;/strong&gt;: ChatGPT-3.5-turbo, llama-4-maverick-17b-128e-instruct가 동일 검색 문서로 독립 답변&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;답변 유사도 계산&lt;/strong&gt;: SentenceTransformer(&lt;code&gt;all-MiniLM-L6-v2&lt;/code&gt;), threshold=0.8&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;일치 시 종료 / 불일치 시 토론&lt;/strong&gt;: 상대 답변이 문서에 근거하는지 문장 직접 인용으로 상호 평가&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="토론-프롬프트-설계"&gt;토론 프롬프트 설계&lt;/h3&gt;
&lt;p&gt;각 모델은 답변 시 아래 세 가지를 함께 작성하도록 했습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;최종 답변&lt;/li&gt;
&lt;li&gt;원본 문서 인용 문장&lt;/li&gt;
&lt;li&gt;해당 근거가 답변을 지지하는 이유&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;답변이 불일치하면, 상대 답변이 문서에 근거하는지를 &lt;span class="high-mark"&gt;&lt;strong&gt;문서 문장을 직접 인용해 평가&lt;/strong&gt;&lt;/span&gt;
하도록 지시했습니다.&lt;/p&gt;
&lt;h3 id="실험-설계"&gt;실험 설계&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;TruthfulQA 중 Wikipedia 출처 질문 50문항 선정&lt;/li&gt;
&lt;li&gt;RAG 기반 독립 답변 생성&lt;/li&gt;
&lt;li&gt;유사도 불일치 시 토론 진행&lt;/li&gt;
&lt;li&gt;Best Answer / Best Incorrect Answer 기준 수동 검증&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;단순 사실 판단 데이터는 제외하고, 정·오답이 라벨링된 문항만 사용해 교정 효과를 수치화했습니다.&lt;/p&gt;
&lt;h3 id="실험-결과"&gt;실험 결과&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th style="text-align: right"&gt;문항 수&lt;/th&gt;
&lt;th&gt;토론 후&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GPT만 정답&lt;/td&gt;
&lt;td style="text-align: right"&gt;3&lt;/td&gt;
&lt;td&gt;정답 교정 1 / 오답 유지 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LLaMA만 정답&lt;/td&gt;
&lt;td style="text-align: right"&gt;13&lt;/td&gt;
&lt;td&gt;정답 교정 7 / 오답 유지 6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;둘 다 오답&lt;/td&gt;
&lt;td style="text-align: right"&gt;14&lt;/td&gt;
&lt;td&gt;정답 교정 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;둘 다 정답&lt;/td&gt;
&lt;td style="text-align: right"&gt;20&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;한 모델만 오답인 경우 약 절반이 토론으로 교정되었고, &lt;span class="high-mark"&gt;&lt;strong&gt;둘 다 오답이면 토론만으로는 교정되지 않았습니다.&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 id="유형별-분석"&gt;유형별 분석&lt;/h3&gt;
&lt;p&gt;Misconceptions, Conspiracies, Superstitions, Paranormal, Fictions 중 &lt;strong&gt;미신(Superstitions)&lt;/strong&gt; 문항에서 오류율이 가장 높았습니다 (GPT 0%, LLaMA 22%).&lt;/p&gt;
&lt;h3 id="결론"&gt;결론&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Generation 단계 모델만 바꿔도 성능 차이가 컸습니다.&lt;/li&gt;
&lt;li&gt;한 모델만 오답일 때 토론의 교정 효과가 확인되었습니다.&lt;/li&gt;
&lt;li&gt;두 모델이 모두 오답이면 RAG 토론만으로는 교정이 어려웠습니다.&lt;/li&gt;
&lt;li&gt;미신 · 잘못된 상식류 문항에서 특히 취약했습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="사례"&gt;사례&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;둘 다 정답&lt;/strong&gt;: Fortune cookie 기원 질문 — 유사도 0.97, Conflict False로 종료&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;한 모델만 정답 → 교정&lt;/strong&gt;: 식사 후 수영 대기 시간 질문 — 1차 불일치 후, 문서에 대기 시간 언급이 없다는 인용 평가로 합의 도달&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="프로젝트를-진행하며-느낀점"&gt;프로젝트를 진행하며 느낀점&lt;/h3&gt;
&lt;p&gt;멀티 에이전트 챗봇 토론 시스템을 활용한 환각 교정 서비스를 개발하면서 환각 문제를 깊이 분석하던 중, 연구를 더욱 발전시킬 수 있는 새로운 방향을 발견했습니다. 일반적인 사실 오류뿐만 아니라, &lt;span class="high-mark"&gt;&lt;strong&gt;출처 환각(Attribution Hallucination)&lt;/strong&gt;&lt;/span&gt;
역시 실제 서비스 환경에서 빈번하게 발생하는 중요한 문제라는 점을 알게 되었고, 이를 해결하기 위해 본 프로젝트를 진행하게 되었습니다.&lt;/p&gt;
&lt;p&gt;본 연구에서는 각 LLM에 RAG(Retrieval-Augmented Generation) 시스템을 구축하고, 서로의 답변에 포함된 출처를 교차 검증하도록 설계하여 출처 환각을 줄이는 것을 목표로 했습니다. 다만 어떤 데이터셋을 구성해야 하는지, 출처의 일치 여부를 어떤 기준으로 검증해야 하는지 등 연구 설계 단계에서 많은 고민이 있었고, 이를 구체화하기 위해 교수님과 지속적으로 논의하며 연구 방향을 수정해 나갔습니다.&lt;/p&gt;
&lt;p&gt;최종적으로는 Prompt Engineering과 LLM 간 대화 구조를 보다 정교하게 설계함으로써 의미 있는 성능 개선을 확인할 수 있었고, 이를 바탕으로 논문화까지 진행할 수 있었습니다. 아직 해결해야 할 한계점이 남아 있지만, 이를 보완하며 출처 환각 탐지 및 교정 성능을 더욱 향상시키는 방향으로 연구를 계속 발전시킬 계획입니다.&lt;/p&gt;</description></item><item><title>블록체인을 활용한 신뢰 기반 이미지 거래 서비스, BlockSnap</title><link>https://inhyuk2000.github.io/projects/blockchain-true-image-app/</link><pubDate>Tue, 15 Jul 2025 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/projects/blockchain-true-image-app/</guid><description>&lt;h3 id="설명"&gt;설명&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 이름&lt;/strong&gt; : 신뢰 기반 이미지 거래 서비스, BlockSnap&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 기간&lt;/strong&gt; : 2026.03 ~ 2026.06&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 설명&lt;/strong&gt; : 블록체인의 온체인에 이미지 메타데이터를 등록해 위조가 불가능한 이미지 데이터를 생성하고, 이를 거래할 수 있는 서비스&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 목적&lt;/strong&gt; : AI로 생성된 이미지가 굉장히 많아, 구별이 힘든 삶을 살아가고 있는 상황 속에서 검증된 이미지를 통해 사용자를 안심시켜주기 위함&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로젝트 성과&lt;/strong&gt; : 이미지 거래 서비스 개발&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="api-설계"&gt;API 설계&lt;/h3&gt;
&lt;p&gt;백엔드 파트를 맡고, 여러 팀원들이 협업하며 동일한 서비스를 개발하기 위해서 API를 통일하고 인지해야 할 필요성이 있었습니다.&lt;/p&gt;
&lt;p&gt;따라서 각 기능 별 &lt;strong&gt;Request Header&lt;/strong&gt;, &lt;strong&gt;Request Body&lt;/strong&gt;, &lt;strong&gt;Response Header&lt;/strong&gt;, &lt;strong&gt;Response Body&lt;/strong&gt;, &lt;strong&gt;Error Type&lt;/strong&gt; 들을 전부 정리하는 식으로 설계를 시작했습니다.&lt;/p&gt;
&lt;h3 id="스마트-컨트랙트-저장-구조-설계"&gt;스마트 컨트랙트 저장 구조 설계&lt;/h3&gt;
&lt;p&gt;이미지 거래 과정에서 발생하는 소유권과 거래 이력을 위변조가 어렵도록 관리하기 위해, 거래에 필요한 핵심 정보는 스마트 컨트랙트에 저장하고 실제 이미지 파일과 일부 상세 정보는 Off-chain 영역에 분리해 저장하도록 설계했습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;필드&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;기본 블록 정보&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;blockNumber&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;거래가 기록된 블록 번호&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;timestamp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;블록이 생성된 시간&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;트랜잭션 정보&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;txHash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;각 거래를 구분하는 고유 트랜잭션 해시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;buyer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;구매자 지갑 주소&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;seller&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;판매자 지갑 주소&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;signature&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;거래 당사자와 소유권을 인증하기 위한 서명값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;이미지 정보&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;imageHash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;이미지 위변조 여부를 검증하기 위한 해시값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;imageUrl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Amazon S3에 저장된 실제 이미지의 Off-chain 주소&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;metadata&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;이미지 제목, 설명, 카테고리 등 부가 정보&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;거래 정보&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;price&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;이미지 거래 가격&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tokenId&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;이미지 자산을 식별하기 위한 토큰 ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tokenType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ERC-721, ERC-1155 등 토큰 표준&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;검증 및 인증 정보&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;verificationStatus&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;이미지 검증 상태 (&lt;code&gt;VERIFIED&lt;/code&gt;, &lt;code&gt;PENDING&lt;/code&gt;, &lt;code&gt;FAILED&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deviceId&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;촬영에 사용된 디바이스 식별 정보&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;로열티 및 수익 분배&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;royaltyRate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;재판매 시 적용되는 원작자 로열티 비율&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;creator&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;원작자의 지갑 주소&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;모든 데이터를 온체인에 저장하면 저장 비용과 처리 부담이 커질 수 있기 때문에, 이미지의 위변조 검증과 소유권 증명에 필요한 &lt;code&gt;imageHash&lt;/code&gt;, 거래 주소, 서명, 가격 등의 핵심 정보는 On-chain에 저장하고, 실제 이미지 파일과 상세 메타데이터는 Amazon S3에 Off-chain으로 관리했습니다.&lt;/p&gt;
&lt;p&gt;이를 통해 블록체인의 무결성과 추적 가능성을 활용하면서도 저장 비용과 시스템 성능을 함께 고려한 구조를 설계했습니다.&lt;/p&gt;
&lt;h3 id="프로젝트를-진행하며-느낀점"&gt;프로젝트를 진행하며 느낀점&lt;/h3&gt;
&lt;p&gt;백엔드 개발을 담당하며 프론트엔드 팀과 스마트 컨트랙트 팀 사이의 협업 과정을 경험했습니다. 프로젝트 초기에는 각 파트가 동일한 기능과 데이터 구조를 이해할 수 있도록 요청·응답 형식과 예외 상황을 포함한 API 명세서를 구체적으로 작성했습니다. &lt;span class="high-mark"&gt;&lt;strong&gt;명세를 정리하는 과정에는 많은 시간이 필요했지만, 이후 파트 간 소통 비용과 구현 과정의 혼선을 줄여 프로젝트 후반부의 개발 속도를 높이는 데 기여했습니다.&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;또한 이미지 해시를 활용한 유사 이미지 검증 로직을 백엔드에 구현하며 여러 예외 상황과 기술적 문제를 해결했습니다. 이 과정에서 API 명세는 단순히 인터페이스를 기록하는 문서가 아니라, 문제의 발생 지점과 각 파트의 책임 범위를 명확하게 정의하고 해결 방향을 공유하는 협업 도구라는 점을 배울 수 있었습니다.&lt;/p&gt;</description></item><item><title>공간 데이터 기반 재난 임시주거시설 최적 후보지 추천 시스템 개발</title><link>https://inhyuk2000.github.io/projects/disaster-shelter/</link><pubDate>Fri, 20 Sep 2024 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/projects/disaster-shelter/</guid><description>
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-orange-100 dark:bg-orange-900 border-orange-500"
data-callout="warning"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-orange-600 dark:text-orange-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0zM12 15.75h.007v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;정리예정입니다.&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>역세권 데이터 기반 7호선 급행열차 최적 정차역 선정 시스템 개발</title><link>https://inhyuk2000.github.io/projects/subway/</link><pubDate>Fri, 20 Sep 2024 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/projects/subway/</guid><description>&lt;h2 id="문제-정의"&gt;문제 정의&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;먼저 &lt;code&gt;좋은 급행 정차역&lt;/code&gt;이 무엇인지 정의함. &lt;span class="high-mark"&gt;&lt;strong&gt;편익 기준&lt;/strong&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;u&gt;&lt;strong&gt;사람이 많이 이용&lt;/strong&gt;&lt;/u&gt;하고, &lt;u&gt;&lt;strong&gt;주변에 중요한 시설이 많은 역&lt;/strong&gt;&lt;/u&gt;일수록 급행이 서야 하지 않을까?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="데이터-수집"&gt;데이터 수집&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Q. &lt;code&gt;1000m&lt;/code&gt; 반경으로 최종 결정한 근거가 뭔지?
&lt;ul&gt;
&lt;li&gt;그 당시에는 200m나 500m 기반으로 했을때는, 값이 거의 0이 많이 나왔음. 그래서 수집이 의미없다고 판단해서 반경을 그냥 늘린거였음. 많은 고민 안하고&amp;hellip; &lt;strong&gt;(이 부분 어떻게 답변 전략 생각해야 할 지 고민 필요)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="전처리-및-eda"&gt;전처리 및 EDA&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;데이터 단위 맞추기 위한 &lt;code&gt;Standard Scaling&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ex. 경찰서 수 = 3, 병원 수 = 15, 인구 = 50000&lt;/code&gt; 처럼 변수마다 숫자의 크기가 완전히 다름. 그대로 모델에 넣으면 인구처럼 숫자가 큰 변수가 지나치게 큰 영향을 줄 수 있어서, &lt;code&gt;Standard Scaling&lt;/code&gt; 표준화를 진행함.&lt;/li&gt;
&lt;li&gt;즉, 각 변수의 평균을 0 근처로 만들고, 서로 비슷한 크기의 척도로 변경&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;다중공선성 해결&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;처음 &lt;strong&gt;독립 변수&lt;/strong&gt;는 24개.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;아파트 수가 많은 지역 - 총 인구도 많을 가능성이 높음 - 주택 수도 많음 - 편의점이나 음식점 수도 많을 수 있음&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;VIF (Variation Inflation Factor)&lt;/code&gt; 계산
&lt;ul&gt;
&lt;li&gt;총 인구: 138, 주택/단독 주택/아파트/연립주택/다세대 주택: &lt;code&gt;inf&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;비슷한 변수들을 &lt;code&gt;PCA&lt;/code&gt; 압축
&lt;ul&gt;
&lt;li&gt;음식점/카페/편의점 - &lt;code&gt;상업 시설&lt;/code&gt;로 압축&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;상관계수&lt;/code&gt;가 &lt;strong&gt;지나치게 높은 변수 제거&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;0.7&lt;/code&gt; 이상인 변수 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;회귀분석을 통해 실제 승하차 인원과 관계있는 변수 찾기&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;처음 24개의 독립 변수를 전부 사용한 경우 모델:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;R²&lt;/code&gt; = &lt;strong&gt;0.89&lt;/strong&gt;, &lt;code&gt;Adjusted R²&lt;/code&gt; = &lt;strong&gt;0.74&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;변수 정리 후 16개의 독립 변수를 사용한 경우 모델:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;R²&lt;/code&gt; = &lt;strong&gt;0.80&lt;/strong&gt;, &lt;code&gt;Adjusted R²&lt;/code&gt; = &lt;strong&gt;0.70&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-blue-100 dark:bg-blue-900 border-blue-500"
data-callout="note"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-blue-600 dark:text-blue-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m16.862 4.487l1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8l.8-2.685a4.5 4.5 0 0 1 1.13-1.897zm0 0L19.5 7.125"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;불필요하고 겹치는 변수를 많이 제거하면서도 대부분의 설명력을 유지함.&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;회귀분석 결과, p-value 이용해 의미 있는 변수 선정&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;p-value&lt;/code&gt; &amp;lt; &lt;code&gt;0.05&lt;/code&gt; 이하인 유의미한 변수 선정&lt;/li&gt;
&lt;li&gt;최종, &lt;code&gt;에스컬레이터&lt;/code&gt;, &lt;code&gt;경찰서&lt;/code&gt;, &lt;code&gt;도서관&lt;/code&gt;, &lt;code&gt;은행&lt;/code&gt;, &lt;code&gt;병원&lt;/code&gt;, &lt;code&gt;상업시설(PCA)&lt;/code&gt; 선정&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;어떤 특성을 가진 역이 중요한지는 어느 정도 알았다.. 하지만 모든 역을 그냥 중요도 순으로 1, 2, 3등으로 줄 세우면 문제가 있음. 예를 들어, &lt;code&gt;강남권의 대형 상업역&lt;/code&gt;, &lt;code&gt;중간 규모 생활권 역&lt;/code&gt;, &lt;code&gt;비교적 작은 지역 역&lt;/code&gt;은 역할 자체가 서로 다름. 그래서 &lt;u&gt;&lt;strong&gt;비슷한 특징을 가진 역끼리 그룹을 만들어보자.&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="계층적-클러스터링-진행"&gt;계층적 클러스터링 진행&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;u&gt;&lt;strong&gt;선택 이유&lt;/strong&gt;&lt;/u&gt; : &lt;strong&gt;표본 수가 약 200개 이하인 데이터에 적합&lt;/strong&gt;하고, 미리 클러스터 개수를 &lt;strong&gt;정확하게 지정하지 않아도 분석할 수 있다&lt;/strong&gt;는 점.&lt;/li&gt;
&lt;li&gt;앞에서 선정한 역새권 특성들이 비슷한 역끼리 군집화됨.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;군집 1&lt;/code&gt;. 상대적으로 중요한 역.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;군집 2&lt;/code&gt;. 중간 정도 역.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;군집 3&lt;/code&gt;. 상대적으로 중요도가 낮은 역.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;각 군집에 가중치를 줌&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;중요한 군집에 속한 역은 최대한 정차시키고, 덜 중요한 군집은 상대적으로 덜 정차시키자.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-yellow-100 dark:bg-yellow-900 border-yellow-500"
data-callout="question"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-yellow-700 dark:text-yellow-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9.879 7.519c1.172-1.025 3.071-1.025 4.243 0c1.171 1.025 1.171 2.687 0 3.712q-.308.268-.67.442c-.746.361-1.452.999-1.452 1.827v.75M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9 5.25h.008v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;이 가중치는 어느 기준으로 어떻게 이 값이 나온거지?&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;군집 별 가중치:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;군집 1&lt;/code&gt;. &lt;code&gt;0.649&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;군집 2&lt;/code&gt;. &lt;code&gt;0.232&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;군집 3&lt;/code&gt;. &lt;code&gt;0.119&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="급행-정차역-선정을-최적화-문제로-바꿈"&gt;급행 정차역 선정을 최적화 문제로 바꿈&lt;/h2&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;가중치 높은 역을 다 세우자! 라고 하면 급행 열차가 아님. 하지만 모든 역에 서면 일반 열차와 똑같음. 따라서 아래와 같은 제약 조건을 넣어줌.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;일반 열차의 운행 시간은 약 &lt;code&gt;84.5분(5070초)&lt;/code&gt;이고, 급행은 이를 약 35% 단축한 &lt;code&gt;53분(3180초)&lt;/code&gt; 수준으로 설정.&lt;/p&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-blue-100 dark:bg-blue-900 border-blue-500"
data-callout="note"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-blue-600 dark:text-blue-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m16.862 4.487l1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8l.8-2.685a4.5 4.5 0 0 1 1.13-1.897zm0 0L19.5 7.125"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;운행 시간은 53분을 넘지 않음녀서, 최대한 중요한 역에 많이 정차하라.&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span class="high-mark"&gt;&lt;strong&gt;슬라이딩 윈도우 기반 최적화 알고리즘&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;각 역의 정차 여부를 &lt;code&gt;0/1&lt;/code&gt;로 정의함.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1&lt;/code&gt;: 급행 열차 정차&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt;: 통과&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;운행시간 &lt;code&gt;53분 이내&lt;/code&gt;라는 &lt;strong&gt;제약조건 설정&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;각 후보 조합에 대해 &lt;code&gt;역 중요도 가중치&lt;/code&gt; X &lt;code&gt;승하차 인원&lt;/code&gt;을 기준으로 &lt;strong&gt;점수 계산&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;시간 제약을 만족하는 조합 중 &lt;strong&gt;목적함수 값이 가장 높은 정차역 조합을 선택&lt;/strong&gt;함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="최종-결과"&gt;최종 결과&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;급행 정차역: &lt;code&gt;17개&lt;/code&gt; 역&lt;/li&gt;
&lt;li&gt;기존 일반 열차: &lt;code&gt;5070초&lt;/code&gt; (약 &lt;code&gt;84.5분&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;급행 열차: &lt;code&gt;3180초&lt;/code&gt; (약 &lt;code&gt;53분&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;운행 시간 약 &lt;code&gt;37%&lt;/code&gt; 감소&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-blue-100 dark:bg-blue-900 border-blue-500"
data-callout="note"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-blue-600 dark:text-blue-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m16.862 4.487l1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8l.8-2.685a4.5 4.5 0 0 1 1.13-1.897zm0 0L19.5 7.125"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;운행 시간 제약을 만족하면서 주요 수요역을 최대한 포함하도록 최적 정차역을 선정함.&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>송인혁의 포스터 홀 둘러보기</title><link>https://inhyuk2000.github.io/projects/inyuck-poster/</link><pubDate>Mon, 17 Jun 2024 00:00:00 +0900</pubDate><guid>https://inhyuk2000.github.io/projects/inyuck-poster/</guid><description>&lt;h3 id="background"&gt;Background&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;학회 발표&lt;/strong&gt;는 듣는 청중이 몇 초 안에 연구의 핵심을 파악할 수 있도록 구성되어야 합니다. 즉, 복잡한 연구 내용도 &lt;strong&gt;한눈에 이해할 수 있도록 정리하고 전달하는 것&lt;/strong&gt;이 중요합니다.&lt;/p&gt;
&lt;p&gt;저의 웹사이트 포트폴리오 역시 마찬가지라고 생각했습니다.&lt;/p&gt;
&lt;p&gt;포트폴리오를 방문한 분들이 여러 프로젝트의 내용을 하나씩 찾아보지 않아도, &lt;strong&gt;제가 어떤 문제를 고민했고 무엇을 만들어왔는지 한눈에 파악할 수 있는 방법&lt;/strong&gt;을 고민했습니다.&lt;/p&gt;
&lt;p&gt;그러다 과거 &lt;strong&gt;KCC 2025 학회&lt;/strong&gt;에 발표를 위해 방문했을 때의 풍경이 떠올랐습니다.
수많은 연구 포스터가 한 공간에 진열되어 있고, 관심 있는 연구를 자유롭게 둘러보던 &lt;strong&gt;포스터 세션&lt;/strong&gt;의 모습이었습니다.&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;그렇다면 내 프로젝트도 학회 포스터처럼 한 공간에 전시해보면 어떨까?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 아이디어에서 시작해, 지금까지 진행한 프로젝트와 연구를 &lt;strong&gt;하나의 학회 포스터 세션처럼 둘러볼 수 있는 공간&lt;/strong&gt;을 만들어보았습니다.&lt;/p&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-blue-100 dark:bg-blue-900 border-blue-500"
data-callout="info"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-blue-600 dark:text-blue-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m11.25 11.25l.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9-3.75h.008v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;Info&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;p&gt; 사이트에 접속해주세요.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="motivation"&gt;Motivation&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="구현-내용"&gt;구현 내용&lt;/h3&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-orange-100 dark:bg-orange-900 border-orange-500"
data-callout="warning"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-orange-600 dark:text-orange-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0zM12 15.75h.007v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;정리예정입니다.&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="참고-자료"&gt;참고 자료&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>