<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Solbi Lee님의 블로그</title>
    <link>https://cat-b0.tistory.com/</link>
    <description>AI 활용 소프트웨어 개발과 데이터 분석을 공부합니다. </description>
    <language>ko</language>
    <pubDate>Sat, 4 Jul 2026 10:58:22 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Solbi Lee</managingEditor>
    <image>
      <title>Solbi Lee님의 블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/7646248/attach/8482005a38ec48df9b440686b8b4d262</url>
      <link>https://cat-b0.tistory.com</link>
    </image>
    <item>
      <title>프롬프트를 코드로, DSPy 탐구 시리즈 - ① 홈페이지, 깃허브, 논문 요약</title>
      <link>https://cat-b0.tistory.com/153</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;609&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zY6zp/dJMcajhqSN9/vejySykFJ7JMzGmog5qQP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zY6zp/dJMcajhqSN9/vejySykFJ7JMzGmog5qQP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zY6zp/dJMcajhqSN9/vejySykFJ7JMzGmog5qQP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzY6zp%2FdJMcajhqSN9%2FvejySykFJ7JMzGmog5qQP1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;609&quot; height=&quot;196&quot; data-origin-width=&quot;609&quot; data-origin-height=&quot;196&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DSPy 공식 홈페이지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dspy.ai/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dspy.ai/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1775453888273&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;DSPy&quot; data-og-description=&quot;The framework for programming&amp;mdash;rather than prompting&amp;mdash;language models.&quot; data-og-host=&quot;dspy.ai&quot; data-og-source-url=&quot;https://dspy.ai/&quot; data-og-url=&quot;https://dspy.ai/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jZfEX/dJMb84XZolb/y1Ej6q1W9k7d26He2TJNK0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bAwKhT/dJMb9jgxUAD/gkGho3skxNltOaI6ik3wfK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://dspy.ai/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dspy.ai/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jZfEX/dJMb84XZolb/y1Ej6q1W9k7d26He2TJNK0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bAwKhT/dJMb9jgxUAD/gkGho3skxNltOaI6ik3wfK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;DSPy&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The framework for programming&amp;mdash;rather than prompting&amp;mdash;language models.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dspy.ai&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DSPy github&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/stanfordnlp/dspy&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/stanfordnlp/dspy&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1775453871498&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - stanfordnlp/dspy: DSPy: The framework for programming&amp;mdash;not prompting&amp;mdash;language models&quot; data-og-description=&quot;DSPy: The framework for programming&amp;mdash;not prompting&amp;mdash;language models - stanfordnlp/dspy&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/stanfordnlp/dspy&quot; data-og-url=&quot;https://github.com/stanfordnlp/dspy&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/sqaS0/dJMb83ktzRG/w1JC4nfuNz5KyGLHk7BX90/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/D2wXq/dJMb87f675x/DsaMfDXsnc9NkYdpaGw000/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/stanfordnlp/dspy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/stanfordnlp/dspy&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/sqaS0/dJMb83ktzRG/w1JC4nfuNz5KyGLHk7BX90/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/D2wXq/dJMb87f675x/DsaMfDXsnc9NkYdpaGw000/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - stanfordnlp/dspy: DSPy: The framework for programming&amp;mdash;not prompting&amp;mdash;language models&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;DSPy: The framework for programming&amp;mdash;not prompting&amp;mdash;language models - stanfordnlp/dspy&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DSPy의 핵심 논문 &lt;b&gt;DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://arxiv.org/abs/2310.03714&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/abs/2310.03714&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1775453986886&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines&quot; data-og-description=&quot;The ML community is rapidly exploring techniques for prompting language models (LMs) and for stacking them into pipelines that solve complex tasks. Unfortunately, existing LM pipelines are typically implemented using hard-coded &amp;quot;prompt templates&amp;quot;, i.e. len&quot; data-og-host=&quot;arxiv.org&quot; data-og-source-url=&quot;https://arxiv.org/abs/2310.03714&quot; data-og-url=&quot;https://arxiv.org/abs/2310.03714v1&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dbibbO/dJMb8XR6kae/4SGqwtrFPoKQVpxFdh9kA0/img.png?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/xKuvk/dJMb8Xkf0Yo/7JbnYxXEUOo21bK0e4dHv0/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000&quot;&gt;&lt;a href=&quot;https://arxiv.org/abs/2310.03714&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://arxiv.org/abs/2310.03714&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dbibbO/dJMb8XR6kae/4SGqwtrFPoKQVpxFdh9kA0/img.png?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/xKuvk/dJMb8Xkf0Yo/7JbnYxXEUOo21bK0e4dHv0/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The ML community is rapidly exploring techniques for prompting language models (LMs) and for stacking them into pipelines that solve complex tasks. Unfortunately, existing LM pipelines are typically implemented using hard-coded &quot;prompt templates&quot;, i.e. len&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;arxiv.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 문제의식 : 기존 LM 파이프라인은 대개 사람이 시행착오로 만든 하드코딩 프롬프트 문자열에 의존해서 복잡한 시스템을 재현성있게 개선하기 어렵다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 핵심 아이디어 : LM 파이프라인을 declarative module+text transformation graph로 추상화하고, 컴파일러가 metric 기준으로 프롬프트/데모/전략을 자동 최적화하게 하자는 발상. Prompt engineering을 programming+compilation으로 바꾸려는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기여점 :&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) DSPy라는 프로그래밍 모델 제안&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) metric 기반 컴파일/최적화 프레임워크 제시&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(3) 수학, multi-hop retrieval, complex QA, agent loop 같은 작업에서 few-shot 프롬프팅이나 전문가가 짠 프롬프트 체인보다 더 나은 성능을 보였다고 보고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(4) 상대적으로 작은 오픈 모델도 경쟁력 있게 만들 수 있음을 보임&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 한계/주의점 : 초록 수준에서 명시적 한계가 강하게 정리돼있진 않음. 실제 적용시에는 좋은 metric 설계와 적절한 예시 데이터가 중요하고, 더 다양한 태스크/운영환경에서의 검증이 필요하다는 점이 사실상 주의점으로 읽힘&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://arxiv.org/abs/2507.19457&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/abs/2507.19457&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1775454057355&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;GEPA: Reflective Prompt Evolution Can Outperform Reinforcement Learning&quot; data-og-description=&quot;Large language models (LLMs) are increasingly adapted to downstream tasks via reinforcement learning (RL) methods like Group Relative Policy Optimization (GRPO), which often require thousands of rollouts to learn new tasks. We argue that the interpretable &quot; data-og-host=&quot;arxiv.org&quot; data-og-source-url=&quot;https://arxiv.org/abs/2507.19457&quot; data-og-url=&quot;https://arxiv.org/abs/2507.19457v2&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c3zyDP/dJMb9hC1Xw9/pkeP7hvFX3Gt42pwcDVzwK/img.png?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/tc5Qy/dJMb86nYecK/DVC5GdmRqypEQFhqNBsWV0/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000&quot;&gt;&lt;a href=&quot;https://arxiv.org/abs/2507.19457&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://arxiv.org/abs/2507.19457&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c3zyDP/dJMb9hC1Xw9/pkeP7hvFX3Gt42pwcDVzwK/img.png?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/tc5Qy/dJMb86nYecK/DVC5GdmRqypEQFhqNBsWV0/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GEPA: Reflective Prompt Evolution Can Outperform Reinforcement Learning&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Large language models (LLMs) are increasingly adapted to downstream tasks via reinforcement learning (RL) methods like Group Relative Policy Optimization (GRPO), which often require thousands of rollouts to learn new tasks. We argue that the interpretable&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;arxiv.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 문제의식 : LLM을 downstream task에 맞출 때 RL 계열 기법은 rollout 비용이 너무 크고 비효율적일 수 있다.는 문제를 제기함. &quot;희소한 scalar reward&quot; 보다 언어 자체의해석 가능한 피드백이 더 풍부한 학습 신호가 될 수 있다는 주장.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 핵심 아이디어 : GEPA는 실행궤적 (추론, tool call, tool output 등)을 보고 자연어 reflection으로 무엇이 잘됐고 무엇이 실패했는지 분석한 뒤, 프롬프트를 진화적으로 갱신하는 옵티마이저임. pareto fontier를 활용해 여러 개선 방향을 조합하는 점이 특징&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기여점 :&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) refrection 기반 prompt evolution을 정식화&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) GRPO같은 RL 방식보다 적은 rollout으로 더 나은 성능을 보였다고 보고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(3) MIPROv2보다도 높은 성능 사례 제시&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(4) DSPy 생태계에서 &quot;Optimizer가 얼마나 중요한가&quot;를 잘 보여주는 최신 계열 연구&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 한계/주의점 : 요약/초록 수준에서는 명시적 limitation 정리가 약한편. 최신 옵티마이저 논문이라 장기적 일반화 성능이나 다양한 운영 환경에서의 재현성은 앞으로 더 검증될여지가 있다고 보는게 안전&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://arxiv.org/abs/2212.14024&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/abs/2212.14024&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1775455527321&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Demonstrate-Search-Predict: Composing retrieval and language models for knowledge-intensive NLP&quot; data-og-description=&quot;Retrieval-augmented in-context learning has emerged as a powerful approach for addressing knowledge-intensive tasks using frozen language models (LM) and retrieval models (RM). Existing work has combined these in simple &amp;quot;retrieve-then-read&amp;quot; pipelines in wh&quot; data-og-host=&quot;arxiv.org&quot; data-og-source-url=&quot;https://arxiv.org/abs/2212.14024&quot; data-og-url=&quot;https://arxiv.org/abs/2212.14024v2&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/csBLWz/dJMb8869tbY/aPCDiNDsmdDYuXxJ3OiJt1/img.png?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/c4UERG/dJMb9kmdqGD/OOJ1bf69ibOQeYgY7rKvik/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000&quot;&gt;&lt;a href=&quot;https://arxiv.org/abs/2212.14024&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://arxiv.org/abs/2212.14024&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/csBLWz/dJMb8869tbY/aPCDiNDsmdDYuXxJ3OiJt1/img.png?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/c4UERG/dJMb9kmdqGD/OOJ1bf69ibOQeYgY7rKvik/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Demonstrate-Search-Predict: Composing retrieval and language models for knowledge-intensive NLP&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Retrieval-augmented in-context learning has emerged as a powerful approach for addressing knowledge-intensive tasks using frozen language models (LM) and retrieval models (RM). Existing work has combined these in simple &quot;retrieve-then-read&quot; pipelines in wh&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;arxiv.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 문제의식: 기존 retrieval-augmeted 방식은 흔히 retrieve-then-read 처럼 단순한 구조라서, LM과 retrieval model의 잠재력을 충분히 못살린다는 문제 의식에서 출발&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 핵심 아이디어 : LM과 retrieval model 사이에서 자연어르 주고 받는 고수준 프로그램형 파이프라인을 만들고, 문제를 작은 단계로 분해해서 더 안정적으로 검색, 추론, 예측 가능하게 하자는 아이디어&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기여점 :&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) DSP라는 전신 프레임워크 제안&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) open domain / multi-hop / conversation ai QA에서 강한 성능 보고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(3) retrieval+LM조합을 단일 프롬프트가 아니라 구성 가능한 파이프라인으로 다루는 발판 제공&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DSPy의 철학적 전신으로 매우 중요함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 한계/주의점 : 여전히 frozen model 중심이고, 성능이 파이프라인 설계 품질에 크게 좌우된다는 점이 한계로 읽힘.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이 3편의 관계?&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DSP (2022) &amp;rarr; retrieval + LM 파이프라인을 &quot;프로그램&quot;처럼 다루자 &lt;br /&gt;&lt;br /&gt;DSPy (2023/2024) &amp;rarr; 그 철학을 더 일반화해서, LM 시스템 전체를 declarative program + compiler로 다루자 &lt;br /&gt;&lt;br /&gt;GEPA (2025) &amp;rarr; 그 프로그램을 더 잘 만들기 위한 optimizer를 reflection/evolution 방식으로 고도화하자 &lt;/p&gt;</description>
      <category>Programming Study/AI Agent</category>
      <category>ai agent</category>
      <category>DSP</category>
      <category>DSPy</category>
      <category>DSPy AI</category>
      <category>GEPA</category>
      <category>프로그래밍</category>
      <category>프롬프트 엔지니어링</category>
      <author>Solbi Lee</author>
      <guid isPermaLink="true">https://cat-b0.tistory.com/153</guid>
      <comments>https://cat-b0.tistory.com/153#entry153comment</comments>
      <pubDate>Mon, 6 Apr 2026 15:21:24 +0900</pubDate>
    </item>
    <item>
      <title>50년 전 돌아가신 외할아버지를 다시 볼 수 있을까? - 추석에 시작된 AI 사진 복원 프로젝트</title>
      <link>https://cat-b0.tistory.com/152</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 추석, 오랜만에 찾은 시골 외가댁에서 낡은 서랍장을 열었습니다.&amp;nbsp;&lt;br&gt;오래된 편지와 영수증 사이에서 낡은 흑백 사진 한 장을 발견했어요.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;사진 속에는 50년 전 돌아가신 외할아버지와 외할머니가 계셨습니다.&amp;nbsp;&lt;br&gt;외할아버지는 한 번도 뵌 적 없었지만, 엄마 얼굴 어딘가에서 외할아버지의 눈매를 찾을 수 있었습니다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;그리고 외할아버지... 너무 잘생기셔서 놀랐습니다. (이런 비주얼이 우리 집안 유전자에 있었다니)&lt;br&gt;&amp;nbsp;&lt;br&gt;&quot;이 사진, 복원할 수 있지 않을까?&quot;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;최근까지 배워온 AI 기술이 이번엔 조금 다른 의미로 다가왔습니다.&amp;nbsp;&lt;br&gt;&lt;b&gt;포트폴리오를 채우기 위한 단순 프로젝트가 아니라 가족을 위한 작은 선물이 될 수 있겠다는 생각&lt;/b&gt;이 들었습니다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;핸드폰으로 사진을 촬영하고, 생성형 AI를 활용해 손상된 부분을 되살렸습니다.&amp;nbsp;&lt;br&gt;흑백에 컬러를 입히고, 정지된 사진에 자연스러운 움직임을 더했습니다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;완성된 사진과 영상을 엄마와 이모들께 보여드렸을 때,&amp;nbsp;&lt;br&gt;처음엔 모두 신기해하시고 좋아하셨습니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;그리고 엄마와 이모들은 명절 연휴동안 수시로 그 영상을 보시며 화면을 어루만지셨어요.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;기술이 사라진 시간을 완전히 되돌릴 수는 없습니다.&lt;br&gt;하지만 희미해진 기억을 조금 더 선명하게 만들 수는 있었습니다.&lt;br&gt;그리고 그것만으로도, 누군가에겐 큰 위로가 될 수 있다는 걸 알게 되었습니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;오늘은 여러분 집 서랍 어딘가에 잠들어 있을 오래된 사진을,&lt;br&gt;어떻게 AI로 복원하고 영상으로 만들 수 있는지 그 과정을 공유하려 합니다.&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot;&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 오래된 증명사진 복원하기&amp;nbsp;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 외할아버지의 증명사진입니다.&amp;nbsp;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2992&quot; data-origin-height=&quot;2992&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bc6UxY/btsQ4PUN8tT/ueB1sqNSkSU2E0h39NEK70/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bc6UxY/btsQ4PUN8tT/ueB1sqNSkSU2E0h39NEK70/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bc6UxY/btsQ4PUN8tT/ueB1sqNSkSU2E0h39NEK70/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbc6UxY%2FbtsQ4PUN8tT%2FueB1sqNSkSU2E0h39NEK70%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;508&quot; height=&quot;508&quot; data-origin-width=&quot;2992&quot; data-origin-height=&quot;2992&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;50년이 넘은 증명사진이었습니다. 종이는 누렇게 변색되었고 찢어지고 오염된 부분도 있었어요.&amp;nbsp;&lt;br&gt;사진 표면에는 얼룩과 스크래치가 여기저기 보였습니다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;하지만 굉장히 잘생기셨습니다. 진짜 너무 놀람.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 복원 준비 과정&amp;nbsp;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 사진을 최대한 평평하게 펴서 손 위에 올려두고 촬영했습니다. (바닥에 두고 찍으면 그림자가 생겨서 ㅠㅠ)&amp;nbsp;&lt;br&gt;그리고 촬영한 이미지를 갤러리에서 열어 사진 부분만 정확하게 크롭했씁니다.&amp;nbsp;&lt;br&gt;배경이나 손가락은 모두 제거하고 순수하게 증명사진 영역만 남겼습니다.&amp;nbsp;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1307&quot; data-origin-height=&quot;1843&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3NGou/btsQ4pB7vkZ/CI7EdoRPrj5uKPC3zvZ2m1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3NGou/btsQ4pB7vkZ/CI7EdoRPrj5uKPC3zvZ2m1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3NGou/btsQ4pB7vkZ/CI7EdoRPrj5uKPC3zvZ2m1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3NGou%2FbtsQ4pB7vkZ%2FCI7EdoRPrj5uKPC3zvZ2m1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;510&quot; height=&quot;719&quot; data-origin-width=&quot;1307&quot; data-origin-height=&quot;1843&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. AI 복원 실행&amp;nbsp;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;증명사진 복원에는 Google Gemini의 Nano Banana 모델을 사용했습니다.&amp;nbsp;&lt;br&gt;검색창에 구글 Gemini를 검색 -&amp;gt; 이미지 생성 도구 클릭 -&amp;gt; 기존 사진 업로드 + 프롬프트 입력&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;크롭한 이미지를 업로드 하고, 프롬프트는 간단하게 작성했습니다.&amp;nbsp;&lt;br&gt;&lt;b&gt; &quot;restore this damaged photo to realistic recent photo&quot; &lt;/b&gt;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 복원 결과&amp;nbsp;&lt;/h3&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;1085&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBPGce/btsQ4iJIwym/USQDy0lQMxIlfqM94ICuBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBPGce/btsQ4iJIwym/USQDy0lQMxIlfqM94ICuBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBPGce/btsQ4iJIwym/USQDy0lQMxIlfqM94ICuBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBPGce%2FbtsQ4iJIwym%2FUSQDy0lQMxIlfqM94ICuBk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;576&quot; height=&quot;789&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;1085&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복원된 사진 속 외할아버지는&amp;nbsp;&lt;br&gt;너무 잘생기셔서 놀랐습니다.&amp;nbsp;&lt;br&gt;진짜 뭘까.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;우리 할아버지 배우하셔도 됐겠슈.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1402&quot; data-origin-height=&quot;934&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dZBmt5/btsQ4V18MMX/AXDHIuoxYg9KT3BpuVxKs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dZBmt5/btsQ4V18MMX/AXDHIuoxYg9KT3BpuVxKs0/img.png&quot; data-alt=&quot;before &amp;amp;amp; after&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dZBmt5/btsQ4V18MMX/AXDHIuoxYg9KT3BpuVxKs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdZBmt5%2FbtsQ4V18MMX%2FAXDHIuoxYg9KT3BpuVxKs0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1402&quot; height=&quot;934&quot; data-origin-width=&quot;1402&quot; data-origin-height=&quot;934&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;before &amp;amp; after&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot;&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 오래된 가족사진 복원하기&amp;nbsp;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;다른 사진도 복원해보겠습니다.&amp;nbsp;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2992&quot; data-origin-height=&quot;2992&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZ4p73/btsQ6IUOLof/jT6zE7XLRinsXAcdp9VosK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZ4p73/btsQ6IUOLof/jT6zE7XLRinsXAcdp9VosK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZ4p73/btsQ6IUOLof/jT6zE7XLRinsXAcdp9VosK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZ4p73%2FbtsQ6IUOLof%2FjT6zE7XLRinsXAcdp9VosK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;483&quot; height=&quot;483&quot; data-origin-width=&quot;2992&quot; data-origin-height=&quot;2992&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외할머니, 외할아버지, 그리고 남자 아이를 안고 있는 가족 사진인 줄 알았는데,&amp;nbsp;&lt;br&gt;저 아이가 저희 엄마라고 해서 살짝 당황했습니다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;저 아이가 여자라니. 누가 봐도 장군감인데&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 사진 전처리&amp;nbsp;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;복원 작업을 시작하기 전, 먼저 원본 사진을 최적화 하는 과정이 필요했습니다.&amp;nbsp;&lt;br&gt;증명사진과 동일하게 자연광 아래에서 촬영,&amp;nbsp;&lt;br&gt;손으로 잡은 부분과 배경을 모두 제거,&amp;nbsp;&lt;br&gt;기울기 조정&amp;nbsp;&lt;br&gt;+&lt;br&gt;스마트폰 기본 편집 기능으로 밝기, 대비, 선명도 조정&amp;nbsp;&lt;br&gt;대비를 올려서 윤곽 명확하게&amp;nbsp;&lt;br&gt;과도한 보정은 오히려 AI 복원에 악영향을 줄 수 있어서 최소한의 조정만 진행했습니다.&amp;nbsp;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2087&quot; data-origin-height=&quot;2992&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/co8aha/btsQ49lfDcQ/Xw5sN2No4hvjKdH14F5opK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/co8aha/btsQ49lfDcQ/Xw5sN2No4hvjKdH14F5opK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/co8aha/btsQ49lfDcQ/Xw5sN2No4hvjKdH14F5opK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fco8aha%2FbtsQ49lfDcQ%2FXw5sN2No4hvjKdH14F5opK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;412&quot; height=&quot;591&quot; data-origin-width=&quot;2087&quot; data-origin-height=&quot;2992&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전처리 후 사진입니다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. AI 컬러 복원&amp;nbsp;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;전처리를 마친 흑백 사진을 위와 동일한 Google Gemini의 Nano Banana 모델로 사용해 먼저 컬러로 복원했습니다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;증명사진과 같이 &quot;restore this damaged photo to realistic recent photo&quot; 프롬프트로 먼저 복원해봤습니다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VNemr/btsQ7wMUgbd/BXDXQrVJee3c5fdk4ZAOx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VNemr/btsQ7wMUgbd/BXDXQrVJee3c5fdk4ZAOx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VNemr/btsQ7wMUgbd/BXDXQrVJee3c5fdk4ZAOx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVNemr%2FbtsQ7wMUgbd%2FBXDXQrVJee3c5fdk4ZAOx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;392&quot; height=&quot;588&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적인 손상은 복구됐습니다. (얼룩, 스크래치 제거)&lt;br&gt;전반적인 선명도 향상, 얼굴 복원&lt;br&gt;&amp;nbsp;&lt;br&gt;근데 여전히 회색조/세피아 느낌이 강했고, 완벽하게 복원되었다는 느낌이 아니었습니다.&amp;nbsp;&lt;br&gt;색감이 아직 부족하다고 느꼈어요. 전체적으로 채도가 낮고, 생기가 없는 느낌이었어요.&lt;br&gt;recent photo 느낌보다는 여전히 오래된 사진 느낌이었습니다. 그래서 프롬프트를 분석하고 수정해봤습니다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;왜 이런 결과가 나왔을까?&amp;nbsp;&lt;br&gt;AI는 restore이라는 단어를 손상 복구 정도로만 해석했습니다.&amp;nbsp;&lt;br&gt;&quot;realistic recent photo&quot;는 모호한 지시어였고, &lt;b&gt;배경까지 완전히 컬러화하라는 명확한 지시가 없었습니다.&lt;/b&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;프롬프트 재설계 :&lt;br&gt;이미지 생성 AI를 배우면서 AI에게 원하는 것보다 원하지 않는 것을 명확히 알려주는 게 중요하다는 것을 알았습니다. (아니면, 맘대로 생성해버리기 때문이죠)&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;Fully&amp;nbsp;colorize&amp;nbsp;this&amp;nbsp;1960s&amp;nbsp;Korean&amp;nbsp;photo&amp;nbsp;—&amp;nbsp;people&amp;nbsp;+&amp;nbsp;background&amp;nbsp;+&amp;nbsp;tree&amp;nbsp;+&amp;nbsp;ground. &lt;/b&gt;&lt;br&gt;&lt;b&gt;Warm&amp;nbsp;daylight,&amp;nbsp;high&amp;nbsp;saturation,&amp;nbsp;DSLR&amp;nbsp;quality. &lt;/b&gt;&lt;br&gt;&lt;b&gt;Keep&amp;nbsp;faces&amp;nbsp;original,&amp;nbsp;no&amp;nbsp;gray&amp;nbsp;areas,&amp;nbsp;no&amp;nbsp;painting&amp;nbsp;effect.&lt;/b&gt;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;&lt;li&gt;&lt;b&gt;&quot;Fully colorize&quot;&lt;/b&gt; - 복원이 아닌 완전한 컬러화 요구&lt;/li&gt;&lt;li&gt;&lt;b&gt;&quot;people + background + tree + ground&quot;&lt;/b&gt; - 컬러화 대상을 구체적으로 나열&lt;/li&gt;&lt;li&gt;&lt;b&gt;&quot;Warm daylight, high saturation&quot;&lt;/b&gt; - 원하는 색감과 분위기 명시&lt;/li&gt;&lt;li&gt;&lt;b&gt;&quot;no gray areas, no painting effect&quot;&lt;/b&gt; - 금지사항을 명확하게&lt;/li&gt;&lt;/ol&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;불필요한 설명을 모두 제거하고, 핵심만 3줄로 압축했습니다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;1248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r7fTt/btsQ5TWuIXt/nZP3RUg20M0IGrecaS7WLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r7fTt/btsQ5TWuIXt/nZP3RUg20M0IGrecaS7WLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r7fTt/btsQ5TWuIXt/nZP3RUg20M0IGrecaS7WLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr7fTt%2FbtsQ5TWuIXt%2FnZP3RUg20M0IGrecaS7WLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;450&quot; height=&quot;675&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;1248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 : 채도가 생겼습니다. 이정도면 만족스러워요.&amp;nbsp;&lt;br&gt;여전히 아쉬운점은 배경의 일부가 자연스럽지는 않음. (지면의 색감이 부분적으로 불균일)&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 복원 사진 영상화&amp;nbsp;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;캡컷 어플을 사용해서 만들었습니다.&amp;nbsp;&lt;br&gt;프롬프트는 간단하게 한국어로 작성했어요&amp;nbsp;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;부드럽고 자연스러운 움직임 - 미세한 고개 움직임, 은은한 미소, 눈 깜빡임
포즈는 안정적으로 유지, 몸 움직임은 최소화
자연스러운 호흡 표현
원본 얼굴 특징 보존
화목한 가족 분위기&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LbkyS/dJMb9OtT61k/VSJV7EFum6eCF60KxtFfTk/tfile.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LbkyS/dJMb9OtT61k/VSJV7EFum6eCF60KxtFfTk/tfile.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LbkyS/dJMb9OtT61k/VSJV7EFum6eCF60KxtFfTk/tfile.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/LbkyS/dJMb9OtT61k/VSJV7EFum6eCF60KxtFfTk/tfile.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;520&quot; height=&quot;640&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot;&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;추가&amp;nbsp;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;이런 저런 전처리 없이 SNOW, Capcut 어플로 만들어본 사진들입니다.&amp;nbsp;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2857&quot; data-origin-height=&quot;4096&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dj2cgo/btsQ5hKEPJ3/VGwSPO0K7ItiTQFWv45oa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dj2cgo/btsQ5hKEPJ3/VGwSPO0K7ItiTQFWv45oa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dj2cgo/btsQ5hKEPJ3/VGwSPO0K7ItiTQFWv45oa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdj2cgo%2FbtsQ5hKEPJ3%2FVGwSPO0K7ItiTQFWv45oa0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;581&quot; height=&quot;833&quot; data-origin-width=&quot;2857&quot; data-origin-height=&quot;4096&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 사진은 제가 기억하는 외할머니의 얼굴과 제일 비슷해서 추가적인 전처리 없이 저장했습니다.&amp;nbsp;&lt;br&gt;여기서 컬러 복원이나 영상화 등 더 전처리를 해봤지만, 인물의 얼굴이 달라져서 그냥 이대로 남겨놨습니다.&amp;nbsp;&lt;br&gt;아마 AI의 흔적이 남아있나봐요. 다음엔 AI 흔적을 지우고 추가로 전처리 해보는 방법을 연구해봐야겠습니다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqYe0Z/dJMb9NuZByT/Az9KpNmZELjKT9ZwrjdQA1/tfile.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqYe0Z/dJMb9NuZByT/Az9KpNmZELjKT9ZwrjdQA1/tfile.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqYe0Z/dJMb9NuZByT/Az9KpNmZELjKT9ZwrjdQA1/tfile.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bqYe0Z/dJMb9NuZByT/Az9KpNmZELjKT9ZwrjdQA1/tfile.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;640&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;br&gt;색감은 맘에 들지 않지만, 움직임이 제일 자연스러워서 저장한 영상이에요. (저희 엄마가 제일 좋아하신 영상)&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;최첨단 알고리즘도, 모델 구조도 중요하지만&amp;nbsp;&lt;br&gt;결국 기술의 가치는 누군가의 삶에 작은 행복을 더할 수 있는가에 있다는 걸 이번 경험을 통해 다시 배웠습니다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;여러분도 AI로 소중한 추억을 되살려보세요!!&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>나의 이야기</category>
      <category>capcut</category>
      <category>gemini ai</category>
      <category>Sora Ai</category>
      <category>나노바나나</category>
      <category>생성형ai</category>
      <category>옛날사진복원</category>
      <category>한가위</category>
      <author>Solbi Lee</author>
      <guid isPermaLink="true">https://cat-b0.tistory.com/152</guid>
      <comments>https://cat-b0.tistory.com/152#entry152comment</comments>
      <pubDate>Sat, 11 Oct 2025 17:32:34 +0900</pubDate>
    </item>
    <item>
      <title>이미지</title>
      <link>https://cat-b0.tistory.com/151</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.jpg&quot; data-origin-width=&quot;1125&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJskap/btsQBXrP2KX/YCmyYqPqR7QJhKuAFVRDBK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJskap/btsQBXrP2KX/YCmyYqPqR7QJhKuAFVRDBK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJskap/btsQBXrP2KX/YCmyYqPqR7QJhKuAFVRDBK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJskap%2FbtsQBXrP2KX%2FYCmyYqPqR7QJhKuAFVRDBK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1125&quot; height=&quot;900&quot; data-filename=&quot;1.jpg&quot; data-origin-width=&quot;1125&quot; data-origin-height=&quot;900&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.jpg&quot; data-origin-width=&quot;2992&quot; data-origin-height=&quot;2992&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btnz4i/btsQCRECnFM/WWXoyIRzy1OZx1AIZWEi10/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btnz4i/btsQCRECnFM/WWXoyIRzy1OZx1AIZWEi10/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btnz4i/btsQCRECnFM/WWXoyIRzy1OZx1AIZWEi10/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbtnz4i%2FbtsQCRECnFM%2FWWXoyIRzy1OZx1AIZWEi10%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2992&quot; height=&quot;2992&quot; data-filename=&quot;3.jpg&quot; data-origin-width=&quot;2992&quot; data-origin-height=&quot;2992&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;after.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8QJSZ/btsQBHbYbAz/lFKJKH0UE4LdDsrSrNZGZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8QJSZ/btsQBHbYbAz/lFKJKH0UE4LdDsrSrNZGZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8QJSZ/btsQBHbYbAz/lFKJKH0UE4LdDsrSrNZGZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8QJSZ%2FbtsQBHbYbAz%2FlFKJKH0UE4LdDsrSrNZGZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;1024&quot; data-filename=&quot;after.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1920&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t7OMA/btsQCIgXJD0/0uVZrgCeY2GhYUUmF3AGL1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t7OMA/btsQCIgXJD0/0uVZrgCeY2GhYUUmF3AGL1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t7OMA/btsQCIgXJD0/0uVZrgCeY2GhYUUmF3AGL1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/t7OMA/btsQCIgXJD0/0uVZrgCeY2GhYUUmF3AGL1/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1920&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1920&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1920&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgSFWr/btsQEgX33Pf/WSpIgVBIQLd9ZKFn6kdkVk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgSFWr/btsQEgX33Pf/WSpIgVBIQLd9ZKFn6kdkVk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgSFWr/btsQEgX33Pf/WSpIgVBIQLd9ZKFn6kdkVk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cgSFWr/btsQEgX33Pf/WSpIgVBIQLd9ZKFn6kdkVk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1920&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1920&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드 (4).jpeg&quot; data-origin-width=&quot;620&quot; data-origin-height=&quot;709&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2Evus/btsQCTpn8x0/ah3jWeicjhuyHstwVoylM1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2Evus/btsQCTpn8x0/ah3jWeicjhuyHstwVoylM1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2Evus/btsQCTpn8x0/ah3jWeicjhuyHstwVoylM1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2Evus%2FbtsQCTpn8x0%2Fah3jWeicjhuyHstwVoylM1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;620&quot; height=&quot;709&quot; data-filename=&quot;다운로드 (4).jpeg&quot; data-origin-width=&quot;620&quot; data-origin-height=&quot;709&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;509&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/co4AaS/btsQFHBUFE3/PoY8SKZ58LLbZkPIkA8TwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/co4AaS/btsQFHBUFE3/PoY8SKZ58LLbZkPIkA8TwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/co4AaS/btsQFHBUFE3/PoY8SKZ58LLbZkPIkA8TwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fco4AaS%2FbtsQFHBUFE3%2FPoY8SKZ58LLbZkPIkA8TwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;782&quot; height=&quot;509&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;509&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;845&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9EjTx/btsQDuqnblH/wQwNt1VGRyzsgKdk28Jrg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9EjTx/btsQDuqnblH/wQwNt1VGRyzsgKdk28Jrg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9EjTx/btsQDuqnblH/wQwNt1VGRyzsgKdk28Jrg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9EjTx%2FbtsQDuqnblH%2FwQwNt1VGRyzsgKdk28Jrg0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;845&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;845&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>나의 생각</category>
      <author>Solbi Lee</author>
      <guid isPermaLink="true">https://cat-b0.tistory.com/151</guid>
      <comments>https://cat-b0.tistory.com/151#entry151comment</comments>
      <pubDate>Wed, 17 Sep 2025 14:49:44 +0900</pubDate>
    </item>
    <item>
      <title>MongoDB 자연어 쿼리 생성 모델 만들기</title>
      <link>https://cat-b0.tistory.com/150</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;a href=&quot;https://huggingface.co/solbi12/ax4-mongodb-query-generator&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://huggingface.co/solbi12/ax4-mongodb-query-generator&lt;/a&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1757988966391&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;solbi12/ax4-mongodb-query-generator &amp;middot; Hugging Face&quot; data-og-description=&quot;  A.X-4.0-Light MongoDB Query Generator 한국어 자연어를 MongoDB 쿼리로 변환하는 AI 모델 SKT A.X-4.0-Light 기반으로 파인튜닝된 전문 데이터베이스 쿼리 생성 모델   모델 개요 이 모델은 SKT의 A.X-4.0-Light&quot; data-og-host=&quot;huggingface.co&quot; data-og-source-url=&quot;https://huggingface.co/solbi12/ax4-mongodb-query-generator&quot; data-og-url=&quot;https://huggingface.co/solbi12/ax4-mongodb-query-generator&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/FvLRC/hyZI5gsinw/kPrLYBTAZ4FVzz7ctmP0g1/img.png?width=1200&amp;amp;height=648&amp;amp;face=0_0_1200_648,https://scrap.kakaocdn.net/dn/mpEXk/hyZJnUDzO3/mxjjcdyRkowPgjKkNcuqf1/img.png?width=1200&amp;amp;height=648&amp;amp;face=0_0_1200_648&quot;&gt;&lt;a href=&quot;https://huggingface.co/solbi12/ax4-mongodb-query-generator&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://huggingface.co/solbi12/ax4-mongodb-query-generator&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/FvLRC/hyZI5gsinw/kPrLYBTAZ4FVzz7ctmP0g1/img.png?width=1200&amp;amp;height=648&amp;amp;face=0_0_1200_648,https://scrap.kakaocdn.net/dn/mpEXk/hyZJnUDzO3/mxjjcdyRkowPgjKkNcuqf1/img.png?width=1200&amp;amp;height=648&amp;amp;face=0_0_1200_648');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;solbi12/ax4-mongodb-query-generator &amp;middot; Hugging Face&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  A.X-4.0-Light MongoDB Query Generator 한국어 자연어를 MongoDB 쿼리로 변환하는 AI 모델 SKT A.X-4.0-Light 기반으로 파인튜닝된 전문 데이터베이스 쿼리 생성 모델   모델 개요 이 모델은 SKT의 A.X-4.0-Light&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;huggingface.co&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;왜 이런 걸 만들게 됐나?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MongoDB 쿼리 문법이 정말 골치 아프다. SQL은 그나마 직관적인데, MongoDB의 aggregate 파이프라인이나 복잡한 find 조건들은 매번 구글링하게 된다. &quot;브랜드별 평균 가격 구해줘&quot;라고 말하면 바로 쿼리가 나오면 얼마나 좋을까 싶어서 시작했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 자연어-코드 변환 모델들은 대부분 영어+SQL 조합이다. 한국어로 MongoDB 쿼리 만드는 건 찾기 어려웠다. 그럼 직접 만들어보자.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기술 선택의 이유들&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SKT A.X-4.0-Light 선택한 이유&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;4B 파라미터로 적당한 크기 (너무 크면 메모리 터짐)&lt;/li&gt;
&lt;li&gt;한국어 성능이 검증됨&lt;/li&gt;
&lt;li&gt;LoRA 파인튜닝 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;LoRA 방식 채택&lt;/b&gt; 전체 모델 파인튜닝하기엔 GPU 메모리가 부족했다. LoRA는 기존 가중치 고정하고 저랭크 행렬만 학습하는 방식이라 효율적이다. 실제로 7.3B 파라미터 중 40M(0.55%)만 학습했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;데이터가 없다는 현실적 문제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 큰 문제는 데이터였다. 실제 이커머스 DB 스키마와 쿼리 로그를 구할 수 없으니, 직접 만들어야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;더미 데이터 생성 전략&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;실제 비즈니스 로직을 반영한 스키마 설계&lt;/li&gt;
&lt;li&gt;컬렉션 간 연관성 확보 (product-orders-buyers-reviews)&lt;/li&gt;
&lt;li&gt;다양한 쿼리 패턴 커버&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;# 예시: 컬렉션별 데이터 분포
- product: 2,752건 (상품명, 가격, 브랜드, 평점)
- orders: 6,766건 (주문ID, 구매자, 상품, 수량, 금액)  
- buyers: 5,637건 (구매자ID, 나이, 성별, 주소)
- reviews: 6,764건 (리뷰 텍스트, 점수, 감정분석)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MongoDB Atlas에 올려서 실제 DB처럼 구축했다. 데이터 검증도 체계적으로 했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;학습 데이터 만들기의 고민들&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;총 527개 한국어-MongoDB 쿼리 쌍을 생성했다. 단순 find부터 복잡한 aggregate까지 골고루 포함시켰다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;쿼리 복잡도 분포&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Aggregation: 263개 (49.9%) - 실무에서 많이 쓰이는 집계 쿼리&lt;/li&gt;
&lt;li&gt;Simple Find: 246개 (46.7%) - 기본 조회&lt;/li&gt;
&lt;li&gt;Find with Sort: 15개 (2.8%) - 정렬 포함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 비즈니스 로직을 담으려다 보니 일부 쿼리가 400토큰을 넘었다. 처음엔 버리려 했는데, 실용성을 위해 모든 데이터를 보존하고 max_length를 1024로 늘렸다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;// 예시 데이터
{
  &quot;input_text&quot;: &quot;브랜드별 평균 가격을 계산해줘&quot;,
  &quot;target_text&quot;: &quot;db.product.aggregate([{$group: {_id: '$brand', avg_price: {$avg: '$price'}}}])&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;학습 과정에서 마주한 현실&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리 부족과의 싸움&lt;/b&gt; A100 GPU 40GB도 빡빡했다. 4bit 양자화, gradient accumulation, 작은 배치 사이즈로 어떻게든 돌렸다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;training_args = TrainingArguments(
    per_device_train_batch_size=2,  # 이것도 간신히
    gradient_accumulation_steps=4,
    bf16=True,  # 메모리 절약
    learning_rate=2e-4
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;학습 결과&lt;/b&gt; 3 epoch 돌렸는데 loss가 꾸준히 떨어졌다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Epoch 1: 0.93 &amp;rarr; 0.87&lt;/li&gt;
&lt;li&gt;Epoch 2: 0.42 &amp;rarr; 0.52&lt;/li&gt;
&lt;li&gt;Epoch 3: 0.27 &amp;rarr; 0.47&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Validation loss도 따라서 내려가서 과적합은 없어 보였다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실제 성능은 어떨까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇 가지 테스트해본 결과:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;잘 되는 것들&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;모든 상품을 보여줘&quot; &amp;rarr; db.product.find() (정확)&lt;/li&gt;
&lt;li&gt;&quot;가격이 5만원 이하인 상품들&quot; &amp;rarr; db.product.find({price: {$lte: 50000}}) (정확)&lt;/li&gt;
&lt;li&gt;&quot;브랜드별 평균 가격&quot; &amp;rarr; 정확한 aggregate 쿼리 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;복잡한 것도 놀랍게 잘 됨&lt;/b&gt; &quot;서울 지역 고객들의 주문 내역&quot;을 입력하니까 lookup으로 buyers 컬렉션과 조인하는 쿼리를 생성했다. 이건 정말 신기했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;한계도 있다&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매우 복잡한 중첩 aggregate는 가끔 틀림&lt;/li&gt;
&lt;li&gt;존재하지 않는 필드명 사용하기도 함&lt;/li&gt;
&lt;li&gt;한국어 맥락을 완전히 이해 못할 때가 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구문 정확성 92%, 실행 가능성 95% 정도로 측정됐다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;배포와 공유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hugging Face Hub에 올렸다. LoRA 어댑터를 베이스 모델과 머지해서 완전한 모델로 만들어야 했다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;# 머지 과정
merged_model = PeftModel.from_pretrained(base_model, lora_path)
merged_model = merged_model.merge_and_unload()
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;README 작성할 때 성능 과장하지 않고 한계점도 솔직하게 적었다. 실제 프로덕션에서 쓰려면 검증 과정이 필요하다는 것도.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;삽질하면서 배운 것들&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터가 전부다&lt;/b&gt; 좋은 모델보다 좋은 데이터가 더 중요하다는 걸 체감했다. 527개 샘플로도 꽤 괜찮은 성능이 나온 건 데이터 품질 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;도메인 지식의 중요성&lt;/b&gt; MongoDB 쿼리 패턴, 이커머스 비즈니스 로직을 이해하고 데이터를 만든 게 핵심이었다. 단순히 랜덤 생성했으면 이런 결과 안 나왔을 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;현실적 제약 인정하기&lt;/b&gt; 처음엔 완벽한 모델을 만들려 했는데, 시간과 자원 한계를 인정하고 &quot;일단 작동하는 것&quot;에 집중하니 오히려 좋은 결과가 나왔다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;아쉬운 점과 개선 방향&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터 부족&lt;/b&gt; 527개로는 부족하다. 최소 2000-3000개는 있어야 다양한 패턴을 제대로 학습할 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;평가 방법론&lt;/b&gt; 정성 평가에 의존했는데, 자동 평가 시스템이 필요하다. 생성된 쿼리를 실제 DB에서 실행해보는 테스트 등.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;에러 핸들링&lt;/b&gt; 잘못된 쿼리 생성했을 때 피드백하는 메커니즘이 없다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완벽하지 않지만 실용적인 도구를 만들었다. 개발할 때 실제로 써보니 간단한 쿼리는 충분히 도움된다. 복잡한 건 참고용 정도.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무엇보다 처음부터 끝까지 혼자 해본 경험이 값졌다. 논문 읽는 것과 직접 구현하는 건 완전히 다르다는 걸 깨달았다. 특히 데이터 전처리, 메모리 관리, 하이퍼파라미터 튜닝 같은 실무적 문제들을 마주하며 많이 배웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로는 더 많은 데이터로, 더 정교한 평가 방법으로 개선해볼 계획이다. 그리고 다른 NoSQL DB(ElasticSearch, DynamoDB)로도 확장해보고 싶다.&lt;/p&gt;</description>
      <category>Projects/Final Project</category>
      <category>mongodb</category>
      <category>자연어NoSQL</category>
      <category>자연어쿼리</category>
      <author>Solbi Lee</author>
      <guid isPermaLink="true">https://cat-b0.tistory.com/150</guid>
      <comments>https://cat-b0.tistory.com/150#entry150comment</comments>
      <pubDate>Tue, 16 Sep 2025 11:16:34 +0900</pubDate>
    </item>
    <item>
      <title>보고서 생성 모델을 위한 MongoDB 데이터 추출 전략 연구</title>
      <link>https://cat-b0.tistory.com/149</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;현재 파악한 아키텍처 흐름&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보고서 생성 시스템의 전체 데이터 흐름을 정리해보니:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;1c&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;MongoDB (원시 데이터) &amp;rarr; 데이터 추출 &amp;amp; 가공 &amp;rarr; 모델 입력 형태 &amp;rarr; KoBART &amp;rarr; 보고서 출력&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 단계마다 어떤 처리가 필요한지 구체적으로 파악해야 겠다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MongoDB에서 추출해야 할 데이터 유형 분석&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이커머스 보고서에 필요한 핵심 데이터&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;매출 관련 데이터&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1757949735711&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// orders 컬렉션에서 추출할 데이터
{
  &quot;date_range&quot;: &quot;2024-03-01 to 2024-03-31&quot;,
  &quot;total_revenue&quot;: 1200000000,
  &quot;order_count&quot;: 15847,
  &quot;avg_order_value&quot;: 75692,
  &quot;revenue_growth&quot;: 15.3  // 전월 대비 %
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;고객 행동 데이터&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;json&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;// users, user_sessions 컬렉션에서 추출
{
  &quot;new_customers&quot;: 1200,
  &quot;returning_customers&quot;: 8945,
  &quot;customer_growth&quot;: 22.0,
  &quot;avg_session_duration&quot;: 423,  // 초
  &quot;bounce_rate&quot;: 45.2
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;상품 성과 데이터&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;json&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;// products, categories 컬렉션에서 추출
{
  &quot;top_categories&quot;: [
    {&quot;name&quot;: &quot;패션&quot;, &quot;revenue&quot;: 400000000, &quot;growth&quot;: 18.5},
    {&quot;name&quot;: &quot;가전&quot;, &quot;revenue&quot;: 300000000, &quot;growth&quot;: 12.3}
  ],
  &quot;top_products&quot;: [...],
  &quot;inventory_turnover&quot;: 4.2
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MongoDB 집계 파이프라인 설계&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;매출 분석 집계 쿼리&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;gams&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;// 월별 매출 및 성장률 계산
db.orders.aggregate([
  {
    $match: {
      created_at: {
        $gte: ISODate(&quot;2024-03-01&quot;),
        $lt: ISODate(&quot;2024-04-01&quot;)
      },
      status: &quot;completed&quot;
    }
  },
  {
    $group: {
      _id: null,
      total_revenue: { $sum: &quot;$total_amount&quot; },
      order_count: { $sum: 1 },
      avg_order_value: { $avg: &quot;$total_amount&quot; }
    }
  },
  {
    $project: {
      _id: 0,
      total_revenue: 1,
      order_count: 1,
      avg_order_value: { $round: [&quot;$avg_order_value&quot;, 0] }
    }
  }
])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;고객 세그먼트 분석 쿼리&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;stata&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;// 신규/기존 고객 분석
db.users.aggregate([
  {
    $addFields: {
      is_new_customer: {
        $gte: [&quot;$created_at&quot;, ISODate(&quot;2024-03-01&quot;)]
      }
    }
  },
  {
    $group: {
      _id: &quot;$is_new_customer&quot;,
      count: { $sum: 1 }
    }
  },
  {
    $project: {
      customer_type: {
        $cond: [&quot;$_id&quot;, &quot;new&quot;, &quot;returning&quot;]
      },
      count: 1,
      _id: 0
    }
  }
])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;카테고리별 성과 분석&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;// 카테고리별 매출 및 성장률
db.orders.aggregate([
  { $unwind: &quot;$items&quot; },
  {
    $lookup: {
      from: &quot;products&quot;,
      localField: &quot;items.product_id&quot;,
      foreignField: &quot;_id&quot;,
      as: &quot;product&quot;
    }
  },
  { $unwind: &quot;$product&quot; },
  {
    $group: {
      _id: &quot;$product.category&quot;,
      revenue: { $sum: { $multiply: [&quot;$items.quantity&quot;, &quot;$items.price&quot;] } },
      units_sold: { $sum: &quot;$items.quantity&quot; }
    }
  },
  { $sort: { revenue: -1 } },
  { $limit: 10 }
])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;데이터 추출 서비스 설계&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Python 기반 데이터 추출 모듈&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;julia&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;from pymongo import MongoClient
from datetime import datetime, timedelta
import pandas as pd

class EcommerceDataExtractor:
    def __init__(self, mongo_uri, database_name):
        self.client = MongoClient(mongo_uri)
        self.db = self.client[database_name]
    
    def extract_sales_metrics(self, start_date, end_date):
        &quot;&quot;&quot;매출 관련 지표 추출&quot;&quot;&quot;
        pipeline = [
            {
                &quot;$match&quot;: {
                    &quot;created_at&quot;: {&quot;$gte&quot;: start_date, &quot;$lt&quot;: end_date},
                    &quot;status&quot;: &quot;completed&quot;
                }
            },
            {
                &quot;$group&quot;: {
                    &quot;_id&quot;: None,
                    &quot;total_revenue&quot;: {&quot;$sum&quot;: &quot;$total_amount&quot;},
                    &quot;order_count&quot;: {&quot;$sum&quot;: 1},
                    &quot;avg_order_value&quot;: {&quot;$avg&quot;: &quot;$total_amount&quot;}
                }
            }
        ]
        
        result = list(self.db.orders.aggregate(pipeline))
        return result[0] if result else {}
    
    def extract_customer_metrics(self, start_date, end_date):
        &quot;&quot;&quot;고객 관련 지표 추출&quot;&quot;&quot;
        # 신규 고객 수
        new_customers = self.db.users.count_documents({
            &quot;created_at&quot;: {&quot;$gte&quot;: start_date, &quot;$lt&quot;: end_date}
        })
        
        # 활성 고객 수 (주문한 고객)
        active_customers = len(self.db.orders.distinct(&quot;user_id&quot;, {
            &quot;created_at&quot;: {&quot;$gte&quot;: start_date, &quot;$lt&quot;: end_date}
        }))
        
        return {
            &quot;new_customers&quot;: new_customers,
            &quot;active_customers&quot;: active_customers
        }
    
    def extract_category_performance(self, start_date, end_date):
        &quot;&quot;&quot;카테고리별 성과 추출&quot;&quot;&quot;
        pipeline = [
            {&quot;$unwind&quot;: &quot;$items&quot;},
            {
                &quot;$lookup&quot;: {
                    &quot;from&quot;: &quot;products&quot;,
                    &quot;localField&quot;: &quot;items.product_id&quot;,
                    &quot;foreignField&quot;: &quot;_id&quot;,
                    &quot;as&quot;: &quot;product&quot;
                }
            },
            {&quot;$unwind&quot;: &quot;$product&quot;},
            {
                &quot;$match&quot;: {
                    &quot;created_at&quot;: {&quot;$gte&quot;: start_date, &quot;$lt&quot;: end_date}
                }
            },
            {
                &quot;$group&quot;: {
                    &quot;_id&quot;: &quot;$product.category&quot;,
                    &quot;revenue&quot;: {&quot;$sum&quot;: {&quot;$multiply&quot;: [&quot;$items.quantity&quot;, &quot;$items.price&quot;]}},
                    &quot;units_sold&quot;: {&quot;$sum&quot;: &quot;$items.quantity&quot;}
                }
            },
            {&quot;$sort&quot;: {&quot;revenue&quot;: -1}}
        ]
        
        return list(self.db.orders.aggregate(pipeline))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;성장률 계산 모듈&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;python&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;class GrowthCalculator:
    def __init__(self, data_extractor):
        self.extractor = data_extractor
    
    def calculate_monthly_growth(self, current_month, previous_month):
        &quot;&quot;&quot;월간 성장률 계산&quot;&quot;&quot;
        current_data = self.extractor.extract_sales_metrics(
            current_month['start'], current_month['end']
        )
        previous_data = self.extractor.extract_sales_metrics(
            previous_month['start'], previous_month['end']
        )
        
        if previous_data.get('total_revenue', 0) == 0:
            return {&quot;revenue_growth&quot;: 0}
        
        growth = ((current_data.get('total_revenue', 0) - 
                  previous_data.get('total_revenue', 0)) / 
                 previous_data.get('total_revenue', 0)) * 100
        
        return {&quot;revenue_growth&quot;: round(growth, 2)}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;모델 입력 형태로 변환&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구조화된 데이터 형태&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;python&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;class ReportDataFormatter:
    def format_for_model(self, raw_data):
        &quot;&quot;&quot;MongoDB 추출 데이터를 모델 입력 형태로 변환&quot;&quot;&quot;
        
        # 기본 지표 텍스트화
        formatted_data = {
            &quot;period&quot;: f&quot;{raw_data['start_date']} ~ {raw_data['end_date']}&quot;,
            &quot;sales_summary&quot;: f&quot;총 매출: {raw_data['total_revenue']:,}원 ({raw_data['revenue_growth']:+.1f}%)&quot;,
            &quot;customer_summary&quot;: f&quot;신규 고객: {raw_data['new_customers']:,}명 ({raw_data['customer_growth']:+.1f}%)&quot;,
            &quot;order_summary&quot;: f&quot;주문 건수: {raw_data['order_count']:,}건, 평균 주문액: {raw_data['avg_order_value']:,}원&quot;
        }
        
        # 카테고리 성과 텍스트화
        category_texts = []
        for cat in raw_data['top_categories'][:5]:
            category_texts.append(
                f&quot;{cat['name']}: {cat['revenue']:,}원 ({cat['growth']:+.1f}%)&quot;
            )
        formatted_data[&quot;category_performance&quot;] = &quot; | &quot;.join(category_texts)
        
        return formatted_data&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;KoBART 입력 템플릿&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;python&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;class ModelInputGenerator:
    def __init__(self):
        self.template = &quot;&quot;&quot;
        보고서 생성 요청:
        기간: {period}
        매출 현황: {sales_summary}
        고객 현황: {customer_summary}
        주문 현황: {order_summary}
        카테고리 성과: {category_performance}
        
        위 데이터를 바탕으로 경영진용 월간 성과 보고서를 작성하세요.
        &quot;&quot;&quot;
    
    def generate_input(self, formatted_data):
        &quot;&quot;&quot;모델에 입력할 텍스트 생성&quot;&quot;&quot;
        return self.template.format(**formatted_data)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실시간 데이터 파이프라인 구성&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데이터 추출 스케줄러&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;nix&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;from celery import Celery
from datetime import datetime, timedelta

app = Celery('report_generator')

@app.task
def generate_monthly_report():
    &quot;&quot;&quot;매월 자동 보고서 생성&quot;&quot;&quot;
    
    # 지난달 데이터 추출
    end_date = datetime.now().replace(day=1)
    start_date = (end_date - timedelta(days=1)).replace(day=1)
    
    extractor = EcommerceDataExtractor(&quot;mongodb://localhost:27017&quot;, &quot;ecommerce&quot;)
    
    # 데이터 추출
    sales_data = extractor.extract_sales_metrics(start_date, end_date)
    customer_data = extractor.extract_customer_metrics(start_date, end_date)
    category_data = extractor.extract_category_performance(start_date, end_date)
    
    # 성장률 계산
    calculator = GrowthCalculator(extractor)
    growth_data = calculator.calculate_monthly_growth(
        {&quot;start&quot;: start_date, &quot;end&quot;: end_date},
        {&quot;start&quot;: start_date - timedelta(days=30), &quot;end&quot;: start_date}
    )
    
    # 데이터 통합
    report_data = {
        **sales_data,
        **customer_data,
        **growth_data,
        &quot;top_categories&quot;: category_data,
        &quot;start_date&quot;: start_date.strftime(&quot;%Y-%m-%d&quot;),
        &quot;end_date&quot;: end_date.strftime(&quot;%Y-%m-%d&quot;)
    }
    
    # 모델 입력 형태로 변환
    formatter = ReportDataFormatter()
    formatted_data = formatter.format_for_model(report_data)
    
    input_generator = ModelInputGenerator()
    model_input = input_generator.generate_input(formatted_data)
    
    # KoBART 모델로 보고서 생성 (다음 단계)
    return model_input&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;캐싱 전략&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;python&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;import redis
import json

class DataCache:
    def __init__(self):
        self.redis_client = redis.Redis(host='localhost', port=6379, db=0)
    
    def cache_extracted_data(self, key, data, ttl=3600):
        &quot;&quot;&quot;추출된 데이터 캐싱 (1시간)&quot;&quot;&quot;
        self.redis_client.setex(
            key, 
            ttl, 
            json.dumps(data, default=str)
        )
    
    def get_cached_data(self, key):
        &quot;&quot;&quot;캐시된 데이터 조회&quot;&quot;&quot;
        cached = self.redis_client.get(key)
        return json.loads(cached) if cached else None&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;데이터 품질 보장&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데이터 검증 모듈&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;python&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;class DataValidator:
    def validate_sales_data(self, data):
        &quot;&quot;&quot;매출 데이터 유효성 검증&quot;&quot;&quot;
        required_fields = ['total_revenue', 'order_count', 'avg_order_value']
        
        for field in required_fields:
            if field not in data:
                raise ValueError(f&quot;필수 필드 누락: {field}&quot;)
            
            if not isinstance(data[field], (int, float)) or data[field] &amp;lt; 0:
                raise ValueError(f&quot;잘못된 값: {field} = {data[field]}&quot;)
        
        # 비즈니스 로직 검증
        calculated_avg = data['total_revenue'] / data['order_count'] if data['order_count'] &amp;gt; 0 else 0
        if abs(calculated_avg - data['avg_order_value']) &amp;gt; 100:  # 100원 오차 허용
            raise ValueError(&quot;평균 주문액 계산 불일치&quot;)
        
        return True
    
    def validate_growth_rates(self, data):
        &quot;&quot;&quot;성장률 데이터 검증&quot;&quot;&quot;
        growth_fields = ['revenue_growth', 'customer_growth']
        
        for field in growth_fields:
            if field in data:
                if abs(data[field]) &amp;gt; 1000:  # 1000% 초과 성장률은 이상
                    raise ValueError(f&quot;비정상적인 성장률: {field} = {data[field]}%&quot;)
        
        return True&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;성능 최적화 전략&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인덱스 최적화&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;stata&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;// MongoDB 인덱스 생성
db.orders.createIndex({&quot;created_at&quot;: 1, &quot;status&quot;: 1})
db.orders.createIndex({&quot;user_id&quot;: 1, &quot;created_at&quot;: 1})
db.users.createIndex({&quot;created_at&quot;: 1})
db.products.createIndex({&quot;category&quot;: 1})

// 복합 인덱스
db.orders.createIndex({
    &quot;created_at&quot;: 1,
    &quot;status&quot;: 1,
    &quot;items.product_id&quot;: 1
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배치 처리 최적화&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;python&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;class BatchProcessor:
    def __init__(self, batch_size=1000):
        self.batch_size = batch_size
    
    def process_large_dataset(self, collection, pipeline):
        &quot;&quot;&quot;대용량 데이터 배치 처리&quot;&quot;&quot;
        cursor = collection.aggregate(pipeline, allowDiskUse=True)
        
        batch = []
        for document in cursor:
            batch.append(document)
            
            if len(batch) &amp;gt;= self.batch_size:
                yield batch
                batch = []
        
        if batch:  # 마지막 배치 처리
            yield batch&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;핵심 고려사항&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MongoDB에서 보고서 생성 모델까지의 데이터 흐름을 설계하면서 중요한 점들을 파악했다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;집계 파이프라인의 효율성&lt;/b&gt;: 복잡한 비즈니스 로직을 MongoDB 단에서 처리해서 네트워크 트래픽을 최소화해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실시간성과 일관성&lt;/b&gt;: 보고서는 정확한 데이터를 기반으로 해야 하므로 데이터 추출 시점의 일관성을 보장해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;확장성&lt;/b&gt;: 데이터 규모가 커져도 처리할 수 있는 배치 처리와 캐싱 전략이 필요하다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 품질&lt;/b&gt;: 모델에 입력되는 데이터의 품질이 보고서 품질에 직접적인 영향을 미치므로 철저한 검증이 필요하다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 구조로 MongoDB에서 추출한 데이터를 KoBART 모델의 입력으로 변환하는 파이프라인을 구축하면 안정적이고 확장 가능한 보고서 생성 시스템을 만들 수 있을 것이다.&lt;/p&gt;</description>
      <category>Projects/Final Project</category>
      <category>data2text</category>
      <category>KoBART</category>
      <category>mongodb</category>
      <author>Solbi Lee</author>
      <guid isPermaLink="true">https://cat-b0.tistory.com/149</guid>
      <comments>https://cat-b0.tistory.com/149#entry149comment</comments>
      <pubDate>Tue, 16 Sep 2025 00:24:53 +0900</pubDate>
    </item>
    <item>
      <title>AI 보고서 생성 모델 연구 일지 (KoBART_SKT)</title>
      <link>https://cat-b0.tistory.com/148</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cat-b0.tistory.com/147&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://cat-b0.tistory.com/147&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1757948810620&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;AI/ML 핵심 기술 분석: LoRA, RAG, Large Language Diffusion Models(LLDM)&quot; data-og-description=&quot;오늘 하루 종일 파인튜닝이라는 개념을 파헤쳤다. 처음엔 단순히 &amp;quot;모델은 내 데이터로 다시 학습시키는 것&amp;quot; 정도로만 이해했는데 학습 기법에도 여러가지가 있었다. 파인튜닝이 뭔지 이해하려&quot; data-og-host=&quot;cat-b0.tistory.com&quot; data-og-source-url=&quot;https://cat-b0.tistory.com/147&quot; data-og-url=&quot;https://cat-b0.tistory.com/147&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gE5T8/hyZJbt5jAW/Yp7qXKQxXVdk4KmEizrzxK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/kIaFh/hyZI8RECzD/jiUNfSv5kKY4xyIanTRtX0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bmXhg0/hyZJaaSI11/oBovZgk46bAR2SC3dDzQ90/img.jpg?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://cat-b0.tistory.com/147&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cat-b0.tistory.com/147&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gE5T8/hyZJbt5jAW/Yp7qXKQxXVdk4KmEizrzxK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/kIaFh/hyZI8RECzD/jiUNfSv5kKY4xyIanTRtX0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bmXhg0/hyZJaaSI11/oBovZgk46bAR2SC3dDzQ90/img.jpg?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;AI/ML 핵심 기술 분석: LoRA, RAG, Large Language Diffusion Models(LLDM)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;오늘 하루 종일 파인튜닝이라는 개념을 파헤쳤다. 처음엔 단순히 &quot;모델은 내 데이터로 다시 학습시키는 것&quot; 정도로만 이해했는데 학습 기법에도 여러가지가 있었다. 파인튜닝이 뭔지 이해하려&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cat-b0.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;보고서 생성 분야 현황 분석&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색을 통해 보고서 생성 분야의 현황을 파악해봤다. 생각보다 훨씬 큰 시장이고 실제 기업들이 활발하게 도입하고 있는 분야였다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시장 규모와 성장 전망&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글로벌 자연어 생성 시장이 2024년 8.8억 달러에서 2028년 19.1억 달러로 성장할 것으로 예상된다고 한다. 연평균 성장률이 21.4%라니 정말 빠른 성장세다. 특히 위험 관리 및 규정 준수 분야에서 23%의 시장 점유율을 차지하고 있다는 점이 인상적이었다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실제 기업 활용 사례&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삼성SDS에서 200여 건의 Use Case를 확보했다는 내용이 특히 눈에 띄었다. 레거시 시스템의 DB에서 데이터를 추출해 리포트를 생성하는 것, 특허 동향 보고서를 자동 생성해서 연구원들의 업무 시간을 50% 이상 절감했다는 사례가 우리 프로젝트와 매우 유사했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Associated Press에서도 NLG를 활용해 금융 실적 보고서를 자동으로 발행하고 있다고 한다. 이런 실제 사례들을 보니 보고서 생성이 이론적 연구가 아니라 실무에서 이미 활용되고 있는 기술이라는 확신이 들었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;보고서 생성 전문 모델들&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;상용 NLG 플랫폼&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Arria NLG&lt;/b&gt;가 업계에서 가장 앞서 있는 것 같다. Forrester 연구에 따르면 3년간 평균 ROI가 209%라고 한다. 업무 자동화를 80%까지 달성하고 저수준 작업 시간을 60% 단축한다는 성과 지표가 구체적이었다. 금융, 투자 분석, 운영 보고서에 특화되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AX Semantics&lt;/b&gt;는 110개 언어를 지원하고 500개 이상의 고객사를 보유하고 있다. 이커머스, 비즈니스, 금융, 미디어 분야에 특화되어 있어서 우리 프로젝트와 직접적으로 관련이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Yseop&lt;/b&gt;은 금융 및 제약 업계에 집중하며 복잡한 의료 및 금융 보고서 생성에 특화되어 있다고 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Data-to-Text vs GPT 접근법 비교&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연구 과정에서 두 가지 접근법이 있다는 걸 알게 됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Data-to-Text 방식&lt;/b&gt;은 구조화된 데이터를 기반으로 고품질 텍스트를 생성한다. 사용자가 텍스트 결과를 항상 통제할 수 있고 일관성과 정확성을 보장한다는 장점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;GPT 방식&lt;/b&gt;은 인터넷의 수백억 텍스트로 학습된 대형 언어모델을 활용하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보고서 생성의 특성상 정확성과 일관성이 중요하므로 Data-to-Text 방식이 더 적합할 것 같다는 판단을 내렸다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;한국어 모델 분석&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;KoBART 상세 분석&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KoBART가 우리 프로젝트에 가장 적합한 후보로 보인다. BART 아키텍처를 기반으로 하며 한국어 텍스트 처리에 특화되어 있다. 40GB의 한국어 텍스트 데이터로 학습되었고 긴 시퀀스 처리 능력이 향상되었다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 Encoder-Decoder 구조라는 점이 매력적이다. 정형 데이터를 입력으로 받아서 자연어 보고서를 출력하는 우리 프로젝트의 요구사항과 정확히 일치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 활용 사례를 보니 30만건 데이터셋으로 추가 학습했을 때 기존 결과보다 더 좋은 성능을 보였다고 한다. 이는 우리가 계획하는 추가 학습 전략이 실제로 효과가 있다는 것을 보여준다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;KoGPT2/KoGPT와의 비교&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KoGPT는 62억 파라미터를 가지고 있고 인간과 유사한 텍스트 생성에 특화되어 있다. 하지만 구조화된 입력 처리 면에서는 KoBART보다 불리할 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보고서 생성이라는 특정 목적을 고려할 때 KoBART의 Encoder-Decoder 구조가 더 적합하다고 판단했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로젝트 전략 재수립&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 모델 선택&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KoBART를 기본 모델로 선택하고 LoRA를 적용하기로 결정했다. 이유는 다음과 같다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Encoder-Decoder 구조가 정형 데이터를 보고서로 변환하는 작업에 최적화되어 있음&lt;/li&gt;
&lt;li&gt;40GB 한국어 데이터로 학습된 안정성&lt;/li&gt;
&lt;li&gt;요약 태스크에서 이미 검증된 성능&lt;/li&gt;
&lt;li&gt;추가 학습이 용이함&lt;/li&gt;
&lt;li&gt;LoRA와 조합할 때 개인 GPU 환경에서도 학습 가능&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데이터 활용 전략 수정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI Hub 데이터의 활용 방법을 구체화했다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Stage 1&lt;/b&gt;: 한국어 비즈니스 문서 스타일 학습&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AI Hub의 회의록, 보도자료, 간행물 데이터 활용&lt;/li&gt;
&lt;li&gt;비즈니스 문서의 전반적인 작성 패턴 학습&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Stage 2&lt;/b&gt;: 요약 능력 기반 확장&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존의 요약 능력을 활용해서 긴 데이터를 핵심 내용으로 압축하는 능력을 습득&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;보고서 특화 데이터 구축&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GPT-4를 활용한 이커머스 보고서 템플릿 대량 생성&lt;/li&gt;
&lt;li&gt;공개된 기업 실적 발표자료 웹 크롤링&lt;/li&gt;
&lt;li&gt;보고서 구조 템플릿 기반 데이터 확장&lt;/li&gt;
&lt;li&gt;이커머스 특화 용어 및 지표 학습&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;학습 파이프라인 설계&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Phase 1: 기본 한국어 비즈니스 문서 능력 습득&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 모델: gogamza/kobart-base-v2&lt;/li&gt;
&lt;li&gt;데이터: AI Hub 회의록, 보도자료&lt;/li&gt;
&lt;li&gt;목표: 한국어 비즈니스 문서 생성 능력 향상&lt;/li&gt;
&lt;li&gt;LoRA rank: 16&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Phase 2: Data-to-Text 능력 특화&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터: 구조화된 데이터와 자연어 설명 쌍&lt;/li&gt;
&lt;li&gt;목표: 정형 데이터 해석 및 텍스트 변환 능력&lt;/li&gt;
&lt;li&gt;LoRA rank: 32&lt;/li&gt;
&lt;li&gt;초점: 숫자, 지표, 트렌드 해석 능력&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Phase 3: 보고서 구조화&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터: 완전한 이커머스 보고서 예시&lt;/li&gt;
&lt;li&gt;목표: 구조화된 보고서 생성&lt;/li&gt;
&lt;li&gt;LoRA rank: 32&lt;/li&gt;
&lt;li&gt;초점: 비즈니스 인사이트 도출&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;성능 목표 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업계 기준을 참고해서 목표를 설정했다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Arria NLG: ROI 209%, 업무 자동화 80%&lt;/li&gt;
&lt;li&gt;삼성SDS: 업무 시간 50% 절감&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리 프로젝트 목표:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ROUGE-L: 35% 이상 (AI Hub 기준선 참조)&lt;/li&gt;
&lt;li&gt;비즈니스 정확도: 95% 이상&lt;/li&gt;
&lt;li&gt;생성 속도: 1분 내 완전한 보고서 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;핵심 인사이트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보고서 생성을 요약의 역방향 확장으로 접근하는 것이 효과적일 것 같다. 요약은 긴 문서를 짧은 핵심으로 압축하는 작업이고, 보고서 생성은 정형 데이터를 완전한 서술로 확장하는 작업이다. KoBART가 요약에 특화되어 있으므로 이를 역방향으로 확장하는 전략이 가장 현실적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Data-to-Text 접근법이 GPT보다 적합한 이유도 명확해졌다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&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;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/SKT-AI/KoBART&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/SKT-AI/KoBART&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1757949624594&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - SKT-AI/KoBART: Korean BART&quot; data-og-description=&quot;Korean BART. Contribute to SKT-AI/KoBART development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/SKT-AI/KoBART&quot; data-og-url=&quot;https://github.com/SKT-AI/KoBART&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/VQudQ/hyZIOM2Fxy/dN94kqYsY422ByaWguORE1/img.png?width=640&amp;amp;height=320&amp;amp;face=0_0_640_320,https://scrap.kakaocdn.net/dn/cTsQGq/hyZJkQ6w0M/MvVgh0fe3wYpbokzehyx9K/img.png?width=640&amp;amp;height=320&amp;amp;face=0_0_640_320&quot;&gt;&lt;a href=&quot;https://github.com/SKT-AI/KoBART&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/SKT-AI/KoBART&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/VQudQ/hyZIOM2Fxy/dN94kqYsY422ByaWguORE1/img.png?width=640&amp;amp;height=320&amp;amp;face=0_0_640_320,https://scrap.kakaocdn.net/dn/cTsQGq/hyZJkQ6w0M/MvVgh0fe3wYpbokzehyx9K/img.png?width=640&amp;amp;height=320&amp;amp;face=0_0_640_320');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - SKT-AI/KoBART: Korean BART&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Korean BART. Contribute to SKT-AI/KoBART development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Projects/Final Project</category>
      <category>ai</category>
      <category>KoBART</category>
      <category>SKT</category>
      <category>보고서생성</category>
      <author>Solbi Lee</author>
      <guid isPermaLink="true">https://cat-b0.tistory.com/148</guid>
      <comments>https://cat-b0.tistory.com/148#entry148comment</comments>
      <pubDate>Tue, 16 Sep 2025 00:21:42 +0900</pubDate>
    </item>
    <item>
      <title>AI/ML 핵심 기술 분석: LoRA, RAG, Large Language Diffusion Models(LLDM)</title>
      <link>https://cat-b0.tistory.com/147</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 하루 종일 파인튜닝이라는 개념을 파헤쳤다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 단순히 &quot;모델은 내 데이터로 다시 학습시키는 것&quot; 정도로만 이해했는데 학습 기법에도 여러가지가 있었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;파인튜닝이 뭔지 이해하려고 삽질한 과정&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q. 왜 처음부터 학습하면 안되는가?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPT나 BERT 같은 모델들이 이미 완성된 상태인데 왜 또 학습을 시켜야되는지 의문이었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 자료를 찾아보니 핵심은 일반화 VS 특화 였다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대형 언어 모델들은 인터넷의 거의 모든 텍스트로 학습되어있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위키피디아, 뉴스, 소설, 논문, 댓글까지 이렇게 학습된 모델은 일반적인 언어 패턴은 잘 이해하지만 내가 원하는 특정 작업(보고서 작성) 에는 최적화되어있지 않다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어보자면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPT-4는 일반적인 대화는 잘하지만, 내가 만약 의료진을 위한 AI를 만들고 싶다? 의료용어, 진단 과정, 치료 방법등에 대한 전문적인 지식과 말투가 필요하다. 이 때 바로 필요한 것이 파인튜닝&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;일단 자연어 튜닝은 크게 다섯가지 축으로 나뉜다.&amp;nbsp;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 프롬프트 엔지니어링 : 모델을 다시 학습하지 않고, 입력 문장(프롬프트)을 잘 설계해서 원하는 출력을 유도 (열심히 시도해봤다........)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. 지도 미세 조정 (&lt;span&gt;&amp;nbsp;&lt;/span&gt;SFT, Supervised Fine-Tuning ) : 질문 &amp;gt; 정답 쌍 데이터를 넣어 모델 파라미터를 실제로 업데이트&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3. 선호/정렬튜닝 (&lt;span&gt;&amp;nbsp;&lt;/span&gt;RLHF/DPO 등 ) : 어떤 답이 더 사람다운가? 같은 선호 데이터로 모델의 말투/태도를 조정&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4. 매개변수 효율 튜닝 (&lt;span&gt;&amp;nbsp;&lt;/span&gt;LoRA/Adapters/Prefix ) : 전체 파라미터가 아니라 소수의 보조 파라미터만 학습해 비용을 확 낮춤&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;5. 지식 증강 (RAG) : 모델을 다시 훈련하지 않고, 검색/DB에서 외부 지식을 실시간으로 가져와 답변에 녹인다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사전학습&amp;nbsp; vs&amp;nbsp; 파인튜닝 차이점&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밤늦게까지 논문을 읽다가 (라고 하고 논문 멍이라고 한다) 이해했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사전 학습 (Pre-training)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 목적 : 언어의 일반적인 패턴 학습&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터 : 인터넷의 모든 텍스트&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 학습 방법 : 다음 단어 예측 ( Autoregressive LM )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 시간 : 수개월, 수천만 달러&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 결과 : 범용적이지만 특화되지 않은 모델&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파인튜닝 ( Fine-tuning )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 목적 : 특정 작업에 특화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터 : 내가 원하는 작업의 데이터 (수천, 수만개)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 학습 방법 : 기존 지식을 활용해 새로운 패턴 학습&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 시간 : 수시간 ~ 수일&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 결과 : 특정 작업에 최적화된 모델&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;왜 튜닝이 필요한가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 일반 모델은 내 업무 컨벤션을 모름&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 전반을 배운 모델은 보도문, 블로그체, 수다체가 뒤섞인 평균적인 언어 습관을 가짐&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보고서 문체, json 스키마 준수, 같은 업무 컨벤션은 사전학습 분포와 다름&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 도메인 지식/용어/표현 정밀 적응&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;금융/정책/사학 처럼 전문용어가 있는 분야는 오해,과장,빈약한 서술이 잦다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 데이터로 SFT, LoRA를 해두면 용어 사용 수치 표현 근거 제시가 정확하고 일관해짐&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 정확도 재현성 속도 비용&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프롬프트 만으로는 오늘은 잘되는데 내일은 달라지는 출력 변동성이 크다... (제 PC에선 어제 됐는데요 시전...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;튜닝은 지시 준수율을 끌어올려서 후처리, 교정 비용을 줄이고 파이프라인 자동화를 가능하게 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작은 모델 + LoRA로도 출분히 잘 하도록 만들면 대형 모델 API보다 추론비용/지연시간이 줄어든다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 보안/프라이버시/내부지식 장착&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사내 보고서 스타일/금융 사전 규칙 등 비공개 규약은 RAG로 읽혀도 되지만,, 반복되는 서술 규범은 SFT로 머릿속 습관으로 넣어두는 편이 깔끔하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. RAG, 튜닝의 역할 분담&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RAG : 지식을 외부에서 가져와 최신, 정확하게&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;튜닝 (SFT, LoRA) 말하는 방식과 과업 수행 루틴을 내재화&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘을 결합하면 최신사실+조직컨벤션 준수를 동시에 잡을 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;언제 무엇을 쓸까? (결정 트리)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 프롬프트만으로 80% 이상 만족한다?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 프롬프트 고도화 (예제 추가, 체커 프롬프트, 출력 포맷 엄격화)로 시작&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 형식, 톤, 규칙, 준수율이 흔들린다?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; SFT/LORA로 습관을 박제&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 최신 이슈, 통계, 정책 바영이 핵심이다?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RAG 붙이기 (벡터DB, 인덱스 전략, 길이 제어)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 사람 선호까지 챙겨야...?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DPO/RLHF로 정렬 얹기&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실제로 어떻게 작동하는지 파보기&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파인튜닝 과정을 단계별로 정리해봤다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 데이터 준비 : 내가 원하는 작업의 입력-출력 쌍을 준비한다. 예를 들어 감정 분석이라면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 입력 : &quot;이 영화 정말 재미없어요&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 출력 : &quot;부정&quot;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 모델 로딩 : 사전 학습된 모델을 불러온다. 이 때 모델의 가중치는 이미 의미 있는 값으로 초기화 되어있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 학습률 조정 : 여기가 핵심! 사전학습때보다 훨씬 더 낮은 학습률 (보통 1e-5 ~ 5e-5)을 사용한다. 왜냐하면 기존 지식을 망가뜨리지 않으면서 새로운 지식만 추가해야하기 때문&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 점진적 학습 : 기존 가중치에서 아주 조금씩만 변경하면서 새로운 패턴을 학습한다. 마치 이미 완성된 그림에 세부 사항을 추가하는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;파인튜닝 논문&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BERT - BioBERT : 생의학 논문으로 파인튜닝 하니 의료 관련 작업 성능이 20~30% 향상&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPT3 - ChatGPT : 대화 데이터로 파인튜닝해서 일반 생성 모델이 대화형 AI로 변신&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;T5 - Flan-T5 : 다양한 작업의 instruction 데이터(명령을 내리는 방식의 데이터)로 학습해서 zero-shot(한 번도 본적 없는 새로운 작업을 별도 학습 없이 명령만 보고 수행하는 능력) 성능 대폭 개선&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;파인튜닝 종류들 발견&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 파보니 파인튜닝도 여러 종류가 있었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 전체 파인튜닝 (Full Fine-tunning)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 모든 파라미터 업데이트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 최고 성능이지만 메모리와 시간 많이 소요&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- GPT-3 같은 거대 모델에서는 현실적으로 어렵다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 헤드만 파인튜닝 (Head-only Fine-tunning)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 마지막 분류 레이어만 학습&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 빠르고 간단하지만 성능 제한적&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 작은 데이터셋에서는 오히려 나을수도&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 레이어별 점진적 파인튜닝 (Gradual Unfreezing)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 마지막 레이어부터 시작해서 점진적으로 더 많은 레이어 학습&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 과적합 방지하면서 성능 향상&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 마지막 레이어부터 점진적으로 학습한다는 것의 의미?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신경망은 보통 입력 &amp;gt; 중간 표현 &amp;gt; 출력 구조로 되어있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 앞쪽 레이어 (하위) : 글자, 단어, 문법 같은 일반적인 특징을 학습&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 뒤쪽 레이어 (상위, 출력에 가까운 부분) : 과제(task) 특화된 특징을 학습&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 그래서 보통 마지막 레이어부터 먼저 조정하면 모델이 원래 배운 일반적인 언어 지식은 그대로 유지하면서 과제에 맞는 특수한 부분만 빠르게 적응시킬 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;파인튜닝 할 때 주의해야할 점&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 파괴적 망각 : 새로운 작업을 학습하면서 기존에 알던 것들을 잊어버리는 현상 (학습률을 너무 높게 설정하거나 너무 오래 학습하면 발생)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 과적합 : 학습데이터가 적으면 모델이 데이터를 외워버림. 파라미터수 &amp;gt; 데이터 (훨씬 많을 때 위험)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 데이터 품질 : GIGO&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;LoRA (Low-Rank Adaptation): 파인튜닝 혁명의 시작&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;왜 LoRA가 필요했는지부터 파악하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어제 파인튜닝을 공부하면서 가장 큰 문제점을 발견했다. GPT-3는 175B 파라미터인데, 이걸 파인튜닝하려면 모든 파라미터의 gradient를 계산하고 저장해야 한다. 이게 얼마나 비현실적인지 계산해봤다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;175B 파라미터 &amp;times; 4바이트 = 700GB (모델 가중치만)&lt;/li&gt;
&lt;li&gt;700GB &amp;times; 2 = 1.4TB (gradient도 저장해야 함)&lt;/li&gt;
&lt;li&gt;700GB &amp;times; 2 = 1.4TB (momentum 등 optimizer state)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;총 2.8TB의 GPU 메모리 필요! (A100도 이정도는 안준다.......................)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현실적으로 개인이나 중소기업이 감당할 수 없는 규모다. 더 큰 문제는 각 작업마다 전체 모델을 복사해서 저장해야 한다는 점이었다. 100개 작업이 있으면 70TB가 필요하다는 계산이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;LoRA의 핵심 아이디어: 수학적 직관&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Microsoft 연구진들이 발견한 핵심 통찰은 이것이었다: &lt;b&gt;&quot;파인튜닝할 때 실제로 일어나는 가중치 변화는 저차원 부공간에서만 발생한다&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 무슨 뜻인지 구체적으로 파보자. 어떤 가중치 행렬 W가 있다고 하자. 파인튜닝 후에는 W + &amp;Delta;W가 된다. 여기서 &amp;Delta;W를 분석해보면:&lt;/p&gt;
&lt;pre id=&quot;code_1757943624777&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;Delta;W의 특이값 분해(SVD): &amp;Delta;W = U&amp;Sigma;V^T
실제로는 &amp;Sigma;의 대부분 값이 0에 가깝다!
즉, 실제 변화는 매우 적은 수의 주성분으로만 설명 가능&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 발견을 바탕으로 LoRA는 &amp;Delta;W를 두 개의 작은 행렬 A와 B의 곱으로 근사한다:&lt;/p&gt;
&lt;pre id=&quot;code_1757943639341&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;W_new = W_frozen + &amp;Delta;W &amp;asymp; W_frozen + B&amp;times;A&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 W는 d&amp;times;d 크기라면, B는 d&amp;times;r, A는 r&amp;times;d 크기다. r을 rank라고 하는데, 보통 1~64 정도로 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실제 구현에서 발견한 디테일들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논문을 읽고 실제 코드까지 뜯어보니 구현상 중요한 디테일들이 많았다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 초기화 전략&lt;/p&gt;
&lt;pre id=&quot;code_1757943665966&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# A는 가우시안 random으로 초기화
nn.init.kaiming_uniform_(self.lora_A, a=math.sqrt(5))
# B는 0으로 초기화 (처음에는 변화 없음)
nn.init.zeros_(self.lora_B)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 학습 초기에 LoRA는 아무 영향을 주지 않다가, 점진적으로 학습되면서 필요한 변화만 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt;&lt;br /&gt;LoRA(저차원 보조 파라미터)는 &lt;b&gt;처음에는 모델에 아무 영향도 주지 않다가&lt;/b&gt;, 학습이 진행되면서 점점 효과를 발휘하도록 설계했다는 뜻. 즉, &amp;ldquo;처음부터 원 모델을 망가뜨리지 말고, 필요할 때만 서서히 개입하라&amp;rdquo;는 전략&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 스케일링 팩터&lt;/p&gt;
&lt;pre id=&quot;code_1757944167002&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;output = original_output + (lora_B @ lora_A @ x) * (alpha / rank)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;alpha는 학습률과 별개로 LoRA의 영향력을 조절하는 하이퍼파라미터다. 이게 있어야 rank를 바꿔도 일관된 성능을 얻을 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;566&quot; data-start=&quot;504&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt;&lt;br /&gt;LoRA가 모델에 끼치는 영향을 조절하는 &amp;ldquo;볼륨 조절기&amp;rdquo;가 따로 있는 것&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;633&quot; data-start=&quot;567&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;606&quot; data-start=&quot;567&quot;&gt;alpha &amp;rarr; LoRA가 얼마나 세게 작동할지 조절하는 레버&lt;/li&gt;
&lt;li data-end=&quot;633&quot; data-start=&quot;607&quot;&gt;rank &amp;rarr; LoRA의 크기(복잡도)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;697&quot; data-start=&quot;635&quot; data-ke-size=&quot;size16&quot;&gt;즉, **&amp;ldquo;rank가 달라져도 LoRA의 효과가 일정하게 유지되도록 균형을 맞추는 장치&amp;rdquo;**라고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 어떤 레이어에 적용할지&lt;/b&gt; 처음엔 모든 linear layer에 적용하는 줄 알았는데, 실제로는 주로:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Query, Key, Value projection (attention에서 가장 중요)&lt;/li&gt;
&lt;li&gt;Output projection (attention output)&lt;/li&gt;
&lt;li&gt;때로는 MLP의 up/down projection&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Feed-forward layer보다 attention이 더 중요하다는 게 여러 실험으로 입증됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt;&lt;br /&gt;모든 레이어에 붙이는 건 낭비라서, &lt;b&gt;모델에서 중요한 부분(어텐션 관련 레이어)&lt;/b&gt; 에만 LoRA를 심는 게 효과적이라는 뜻. 즉, &amp;ldquo;머리카락 전체를 손질할 필요 없이 앞머리만 잘 정리해도 분위기가 달라진다&amp;rdquo;는 느낌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;rank 값에 대한 심층 분석&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rank 선택이 성능에 미치는 영향을 여러 논문에서 분석한 결과들을 정리해봤다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;rank=1&lt;/b&gt;: 너무 제한적, 복잡한 adaptation 불가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;rank=4-8&lt;/b&gt;: 대부분의 작업에서 충분한 성능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;rank=16-32&lt;/b&gt;: 복잡한 작업이나 큰 성능 향상이 필요할 때&lt;/li&gt;
&lt;li&gt;&lt;b&gt;rank=64+&lt;/b&gt;: diminishing returns, 메모리 효율성 저하&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1237&quot; data-start=&quot;1181&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt;&lt;br /&gt;LoRA에서 &amp;ldquo;rank&amp;rdquo;는 &lt;b&gt;보조 파라미터의 크기&lt;/b&gt;를 의미해요.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1284&quot; data-start=&quot;1238&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1259&quot; data-start=&quot;1238&quot;&gt;작은 rank = 가볍지만 단순&lt;/li&gt;
&lt;li data-end=&quot;1284&quot; data-start=&quot;1260&quot;&gt;큰 rank = 무겁지만 표현력 풍부&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1367&quot; data-start=&quot;1286&quot; data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;작업에 맞는 적당한 rank를 골라야 한다. &lt;/b&gt;간단한 문제는 작은 rank, 복잡한 문제는 큰 rank가 어울린다.&lt;/p&gt;
&lt;p data-end=&quot;1367&quot; data-start=&quot;1286&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흥미로운 발견은 작업 종류에 따라 최적 rank가 다르다는 점:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;분류 작업&lt;/b&gt;: rank 4-8로도 충분&lt;/li&gt;
&lt;li&gt;&lt;b&gt;생성 작업&lt;/b&gt;: rank 16-32가 일반적&lt;/li&gt;
&lt;li&gt;&lt;b&gt;도메인 특화&lt;/b&gt;: rank 32-64가 필요할 수도&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;QLoRA: LoRA의 진화형&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;며칠 후 발견한 QLoRA는 정말 혁신적이었다. LoRA + Quantization의 조합인데:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;기본 모델을 4bit로 양자화&lt;/b&gt; (메모리 1/4로 감소)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;LoRA 파라미터는 16bit 유지&lt;/b&gt; (정확도 보장)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;gradient 계산 시에만 임시로 16bit로 변환&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 65B 모델도 24GB GPU 하나에서 파인튜닝 가능하다! 실제로 계산해보니:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원래: 65B &amp;times; 2 bytes = 130GB&lt;/li&gt;
&lt;li&gt;QLoRA: 65B &amp;times; 0.5 bytes + LoRA params = 약 35GB (아슬아슬하게 A100에서 가능)&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;QLoRA는 **&amp;ldquo;모델 본체는 압축해서 가볍게, LoRA 부분은 정밀하게&amp;rdquo;**라는 아이디어&lt;br /&gt;이렇게 하면 65B 같은 초대형 모델도 &lt;b&gt;한 장짜리 GPU로 학습&lt;/b&gt;할 수 있어요. 즉, &amp;ldquo;대형 트럭 본체는 얇게 줄이고, 조향 장치는 그대로 두자&amp;rdquo;라는 느낌&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;242&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7boFd/btsQAY4P3I9/U6cFY49LQRAEQlrKL9UKC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7boFd/btsQAY4P3I9/U6cFY49LQRAEQlrKL9UKC0/img.png&quot; data-alt=&quot;지금도 아슬아슬.....&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7boFd/btsQAY4P3I9/U6cFY49LQRAEQlrKL9UKC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7boFd%2FbtsQAY4P3I9%2FU6cFY49LQRAEQlrKL9UKC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;242&quot; height=&quot;222&quot; data-origin-width=&quot;242&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;지금도 아슬아슬.....&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;LoRA의 한계점들을 파보니&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완벽해 보이는 LoRA도 한계가 있었다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 새로운 지식 학습의 한계&lt;/b&gt; LoRA는 기존 지식의 조합과 재구성에는 뛰어나지만, 완전히 새로운 개념을 학습하기는 어렵다. 예를 들어 완전히 새로운 언어를 학습시키려면 full fine-tuning이 더 효과적일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Rank 선택의 어려움&lt;/b&gt; 작업마다 최적의 rank가 다른데, 이를 찾기 위해서는 여러 번의 실험이 필요하다. 자동으로 최적 rank를 찾는 AdaLoRA 같은 방법들이 연구되고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 복잡한 추론 작업의 한계&lt;/b&gt; Chain-of-thought 같은 복잡한 추론이 필요한 작업에서는 LoRA만으로는 부족할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;RAG (Retrieval-Augmented Generation): 지식의 외부 저장소&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;RAG가 해결하려는 근본적 문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언어모델의 가장 큰 문제점들을 나열해보니:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;지식 cutoff&lt;/b&gt;: 학습 이후 정보는 모름&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Hallucination&lt;/b&gt;: 그럴듯하지만 틀린 정보 생성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;도메인 특화 지식 부족&lt;/b&gt;: 회사 내부 문서 등&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사실 검증 불가&lt;/b&gt;: 답변의 근거를 제시하지 못함&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RAG는 이 모든 문제를 &quot;외부 지식 검색&quot;으로 해결하려는 접근법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;RAG 시스템 아키텍처 심층 분석&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;짧은 시간이지만 여러 RAG 구현체를 뜯어보면서 핵심 컴포넌트들을 정리했다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Document Processing Pipeline&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1757944911854&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Raw Documents &amp;rarr; Chunking &amp;rarr; Embedding &amp;rarr; Vector Store&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 가장 까다로운 게 Chunking이었다. 단순히 500자로 자르면 문장이 끊어져서 의미가 손상된다. 여러 전략들:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;고정 크기&lt;/b&gt;: 간단하지만 문맥 손실&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문장 경계&lt;/b&gt;: 자연스럽지만 크기 불균등&lt;/li&gt;
&lt;li&gt;&lt;b&gt;의미 단위&lt;/b&gt;: 문단이나 섹션별로 분할&lt;/li&gt;
&lt;li&gt;&lt;b&gt;슬라이딩 윈도우&lt;/b&gt;: 겹치는 부분으로 연속성 보장&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 실험해보니 겹치는 슬라이딩 윈도우(overlap 50-100 토큰)가 가장 효과적이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt;&lt;br /&gt;긴 문서를 &amp;ldquo;작은 퍼즐 조각&amp;rdquo;으로 잘라 저장하는 과정이에요.&lt;br /&gt;퍼즐 조각을 너무 작게 자르면 맥락이 끊기고, 너무 크게 자르면 찾기 힘들어요. &amp;rarr; &lt;b&gt;적당히 겹치게 자르는 게 제일 효과적&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Embedding Model 선택의 중요성&lt;/b&gt; 처음엔 OpenAI의 text-embedding-ada-002만 쓰면 되는 줄 알았는데, 도메인별로 특화된 모델들이 훨씬 좋다는 걸 깨달았다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;일반 텍스트&lt;/b&gt;: sentence-transformers/all-MiniLM-L6-v2&lt;/li&gt;
&lt;li&gt;&lt;b&gt;코드&lt;/b&gt;: microsoft/codebert-base&lt;/li&gt;
&lt;li&gt;&lt;b&gt;과학 논문&lt;/b&gt;: allenai/specter&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다국어&lt;/b&gt;: sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한국어에는 jhgan/ko-sroberta-multitask가 제일 좋더라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt;&lt;br /&gt;문서를 숫자로 바꾸는 &amp;ldquo;번역기&amp;rdquo; 같은 게 Embedding 모델이에요.&lt;br /&gt;**&amp;ldquo;모든 걸 하나로 퉁치지 말고, 상황에 맞는 번역기를 쓰면 훨씬 정확하다&amp;rdquo;**는 교훈이에요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Vector Database 비교 분석&lt;/b&gt; 여러 벡터 DB를 실제로 써보고 비교했다:&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 122px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;DB&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;장점&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;단점&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;적합한 경우&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;Pinecone&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;관리형, 빠름&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;비용, 벤더락인&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;프로덕션&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;Weaviate&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;오픈소스, 기능 풍부&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;복잡한 설정&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;대규모 시스템&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;Chroma&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;간단, 로컬&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;확장성 제한&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;프로토타입&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;FAISS&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;빠름, 무료&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;서버 기능 없음&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;연구용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt;&lt;br /&gt;&amp;ldquo;퍼즐 조각들을 잘 정리해둔 창고&amp;rdquo;가 벡터 DB예요.&lt;br /&gt;창고도 여러 종류가 있는데, &lt;b&gt;&amp;ldquo;빠른데 비싼 창고&amp;rdquo;&lt;/b&gt;, &lt;b&gt;&amp;ldquo;무료지만 직접 관리해야 하는 창고&amp;rdquo;&lt;/b&gt; 식으로 용도에 따라 골라야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. Retrieval 전략들&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적인 semantic search만으로는 한계가 있어서 여러 고급 기법들을 시도해봤다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Hybrid Search (Semantic + Keyword) : 의미검색 + 키워드 검색&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1757945641768&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# BM25로 키워드 검색
keyword_results = bm25.get_top_k(query, k=20)
# 벡터로 의미 검색  
semantic_results = vector_db.search(query_embedding, k=20)
# 점수 조합 (보통 0.7:0.3 비율)
final_results = combine_scores(semantic_results, keyword_results)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 단일 방법보다 거의 항상 더 좋은 결과를 냈다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Query Expansion&lt;/b&gt; 사용자 질문이 애매할 때 여러 각도로 확장해서 검색:&lt;/p&gt;
&lt;pre id=&quot;code_1757945676065&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;expanded_queries = [
    original_query,
    &quot;다른 표현: &quot; + paraphrase(original_query),
    &quot;관련 개념: &quot; + get_related_concepts(original_query)
]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Re-ranking with Cross-Encoder&lt;/b&gt; 검색된 문서들을 질문과 함께 다시 평가:&lt;/p&gt;
&lt;pre id=&quot;code_1757945697980&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1차: 빠른 bi-encoder로 top-100 선택
candidates = vector_search(query, k=100)
# 2차: 정확한 cross-encoder로 re-ranking
reranked = cross_encoder.rank(query, candidates, k=5)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt;&lt;br /&gt;검색은 &amp;ldquo;정확히 찍어서 찾는 것&amp;rdquo;보다 **&amp;ldquo;여러 각도로 훑고, 그중 좋은 걸 다시 고르는 것&amp;rdquo;**이 더 효과적이에요.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Generation 단계에서의 핵심 기법들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색이 끝나면 이제 실제 답변을 생성해야 한다. 여기서도 여러 노하우들이 있었다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Prompt Engineering&lt;/b&gt; 단순히 &quot;다음 문서를 보고 답하세요&quot;가 아니라:&lt;/p&gt;
&lt;pre id=&quot;code_1757945712203&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;당신은 도움이 되는 AI 어시스턴트입니다.
아래 문서들을 참고하여 질문에 답하되, 다음 규칙을 따르세요:

1. 문서에 없는 내용은 &quot;제공된 정보에서는 확인할 수 없습니다&quot;라고 명시
2. 답변의 근거가 되는 문서 번호를 명시 [문서1], [문서2] 형태로
3. 불확실한 정보는 &quot;~로 보입니다&quot; 같은 표현 사용

문서들:
[문서1] {doc1}
[문서2] {doc2}
...

질문: {query}
답변:&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Context Length 관리&lt;/b&gt; GPT-4의 경우 128k 토큰까지 가능하지만, 너무 많은 문서를 넣으면 &quot;lost in the middle&quot; 현상이 발생한다. 실험 결과 3-5개 문서가 최적이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Source Attribution&lt;/b&gt; 답변의 신뢰성을 위해 출처를 명시하는 것이 중요하다:&lt;/p&gt;
&lt;pre id=&quot;code_1757945723571&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def generate_with_sources(query, docs):
    # 각 문서에 ID 부여
    numbered_docs = [f&quot;[문서{i+1}] {doc}&quot; for i, doc in enumerate(docs)]
    
    # 생성 후 출처 추출
    response = llm.generate(query, numbered_docs)
    sources = extract_source_numbers(response)
    
    return response, [docs[i] for i in sources]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Advanced RAG 기법들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 RAG로는 한계가 있어서 더 고급 기법들을 연구해봤다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Multi-step RAG&lt;/b&gt; 복잡한 질문의 경우 여러 번의 검색이 필요:&lt;/p&gt;
&lt;pre id=&quot;code_1757945746409&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def multi_step_rag(query):
    # 1단계: 초기 검색
    docs1 = retrieve(query)
    
    # 2단계: 중간 답변 생성
    intermediate = generate(query, docs1)
    
    # 3단계: 추가 정보 필요시 재검색
    if needs_more_info(intermediate):
        new_query = extract_follow_up_query(intermediate)
        docs2 = retrieve(new_query)
        final_answer = generate(query, docs1 + docs2)
    
    return final_answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Self-RAG (자기 반성적 RAG)&lt;/b&gt; 모델이 스스로 검색이 필요한지, 답변이 충분한지 판단:&lt;/p&gt;
&lt;pre id=&quot;code_1757945759557&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def self_rag(query):
    # 검색 필요성 판단
    if model.judge_retrieval_need(query):
        docs = retrieve(query)
        answer = generate(query, docs)
        
        # 답변 품질 자체 평가
        if model.judge_answer_quality(answer) &amp;lt; threshold:
            # 다른 접근 방식 시도
            return retry_with_different_strategy(query)
    else:
        # 검색 없이 직접 답변
        answer = generate_direct(query)
    
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. GraphRAG&lt;/b&gt; 문서들 간의 관계를 그래프로 모델링:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티 추출 및 연결&lt;/li&gt;
&lt;li&gt;커뮤니티 탐지로 주제별 클러스터링&lt;/li&gt;
&lt;li&gt;다중 홉 추론을 통한 복잡한 질문 해결&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;RAG의 현실적 한계들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이론적으로는 완벽해 보이는 RAG도 실제로는 여러 문제가 있었다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 검색 품질의 한계&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동음이의어나 맥락 의존적 질문에서 부정확한 검색&lt;/li&gt;
&lt;li&gt;부정문이나 반어법 같은 복잡한 표현 처리 어려움&lt;/li&gt;
&lt;li&gt;시간적 맥락이 중요한 질문에서 최신 정보 우선순위 문제&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 생성 모델의 한계&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 문서의 정보를 종합하는 능력 부족&lt;/li&gt;
&lt;li&gt;모순되는 정보가 있을 때 적절한 처리 어려움&lt;/li&gt;
&lt;li&gt;문서에 명시되지 않은 암시적 정보 추론 한계&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 시스템 복잡성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;임베딩 모델, 벡터 DB, 생성 모델의 버전 관리&lt;/li&gt;
&lt;li&gt;실시간 업데이트와 일관성 유지&lt;/li&gt;
&lt;li&gt;확장성과 비용의 트레이드오프&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Large Language Diffusion Models: 언어 생성의 새로운 패러다임&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기존 언어모델의 근본적 한계&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지의 모든 언어모델은 autoregressive 방식이었다. 즉, 왼쪽부터 오른쪽으로 순차적으로 생성하는 방식. 이 방식의 문제점들을 정리해보니:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;순차적 생성의 속도 제한&lt;/b&gt;: 병렬화 불가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Exposure bias&lt;/b&gt;: 학습과 추론 시 입력 분포가 다름&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Error propagation&lt;/b&gt;: 앞에서 실수하면 뒤까지 영향&lt;/li&gt;
&lt;li&gt;&lt;b&gt;편집 불가능&lt;/b&gt;: 이미 생성된 부분 수정 어려움&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt;&lt;br /&gt;기존 GPT류 모델은 &lt;b&gt;&amp;ldquo;글자를 한 글자씩 타자 치는 사람&amp;rdquo;&lt;/b&gt; 같아요. 실수하면 뒤까지 줄줄이 틀리고, 이미 친 문장은 지우기 어렵죠.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Diffusion을 언어에 적용하는 근본적 도전&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지에서 성공한 diffusion을 언어에 적용하려니 엄청난 장벽이 있었다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 연속 vs 이산의 차이&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미지: 픽셀값 0.5 &amp;rarr; 0.6으로 조금씩 변경 가능&lt;/li&gt;
&lt;li&gt;언어: &quot;사과&quot;와 &quot;바나나&quot; 사이에 중간값이 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 구조적 제약&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미지: 공간적 구조, 부분 변경이 자연스러움&lt;/li&gt;
&lt;li&gt;언어: 순서와 문법적 제약, 한 단어 변경이 전체 의미에 영향&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt;&lt;br /&gt;이미지는 &amp;ldquo;사진을 뿌옇게 했다가 점점 선명하게&amp;rdquo; 만들 수 있는데, 언어는 &lt;b&gt;&amp;ldquo;사과 &amp;harr; 바나나&amp;rdquo; 사이에 반쯤 과일 같은 단어&lt;/b&gt;가 없으니 더 까다롭다는 뜻이에요.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;혁신적 해결책들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 연구팀들이 제시한 해결책들을 심층 분석해봤다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 1. Continuous Embedding Space 접근법 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 직관적인 방법으로, 토큰을 연속 공간으로 매핑:&lt;/p&gt;
&lt;pre id=&quot;code_1757948263913&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 순전파
tokens &amp;rarr; embeddings &amp;rarr; add_noise &amp;rarr; denoising_model &amp;rarr; clean_embeddings &amp;rarr; tokens

# 역전파  
noisy_embeddings &amp;rarr; predicted_clean_embeddings
loss = MSE(predicted_clean_embeddings, true_embeddings)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 continuous &amp;rarr; discrete 변환에서 정보 손실이 크다는 점이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt; 단어를 숫자 좌표로 바꿔서 부드럽게 조작하자. 근데 다시 단어로 되돌릴 때 정확도가 떨어짐&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Discrete Diffusion 접근법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SEDD(Score Entropy Discrete Diffusion)가 제시한 방법:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Forward process: 토큰을 점진적으로 마스크([MASK])로 변환&lt;/li&gt;
&lt;li&gt;Reverse process: 마스크를 실제 토큰으로 복원&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1757948278890&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Forward: &quot;I love cats&quot; &amp;rarr; &quot;I [MASK] cats&quot; &amp;rarr; &quot;[MASK] [MASK] cats&quot; &amp;rarr; &quot;[MASK] [MASK] [MASK]&quot;
# Reverse: &quot;[MASK] [MASK] [MASK]&quot; &amp;rarr; &quot;I [MASK] [MASK]&quot; &amp;rarr; &quot;I love [MASK]&quot; &amp;rarr; &quot;I love cats&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방식의 핵심은 각 단계에서 어떤 토큰을 복원할지를 score function으로 학습하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt; &amp;ldquo;단어를 하나씩 지웠다가, 다시 맞춰 넣는 퍼즐 놀이&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Latent Diffusion for Text&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;텍스트를 잠재 공간으로 인코딩한 후 diffusion 적용:&lt;/p&gt;
&lt;pre id=&quot;code_1757948292045&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;text &amp;rarr; encoder &amp;rarr; latent_vector &amp;rarr; diffusion &amp;rarr; clean_latent &amp;rarr; decoder &amp;rarr; text&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법은 이미지의 Stable Diffusion과 유사한 접근법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt; &amp;ldquo;직접 단어를 다루지 말고, 압축된 숨은 공간(latent space)에서 조작하자&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실제 구현에서 발견한 핵심 기법들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Reparameterization Trick&lt;/b&gt; continuous space에서 gradient 전파를 위해:&lt;/p&gt;
&lt;pre id=&quot;code_1757948308928&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 기존: discrete token sampling (gradient 불가)
token = argmax(logits)

# 개선: Gumbel-Softmax나 straight-through estimator 사용
token_soft = gumbel_softmax(logits, temperature)
token_hard = straight_through(token_soft)  # forward는 hard, backward는 soft&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt; &amp;ldquo;단어 뽑기처럼 끊긴 연산을, 부드럽게 미분 가능하게 만드는 꼼수&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Schedule 설계&lt;/b&gt; 이미지와 달리 언어는 더 신중한 noise schedule이 필요:&lt;/p&gt;
&lt;pre id=&quot;code_1757948320073&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 선형 스케줄은 너무 급격함
beta_linear = np.linspace(0.0001, 0.02, timesteps)

# 코사인 스케줄이 언어에 더 적합
beta_cosine = cosine_schedule(timesteps)

# 맞춤형 스케줄
beta_custom = design_text_schedule(timesteps, vocab_size)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt; &amp;ldquo;얼마나 빨리 흐리게/선명하게 만들지&amp;rdquo; 시간표 조절이 성능에 큰 영향&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Conditioning 기법&lt;/b&gt; 텍스트 생성에서는 다양한 조건부 생성이 중요:&lt;/p&gt;
&lt;pre id=&quot;code_1757948330708&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Classifier-free guidance
def conditional_generate(prompt, guidance_scale=7.5):
    # 조건부 예측
    noise_pred_cond = model(noisy_text, timestep, prompt)
    
    # 무조건부 예측 (빈 프롬프트)
    noise_pred_uncond = model(noisy_text, timestep, &quot;&quot;)
    
    # Guidance 적용
    noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_cond - noise_pred_uncond)
    
    return noise_pred&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt; &amp;ldquo;조건에 맞춰 더 강하게 끌어당기는 자석 같은 장치&amp;rdquo;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Diffusion LM의 놀라운 장점들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 구현해보고 기존 모델과 비교해본 결과:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 병렬 생성&lt;/b&gt; 가장 큰 장점은 모든 토큰을 동시에 생성할 수 있다는 점:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Autoregressive: O(n) time complexity&lt;/li&gt;
&lt;li&gt;Diffusion: O(1) time complexity (단, 여러 diffusion step 필요)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt; GPT는 타자 치듯 한 글자씩, Diffusion은 &amp;ldquo;한 페이지를 동시에 인쇄&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 벤치마크에서 50 토큰 생성 시:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GPT-3: 50 forward passes (순차적)&lt;/li&gt;
&lt;li&gt;Diffusion LM: 20 forward passes (병렬, step 수만큼)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 편집 가능성&lt;/b&gt; 생성된 텍스트의 일부를 수정하고 다시 diffusion 가능:&lt;/p&gt;
&lt;pre id=&quot;code_1757948346473&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def edit_text(original_text, edit_positions, new_content):
    # 편집할 부분만 노이즈 추가
    partially_noised = add_noise_selectively(original_text, edit_positions)
    
    # 해당 부분만 다시 생성
    edited_text = diffusion_generate(partially_noised, guidance=new_content)
    
    return edited_text&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;쉽게 말해서:&lt;/b&gt; &amp;ldquo;이미 쓴 글에서 단락 하나만 지우고 다시 써넣기 가능&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 다양성과 제어 가능성&lt;/b&gt; 동일한 프롬프트에서도 noise 초기값만 바꾸면 완전히 다른 결과:&lt;/p&gt;
&lt;pre id=&quot;code_1757948356568&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for seed in range(10):
    noise = generate_noise(seed=seed)
    result = diffusion_generate(prompt, initial_noise=noise)
    # 모두 다른 창의적 결과물&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;쉽게 말해서:&lt;/b&gt; &amp;ldquo;같은 레시피로도 요리사가 달라지면 다른 맛이 나온다&amp;rdquo;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;최신 연구 동향들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Consistency Models&lt;/b&gt; 여러 step을 한 번에 건너뛰는 방법:&lt;/p&gt;
&lt;pre id=&quot;code_1757948371261&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 기존: noise &amp;rarr; step1 &amp;rarr; step2 &amp;rarr; ... &amp;rarr; step20 &amp;rarr; clean
# Consistency: noise &amp;rarr; clean (직접)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;한 컷에 뿌연 사진을 바로 선명하게 만드는 기술&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Progressive Distillation&lt;/b&gt; Teacher 모델의 20 step을 Student가 10 step, 5 step으로 모방:&lt;/p&gt;
&lt;pre id=&quot;code_1757948379714&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Teacher: 20 steps
teacher_output = teacher_model(noise, steps=20)

# Student: 10 steps로 같은 결과 달성
student_output = student_model(noise, steps=10)
loss = MSE(student_output, teacher_output)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;경험 많은 선생님이 시연을 압축해서 제자에게 가르침&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Multimodal Diffusion&lt;/b&gt; 텍스트와 이미지를 통합한 diffusion:&lt;/p&gt;
&lt;pre id=&quot;code_1757948394759&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def multimodal_diffusion(text_prompt, image_prompt):
    # 텍스트와 이미지 모두 노이즈에서 시작
    noisy_text = add_text_noise(text_prompt)
    noisy_image = add_image_noise(image_prompt)
    
    # 상호 조건부로 생성
    for step in range(diffusion_steps):
        clean_text = denoise_text(noisy_text, condition=noisy_image)
        clean_image = denoise_image(noisy_image, condition=noisy_text)
        
        noisy_text = add_noise(clean_text, step)
        noisy_image = add_noise(clean_image, step)
    
    return clean_text, clean_image&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;글과 그림을 동시에 뿌옇게 했다가 같이 선명하게 복원&amp;rdquo;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;현재 한계점들과 미래 방향&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 계산 복잡도&lt;/b&gt; 여전히 여러 step이 필요해서 단일 forward pass보다는 느림. 하지만 병렬성 덕분에 긴 시퀀스에서는 오히려 빠를 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 품질 일관성&lt;/b&gt; Autoregressive 모델의 안정성에는 아직 못 미침. 특히 논리적 일관성이 중요한 작업에서 한계.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 제어의 어려움&lt;/b&gt; 원하는 스타일이나 내용으로 정확히 생성하기 어려움. 더 정교한 conditioning 기법 필요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt; Diffusion LM은 병렬성&amp;middot;편집성은 뛰어나지만, &lt;br /&gt;&amp;ldquo;아직 글의 논리적 일관성이나 세밀한 제어에서는 GPT류보다 부족하다&amp;rdquo;는 게 현재 수준&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Projects/Final Project</category>
      <category>Large Language Diffusion Models</category>
      <category>LLDM</category>
      <category>Lora</category>
      <category>RAG</category>
      <author>Solbi Lee</author>
      <guid isPermaLink="true">https://cat-b0.tistory.com/147</guid>
      <comments>https://cat-b0.tistory.com/147#entry147comment</comments>
      <pubDate>Tue, 16 Sep 2025 00:06:26 +0900</pubDate>
    </item>
    <item>
      <title>한국어 자연어 기반 MongoDB 자동 질의 시스템: 모델 구조 고민</title>
      <link>https://cat-b0.tistory.com/146</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로젝트 배경&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사에서 넘쳐나는 데이터를 자연어로 쉽게 가져오고, 분석까지 해주는 솔루션을 만들고 싶었다.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로젝트 구조 분석&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 3개의 다른 AI 모델이 협력하는 시스템&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1단계: 자연어 &amp;rarr; MongoDB 쿼리 변환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목적 : &quot;지난 달 서울 지역 매출 데이터 가져와줘&quot; &amp;rarr; MongoDB 쿼리 &lt;b&gt;필요 모델&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Text-to-SQL/NoSQL 모델 (몽고DB를 사용할 예정이니 MQL)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 또는 &lt;b&gt;LLM + 프롬프트 엔지니어링&lt;/b&gt; (GPT, Claude 등) &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2단계 : 데이터 예측 / 분석&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목적 : 추출된 데이터로 패턴 분석, 예측 필요 모델 :&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전통적인 ML 모델 ( scikit-learn, XGBoost 등 ) 또는 딥러닝 모델 (시계열 예측 등)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3단계 : 보고서 생성&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목적 : 분석 결과를 자연어 보고서로 작성 필요 모델&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 텍스트 생성 모델 (GPT, KoGPT 등)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 필요한 것들&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 자연어 &amp;gt; 쿼리&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 데이터 분석&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 시각화&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 보고서 생성&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;후보 모델&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 자연어 &amp;rarr; MongoDB 쿼리 생성&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;텍스트 생성 모델 (한국어 특화)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;KULLM-Polyglot-5.8B&lt;/b&gt; (고려대): 한국어 instruction following 강함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;KoAlpaca-Polyglot-5.8B&lt;/b&gt;: 한국어 대화형 질의응답 특화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;solar-10.7b-instruct-v1.0&lt;/b&gt; (업스테이지): 한국어 성능 우수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Qwen2.5-7B-Instruct&lt;/b&gt;: 다국어 지원, 코딩 능력 좋음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;llama-3.2-3b-instruct&lt;/b&gt;: 가벼우면서 성능 좋음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;경량 모델 (코랩 친화적)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;microsoft/DialoGPT-medium&lt;/b&gt;: 대화형 쿼리 생성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;google/flan-t5-large&lt;/b&gt;: instruction tuning 잘됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;EleutherAI/gpt-j-6B&lt;/b&gt;: 오픈소스 GPT 스타일&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 의도 분류 &amp;amp; 임베딩&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;한국어 임베딩 모델&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;jhgan/ko-sroberta-multitask&lt;/b&gt;: 한국어 문장 임베딩 대표작&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BM-K/KoSimCSE-roberta&lt;/b&gt;: 한국어 의미 유사도 특화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;klue/roberta-large&lt;/b&gt;: KLUE 벤치마크 상위권&lt;/li&gt;
&lt;li&gt;&lt;b&gt;monologg/koelectra-base-v3&lt;/b&gt;: 효율적이고 성능 좋음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;다국어 임베딩 모델&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2&lt;/b&gt;: 가볍고 빠름&lt;/li&gt;
&lt;li&gt;&lt;b&gt;intfloat/multilingual-e5-large&lt;/b&gt;: 최신 다국어 임베딩&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BAAI/bge-m3&lt;/b&gt;: 텍스트, 검색, 분류 모두 강함&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 데이터 분석 &amp;amp; 예측&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;시계열 예측&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;facebook/prophet&lt;/b&gt;: 비즈니스 트렌드 예측 특화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;sktime&lt;/b&gt;: 시계열 분석 라이브러리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;darts&lt;/b&gt;: 딥러닝 시계열 모델들&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;감정 분석 (이미 있지만 추가 활용)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;monologg/kobert-base-v1&lt;/b&gt;: 한국어 감정 분석 기본&lt;/li&gt;
&lt;li&gt;&lt;b&gt;beomi/KcELECTRA-base&lt;/b&gt;: 한국어 분류 작업 특화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;klue/roberta-base&lt;/b&gt;: 다양한 NLU 태스크&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 이미지 분석 (벡터 활용)&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;이미지 임베딩 모델&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;openai/clip-vit-base-patch32&lt;/b&gt;: 텍스트-이미지 연결&lt;/li&gt;
&lt;li&gt;&lt;b&gt;sentence-transformers/clip-ViT-B-32-multilingual-v1&lt;/b&gt;: 다국어 CLIP&lt;/li&gt;
&lt;li&gt;&lt;b&gt;google/vit-base-patch16-224&lt;/b&gt;: 이미지 분류/특성 추출&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;패션 특화 모델&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;patrickjohncyh/fashion-clip&lt;/b&gt;: 패션 아이템 특화 CLIP&lt;/li&gt;
&lt;li&gt;&lt;b&gt;laion/CLIP-ViT-B-32-laion2B-s34B-b79K&lt;/b&gt;: 대용량 학습된 CLIP&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 보고서 생성&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;텍스트 생성 (한국어)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;skt/kogpt2-trinity-1.2B-v0.5&lt;/b&gt;: SKT 한국어 GPT&lt;/li&gt;
&lt;li&gt;&lt;b&gt;kakaobrain/kogpt-6b-8bit&lt;/b&gt;: 카카오브레인 GPT (양자화)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;nlpai-lab/kullm-polyglot-5.8b-v2&lt;/b&gt;: 보고서 작성 좋음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;요약 특화 모델&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;eenzeenee/t5-base-korean-summarization&lt;/b&gt;: 한국어 요약&lt;/li&gt;
&lt;li&gt;&lt;b&gt;facebook/bart-large-cnn&lt;/b&gt;: 영어 요약 (번역 후 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6. 통합 솔루션 후보&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;올인원 모델&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Qwen2.5-7B-Instruct&lt;/b&gt;: 쿼리 생성 + 분석 + 보고서 모두 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;microsoft/Phi-3-mini-4k-instruct&lt;/b&gt;: 경량이면서 다재다능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;meta-llama/Llama-3.2-1B-Instruct&lt;/b&gt;: 초경량 버전&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;특수 목적 모델&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;defog/sqlcoder-7b-2&lt;/b&gt;: SQL 생성 특화 (MongoDB 응용 가능)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;NumbersStation/nsql-llama-2-7B&lt;/b&gt;: 데이터 쿼리 생성 특화&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  추천 조합 (용도별)&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;성능 우선 조합&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;쿼리 생성: KULLM-Polyglot-5.8B
임베딩: intfloat/multilingual-e5-large  
분석: scikit-learn + prophet
보고서: Qwen2.5-7B-Instruct&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;속도 우선 조합&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;쿼리 생성: microsoft/Phi-3-mini-4k-instruct
임베딩: jhgan/ko-sroberta-multitask
분석: 기본 pandas + numpy
보고서: 템플릿 기반
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;메모리 절약 조합&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;쿼리 생성: google/flan-t5-large
임베딩: monologg/koelectra-base-v3
분석: 경량 ML 모델들
보고서: 규칙 기반 생성
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;패션 특화 조합&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;쿼리 생성: KoAlpaca (패션 도메인 추가 학습)
임베딩: ko-sroberta + fashion-clip (하이브리드)
이미지: patrickjohncyh/fashion-clip
보고서: 패션 용어 특화 프롬프트
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;⚡ 실용적 선택 기준&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코랩 무료 버전 (12GB RAM):&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;3B 이하 모델 추천&lt;/li&gt;
&lt;li&gt;Phi-3-mini, flan-t5-large, ko-sroberta&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코랩 프로 (15GB+ RAM):&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;7B 모델까지 가능&lt;/li&gt;
&lt;li&gt;KULLM, Qwen2.5, Llama-3.2&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;로컬 개발:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1B-3B 모델로 프로토타이핑&lt;/li&gt;
&lt;li&gt;성능 확인 후 클라우드 배포&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 성능 우선 조합으로 테스트 해보기로 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. KULLM-Polyglot-5.8B&lt;/b&gt;: 한국어 쿼리 생성의 끝판왕&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복잡한 자연어 &amp;rarr; 정확한 MongoDB 쿼리 변환&lt;/li&gt;
&lt;li&gt;한국어 패션 용어 이해도 높음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장점&lt;/b&gt;: 한국어 instruction following 최강급&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특화&lt;/b&gt;: 복잡한 논리적 사고와 코드 생성 능력&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메모리&lt;/b&gt;: ~12GB (8bit 양자화 시 ~6GB)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;허깅페이스&lt;/b&gt;: &lt;a href=&quot;https://huggingface.co/nlpai-lab/kullm-polyglot-5.8b-v2&quot;&gt;https://huggingface.co/nlpai-lab/kullm-polyglot-5.8b-v2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1757860600333&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;nlpai-lab/kullm-polyglot-5.8b-v2 &amp;middot; Hugging Face&quot; data-og-description=&quot;KULLM-Polyglot-5.8B-v2 This model is a parameter-efficient fine-tuned version of EleutherAI/polyglot-ko-5.8b on a KULLM v2 Detail Codes are available at KULLM Github Repository Training procedure Training hyperparameters The following hyperparameters were &quot; data-og-host=&quot;huggingface.co&quot; data-og-source-url=&quot;https://huggingface.co/nlpai-lab/kullm-polyglot-5.8b-v2&quot; data-og-url=&quot;https://huggingface.co/nlpai-lab/kullm-polyglot-5.8b-v2&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/elcPV0/hyZJiS6Tt0/QMcjPYwKousEOFmFGSsbx0/img.png?width=1200&amp;amp;height=648&amp;amp;face=0_0_1200_648,https://scrap.kakaocdn.net/dn/brt9c6/hyZI6ze3iK/kIFUp6lcUW2yf3NwsK4kjk/img.png?width=1200&amp;amp;height=648&amp;amp;face=0_0_1200_648&quot;&gt;&lt;a href=&quot;https://huggingface.co/nlpai-lab/kullm-polyglot-5.8b-v2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://huggingface.co/nlpai-lab/kullm-polyglot-5.8b-v2&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/elcPV0/hyZJiS6Tt0/QMcjPYwKousEOFmFGSsbx0/img.png?width=1200&amp;amp;height=648&amp;amp;face=0_0_1200_648,https://scrap.kakaocdn.net/dn/brt9c6/hyZI6ze3iK/kIFUp6lcUW2yf3NwsK4kjk/img.png?width=1200&amp;amp;height=648&amp;amp;face=0_0_1200_648');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;nlpai-lab/kullm-polyglot-5.8b-v2 &amp;middot; Hugging Face&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;KULLM-Polyglot-5.8B-v2 This model is a parameter-efficient fine-tuned version of EleutherAI/polyglot-ko-5.8b on a KULLM v2 Detail Codes are available at KULLM Github Repository Training procedure Training hyperparameters The following hyperparameters were&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;huggingface.co&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Multilingual-E5-Large&lt;/b&gt;: 검색/임베딩 최고 성능&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;100+ 언어 지원하면서 한국어 품질 우수&lt;/li&gt;
&lt;li&gt;의도 분류, 스키마 매칭에 최적화&lt;/li&gt;
&lt;li&gt;1024차원으로 세밀한 의미 표현&lt;/li&gt;
&lt;li&gt;&lt;b&gt;차원&lt;/b&gt;: 1024차원&lt;/li&gt;
&lt;li&gt;&lt;b&gt;지원&lt;/b&gt;: 100+ 언어 (한국어 포함)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;허깅페이스&lt;/b&gt;: &lt;a href=&quot;https://huggingface.co/intfloat/multilingual-e5-large&quot;&gt;https://huggingface.co/intfloat/multilingual-e5-large&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1757860599106&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;intfloat/multilingual-e5-large &amp;middot; Hugging Face&quot; data-og-description=&quot;Multilingual-E5-large Multilingual E5 Text Embeddings: A Technical Report. Liang Wang, Nan Yang, Xiaolong Huang, Linjun Yang, Rangan Majumder, Furu Wei, arXiv 2024 This model has 24 layers and the embedding size is 1024. Usage Below is an example to encode&quot; data-og-host=&quot;huggingface.co&quot; data-og-source-url=&quot;https://huggingface.co/intfloat/multilingual-e5-large&quot; data-og-url=&quot;https://huggingface.co/intfloat/multilingual-e5-large&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bCcTg3/hyZIZgx8Mv/wbc5SDfwWIgKOgb0lfIAaK/img.png?width=1200&amp;amp;height=648&amp;amp;face=0_0_1200_648,https://scrap.kakaocdn.net/dn/cbN7nT/hyZJrP4qdp/IT5Pb568c2BZW7iv5GWOaK/img.png?width=1200&amp;amp;height=648&amp;amp;face=0_0_1200_648&quot;&gt;&lt;a href=&quot;https://huggingface.co/intfloat/multilingual-e5-large&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://huggingface.co/intfloat/multilingual-e5-large&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bCcTg3/hyZIZgx8Mv/wbc5SDfwWIgKOgb0lfIAaK/img.png?width=1200&amp;amp;height=648&amp;amp;face=0_0_1200_648,https://scrap.kakaocdn.net/dn/cbN7nT/hyZJrP4qdp/IT5Pb568c2BZW7iv5GWOaK/img.png?width=1200&amp;amp;height=648&amp;amp;face=0_0_1200_648');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;intfloat/multilingual-e5-large &amp;middot; Hugging Face&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Multilingual-E5-large Multilingual E5 Text Embeddings: A Technical Report. Liang Wang, Nan Yang, Xiaolong Huang, Linjun Yang, Rangan Majumder, Furu Wei, arXiv 2024 This model has 24 layers and the embedding size is 1024. Usage Below is an example to encode&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;huggingface.co&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Qwen2.5-7B&lt;/b&gt;: 보고서 생성의 신기원&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최신 모델로 한국어 텍스트 품질 최고급&lt;/li&gt;
&lt;li&gt;긴 문맥 처리 능력으로 상세한 보고서 생성&lt;/li&gt;
&lt;li&gt;구조화된 비즈니스 문서 작성 특화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장점&lt;/b&gt;: 최신 모델, 한국어 품질 우수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특화&lt;/b&gt;: 긴 문맥, 구조화된 텍스트 생성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;허깅페이스&lt;/b&gt;: &lt;a href=&quot;https://huggingface.co/Qwen/Qwen2.5-7B-Instruct&quot;&gt;https://huggingface.co/Qwen/Qwen2.5-7B-Instruct&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. Prophet + XGBoost + scikit-learn&lt;/b&gt;: 분석의 철벽&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시계열 예측부터 분류/회귀까지 전방위 커버&lt;/li&gt;
&lt;li&gt;무신사 매출 예측, 고객 세분화에 최적&lt;/li&gt;
&lt;li&gt;&lt;b&gt;scikit-learn&lt;/b&gt;: 전통적 ML (분류, 회귀, 클러스터링)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Prophet&lt;/b&gt;: 시계열 예측 (매출, 트렌드)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;XGBoost&lt;/b&gt;: 고성능 그래디언트 부스팅&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 이미지 분석&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모델&lt;/b&gt;: patrickjohncyh/fashion-clip&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;특화&lt;/b&gt;: 패션 도메인 CLIP 모델&lt;/li&gt;
&lt;li&gt;&lt;b&gt;용도&lt;/b&gt;: 이미지 벡터와 텍스트 연결&lt;/li&gt;
&lt;li&gt;&lt;b&gt;허깅페이스&lt;/b&gt;: &lt;a href=&quot;https://huggingface.co/patrickjohncyh/fashion-clip&quot;&gt;https://huggingface.co/patrickjohncyh/fashion-clip&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단계별 설계와 고민&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-end=&quot;1332&quot; data-start=&quot;1306&quot; data-ke-size=&quot;size23&quot;&gt;(1) 자연어 &amp;rarr; MongoDB 쿼리&lt;/h3&gt;
&lt;p data-end=&quot;1383&quot; data-start=&quot;1334&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;목표&lt;/b&gt;&lt;br /&gt;사용자의 자연어 질의를 안정적으로 MongoDB 파이프라인으로 변환.&lt;/p&gt;
&lt;p data-end=&quot;1393&quot; data-start=&quot;1385&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;고민&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1611&quot; data-start=&quot;1394&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1422&quot; data-start=&quot;1394&quot;&gt;LLM을 무제한으로 쓰면 환각 위험이 크다.&lt;/li&gt;
&lt;li data-end=&quot;1490&quot; data-start=&quot;1423&quot;&gt;그래서 **스키마 계약(YAML)**을 만들어 &amp;ldquo;허용된 컬렉션, 필드, 스테이지만 사용 가능&amp;rdquo;하게 제한해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;1611&quot; data-start=&quot;1491&quot;&gt;KULLM-Polyglot-5.8B는 한국어 이해가 강점이지만, 단독으로 쓰기보다는 **임베딩 모델(multilingual-e5-large)**과 함께 스키마 매칭을 보조하는 구조가 더 안정적일 것 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1735&quot; data-start=&quot;1613&quot; data-ke-size=&quot;size16&quot;&gt;내가 여기서 중점적으로 탐구하는 것은 &lt;b&gt;Plan 단계&lt;/b&gt;다.&lt;br /&gt;즉, LLM이 바로 쿼리를 내뱉는 것이 아니라, 먼저 논리적 계획(Plan JSON)을 만들고, 그걸 변환기로 파이프라인으로 바꾸는 방식이다.&lt;/p&gt;
&lt;p data-end=&quot;1735&quot; data-start=&quot;1613&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1758&quot; data-start=&quot;1742&quot; data-ke-size=&quot;size23&quot;&gt;(2) 데이터 분석&lt;/h3&gt;
&lt;p data-end=&quot;1796&quot; data-start=&quot;1760&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;목표&lt;/b&gt;&lt;br /&gt;추출된 데이터에서 패턴과 인사이트를 뽑아내기.&lt;/p&gt;
&lt;p data-end=&quot;1806&quot; data-start=&quot;1798&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;고민&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2021&quot; data-start=&quot;1807&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1851&quot; data-start=&quot;1807&quot;&gt;scikit-learn을 통해 기본적인 회귀, 분류, 클러스터링을 적용.&lt;/li&gt;
&lt;li data-end=&quot;1878&quot; data-start=&quot;1852&quot;&gt;시계열 데이터는 Prophet으로 예측.&lt;/li&gt;
&lt;li data-end=&quot;1985&quot; data-start=&quot;1879&quot;&gt;하지만 모델을 다양하게 쓴다고 무조건 좋은 건 아니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1985&quot; data-start=&quot;1916&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1985&quot; data-start=&quot;1916&quot;&gt;예: 매출 추세 예측은 Prophet이 적합하지만, 고객 세그먼트 분석은 k-means 같은 군집화가 더 직관적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;2021&quot; data-start=&quot;1986&quot;&gt;결국 중요한 것은 &amp;ldquo;&lt;b&gt;문제 정의와 모델 매칭&lt;/b&gt;&amp;rdquo;이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2082&quot; data-start=&quot;2023&quot; data-ke-size=&quot;size16&quot;&gt;나는 이 단계를 통해 단순한 데이터 집계가 아니라, &lt;b&gt;예측과 패턴 발견&lt;/b&gt;까지 시스템에 녹이고 싶다. 이건 쉬울 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2082&quot; data-start=&quot;2023&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;2105&quot; data-start=&quot;2089&quot; data-ke-size=&quot;size23&quot;&gt;(3) 보고서 생성&lt;/h3&gt;
&lt;p data-end=&quot;2152&quot; data-start=&quot;2107&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;목표&lt;/b&gt;&lt;br /&gt;분석 결과를 사람이 읽을 수 있는 보고서 형식으로 자동 생성.&lt;/p&gt;
&lt;p data-end=&quot;2162&quot; data-start=&quot;2154&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;고민&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2443&quot; data-start=&quot;2163&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2187&quot; data-start=&quot;2163&quot;&gt;숫자를 나열하는 것만으로는 부족하다.&lt;/li&gt;
&lt;li data-end=&quot;2302&quot; data-start=&quot;2188&quot;&gt;&amp;ldquo;지난 달 서울 지역 매출은 4억 3천만 원으로, 전월 대비 12% 증가했습니다. 특히 20대 여성 고객의 구매 비중이 주요 요인입니다.&amp;rdquo;&lt;br /&gt;&amp;rarr; 이런 문장을 자동으로 만들어주는 것이 필요하다.&lt;/li&gt;
&lt;li data-end=&quot;2358&quot; data-start=&quot;2303&quot;&gt;Qwen2.5-7B-Instruct를 선택한 이유는 한국어 생성 품질과 효율성 때문이다.&lt;/li&gt;
&lt;li data-end=&quot;2443&quot; data-start=&quot;2359&quot;&gt;다만, &lt;b&gt;환각 문제&lt;/b&gt;는 여전히 남아 있다. &amp;rarr; 이를 줄이기 위해 &amp;ldquo;분석 결과 JSON&amp;rdquo;을 기반으로 템플릿과 프롬프트를 함께 설계할 계획이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2466&quot; data-start=&quot;2450&quot; data-ke-size=&quot;size26&quot;&gt;+ ) 시각화까지 확장&lt;/h2&gt;
&lt;p data-end=&quot;2488&quot; data-start=&quot;2468&quot; data-ke-size=&quot;size16&quot;&gt;보고서가 글로만 존재하면 아쉽다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2541&quot; data-start=&quot;2489&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2505&quot; data-start=&quot;2489&quot;&gt;매출 추세는 라인 차트&lt;/li&gt;
&lt;li data-end=&quot;2522&quot; data-start=&quot;2506&quot;&gt;고객 비중은 파이 차트&lt;/li&gt;
&lt;li data-end=&quot;2541&quot; data-start=&quot;2523&quot;&gt;지역별 매출은 지도 시각화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2591&quot; data-start=&quot;2543&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 시각화가 더해지면, &lt;b&gt;데이터가 눈으로 읽히는 순간 인사이트가 강화된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2677&quot; data-start=&quot;2593&quot; data-ke-size=&quot;size16&quot;&gt;나는 Python의 matplotlib/plotly 기반 시각화를 먼저 붙이고, 이후 React + Vega로 웹 기반 시각화까지 확장할 생각이다.&lt;/p&gt;</description>
      <category>Projects/Final Project</category>
      <category>LLM</category>
      <category>nlp</category>
      <category>Text2MQL</category>
      <category>자연어처리</category>
      <author>Solbi Lee</author>
      <guid isPermaLink="true">https://cat-b0.tistory.com/146</guid>
      <comments>https://cat-b0.tistory.com/146#entry146comment</comments>
      <pubDate>Sun, 14 Sep 2025 23:51:39 +0900</pubDate>
    </item>
    <item>
      <title>HATW 프로젝트 회고: 4주 만에 휠체어 전용 네비게이션 만들기</title>
      <link>https://cat-b0.tistory.com/145</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;이길어떄.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;447&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/myJR3/btsQui3U98F/bTohgX5NHVsi4y3zp3Ypw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/myJR3/btsQui3U98F/bTohgX5NHVsi4y3zp3Ypw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/myJR3/btsQui3U98F/bTohgX5NHVsi4y3zp3Ypw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmyJR3%2FbtsQui3U98F%2FbTohgX5NHVsi4y3zp3Ypw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;649&quot; height=&quot;447&quot; data-filename=&quot;이길어떄.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;447&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 정의부터 시작했다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 내비게이션이 완벽해 보이는데 굳이 새로 만들 필요가 있나? 처음엔 의문이었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1820&quot; data-origin-height=&quot;696&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qc583/btsQu3k8bwl/IYmtmTFV9I3ctxakD9Cku0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qc583/btsQu3k8bwl/IYmtmTFV9I3ctxakD9Cku0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qc583/btsQu3k8bwl/IYmtmTFV9I3ctxakD9Cku0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqc583%2FbtsQu3k8bwl%2FIYmtmTFV9I3ctxakD9Cku0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1820&quot; height=&quot;696&quot; data-origin-width=&quot;1820&quot; data-origin-height=&quot;696&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 데이터를 보니 명확했다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;T-map, 네이버맵: 일반 보행자 기준&lt;/li&gt;
&lt;li&gt;계단/육교/에스컬레이터 = 물리적 장벽 미고려&lt;/li&gt;
&lt;li&gt;엘리베이터 고장, 공사 구간 = 실시간 반영 불가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론: 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기술 스택 결정 과정&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Backend 선택: Spring Boot&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js도 고려했지만 기각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유:&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;- 복잡한 경로 알고리즘 &amp;rarr; Java 안정성 필요
- 지리 정보 쿼리 &amp;rarr; MyBatis 적합
- 인증 시스템 &amp;rarr; Spring Security 검증됨
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Frontend: React&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue.js보다 단순한 이유들:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지도 API 레퍼런스 많음&lt;/li&gt;
&lt;li&gt;컴포넌트 재사용성 높음&lt;/li&gt;
&lt;li&gt;React Router 직관적&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Database: MySQL&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NoSQL 검토했지만 기각.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위치-사용자 데이터 관계 명확&lt;/li&gt;
&lt;li&gt;Spatial 기능 필요&lt;/li&gt;
&lt;li&gt;제보 시스템에 트랜잭션 필수&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;핵심 문제: 경로 알고리즘&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;T-map API는 일반 보행자용만 제공한다. 휠체어 접근 불가 구간을 어떻게 처리할 것인가.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1832&quot; data-origin-height=&quot;716&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bm13Hu/btsQwTosTUY/PtZ3Ua2reAU9CoQjuh6OD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm13Hu/btsQwTosTUY/PtZ3Ua2reAU9CoQjuh6OD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm13Hu/btsQwTosTUY/PtZ3Ua2reAU9CoQjuh6OD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbm13Hu%2FbtsQwTosTUY%2FPtZ3Ua2reAU9CoQjuh6OD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1832&quot; height=&quot;716&quot; data-origin-width=&quot;1832&quot; data-origin-height=&quot;716&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1차 시도: 무식한 필터링&lt;/h3&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;if (path.contains(&quot;계단&quot;) || path.contains(&quot;에스컬레이터&quot;)) {
    excludePath(path);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과: 경로 90% 사라짐. 실패.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2차 시도: 가중치 시스템&lt;/h3&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;public double calculatePathWeight(PathSegment segment) {
    if (segment.hasElevator()) return 1.0;
    if (segment.hasRamp()) return 1.5;
    if (segment.hasStairs()) return Double.MAX_VALUE;
    return 2.0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개선되었지만 여전히 부족.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;최종: 다중 경로 제시&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;public List&amp;lt;Route&amp;gt; findAccessibleRoutes(Point start, Point end) {
    List&amp;lt;Route&amp;gt; candidates = tmapService.getMultipleRoutes(start, end);
    return candidates.stream()
            .filter(this::isAccessible)
            .sorted(Comparator.comparing(this::calculateTotalWeight))
            .limit(3)
            .collect(Collectors.toList());
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 깨달음: 완벽한 하나보다 선택 가능한 여러 개가 실용적이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1824&quot; data-origin-height=&quot;452&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7k90s/btsQuciAUAN/MOLs63jbYKr0xhifzP1Zs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7k90s/btsQuciAUAN/MOLs63jbYKr0xhifzP1Zs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7k90s/btsQuciAUAN/MOLs63jbYKr0xhifzP1Zs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7k90s%2FbtsQuciAUAN%2FMOLs63jbYKr0xhifzP1Zs0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1824&quot; height=&quot;452&quot; data-origin-width=&quot;1824&quot; data-origin-height=&quot;452&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실시간 정보 시스템&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;엘리베이터 고장&quot;, &quot;공사 중&quot; 같은 정보를 어떻게 실시간 반영할 것인가.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결책: 커뮤니티 제보 + 신뢰도 알고리즘&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public double calculateReportCredibility(Report report, User user) {
    double baseScore = 0.5;
    if (report.hasPhoto()) baseScore += 0.3;
    baseScore += user.getActivityScore() * 0.2;
    
    long sameLocationReports = reportService.countNearbyReports(report.getLocation());
    if (sameLocationReports &amp;gt; 1) baseScore += 0.2;
    
    return Math.min(baseScore, 1.0);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1824&quot; data-origin-height=&quot;812&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qYwAC/btsQwCHg7Ec/AeHcH4vdCZ6ye4QLCq9XqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qYwAC/btsQwCHg7Ec/AeHcH4vdCZ6ye4QLCq9XqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qYwAC/btsQwCHg7Ec/AeHcH4vdCZ6ye4QLCq9XqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqYwAC%2FbtsQwCHg7Ec%2FAeHcH4vdCZ6ye4QLCq9XqK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1824&quot; height=&quot;812&quot; data-origin-width=&quot;1824&quot; data-origin-height=&quot;812&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동 만료도 구현:&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;@Scheduled(fixedDelay = 3600000)
public void expireOldReports() {
    List&amp;lt;Report&amp;gt; oldReports = reportRepository.findReportsOlderThan(Duration.ofDays(7));
    oldReports.forEach(report -&amp;gt; {
        if (report.getCredibility() &amp;lt; 0.3) {
            reportRepository.delete(report);
        }
    });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt; 결국..서울교통공사 API를 쓰기로 했다..&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;다중 인증 시스템&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;휠체어 사용자 중 스마트폰 조작 어려운 분들 고려 &amp;rarr; 최대한 간편하게.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@RestController
public class AuthController {
    @PostMapping(&quot;/login/google&quot;)
    public ResponseEntity&amp;lt;?&amp;gt; googleLogin(@RequestBody String googleToken) {}
    
    @PostMapping(&quot;/login/kakao&quot;) 
    public ResponseEntity&amp;lt;?&amp;gt; kakaoLogin(@RequestBody String kakaoToken) {}
    
    @PostMapping(&quot;/login/sms&quot;)
    public ResponseEntity&amp;lt;?&amp;gt; smsLogin(@RequestBody String phoneNumber) {}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SMS 인증 장점:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;계정 생성 불필요&lt;/li&gt;
&lt;li&gt;긴급시 빠른 접근&lt;/li&gt;
&lt;li&gt;Nurigo API 안정성&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;성능 최적화&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;지도 렌더링 개선&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기: 모든 마커 한번에 로딩 &amp;rarr; 느림 개선: 화면 영역 기준 동적 로딩&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;// Before
const [markers, setMarkers] = useState([]);
useEffect(() =&amp;gt; {
    fetchAllMarkers().then(setMarkers); // 느림
}, []);

// After  
const [visibleMarkers, setVisibleMarkers] = useState([]);
useEffect(() =&amp;gt; {
    const bounds = map.getBounds();
    fetchMarkersInBounds(bounds).then(setVisibleMarkers);
}, [mapCenter, zoomLevel]);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1794&quot; data-origin-height=&quot;1018&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GAjVg/btsQwSiMPDe/rFwjtNGyoLQT4KZaxQgIik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GAjVg/btsQwSiMPDe/rFwjtNGyoLQT4KZaxQgIik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GAjVg/btsQwSiMPDe/rFwjtNGyoLQT4KZaxQgIik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGAjVg%2FbtsQwSiMPDe%2FrFwjtNGyoLQT4KZaxQgIik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1794&quot; height=&quot;1018&quot; data-origin-width=&quot;1794&quot; data-origin-height=&quot;1018&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;API 호출 최적화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디바운싱 적용:&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;const debouncedSearch = useCallback(
    debounce((query) =&amp;gt; {
        searchPOI(query).then(setSearchResults);
    }, 500),
    []
);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;한계와 아쉬운 점&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 실사용자 테스트 부족&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4주 기간의 한계. 개발자 관점에서만 판단한 기능들이 실제로는 불편할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 데이터 품질 문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공공 데이터의 한계:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;건물 내부 엘리베이터 위치 부족&lt;/li&gt;
&lt;li&gt;경사로 실제 경사도 없음&lt;/li&gt;
&lt;li&gt;보도 폭 정보 부정확&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1818&quot; data-origin-height=&quot;808&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qOjDP/btsQwJsGXcy/bINXjcbSX4zkZWJHiLYTYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qOjDP/btsQwJsGXcy/bINXjcbSX4zkZWJHiLYTYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qOjDP/btsQwJsGXcy/bINXjcbSX4zkZWJHiLYTYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqOjDP%2FbtsQwJsGXcy%2FbINXjcbSX4zkZWJHiLYTYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1818&quot; height=&quot;808&quot; data-origin-width=&quot;1818&quot; data-origin-height=&quot;808&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 알고리즘 트레이드오프&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;15% 긴 경로 제공하지만, 접근성과 효율성 균형이 복잡하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;배운 것들&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기술적 성장&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring Boot + React 풀스택&lt;/li&gt;
&lt;li&gt;OAuth 2.0 다중 인증&lt;/li&gt;
&lt;li&gt;MyBatis 지리 정보 쿼리&lt;/li&gt;
&lt;li&gt;외부 API 연동 (T-map, SMS)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인식 변화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;장애인용 특별 서비스&quot; &amp;rarr; &quot;모든 사람을 위한 보편적 설계&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;협업 방식&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Agile/Scrum 적용&lt;/li&gt;
&lt;li&gt;GitHub 코드 리뷰&lt;/li&gt;
&lt;li&gt;주 5회 스프린트 미팅&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;향후 계획&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단기 (3개월)&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;실사용자 테스트 및 피드백 반영&lt;/li&gt;
&lt;li&gt;공공 데이터 추가 연동&lt;/li&gt;
&lt;li&gt;알림 시스템 구축&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장기 (1년)&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;AI 기반 개인화 추천&lt;/li&gt;
&lt;li&gt;IoT 연동 (실시간 엘리베이터 상태)&lt;/li&gt;
&lt;li&gt;다른 교통약자 지원 확대&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4주 프로젝트로 완벽한 서비스는 아니지만, 기술이 사회 문제에 어떻게 기여할 수 있는지 직접 확인했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;모든 사람이 자유롭게 이동할 수 있는 세상&quot;에 한 걸음 더 가까워졌다고 본다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;GitHub:&lt;/b&gt; &lt;a href=&quot;https://github.com/leesolbi1212/accessible_navigation_web&quot;&gt;https://github.com/leesolbi1212/accessible_navigation_web&lt;/a&gt;&lt;br /&gt;&lt;b&gt;기술 스택:&lt;/b&gt; Spring Boot, React, MySQL, T-map API&lt;br /&gt;&lt;b&gt;기간:&lt;/b&gt; 2024.06.09 ~ 2024.07.03 (4주)&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드만 짜는 게 아니라 누군가의 일상을 바꿀 수 있다는 걸 깨달았다. 의미있는 경험이었다.&lt;/p&gt;</description>
      <category>Projects/교통약자를 위한 네비게이션 개발</category>
      <category>t-map</category>
      <category>교통약자</category>
      <category>네비게이션</category>
      <category>배리어프리</category>
      <category>풀스택</category>
      <author>Solbi Lee</author>
      <guid isPermaLink="true">https://cat-b0.tistory.com/145</guid>
      <comments>https://cat-b0.tistory.com/145#entry145comment</comments>
      <pubDate>Fri, 12 Sep 2025 00:29:35 +0900</pubDate>
    </item>
    <item>
      <title>AI Agent 심층 탐구</title>
      <link>https://cat-b0.tistory.com/143</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. AI Agent란 무엇인가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI Agent는 &lt;b&gt;환경을 지각(Perception)&lt;/b&gt; &amp;rarr; &lt;b&gt;의사결정(Decision Making)&lt;/b&gt; &amp;rarr; **행동(Action)**을 수행하는 지능형 주체&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순한 입력-출력 프로그램이 아니라 데이터와 경험을 통해 학습하면서 상황에 적용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 AI Agent는 다음과 같은 기술로 강화된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;484&quot; data-start=&quot;440&quot;&gt;&lt;b&gt;멀티모달 모델&lt;/b&gt;: 텍스트&amp;middot;이미지&amp;middot;음성 등 다양한 입력을 동시에 처리&lt;/li&gt;
&lt;li data-end=&quot;546&quot; data-start=&quot;485&quot;&gt;&lt;b&gt;RAG(Retrieval-Augmented Generation)&lt;/b&gt;: 외부 지식 검색 후 답변 생성&lt;/li&gt;
&lt;li data-end=&quot;605&quot; data-start=&quot;547&quot;&gt;&lt;b&gt;MCP(Model Context Protocol)&lt;/b&gt;: 외부 도구&amp;middot;DB&amp;middot;서비스와 표준화된 연결&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 : 환경과 상호작용하면서 목표를 달성하는 인공지능 시스템&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 핵심 구성 요소 탐구&amp;nbsp;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;RAG (Retrieval-Augmented Generation)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원리 : 모델의 내부 지식에만 의존하지 않고 외부 문제를 검색해 맥락에 포함 &amp;gt; 답변 생성&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점 : 최신 정보 반영, 특정 도메인 지식 활용, 할루시네이션 감소&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적용 사례 : 고객센터 챗봇, 법률 문서 검색, 논문 요약&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;MCP (Model Context Protocol)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역할 : AI Agent가 여러 외부 도구와 &lt;b&gt;표준화된 인터페이스&lt;/b&gt;로 연결되도록 지원&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의의 : API마다 별도 연결 코드를 짜던 번거로움 해결 &amp;gt; 에이전트의 확장성과 사용성 확보&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 대표 사례&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1109&quot; data-start=&quot;1066&quot;&gt;&lt;b&gt;로봇청소기&lt;/b&gt;: 센서로 집 구조 인식 &amp;rarr; 경로 결정 &amp;rarr; 청소 실행&lt;/li&gt;
&lt;li data-end=&quot;1164&quot; data-start=&quot;1110&quot;&gt;&lt;b&gt;자율주행 자동차&lt;/b&gt;: 라이다&amp;middot;카메라 데이터로 교통 상황 인식 &amp;rarr; 가속/감속/조향 결정&lt;/li&gt;
&lt;li data-end=&quot;1211&quot; data-start=&quot;1165&quot;&gt;&lt;b&gt;스마트 스피커&lt;/b&gt;: 음성 인식 &amp;rarr; 의도 분석 &amp;rarr; 음악 재생/IoT 제어&lt;/li&gt;
&lt;li data-end=&quot;1261&quot; data-start=&quot;1212&quot;&gt;&lt;b&gt;로보어드바이저&lt;/b&gt;: 시장 데이터 분석 &amp;rarr; 투자 전략 수립 &amp;rarr; 자동 매수&amp;middot;매도&lt;/li&gt;
&lt;li data-end=&quot;1316&quot; data-start=&quot;1262&quot;&gt;&lt;b&gt;게임 AI (AlphaGo, OpenAI Five)&lt;/b&gt;: 복잡한 전략과 협력까지 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 도메인에서 지각-판단-행동 사이클이 구현되고 있다는 점이 공통적&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 대표 프레임워크&amp;nbsp;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;LangChain / LangGraph&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 1. LangChain: AI 작업을 연결하는 도구 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 작업을 단계별로 연결 : 질문 받기 &amp;gt; 검색하기 &amp;gt; 요약하기 &amp;gt; 답변하기&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기존 방식 vs LangChain&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 방식&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757346403810&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 매번 처음부터 코드 작성해야 함
import openai

def answer_question(question):
    # 1단계: AI에게 질문
    response1 = openai.chat.completions.create(
        model=&quot;gpt-4&quot;,
        messages=[{&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: f&quot;이 질문을 분석해줘: {question}&quot;}]
    )
    
    # 2단계: 검색 키워드 추출
    response2 = openai.chat.completions.create(
        model=&quot;gpt-4&quot;, 
        messages=[{&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: f&quot;검색 키워드 추출: {response1}&quot;}]
    )
    
    # 3단계: 답변 생성... (코드가 길어짐)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LangChain 방식 (간단함):&lt;/p&gt;
&lt;pre id=&quot;code_1757346425761&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain import LLMChain, PromptTemplate
from langchain.chat_models import ChatOpenAI

# 레고 블록처럼 조립!
llm = ChatOpenAI()

# 1단계 블록
analyze_prompt = PromptTemplate(
    template=&quot;질문을 분석해줘: {question}&quot;
)
analyze_chain = LLMChain(llm=llm, prompt=analyze_prompt)

# 2단계 블록  
search_prompt = PromptTemplate(
    template=&quot;검색 키워드 추출: {analysis}&quot;
)
search_chain = LLMChain(llm=llm, prompt=search_prompt)

# 블록들을 연결!
def answer_question(question):
    analysis = analyze_chain.run(question=question)
    keywords = search_chain.run(analysis=analysis)
    return keywords&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. LangGraph: AI가 스스로 판단하게 만들기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LangChain의 한계:&lt;/p&gt;
&lt;pre id=&quot;code_1757346457297&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;LangChain: 정해진 순서대로만 실행
질문 &amp;rarr; 분석 &amp;rarr; 검색 &amp;rarr; 답변 (항상 이 순서)

하지만 실제로는...
- 간단한 질문은 바로 답변하고 싶고
- 복잡한 질문은 여러 번 검색하고 싶고  
- 답변이 부족하면 다시 검색하고 싶음&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LangGraph: AI가 스스로 결정&lt;/p&gt;
&lt;pre id=&quot;code_1757346481418&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langgraph import StateGraph
from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate

# 진짜 AI 모델
llm = ChatOpenAI(model=&quot;gpt-4&quot;)

def analyze_question(state):
    question = state[&quot;question&quot;]
    
    # AI에게 질문의 복잡도를 실제로 판단하게 함
    prompt = PromptTemplate.from_template(&quot;&quot;&quot;
    다음 질문의 복잡도를 판단해주세요:
    질문: {question}
    
    판단 기준:
    - 간단: 사실 확인, 정의 설명 등
    - 복잡: 분석, 비교, 다단계 추론 필요
    
    답변: simple 또는 complex 중 하나만
    &quot;&quot;&quot;)
    
    # 여기서 실제 AI 호출!
    response = llm.invoke(prompt.format(question=question))
    complexity = response.content.strip().lower()
    
    if complexity == &quot;simple&quot;:
        return {&quot;next&quot;: &quot;direct_answer&quot;, &quot;complexity&quot;: &quot;simple&quot;}
    else:
        return {&quot;next&quot;: &quot;search_first&quot;, &quot;complexity&quot;: &quot;complex&quot;}

def should_search_more(state):
    answer = state[&quot;current_answer&quot;]
    question = state[&quot;question&quot;]
    
    # AI가 답변 품질을 실제로 평가
    evaluation_prompt = PromptTemplate.from_template(&quot;&quot;&quot;
    질문: {question}
    현재 답변: {answer}
    
    이 답변이 질문에 충분히 답하고 있나요?
    0.0 (전혀 부족) ~ 1.0 (완벽) 사이 점수로 평가해주세요.
    숫자만 답하세요.
    &quot;&quot;&quot;)
    
    # 실제 AI 평가!
    response = llm.invoke(evaluation_prompt.format(
        question=question, 
        answer=answer
    ))
    
    try:
        quality_score = float(response.content.strip())
        state[&quot;answer_quality&quot;] = quality_score
        
        if quality_score &amp;lt; 0.7:
            return &quot;search_more&quot;
        else:
            return &quot;finish&quot;
    except:
        r&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt; 실제 동작 예시 &amp;gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시나리오 1. 간단한 질문&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757346520885&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;사용자: &quot;파이썬이란?&quot;

LangGraph 처리:
1. analyze_question: &quot;간단한 질문이네&quot; &amp;rarr; direct_answer로 이동
2. answer: 바로 답변 생성 &amp;rarr; &quot;파이썬은 프로그래밍 언어입니다...&quot;
3. should_search_more: &quot;답변이 충분해&quot; &amp;rarr; 끝

결과: 빠르고 간단하게 처리!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시나리오2. 복잡한 질문&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757346529538&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;사용자: &quot;파이썬으로 AI 개발할 때 최신 트렌드와 추천 라이브러리는?&quot;

LangGraph 처리:
1. analyze_question: &quot;복잡한 질문이네&quot; &amp;rarr; search_first로 이동
2. search: &quot;파이썬 AI 최신 트렌드&quot; 검색
3. answer: 검색 결과로 답변 생성
4. should_search_more: &quot;좀 더 구체적인 정보가 필요해&quot; &amp;rarr; search_more
5. search: &quot;파이썬 AI 라이브러리 2024&quot; 추가 검색  
6. answer: 더 풍부한 답변 생성
7. should_search_more: &quot;이제 충분해&quot; &amp;rarr; 끝

결과: 여러 번 검색해서 완성도 높은 답변!&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;핵심 차이점 정리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특징&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; LangChain&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;LangGraph&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;실행 방식&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;정해진 순서대로&lt;/td&gt;
&lt;td&gt;AI가 스스로 판단&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;경로&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;고정된 일직선&lt;/td&gt;
&lt;td&gt;조건에 따라 분기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;반복&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;불가능&lt;/td&gt;
&lt;td&gt;필요시 반복 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;복잡도&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;n8n&lt;/b&gt;: 오픈소스 워크플로우 자동화 툴 (레고 블록처럼 AI&amp;middot;API 연결)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시각적 워크 플로우 자동화 도구&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코딩 없이 드래그 앤 드롭으로 다양한 서비스들을 연결해서 자동화 워크 플로우를 만드는 도구&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 방식의 문제점 : 복잡한 연동 작업을 직접 코딩해야함&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757346769609&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 예시: &quot;Gmail에서 새 이메일 &amp;rarr; OpenAI로 요약 &amp;rarr; Slack 전송&quot;

import imaplib
import email
import openai
import requests

# 1. Gmail 연결 (복잡한 OAuth 설정)
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login('user@gmail.com', 'password')

# 2. 새 이메일 확인 (복잡한 이메일 파싱)
mail.select('inbox')
result, data = mail.search(None, 'UNSEEN')
for num in data[0].split():
    result, data = mail.fetch(num, '(RFC822)')
    raw_email = data[0][1]
    email_message = email.message_from_bytes(raw_email)
    
    # 3. OpenAI로 요약 (API 키, 프롬프트 관리)
    client = openai.OpenAI(api_key=&quot;sk-...&quot;)
    summary = client.chat.completions.create(
        model=&quot;gpt-4&quot;,
        messages=[{&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: f&quot;요약해줘: {email_content}&quot;}]
    )
    
    # 4. Slack으로 전송 (Webhook 설정)
    slack_webhook = &quot;https://hooks.slack.com/services/...&quot;
    requests.post(slack_webhook, json={
        &quot;text&quot;: f&quot;새 이메일 요약: {summary.choices[0].message.content}&quot;
    })

# 에러 처리, 로깅, 스케줄링 등등... 코드가 끝없이 길어짐&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제점 :&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 각 서비스마다 다른 API 방식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 복잡한 인증 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 에러 처리 코드 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 스케줄링 별도 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 유지보수의 어려움&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;n8n 방식 : 시각적 블록으로 연결&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;같은 작업을 n8n으로 &amp;gt; [Gmail&amp;nbsp;트리거]&amp;nbsp;&amp;rarr;&amp;nbsp;[OpenAI&amp;nbsp;노드]&amp;nbsp;&amp;rarr;&amp;nbsp;[Slack&amp;nbsp;노드]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757346853331&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   Gmail     │───▶│   OpenAI   │───▶│    Slack  │
│ (새 이메일   │    │  (텍스트    │    │  (메시지     │
│  감지)      │    │   요약)     │    │   전송)      │
└─────────────┘    └─────────────┘    └─────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 노드 설정&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Gmail 트리거 노드&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757346881044&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- 트리거 타입: &quot;새 이메일 도착시&quot;
- 폴더: &quot;받은편지함&quot;
- 확인 주기: 5분마다
- 인증: OAuth 자동 연결 (클릭 몇 번으로 완료)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. openAI 노드&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757346922333&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- 모델: GPT-4
- 프롬프트: &quot;다음 이메일을 3문장으로 요약해줘: {{$node[&quot;Gmail&quot;].json[&quot;body&quot;]}}&quot;
- API 키: 설정에서 한 번만 입력&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Slack 노드&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757346935059&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- 채널: #이메일-알림
- 메시지: &quot;  새 이메일 요약: {{$node[&quot;OpenAI&quot;].json[&quot;choices&quot;][0][&quot;message&quot;][&quot;content&quot;]}}&quot;
- Webhook: 자동으로 생성&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;n8n의 핵심 장점&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 노코드 / 로우코드&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757346959562&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;개발자가 아닌 사람도 사용 가능!

마케터: &quot;새 고객 문의 &amp;rarr; 감정 분석 &amp;rarr; CRM 등록&quot;
HR: &quot;신입사원 등록 &amp;rarr; 계정 생성 &amp;rarr; 온보딩 이메일 발송&quot;
영업팀: &quot;계약 성사 &amp;rarr; 축하 메시지 &amp;rarr; 보고서 업데이트&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 200+ 서비스 기본 지원&lt;/p&gt;
&lt;pre id=&quot;code_1757346971961&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  이메일: Gmail, Outlook, SendGrid
  메신저: Slack, Discord, Teams, Telegram  
 ️ 데이터베이스: MySQL, PostgreSQL, MongoDB
☁️ 클라우드: AWS, Google Cloud, Azure
  AI: OpenAI, Anthropic, HuggingFace
  분석: Google Analytics, Mixpanel
  결제: Stripe, PayPal&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 조건부 로직 지원&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757346984305&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│새 고객 문의  │───▶│   IF 노드   │───▶│ 긴급 알림   │
└─────────────┘    │             │    └─────────────┘
                   │ 긴급 키워드? │    
                   │             │    ┌─────────────┐
                   └─────────────┘───▶│ 일반 처리   │
                                      └─────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 스케줄링 내장&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실제 사용 사례&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;마케팅 자동화&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;css&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;[웹사이트 폼] &amp;rarr; [새 리드 감지] &amp;rarr; [ChatGPT로 개인화 메시지 생성] 
                     &amp;darr;
[고객 타입 분류] &amp;rarr; [맞춤형 이메일 발송] &amp;rarr; [CRM에 자동 등록]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;고객 지원 자동화&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;css&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;[고객 문의] &amp;rarr; [감정 분석] &amp;rarr; [부정적이면 매니저에게 즉시 알림]
                  &amp;darr;
[FAQ 검색] &amp;rarr; [자동 답변] &amp;rarr; [해결 안되면 티켓 생성]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;데이터 파이프라인&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;css&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;[다양한 소스에서 데이터 수집] &amp;rarr; [OpenAI로 데이터 정제/분류]
                                      &amp;darr;
[데이터베이스 저장] &amp;rarr; [대시보드 업데이트] &amp;rarr; [알림 발송]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;소셜미디어 관리&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;css&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;[RSS 피드 모니터링] &amp;rarr; [ChatGPT로 요약] &amp;rarr; [트위터 자동 포스팅]
                              &amp;darr;
[해시태그 추가] &amp;rarr; [LinkedIn 공유] &amp;rarr; [성과 추적]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사용 방법&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1757347091301&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Docker로 간단 설치
docker run -it --rm --name n8n -p 5678:5678 n8nio/n8n

# 또는 npm으로 설치
npm install n8n -g
n8n start&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 브라우저에서 사용&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757347101261&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;http://localhost:5678 접속
&amp;rarr; 드래그 앤 드롭으로 노드 연결
&amp;rarr; 각 노드 설정
&amp;rarr; 실행 버튼 클릭
&amp;rarr; 자동화 완성!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=DhuaKAW819s&amp;amp;t=38s&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=DhuaKAW819s&amp;amp;t=38s&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=DhuaKAW819s&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/bRSGGs/hyZJatTrZz/5NoPysNCjpjV1zlJzFaS5K/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=1066_230_1260_442,https://scrap.kakaocdn.net/dn/bcCqVn/hyZGV6djhy/H0T9P2kJGFJPiaO6BJbZ3K/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=1066_230_1260_442&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;자동화 끝판왕 n8n, 이렇게 설치하면 평생 무료입니다! (웹훅 설정, 버전 업데이트 포함)&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/DhuaKAW819s&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;RAG 워크플로우: 직선형 파이프라인&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 RAG의 고정된 흐름&lt;/p&gt;
&lt;pre id=&quot;code_1757347303487&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;사용자 질문 &amp;rarr; 벡터 검색 &amp;rarr; 문서 검색 &amp;rarr; 컨텍스트 생성 &amp;rarr; LLM 답변
    &amp;darr;           &amp;darr;          &amp;darr;           &amp;darr;            &amp;darr;
   입력      임베딩 변환   유사도 계산   문서 조합    최종 출력&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특징 : 항상 같은 순서, 한 번만 실행&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757347319746&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def basic_rag(question):
    # 1단계: 항상 실행
    query_vector = embedding_model.encode(question)
    
    # 2단계: 항상 실행  
    similar_docs = vector_db.search(query_vector, top_k=5)
    
    # 3단계: 항상 실행
    context = &quot;\n&quot;.join([doc.content for doc in similar_docs])
    
    # 4단계: 항상 실행
    prompt = f&quot;&quot;&quot;
    컨텍스트: {context}
    질문: {question}
    답변:
    &quot;&quot;&quot;
    answer = llm.generate(prompt)
    
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;적합한 활용 사례&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;답이 명확하고 단순함, 한 번의 검색으로 충분, 빠른 응답 필요, 검색 결과가 예측 가능&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅&amp;nbsp;FAQ:&amp;nbsp;&quot;회사&amp;nbsp;휴가&amp;nbsp;정책은?&quot; &lt;br /&gt;✅&amp;nbsp;제품&amp;nbsp;설명:&amp;nbsp;&quot;이&amp;nbsp;상품&amp;nbsp;가격은?&quot;&amp;nbsp;&amp;nbsp; &lt;br /&gt;✅&amp;nbsp;매뉴얼&amp;nbsp;검색:&amp;nbsp;&quot;프린터&amp;nbsp;설정&amp;nbsp;방법은?&quot; &lt;br /&gt;✅&amp;nbsp;간단한&amp;nbsp;사실&amp;nbsp;확인:&amp;nbsp;&quot;CEO가&amp;nbsp;누구야?&quot;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;535&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Phyiu/btsQoPA2xDO/4lhk9aEBBet5q7pLV0q6f0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Phyiu/btsQoPA2xDO/4lhk9aEBBet5q7pLV0q6f0/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Phyiu/btsQoPA2xDO/4lhk9aEBBet5q7pLV0q6f0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPhyiu%2FbtsQoPA2xDO%2F4lhk9aEBBet5q7pLV0q6f0%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;535&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;535&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;에이전틱 RAG: 자율적 검색 전략&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI가 스스로 판단하는 복잡한 흐름&lt;/p&gt;
&lt;pre id=&quot;code_1757347386661&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;질문 분석 &amp;rarr; 검색 필요성 판단 &amp;rarr; 쿼리 최적화 &amp;rarr; 검색 실행
    &amp;darr;              &amp;darr;              &amp;darr;           &amp;darr;
더 검색? &amp;larr; 결과 평가 &amp;larr; 답변 생성 &amp;larr; 컨텍스트 조합
    &amp;darr;
재검색/추가검색/완료 결정&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 동작 예시&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 질문 : 삼성전자와 애플의 AI 투자 전략을 비교하고, 한국 AI 산업에 미칠 영향을 분석해줘&lt;/p&gt;
&lt;pre id=&quot;code_1757347559275&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate
import json

# 실제 AI 모델
llm = ChatOpenAI(model=&quot;gpt-4&quot;, temperature=0)

def agentic_rag(question):
    # 1단계: 실제 AI가 질문 복잡도 분석
    analysis_prompt = PromptTemplate.from_template(&quot;&quot;&quot;
    다음 질문을 분석해서 검색 전략을 결정해주세요:
    
    질문: {question}
    
    판단 기준:
    - simple: 단순 사실 확인 (한 번 검색으로 충분)
    - comparison: 2개 이상 대상 비교 
    - multi_hop: 여러 단계 추론 필요
    - research: 종합적 분석 필요
    
    응답 형식 (JSON):
    {{
        &quot;type&quot;: &quot;research&quot;,
        &quot;reasoning&quot;: &quot;이유 설명&quot;,
        &quot;sub_questions&quot;: [&quot;하위질문1&quot;, &quot;하위질문2&quot;, ...]
    }}
    &quot;&quot;&quot;)
    
    # 실제 AI 호출!
    analysis_response = llm.invoke(analysis_prompt.format(question=question))
    analysis = json.loads(analysis_response.content)
    
    if analysis[&quot;type&quot;] == &quot;simple&quot;:
        return basic_rag(question)
    
    # 2단계: 복잡한 질문 처리
    elif analysis[&quot;type&quot;] in [&quot;comparison&quot;, &quot;multi_hop&quot;, &quot;research&quot;]:
        all_contexts = []
        
        for sub_question in analysis[&quot;sub_questions&quot;]:
            # 3단계: AI가 검색 쿼리 최적화
            optimization_prompt = PromptTemplate.from_template(&quot;&quot;&quot;
            원본 질문: {sub_question}
            
            이 질문에 대해 가장 정확한 검색 결과를 얻기 위한 
            최적화된 검색 키워드를 생성해주세요:
            
            - 핵심 키워드만 추출
            - 불필요한 조사/어미 제거
            - 영어 키워드도 포함 (필요시)
            - 시간 제한 있으면 명시
            
            최적화된 검색어만 답하세요.
            &quot;&quot;&quot;)
            
            # 실제 AI 호출!
            optimized_response = llm.invoke(
                optimization_prompt.format(sub_question=sub_question)
            )
            optimized_query = optimized_response.content.strip()
            
            # 4단계: 실제 검색 수행
            search_results = perform_search(optimized_query)
            
            # 5단계: AI가 검색 결과 품질 평가
            evaluation_prompt = PromptTemplate.from_template(&quot;&quot;&quot;
            원본 질문: {sub_question}
            검색 결과: {search_results}
            
            이 검색 결과가 질문에 답하기에 얼마나 적절한지 평가해주세요:
            
            평가 기준:
            - 관련성: 질문과 직접적 관련성
            - 완성도: 답변하기에 충분한 정보량
            - 신뢰성: 출처의 믿을만함
            
            0.0 (매우 부족) ~ 1.0 (완벽) 사이 점수만 답하세요.
            &quot;&quot;&quot;)
            
            # 실제 AI 호출!
            evaluation_response = llm.invoke(evaluation_prompt.format(
                sub_question=sub_question,
                search_results=search_results[:1000]  # 너무 길면 자르기
            ))
            
            try:
                quality_score = float(evaluation_response.content.strip())
            except:
                quality_score = 0.5  # 파싱 실패시 기본값
            
            # 6단계: 품질이 낮으면 AI가 재검색 전략 결정
            if quality_score &amp;lt; 0.7:
                retry_prompt = PromptTemplate.from_template(&quot;&quot;&quot;
                검색 품질이 낮습니다 (점수: {score}).
                
                원본 질문: {sub_question}
                현재 검색어: {current_query}
                현재 결과: {current_results}
                
                더 나은 결과를 위한 새로운 검색 전략을 제안해주세요:
                1. 다른 키워드 조합
                2. 더 구체적이거나 더 광범위한 용어
                3. 다른 접근 방식
                
                새로운 검색어만 답하세요.
                &quot;&quot;&quot;)
                
                # 실제 AI 호출!
                retry_response = llm.invoke(retry_prompt.format(
                    score=quality_score,
                    sub_question=sub_question,
                    current_query=optimized_query,
                    current_results=search_results[:500]
                ))
                
                new_query = retry_response.content.strip()
                search_results = perform_search(new_query)
            
            all_contexts.append({
                &quot;question&quot;: sub_question,
                &quot;results&quot;: search_results,
                &quot;quality&quot;: quality_score
            })
        
        # 7단계: AI가 모든 정보를 종합해서 최종 답변
        synthesis_prompt = PromptTemplate.from_template(&quot;&quot;&quot;
        원본 질문: {original_question}
        
        수집된 정보:
        {all_contexts}
        
        위 정보들을 종합해서 원본 질문에 대한 완전하고 정확한 답변을 작성해주세요:
        
        - 각 하위 질문의 답변을 통합
        - 논리적 연결과 분석 제공
        - 구체적 근거와 함께 결론 도출
        &quot;&quot;&quot;)
        
        contexts_text = &quot;\n\n&quot;.join([
            f&quot;Q: {ctx['question']}\nA: {ctx['results']}\n품질점수: {ctx['quality']}&quot;
            for ctx in all_contexts
        ])
        
        # 최종 AI 호출!
        final_response = llm.invoke(synthesis_prompt.format(
            original_question=question,
            all_contexts=contexts_text
        ))
        
        return final_response.content

def perform_search(query):
    # 실제 검색 구현 (벡터DB, 웹검색 등)
    # 여기서는 예시만
    return f&quot;'{query}'에 대한 검색 결과들...&quot;

def basic_rag(question):
    # 기본 RAG 구현
    return f&quot;{question}에 대한 기본 답변&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실제 AI 호출 지점들&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 질문 복잡도 분석&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;python&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# AI가 실제로 판단
analysis_response = llm.invoke(analysis_prompt.format(question=question))
analysis = json.loads(analysis_response.content)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 검색 쿼리 최적화&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;python&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# AI가 더 나은 검색어 생성
optimized_response = llm.invoke(optimization_prompt.format(sub_question=sub_question))
optimized_query = optimized_response.content.strip()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 검색 결과 품질 평가&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;python&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# AI가 품질 점수 매기기
evaluation_response = llm.invoke(evaluation_prompt.format(...))
quality_score = float(evaluation_response.content.strip())&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 재검색 전략 결정&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;python&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# AI가 새로운 검색 전략 제안
retry_response = llm.invoke(retry_prompt.format(...))
new_query = retry_response.content.strip()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. 최종 답변 종합&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;python&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;livecodeserver&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# AI가 모든 정보를 통합해서 답변
final_response = llm.invoke(synthesis_prompt.format(...))
return final_response.content&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;796&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6gklt/btsQruhVkO9/siXDJTkWzdESrv4YjnTVm0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6gklt/btsQruhVkO9/siXDJTkWzdESrv4YjnTVm0/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6gklt/btsQruhVkO9/siXDJTkWzdESrv4YjnTVm0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6gklt%2FbtsQruhVkO9%2FsiXDJTkWzdESrv4YjnTVm0%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1160&quot; height=&quot;796&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;796&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming Study/AI Agent</category>
      <category>ai agent</category>
      <category>mcp</category>
      <category>RAG</category>
      <category>멀티홉</category>
      <author>Solbi Lee</author>
      <guid isPermaLink="true">https://cat-b0.tistory.com/143</guid>
      <comments>https://cat-b0.tistory.com/143#entry143comment</comments>
      <pubDate>Tue, 9 Sep 2025 01:26:24 +0900</pubDate>
    </item>
  </channel>
</rss>