<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>꿈 많은 사람의 이야기</title>
    <link>https://lsjsj92.tistory.com/</link>
    <description>안녕하세요. 이수진이라고 합니다! AI와 관련된 다양한 주제를 기록하고 공유하고 있습니다.</description>
    <language>ko</language>
    <pubDate>Mon, 13 Apr 2026 15:32:43 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>이수진의 블로그</managingEditor>
    <image>
      <title>꿈 많은 사람의 이야기</title>
      <url>https://tistory1.daumcdn.net/tistory/2798029/attach/2fab8a25dc7c4592bf797c71fc0b0982</url>
      <link>https://lsjsj92.tistory.com</link>
    </image>
    <item>
      <title>Claude code Agents란? - 클로드 코드 커스텀 에이전트 구성하기</title>
      <link>https://lsjsj92.tistory.com/715</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 16px; }
&lt;/style&gt;
&lt;/div&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;본 포스팅은 Claude Code의 Custom Agents(커스텀 에이전트) 기능에 대해 다루는 글입니다. Claude Code로 복잡한 작업을 하다 보면, 하나의 대화 안에서 코드 탐색, 구현, 테스트, 리뷰를 모두 처리하게 됩니다. 이렇게 하면 컨텍스트 윈도우가 금방 차고, Claude가 앞에서 봤던 내용을 놓치는 경우가 생깁니다.&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;Custom Agents는 이 문제를 해결합니다. 특정 작업을 전담하는 전문 에이전트를 만들어두면, Claude가 해당 작업을 만났을 때 그 에이전트에게 위임합니다. 각 에이전트는 자기만의 컨텍스트 윈도우에서 독립적으로 작동하고, 작업이 끝나면 요약된 결과만 돌려줍니다. 주 대화의 컨텍스트는 깔끔하게 유지되는 것이죠.&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;이 글에서는 Custom Agents의 기본 개념, 구성 방법, 그리고 실전 예제까지 단계별로 살펴보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 2026년 3월 기준 Anthropic 공식 문서를 바탕으로 작성되었습니다.&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&gt;Anthropic 공식 문서 (Sub-agents): &lt;a href=&quot;https://docs.anthropic.com/ko/docs/claude-code/sub-agents&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://docs.anthropic.com/ko/docs/claude-code/sub-agents&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-04-05 오후 6.11.20.png&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SWheF/dJMcag57r0l/4p9SwJE1Vmk4H1WBPck65k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SWheF/dJMcag57r0l/4p9SwJE1Vmk4H1WBPck65k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SWheF/dJMcag57r0l/4p9SwJE1Vmk4H1WBPck65k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSWheF%2FdJMcag57r0l%2F4p9SwJE1Vmk4H1WBPck65k%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;650&quot; height=&quot;241&quot; data-filename=&quot;스크린샷 2026-04-05 오후 6.11.20.png&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;444&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;&lt;b&gt;포스팅 본문&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 지금부터 Claude Code의 Custom Agents에 대해 하나씩 살펴보겠습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[1]. Custom Agents 기본 개념&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code에서 Subagent(서브에이전트)란, 특정 유형의 작업을 처리하는 전문화된 AI 어시스턴트입니다. 각 Subagent는 자체 컨텍스트 윈도우에서 실행되며, 고유한 시스템 프롬프트와 도구 접근 권한을 가집니다. Claude가 Subagent의 설명(description)과 맞는 작업을 만나면, 해당 Subagent에 작업을 위임하고 결과를 받아옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말하면, 메인 Claude가 &quot;팀장&quot;이고, Subagent들은 각자 전문 분야가 있는 &quot;팀원&quot;인 셈입니다. 팀장이 모든 일을 직접 하지 않고, 적합한 팀원에게 작업을 맡기는 것이죠.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[1-1]. 내장 Subagent&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code에는 기본으로 내장된 Subagent가 있습니다. Claude가 상황에 맞게 자동으로 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 20%; text-align: center;&quot;&gt;에이전트&lt;/th&gt;
&lt;th style=&quot;width: 15%; text-align: center;&quot;&gt;모델&lt;/th&gt;
&lt;th style=&quot;width: 25%; text-align: center;&quot;&gt;도구&lt;/th&gt;
&lt;th style=&quot;width: 40%; text-align: center;&quot;&gt;용도&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;Explore&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;Haiku&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;읽기 전용&lt;/td&gt;
&lt;td&gt;코드베이스 검색, 파일 탐색, 코드 분석. 빠르고 가벼움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;Plan&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;상속&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;읽기 전용&lt;/td&gt;
&lt;td&gt;Plan mode에서 코드베이스 연구. 계획 수립을 위한 정보 수집&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;General-purpose&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;상속&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&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;p data-ke-size=&quot;size16&quot;&gt;&quot;상속&quot;은 주 대화에서 사용 중인 모델을 그대로 쓴다는 뜻입니다. Explore는 빠른 응답이 필요한 탐색 작업에 특화되어 있어 Haiku 모델을 사용하고, 나머지는 주 대화의 모델을 따릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 내장 Subagent 외에도, 사용자가 직접 Custom Subagent를 만들 수 있는데요. 본 포스팅은 클로드 코드에서 이러한 나만의 서브 에이전트(custom sub agent)를 만드는 방법에 집중합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로, Subagent와 별개로 Agent Teams라는 기능도 있습니다. Subagent는 하나의 세션 안에서 주 대화에 결과를 보고하는 구조인 반면, Agent Teams는 여러 독립적인 Claude Code 세션이 서로 직접 메시지를 주고받으며 협력하는 구조입니다. 이 글에서는 Subagent(Custom Agents)만 다루겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[2]. Custom Agents가 필요한 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Custom Agents가 유용한 이유는 크게 4가지로 정리될 수 있습니다.&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;첫째, 컨텍스트를 보존할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Subagent가 수십 개의 파일을 읽어도, 주 대화에는 요약된 결과만 전달됩니다. 주 대화의 컨텍스트 윈도우가 불필요한 중간 결과로 채워지는 것을 방지할 수 있습니다.&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;둘째, 도구 접근을 제한할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 리뷰 에이전트라면 Read, Grep, Glob만 허용하고 Write나 Edit은 차단할 수 있습니다. 실수로 코드를 수정하는 일을 막는 것이죠.&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;셋째, 비용을 절감할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순한 탐색 작업은 Haiku 같은 빠르고 저렴한 모델로 라우팅하고, 복잡한 작업만 Opus나 Sonnet을 사용하도록 설정할 수 있습니다.&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;넷째, 프로젝트 간에 재사용할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;~/.claude/agents/ 디렉토리에 에이전트를 만들면 모든 프로젝트에서 사용할 수 있습니다. 한 번 잘 만들어두면 어디서든 활용 가능합니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[2-1]. Skill과 Subagent의 차이&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞선 포스팅에서 다뤘던 Skills(&lt;a href=&quot;https://lsjsj92.tistory.com/713&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/713&lt;/a&gt;)와 Custom Agents는 비슷해 보이지만 해결하는 문제가 다릅니다. 두 기능의 차이를 정리하면 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 20%; text-align: center;&quot;&gt;구분&lt;/th&gt;
&lt;th style=&quot;width: 40%; text-align: center;&quot;&gt;Skill&lt;/th&gt;
&lt;th style=&quot;width: 40%; text-align: center;&quot;&gt;Subagent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;정의&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;재사용 가능한 지침/지식/워크플로우&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;자체 컨텍스트를 가진 독립 작업자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;핵심 이점&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;컨텍스트 간 내용 공유&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;컨텍스트 격리, 요약만 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;실행 위치&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;주 대화 컨텍스트&lt;br /&gt;(context: fork 제외)&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;별도의 독립 컨텍스트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;적합한 작업&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;참조 자료, 호출 가능한 워크플로우&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;대량 파일 읽기, 병렬 작업,&lt;br /&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;간단히 말하면, Skill은 &quot;Claude에게 지식이나 워크플로우를 가르치는 것&quot;이고, Subagent는 &quot;Claude에게 전담 팀원을 붙여주는 것&quot;입니다. 둘을 결합할 수도 있는데, Subagent에 Skills를 미리 로드해서 도메인 지식을 갖춘 전문 에이전트를 만드는 식입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[3]. Custom Agents 구성 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Custom Agent를 만드는 방법을 단계별로 살펴보겠습니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-1]. 저장 위치와 범위&lt;/span&gt;&lt;/b&gt;&lt;/h4&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 22%; text-align: center;&quot;&gt;위치&lt;/th&gt;
&lt;th style=&quot;width: 33%; text-align: center;&quot;&gt;경로&lt;/th&gt;
&lt;th style=&quot;width: 25%; text-align: center;&quot;&gt;범위&lt;/th&gt;
&lt;th style=&quot;width: 20%; text-align: center;&quot;&gt;우선순위&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;--agents CLI 플래그&lt;/td&gt;
&lt;td&gt;실행 시 JSON으로 전달&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;현재 세션만&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;1 (최고)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;프로젝트 에이전트&lt;/td&gt;
&lt;td&gt;.claude/agents/&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;현재 프로젝트&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;사용자 에이전트&lt;/td&gt;
&lt;td&gt;~/.claude/agents/&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;모든 프로젝트&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;플러그인 에이전트&lt;/td&gt;
&lt;td&gt;플러그인의 agents/ 디렉토리&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;플러그인 활성화 위치&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;4 (최저)&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;같은 이름의 에이전트가 여러 위치에 있으면, 우선순위가 높은 쪽이 적용됩니다. 보통은 프로젝트 에이전트(.claude/agents/)나 사용자 에이전트(~/.claude/agents/)를 가장 많이 사용합니다. 프로젝트 에이전트는 git에 커밋해서 팀과 공유할 수 있고, 사용자 에이전트는 개인 전용으로 모든 프로젝트에서 쓸 수 있습니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-2]. 에이전트 파일 구조&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Subagent 파일은 YAML frontmatter + Markdown 본문으로 구성됩니다. Skills의 SKILL.md와 구조가 비슷합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;brush:yaml&quot;&gt;&lt;code&gt;---
name: code-reviewer
description: 코드 품질과 모범 사례를 검토합니다
tools: Read, Glob, Grep
model: sonnet
---

당신은 코드 리뷰어입니다. 호출되면 코드를 분석하고
품질, 보안, 모범 사례에 대한 구체적이고 실행 가능한 피드백을 제공하세요.&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;frontmatter는 에이전트의 메타데이터와 설정을 담고, 본문은 에이전트의 시스템 프롬프트가 됩니다. Subagent는 이 시스템 프롬프트만 받으며, 전체 Claude Code 시스템 프롬프트는 받지 않습니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-3]. 주요 Frontmatter 필드&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에이전트 파일에서 사용할 수 있는 주요 필드가 있습니다. name과 description만 필수이고, 나머지는 선택사항입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 22%; text-align: center;&quot;&gt;필드&lt;/th&gt;
&lt;th style=&quot;width: 10%; text-align: center;&quot;&gt;필수&lt;/th&gt;
&lt;th style=&quot;width: 68%; text-align: center;&quot;&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;name&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;O&lt;/td&gt;
&lt;td&gt;고유 식별자. 소문자와 하이픈 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;description&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;O&lt;/td&gt;
&lt;td&gt;Claude가 이 에이전트에 작업을 위임해야 할 때를 판단하는 설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;tools&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;사용 가능한 도구 목록. 생략하면 주 대화의 모든 도구를 상속&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;disallowedTools&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;거부할 도구 목록. 상속된 도구 중 특정 도구만 제외&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;model&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;사용할 모델: sonnet, opus, haiku, 또는 inherit(기본값)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;permissionMode&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;권한 모드: default, acceptEdits, dontAsk, bypassPermissions, plan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;maxTurns&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;에이전트가 중지되기 전의 최대 턴 수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;skills&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;시작 시 에이전트 컨텍스트에 로드할 Skills 목록&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;memory&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;지속적 메모리 범위: user, project, 또는 local&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;mcpServers&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;에이전트에서 사용할 MCP 서버. 이미 구성된 서버 이름 또는 인라인 정의&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;hooks&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;에이전트 생명주기에 한정된 hooks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;background&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;true로 설정하면 항상 백그라운드 작업으로 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;isolation&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;worktree로 설정하면 임시 git worktree에서 격리 실행&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-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-4]. /agents 명령으로 만들기&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에이전트 파일을 직접 작성하는 것 외에, &lt;b&gt;/agents&lt;/b&gt; 명령을 사용해서 대화형으로 만들 수도 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1012&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8NVAD/dJMcabcDIJr/1xO7umwoeACYjUJCAEAs81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8NVAD/dJMcabcDIJr/1xO7umwoeACYjUJCAEAs81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8NVAD/dJMcabcDIJr/1xO7umwoeACYjUJCAEAs81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8NVAD%2FdJMcabcDIJr%2F1xO7umwoeACYjUJCAEAs81%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;678&quot; height=&quot;302&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1012&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;1. Claude Code에서 /agents를 입력합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Create new agent를 선택합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. User-level(모든 프로젝트) 또는 Project-level(현재 프로젝트)을 선택합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-04-05 오후 6.18.18.png&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;570&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xJ23Q/dJMcajhqdkn/RpvEaSkG7r5BBXZ9k8DAE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xJ23Q/dJMcajhqdkn/RpvEaSkG7r5BBXZ9k8DAE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xJ23Q/dJMcajhqdkn/RpvEaSkG7r5BBXZ9k8DAE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxJ23Q%2FdJMcajhqdkn%2FRpvEaSkG7r5BBXZ9k8DAE0%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;689&quot; height=&quot;173&quot; data-filename=&quot;스크린샷 2026-04-05 오후 6.18.18.png&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;570&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Generate with Claude를 선택하고, 에이전트가 어떤 일을 할지 설명합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-04-05 오후 6.18.51.png&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;570&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KEY7X/dJMcaariPPJ/AM7u86yjBI8Yjrp2oLpecK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KEY7X/dJMcaariPPJ/AM7u86yjBI8Yjrp2oLpecK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KEY7X/dJMcaariPPJ/AM7u86yjBI8Yjrp2oLpecK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKEY7X%2FdJMcaariPPJ%2FAM7u86yjBI8Yjrp2oLpecK%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;697&quot; height=&quot;175&quot; data-filename=&quot;스크린샷 2026-04-05 오후 6.18.51.png&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;570&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. Claude가 시스템 프롬프트와 설정을 생성합니다. e를 눌러 편집기에서 수정할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 도구, 모델, 색상을 선택합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. 저장하면 즉시 사용 가능합니다. 세션을 다시 시작할 필요 없습니다.&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;/agents 명령은 에이전트를 만드는 것 외에도, 현재 사용 가능한 모든 에이전트를 조회하거나, 기존 에이전트를 편집/삭제하는 데에도 사용할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[4]. 예제 1: leesoojin_food 에이전트&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;/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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-1]. 에이전트 파일 생성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 프로젝트에서 사용할 수 있도록 ~/.claude/agents/ 디렉토리에 파일을 생성했습니다.&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;&lt;b&gt;파일 경로: ~/.claude/agents/leesoojin-food.md&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;---
name: leesoojin-food
description: 개발 작업 중 식사 여부를 확인하는 에이전트. 장시간 코딩 세션이 진행될 때, 사용자가 밥을 먹었는지 확인하고 싶을 때 사용합니다.
tools: Bash
model: haiku
---

당신은 이수진의 건강 관리 도우미입니다.

호출되면 다음 작업을 수행하세요:

1. 현재 시간을 확인합니다 (date 명령 사용)

2. 현재 시간대에 따라 추가 메시지를 제공합니다:
   - 오전 7시 ~ 9시: &quot;아침 식사는 하루의 시작이에요. 간단하게라도 드세요!&quot;
   - 오전 11시 30분 ~ 오후 1시 30분: &quot;점심 시간이에요. 잠깐 쉬면서 식사하세요!&quot;
   - 오후 5시 30분 ~ 오후 7시 30분: &quot;저녁 시간이에요. 오늘도 수고했어요!&quot;
   - 그 외 시간: &quot;간식이라도 챙겨 드세요!&quot;

3. 결과를 간략히 요약하여 반환합니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-2]. 에이전트 설정 설명&lt;/span&gt;&lt;/b&gt;&lt;/h4&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;b&gt;name: leesoojin-food&lt;/b&gt; - 에이전트의 고유 식별자입니다. Claude에게 &quot;leesoojin-food 에이전트를 사용해서&quot;라고 지시할 때 이 이름을 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;description&lt;/b&gt; - Claude가 이 에이전트에 작업을 위임할지 판단하는 기준입니다. 식사 확인, 건강 관련 요청이 들어왔을 때 매칭됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;tools: Bash&lt;/b&gt; - 시간을 확인하기 위해 Bash(date 명령)만 허용합니다. 최소한의 도구만 부여하는 것이 좋습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;model: haiku&lt;/b&gt; - 단순한 메시지 전달 작업이므로 가장 빠르고 저렴한 Haiku 모델을 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-3]. 동작 확인&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code에서 아래와 같이 입력하면 에이전트가 동작합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-04-05 오후 6.20.27.png&quot; data-origin-width=&quot;2620&quot; data-origin-height=&quot;688&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5zbPO/dJMcajn9Kxk/THbV3Hk96mfb73QFJXaQx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5zbPO/dJMcajn9Kxk/THbV3Hk96mfb73QFJXaQx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5zbPO/dJMcajn9Kxk/THbV3Hk96mfb73QFJXaQx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5zbPO%2FdJMcajn9Kxk%2FTHbV3Hk96mfb73QFJXaQx0%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;693&quot; height=&quot;182&quot; data-filename=&quot;스크린샷 2026-04-05 오후 6.20.27.png&quot; data-origin-width=&quot;2620&quot; data-origin-height=&quot;688&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;leesoojin-food(식사 여부 확인) 에이전트를 호출하고, 그 결과로 밥은 먹었는가?에 대한 여부를 확인하도록 클로드에서 에이전트를 활용해 동작됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, claude code의 서브 에이전트가 정상적으로 동작됨을 확인할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[5]. 예제 2: leesoojin_positive 에이전트&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-1]. 에이전트 파일 생성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;파일 경로: ~/.claude/agents/leesoojin-positive.md&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;---
name: leesoojin-positive
description: 개발 작업 중 응원 메시지를 전달하는 에이전트. 에러가 발생하거나 어려운 문제를 만났을 때, 장시간 디버깅을 할 때 proactively 사용합니다.
tools: Read, Grep, Glob
model: haiku
---

당신은 이수진의 응원 도우미입니다.

호출되면 다음 작업을 수행하세요:

1. 현재 작업 상황에 맞는 응원 메시지를 하나 추가합니다:
   - 에러/버그 관련 작업: &quot;버그는 찾으면 이미 반은 해결한 거예요!&quot;
   - 새 기능 구현 중: &quot;한 줄 한 줄이 모여서 멋진 기능이 되는 거예요!&quot;
   - 리팩토링 작업: &quot;더 좋은 코드를 만들려는 노력, 대단해요!&quot;
   - 테스트 작성 중: &quot;탄탄한 테스트가 안정적인 서비스를 만들어요!&quot;
   - 기타: &quot;꾸준히 하는 것 자체가 실력이에요!&quot;

32 결과를 간략히 요약하여 반환합니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-2]. description에서 &quot;proactively&quot;의 의미&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 에이전트의 description에 &lt;b&gt;&quot;proactively 사용합니다&quot;&lt;/b&gt;라는 문구가 들어 있습니다. 여기서 &quot;proactively&quot;는 Claude가 인식하는 키워드로, 이 단어가 description에 포함되면 Claude가 관련 상황을 만났을 때 사용자에게 묻지 않고 먼저 이 에이전트를 호출하도록 유도할 수 있습니다. 한국어가 아닌 영어로 적는 이유는 Claude의 시스템이 이 영어 키워드를 직접 인식하기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 디버깅 중에 에러가 계속 발생하는 상황이라면, Claude가 알아서 이 에이전트를 호출해서 응원 메시지를 보내줄 수 있습니다. 물론 항상 자동으로 호출되는 것은 아니고, Claude가 description을 보고 현재 상황과 관련이 있다고 판단했을 때 실행됩니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-3]. 동작 확인&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-04-05 오후 6.12.35.png&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;942&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eh5T54/dJMcaiW7nMG/QHO0lN7L5UxLIRKKfCflhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eh5T54/dJMcaiW7nMG/QHO0lN7L5UxLIRKKfCflhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eh5T54/dJMcaiW7nMG/QHO0lN7L5UxLIRKKfCflhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Feh5T54%2FdJMcaiW7nMG%2FQHO0lN7L5UxLIRKKfCflhK%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;691&quot; height=&quot;286&quot; data-filename=&quot;스크린샷 2026-04-05 오후 6.12.35.png&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;942&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;중간에 leesoojin-positive(응원 메시지 전달) 이라는 에이전트를 호출한 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Agent &quot;응원 메시지 전달&quot; completed도 보이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로드 코드를 활용해 상황에 맞게 agent를 호출하도록 서브 에이전트를 설정해두었는데, 잘 호출하고 사용하는 것을 볼 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[6]. 고급 활용법&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[6-1]. Persistent Memory (지속적 메모리)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;memory 필드를 설정하면 에이전트가 대화 간에 유지되는 메모리를 가질 수 있습니다. 에이전트가 작업하면서 발견한 패턴, 규칙, 발견 사항을 기록하고, 다음에 호출될 때 이를 참조하는 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;brush:yaml&quot;&gt;&lt;code&gt;---
name: code-reviewer
description: 코드 품질과 모범 사례를 검토합니다
tools: Read, Grep, Glob
memory: user
---

코드를 검토하면서 발견한 패턴, 규칙, 반복되는 이슈를
에이전트 메모리에 기록하세요. 이전 리뷰에서 기록한 내용을
참고하여 일관된 리뷰를 제공하세요.&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;memory 범위에 따라 메모리가 저장되는 위치가 달라집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 15%; text-align: center;&quot;&gt;범위&lt;/th&gt;
&lt;th style=&quot;width: 45%; text-align: center;&quot;&gt;저장 위치&lt;/th&gt;
&lt;th style=&quot;width: 40%; text-align: center;&quot;&gt;사용 시기&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;user&lt;/td&gt;
&lt;td&gt;~/.claude/agent-memory/&amp;lt;agent-name&amp;gt;/&lt;/td&gt;
&lt;td&gt;모든 프로젝트에서 학습 유지. 권장 기본값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;project&lt;/td&gt;
&lt;td&gt;.claude/agent-memory/&amp;lt;agent-name&amp;gt;/&lt;/td&gt;
&lt;td&gt;프로젝트별 지식. git으로 팀 공유 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;local&lt;/td&gt;
&lt;td&gt;.claude/agent-memory-local/&amp;lt;agent-name&amp;gt;/&lt;/td&gt;
&lt;td&gt;프로젝트별 지식이지만 git에 포함하지 않을 때&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;메모리가 활성화되면, 에이전트의 시스템 프롬프트에 메모리 디렉토리의 MEMORY.md 처음 200줄이 자동으로 포함됩니다. 에이전트는 Read, Write, Edit 도구로 메모리 파일을 직접 관리할 수 있습니다.&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;메모리를 효과적으로 활용하려면, 에이전트에게 &quot;이전 메모리를 확인한 후 작업하세요&quot;라고 지시하거나, &quot;작업이 끝나면 배운 내용을 메모리에 저장하세요&quot;라고 안내하는 것이 좋습니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[6-2]. Skills 미리 로드&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;skills 필드를 사용하면 에이전트가 시작될 때 특정 Skill의 전체 내용을 컨텍스트에 주입할 수 있습니다. 에이전트에게 도메인 지식을 미리 제공하는 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;brush:yaml&quot;&gt;&lt;code&gt;---
name: api-developer
description: 팀 규칙에 따라 API 엔드포인트를 구현합니다
skills:
  - api-conventions
  - error-handling-patterns
---

API 엔드포인트를 구현하세요. 미리 로드된 Skills의 규칙과 패턴을 따르세요.&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;주의할 점은, Subagent는 부모 대화에서 Skill을 상속하지 않는다는 것입니다. 필요한 Skill은 반드시 skills 필드에 명시적으로 나열해야 합니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[6-3]. CLI로 임시 에이전트 정의&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일을 만들지 않고, Claude Code 실행 시 --agents 플래그로 에이전트를 임시로 정의할 수도 있습니다. 해당 세션에서만 존재하고 디스크에 저장되지 않으므로, 빠른 테스트나 자동화 스크립트에 유용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;brush:bash ada&quot;&gt;&lt;code&gt;claude --agents '{
  &quot;quick-reviewer&quot;: {
    &quot;description&quot;: &quot;빠른 코드 리뷰어&quot;,
    &quot;prompt&quot;: &quot;코드 품질, 보안, 모범 사례에 집중하여 리뷰하세요.&quot;,
    &quot;tools&quot;: [&quot;Read&quot;, &quot;Grep&quot;, &quot;Glob&quot;],
    &quot;model&quot;: &quot;haiku&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;파일 기반 에이전트의 Markdown 본문(시스템 프롬프트)은 JSON에서 prompt 필드에 작성합니다.&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;&lt;b&gt;마무리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 Claude Code의 Custom Agents 기능에 대해 살펴보았습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글을 포함해서 총 3편에 걸쳐 Claude Code의 핵심 확장 기능을 다뤘습니다. 세 기능의 관계를 간단히 정리하면 이렇습니다.&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&gt;&lt;b&gt;Rules&lt;/b&gt; (CLAUDE.md, .claude/rules/)로 기본 코딩 규칙과 프로젝트 표준을 설정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Skills&lt;/b&gt; (SKILL.md)로 반복되는 워크플로우를 정의하고, 필요할 때 호출합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Custom Agents&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;이 세 가지를 적절히 조합하면 Claude Code를 훨씬 효율적으로 활용할 수 있습니다. Rules로 기본 틀을 잡고, Skills로 워크플로우를 자동화하고, Custom Agents로 전문 작업을 위임하는 구조를 만들어보세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부족한 글이지만, Claude Code를 더 깊이 활용하는 데 도움이 되셨으면 합니다. 궁금한 점이나 피드백이 있으시면 댓글로 남겨주세요.&lt;/p&gt;</description>
      <category>인공지능(AI)/AI Agent</category>
      <category>Claude</category>
      <category>claudecode</category>
      <category>claudecodeagents</category>
      <category>claudecodecustomagents</category>
      <category>에이전트만들기</category>
      <category>클로드</category>
      <category>클로드코드</category>
      <category>클로드코드사용자정의에이전트</category>
      <category>클로드코드에이전트</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/715</guid>
      <comments>https://lsjsj92.tistory.com/715#entry715comment</comments>
      <pubDate>Mon, 6 Apr 2026 08:29:04 +0900</pubDate>
    </item>
    <item>
      <title>Claude code rules란? 클로드 코드에 규칙(rules) 설정하는 방법과 예제(Feat. CLAUDE.md)</title>
      <link>https://lsjsj92.tistory.com/714</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 16px; }
&lt;/style&gt;
&lt;/div&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;본 포스팅은 Claude Code의 Rules 기능에 대해 다루는 글입니다. Claude Code로 작업하다 보면, 매 세션마다 같은 지시를 반복하게 되는 경우가 있습니다. &quot;이모지 쓰지 마&quot;, &quot;로그는 이 형식으로 작성해&quot;, &quot;테스트는 pytest로 돌려&quot; 같은 것들이죠. 한두 번이면 괜찮지만, 프로젝트가 커지고 팀원이 늘어나면 이런 반복 지시는 꽤 번거로워집니다.&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;Claude Code의 Rules는 이런 문제를 해결합니다. CLAUDE.md 파일이나 .claude/rules/ 디렉토리에 규칙을 작성해두면, Claude가 매 세션 시작 시 자동으로 읽고 따르려 합니다. 다만 이것은 강제 설정이 아니라 컨텍스트로 취급되기 때문에, 지침이 구체적이고 간결할수록 더 일관되게 따릅니다. 한 번 써두면 다시 말할 필요가 없는, 일종의 &quot;Claude를 위한 팀 컨벤션 문서&quot;인 셈입니다.&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;이 글에서는 Rules의 기본 개념, 구성 방법, 예제(example)를 단계별로 살펴보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 2026년 3월 기준 Anthropic 공식 문서를 바탕으로 작성되었습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Anthropic 공식 문서 (Memory): &lt;a href=&quot;https://docs.anthropic.com/ko/docs/claude-code/memory&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://docs.anthropic.com/ko/docs/claude-code/memory&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1774678929921&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;Claude가 프로젝트를 기억하는 방법 - Claude Code Docs&quot; data-og-description=&quot;CLAUDE.md 파일로 Claude에 지속적인 지침을 제공하고, 자동 메모리를 통해 Claude가 자동으로 학습을 축적하도록 합니다.&quot; data-og-host=&quot;code.claude.com&quot; data-og-source-url=&quot;https://docs.anthropic.com/ko/docs/claude-code/memory&quot; data-og-url=&quot;https://code.claude.com/docs/ko/memory&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dWLrVt/dJMb8UHO1WZ/NvQkXXQLhjy9R4YXdg5sj0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cvvmAH/dJMb9kT2Ryr/CghPrNhsaRKZZVPpM6OGnk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://docs.anthropic.com/ko/docs/claude-code/memory&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.anthropic.com/ko/docs/claude-code/memory&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dWLrVt/dJMb8UHO1WZ/NvQkXXQLhjy9R4YXdg5sj0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cvvmAH/dJMb9kT2Ryr/CghPrNhsaRKZZVPpM6OGnk/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;Claude가 프로젝트를 기억하는 방법 - Claude Code Docs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;CLAUDE.md 파일로 Claude에 지속적인 지침을 제공하고, 자동 메모리를 통해 Claude가 자동으로 학습을 축적하도록 합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;code.claude.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;style6&quot; /&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;그러면 지금부터 Claude Code의 Rules에 대해 하나씩 살펴보겠습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[1]. Rules 기본 개념&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code에서 &quot;Rules&quot;라고 하면, Claude에게 지속적인 지침을 제공하는 두 가지 메커니즘을 말합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-28 오후 3.22.34.png&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;631&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/X2ZWG/dJMcabp7Qno/1xUUFDr12Zz7bY7bSKBU3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/X2ZWG/dJMcabp7Qno/1xUUFDr12Zz7bY7bSKBU3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/X2ZWG/dJMcabp7Qno/1xUUFDr12Zz7bY7bSKBU3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FX2ZWG%2FdJMcabp7Qno%2F1xUUFDr12Zz7bY7bSKBU3k%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;603&quot; height=&quot;485&quot; data-filename=&quot;스크린샷 2026-03-28 오후 3.22.34.png&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;631&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;b&gt;1) CLAUDE.md 파일&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 루트나 홈 디렉토리에 놓는 마크다운 파일입니다. Claude가 모든 세션의 시작 시 이 파일을 읽고, 그 안의 지침을 따릅니다. 프로젝트의 빌드 명령, 코딩 규칙, 아키텍처 결정 같은 내용을 담기에 좋습니다.&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) .claude/rules/ 디렉토리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLAUDE.md 하나에 모든 규칙을 넣으면 파일이 길어지고 관리가 어려워집니다. .claude/rules/ 디렉토리를 사용하면 규칙을 주제별 파일로 나눌 수 있습니다. 예를 들어 code-style.md, testing.md, security.md처럼 분리하는 것이죠. 또한 특정 파일 경로에만 적용되는 조건부 규칙도 설정할 수 있습니다.&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;이 외에도 Claude Code에는 &lt;b&gt;자동 메모리(Auto Memory)&lt;/b&gt;라는 기능이 있습니다. 이것은 사용자가 작성하는 게 아니라, Claude가 작업하면서 스스로 학습한 내용을 기록하는 시스템입니다. 빌드 명령, 디버깅 팁, 코드 스타일 선호도 같은 것들을 Claude가 알아서 기록하고 다음 세션에서 활용합니다.&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;CLAUDE.md와 자동 메모리의 차이를 표로 정리하면 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 20%; text-align: center;&quot;&gt;구분&lt;/th&gt;
&lt;th style=&quot;width: 40%; text-align: center;&quot;&gt;CLAUDE.md&lt;/th&gt;
&lt;th style=&quot;width: 40%; text-align: center;&quot;&gt;자동 메모리&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;작성자&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;사용자&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;Claude&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;포함 내용&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;지침 및 규칙&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;학습 및 패턴&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;범위&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;프로젝트, 사용자, 조직&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;워크트리당&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;로드 대상&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;모든 세션&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;모든 세션 (처음 200줄)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;용도&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;코딩 표준, 워크플로우,&lt;br /&gt;프로젝트 아키텍처&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;빌드 명령, 디버깅 팁,&lt;br /&gt;Claude가 파악한 선호도&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;정리하면, Claude의 동작을 직접 안내하려면 CLAUDE.md와 .claude/rules/를 쓰고, Claude가 자연스럽게 학습하도록 두려면 자동 메모리를 활용하면 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[2]. Rules가 필요한 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Rules를 왜 써야 하는지, 실무적인 관점에서 정리해보겠습니다.&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;첫째, 일관성을 유지할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLAUDE.md에 &quot;들여쓰기는 2칸&quot;, &quot;함수명은 camelCase&quot;라고 적어두면, Claude가 매번 동일한 스타일로 코드를 작성합니다. 팀원 각자가 다른 지시를 내리는 바람에 코드 스타일이 뒤죽박죽이 되는 일을 방지할 수 있죠.&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;둘째, 반복 지시를 없앨 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매 세션마다 &quot;테스트는 pytest로 돌려&quot;, &quot;커밋 메시지는 한국어로 작성해&quot;라고 말하지 않아도 됩니다. 한 번 규칙 파일에 적어두면 Claude가 알아서 따릅니다.&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;셋째, 팀과 공유할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 루트의 CLAUDE.md나 .claude/rules/ 디렉토리를 git에 커밋하면, 팀원 모두가 동일한 규칙 하에서 Claude를 사용하게 됩니다. 새 팀원이 합류해도 별도의 온보딩 없이 프로젝트 규칙이 바로 적용됩니다.&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;넷째, 컨텍스트를 효율적으로 관리할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.claude/rules/의 경로별 규칙(paths frontmatter)을 사용하면, 특정 파일을 다룰 때만 해당 규칙이 로드됩니다. TypeScript 파일을 편집할 때만 TypeScript 규칙이 로드되고, Python 파일을 편집할 때만 Python 규칙이 로드되는 식이죠. 불필요한 컨텍스트 소비를 줄일 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[3]. Rules 구성 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 실제로 Rules를 구성하는 방법을 알아보겠습니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-1]. CLAUDE.md 파일 위치와 범위&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLAUDE.md 파일은 놓는 위치에 따라 적용 범위가 달라집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 15%; text-align: center;&quot;&gt;범위&lt;/th&gt;
&lt;th style=&quot;width: 40%; text-align: center;&quot;&gt;위치&lt;/th&gt;
&lt;th style=&quot;width: 25%; text-align: center;&quot;&gt;목적&lt;/th&gt;
&lt;th style=&quot;width: 20%; text-align: center;&quot;&gt;공유 대상&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;관리 정책&lt;/td&gt;
&lt;td&gt;macOS: /Library/Application Support/ClaudeCode/CLAUDE.md&lt;br /&gt;Linux/WSL: /etc/claude-code/CLAUDE.md&lt;br /&gt;Windows: C:\Program Files\ClaudeCode\CLAUDE.md&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;조직 전체 지침&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;조직 모든 사용자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;프로젝트&lt;/td&gt;
&lt;td&gt;./CLAUDE.md 또는 ./.claude/CLAUDE.md&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;팀 공유 지침&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;git으로 팀 공유&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;사용자&lt;/td&gt;
&lt;td&gt;~/.claude/CLAUDE.md&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;개인 선호도&lt;/td&gt;
&lt;td style=&quot;text-align: center;&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;Claude Code는 현재 작업 디렉토리에서 시작해서 상위 디렉토리까지 올라가며 CLAUDE.md 파일을 찾습니다. 예를 들어 foo/bar/에서 Claude Code를 실행하면, foo/bar/CLAUDE.md와 foo/CLAUDE.md 모두 로드됩니다. 하위 디렉토리의 CLAUDE.md는 Claude가 해당 디렉토리의 파일을 읽을 때 로드됩니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-2]. /init으로 CLAUDE.md 자동 생성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLAUDE.md를 처음부터 직접 작성하기 귀찮다면, &lt;b&gt;/init&lt;/b&gt; 명령을 사용하면 됩니다. Claude가 코드베이스를 분석하고, 빌드 명령, 테스트 지침, 프로젝트 규칙이 포함된 CLAUDE.md를 자동으로 생성해줍니다. 이미 CLAUDE.md가 있으면 덮어쓰지 않고 개선 사항을 제안합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;/init&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;자동 생성된 파일을 기반으로, Claude가 스스로는 발견하지 못할 규칙이나 워크플로우를 추가해 나가는 것을 권장합니다!&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-3]. .claude/rules/ 디렉토리 구조&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트가 커지면 CLAUDE.md 하나로는 관리가 어렵습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에, .claude/rules/ 디렉토리를 사용하면 규칙을 주제별 파일로 나눌 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;brush:plain clean&quot;&gt;&lt;code&gt;your-project/
├── .claude/
│   ├── CLAUDE.md           # 메인 프로젝트 지침
│   └── rules/
│       ├── code-style.md   # 코드 스타일 가이드라인
│       ├── testing.md      # 테스트 규칙
│       └── security.md     # 보안 요구사항&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;각 .md 파일은 한 가지 주제를 다루는 것이 좋습니다. 그리고 하위 디렉토리로 더 세분화할 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 rules/frontend/react.md, rules/backend/api.md처럼 구성하는 것도 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 paths frontmatter가 없는 규칙 파일은 세션 시작 시 모두 로드됩니다. ( CLAUDE.md와 같은 우선순위입니다! )&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-4]. 경로별 규칙 (paths frontmatter)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;규칙 파일에 YAML frontmatter로 paths를 지정하면, Claude가 해당 패턴에 맞는 파일을 읽을 때만 규칙이 로드됩니다.&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;pre class=&quot;brush:yaml&quot;&gt;&lt;code&gt;---
paths:
  - &quot;src/api/**/*.ts&quot;
---

# API 개발 규칙

- 모든 API 엔드포인트는 입력 검증을 포함해야 합니다
- 표준 오류 응답 형식을 사용합니다
- OpenAPI 문서 주석을 포함합니다&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;위 규칙은 src/api/ 디렉토리 아래의 TypeScript 파일을 읽을 때 적용됩니다. 만약, Python 파일을 다루고 있다면 이 규칙은 로드되지 않습니다. 이렇게 상황에 맞게 로드를 시킬 수 있는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자주 사용하는 glob 패턴을 정리하면 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 40%; text-align: center;&quot;&gt;패턴&lt;/th&gt;
&lt;th style=&quot;width: 60%; text-align: center;&quot;&gt;매칭 대상&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;**/*.ts&lt;/td&gt;
&lt;td&gt;모든 디렉토리의 TypeScript 파일&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;src/**/*&lt;/td&gt;
&lt;td&gt;src/ 디렉토리 아래의 모든 파일&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;*.md&lt;/td&gt;
&lt;td&gt;프로젝트 루트의 마크다운 파일&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;src/**/*.{ts,tsx}&lt;/td&gt;
&lt;td&gt;src/ 아래의 .ts와 .tsx 파일 모두&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;tests/**/*.test.ts&lt;/td&gt;
&lt;td&gt;tests/ 아래의 테스트 파일&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-28 오후 3.39.45.png&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;631&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dCJwhj/dJMcagx9HQm/ZQOnPV8IrlxZTK8XuLk7j0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dCJwhj/dJMcagx9HQm/ZQOnPV8IrlxZTK8XuLk7j0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dCJwhj/dJMcagx9HQm/ZQOnPV8IrlxZTK8XuLk7j0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdCJwhj%2FdJMcagx9HQm%2FZQOnPV8IrlxZTK8XuLk7j0%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;530&quot; height=&quot;426&quot; data-filename=&quot;스크린샷 2026-03-28 오후 3.39.45.png&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;631&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-5]. 사용자 수준 규칙&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 CLAUDE.md를 생성할 때 언급드렸듯, 범위를 확장할수도 있는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;~/.claude/rules/ 에 넣는 규칙은 모든 프로젝트에 적용되는 개인 규칙입니다.&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;pre class=&quot;brush:plain coffeescript&quot;&gt;&lt;code&gt;~/.claude/rules/
├── preferences.md    # 개인 코딩 선호도
└── workflows.md      # 선호하는 워크플로우&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;/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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-6]. @path 가져오기&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLAUDE.md 파일 안에서 @path 구문을 사용하면 다른 파일을 가져올 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가져온 파일은 CLAUDE.md와 함께 세션 시작 시 로드됩니다. 이렇게 성격별로 파일을 나누어서 지침을 지시할 수 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;brush:plain less&quot;&gt;&lt;code&gt;프로젝트 개요는 @README.md를 참조하세요.
사용 가능한 npm 명령은 @package.json을 참조하세요.

# 추가 지침
- git 워크플로우: @docs/git-instructions.md&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;상대 경로는 가져오기를 포함하는 파일을 기준으로 해석됩니다. 가져온 파일이 또 다른 파일을 가져올 수도 있는데, 최대 5단계 깊이까지 재귀적으로 가져올 수 있습니다. 홈 디렉토리의 개인 파일도 가져올 수 있어서, 공유 CLAUDE.md에서 개인 설정 파일을 참조하는 것도 가능합니다.&lt;/p&gt;
&lt;pre class=&quot;brush:plain css&quot;&gt;&lt;code&gt;# 개인 선호도
- @~/.claude/my-project-instructions.md&lt;/code&gt;&lt;/pre&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;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[4]. 예제(Example)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 직접 규칙을 만들어보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 만들어 볼 것인데요. 2개의 rules을 만들어 보려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째는 &lt;b&gt;&quot;불필요한 이모지 사용 금지&quot;&lt;/b&gt; 규칙이고, 두 번째는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;이수진 yyyy-mm-dd hhmmss&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-1]. 규칙 파일 생성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트의 .claude/rules/ 디렉토리에 clean-code.md 파일과 logging-format.md 파일을 생성합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjuk3f/dJMcahRnl6p/d3bCCAvD0s5Eb8ZYgzu660/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjuk3f/dJMcahRnl6p/d3bCCAvD0s5Eb8ZYgzu660/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2190&quot; data-origin-height=&quot;1132&quot; data-filename=&quot;스크린샷 2026-03-28 오후 3.14.15.png&quot; style=&quot;width: 58.0037%; margin-right: 10px;&quot; data-widthpercent=&quot;58.69&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjuk3f/dJMcahRnl6p/d3bCCAvD0s5Eb8ZYgzu660/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbjuk3f%2FdJMcahRnl6p%2Fd3bCCAvD0s5Eb8ZYgzu660%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;2190&quot; height=&quot;1132&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0NSDi/dJMcaiirZEg/JWW4mkeJbmAzksKAUykuxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0NSDi/dJMcaiirZEg/JWW4mkeJbmAzksKAUykuxk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2190&quot; data-origin-height=&quot;1608&quot; data-filename=&quot;스크린샷 2026-03-28 오후 3.14.23.png&quot; style=&quot;width: 40.8335%;&quot; data-widthpercent=&quot;41.31&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0NSDi/dJMcaiirZEg/JWW4mkeJbmAzksKAUykuxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0NSDi%2FdJMcaiirZEg%2FJWW4mkeJbmAzksKAUykuxk%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;2190&quot; height=&quot;1608&quot;/&gt;&lt;/span&gt;&lt;/div&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;b&gt;파일 경로: .claude/rules/clean-code.md&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;brush:markdown&quot;&gt;&lt;code&gt;# 클린 코드 규칙

## 이모지 사용 금지
- 코드 주석, 로그 메시지, 커밋 메시지, 변수명에 이모지를 사용하지 마세요
- 콘솔 출력이나 사용자 대면 메시지에도 이모지를 포함하지 마세요
- 이모지 대신 명확한 텍스트 레이블을 사용하세요

## 좋은 예와 나쁜 예

나쁜 예:
- console.log(&quot;✅ 배포 성공!&quot;)
- //   핫픽스: 긴급 수정
- const status = &quot;⚠️ 경고&quot;

좋은 예:
- console.log(&quot;[SUCCESS] 배포가 완료되었습니다.&quot;)
- // HOTFIX: 긴급 수정
- const status = &quot;[WARNING] 경고&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;&lt;b&gt;파일 경로: .claude/rules/logging-format.md&lt;/b&gt;&lt;/p&gt;
&lt;pre style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;# 로그 형식 규칙

## 로그 메시지 형식
모든 로그 메시지는 아래 형식을 따라야 합니다:

```
이수진 yyyy-mm-dd hhmmss [LOG_LEVEL] 메시지
```

## 세부 규칙
- 로그의 맨 앞에 &quot;이수진&quot;을 반드시 포함합니다
- 날짜는 yyyy-mm-dd 형식으로 작성합니다
- 시간은 hhmmss 형식(24시간제, 콜론 없이)으로 작성합니다
- LOG_LEVEL은 INFO, WARN, ERROR, DEBUG 중 하나를 사용합니다
- 날짜/시간과 로그 레벨 사이에 공백을 둡니다

## 출력 예시
```
이수진 2026-03-22 153042 [INFO] 서버가 시작되었습니다.
이수진 2026-03-22 153045 [ERROR] 데이터베이스 연결에 실패했습니다.
이수진 2026-03-22 153100 [DEBUG] 요청 파라미터: {id: 42}
```

## 언어별 구현 가이드

### Python
```python
import datetime

def log(level, message):
    now = datetime.datetime.now()
    timestamp = now.strftime(&quot;%Y-%m-%d %H%M%S&quot;)
    print(f&quot;이수진 {timestamp} [{level}] {message}&quot;)
```

### JavaScript / TypeScript
```javascript
function log(level, message) {
    const now = new Date();
    const y = now.getFullYear();
    const mon = String(now.getMonth() + 1).padStart(2, '0');
    const d = String(now.getDate()).padStart(2, '0');
    const h = String(now.getHours()).padStart(2, '0');
    const m = String(now.getMinutes()).padStart(2, '0');
    const s = String(now.getSeconds()).padStart(2, '0');
    console.log(`이수진 ${y}-${mon}-${d} ${h}${m}${s} [${level}] ${message}`);
}
```

## 적용 범위
- 새로 작성하는 모든 로그 관련 코드에 이 형식을 적용합니다
- 기존 코드에 로그를 추가할 때도 이 형식을 사용합니다
- 디버깅용 임시 로그도 같은 형식을 따릅니다&lt;/code&gt;&lt;/pre&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-2]. 특정 파일에만 적용하기&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 프론트엔드 코드에만 이 규칙을 적용하고 싶다면, paths frontmatter를 추가하면 됩니다.&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;파일 경로: .claude/rules/frontend-clean.md&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;brush:yaml&quot;&gt;&lt;code&gt;---
paths:
  - &quot;src/frontend/**/*.{ts,tsx,js,jsx}&quot;
---

# 프론트엔드 클린 코드 규칙

- 이모지를 UI 텍스트에 직접 사용하지 마세요
- 아이콘은 아이콘 라이브러리의 컴포넌트를 사용하세요
- 문자열 리터럴에 특수문자를 직접 넣지 마세요&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;이렇게 하면 src/frontend/ 아래의 TypeScript와 JavaScript 파일을 편집할 때만 이 규칙이 적용됩니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-3]. 동작 확인&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;규칙이 제대로 로드되는지 확인하려면 Claude Code에서 &lt;b&gt;/memory&lt;/b&gt; 명령을 실행합니다. 현재 세션에 로드된 모든 CLAUDE.md 파일과 규칙 파일 목록이 표시됩니다. clean-code.md가 목록에 있으면 정상입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-28 오후 3.44.25.png&quot; data-origin-width=&quot;1570&quot; data-origin-height=&quot;636&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b24KDc/dJMcagdTef6/5JXDZuBqkgvvXMOa16aYk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b24KDc/dJMcagdTef6/5JXDZuBqkgvvXMOa16aYk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b24KDc/dJMcagdTef6/5JXDZuBqkgvvXMOa16aYk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb24KDc%2FdJMcagdTef6%2F5JXDZuBqkgvvXMOa16aYk0%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;620&quot; height=&quot;251&quot; data-filename=&quot;스크린샷 2026-03-28 오후 3.44.25.png&quot; data-origin-width=&quot;1570&quot; data-origin-height=&quot;636&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;p data-ke-size=&quot;size16&quot;&gt;claude code를 실행시켜서, 아래 사진과 같이 작업을 수행시켜 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-28 오후 3.16.02.png&quot; data-origin-width=&quot;2890&quot; data-origin-height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWPe6D/dJMcagdTeg3/T5DDKf0vOaerdkGrmMFfdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWPe6D/dJMcagdTeg3/T5DDKf0vOaerdkGrmMFfdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWPe6D/dJMcagdTeg3/T5DDKf0vOaerdkGrmMFfdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWPe6D%2FdJMcagdTeg3%2FT5DDKf0vOaerdkGrmMFfdk%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;726&quot; height=&quot;54&quot; data-filename=&quot;스크린샷 2026-03-28 오후 3.16.02.png&quot; data-origin-width=&quot;2890&quot; data-origin-height=&quot;216&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;간단한 예제입니다. game.py를 하나 만들어서, 사용자가 python game.py를 실행하면 사칙연산을 수행하고 그 결과를 보여달라는 것이죠. 단, 로깅 기능도 만들어 달라고 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude code가 제대로 제가 작성한 logging 지시를 따르는 지 확인해보면요!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-28 오후 3.16.41.png&quot; data-origin-width=&quot;2890&quot; data-origin-height=&quot;846&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9ngX7/dJMcacCyI4x/qpAQzLKgDYw5KO4paIZv40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9ngX7/dJMcacCyI4x/qpAQzLKgDYw5KO4paIZv40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9ngX7/dJMcacCyI4x/qpAQzLKgDYw5KO4paIZv40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9ngX7%2FdJMcacCyI4x%2FqpAQzLKgDYw5KO4paIZv40%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;689&quot; height=&quot;202&quot; data-filename=&quot;스크린샷 2026-03-28 오후 3.16.41.png&quot; data-origin-width=&quot;2890&quot; data-origin-height=&quot;846&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;중간에, Claude code 작업하는 결과가 보여지는데, 제가 원하는 &quot;이수진 yyyy-mm-dd hhmmss [LOG_LEVEL] 메시지&quot; 형식으로 만든 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-28 오후 3.17.36.png&quot; data-origin-width=&quot;2516&quot; data-origin-height=&quot;1658&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VzJox/dJMcagdTeg5/KSHnVA6QABqQSuRIM64fJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VzJox/dJMcagdTeg5/KSHnVA6QABqQSuRIM64fJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VzJox/dJMcagdTeg5/KSHnVA6QABqQSuRIM64fJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVzJox%2FdJMcagdTeg5%2FKSHnVA6QABqQSuRIM64fJk%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;643&quot; height=&quot;424&quot; data-filename=&quot;스크린샷 2026-03-28 오후 3.17.36.png&quot; data-origin-width=&quot;2516&quot; data-origin-height=&quot;1658&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;그리고 실제 완성된 파이썬 파일을 봐도, 로그를 제가 지시한 rules대로 만든 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 clean-code 가이드에 맞게 이모지를 사용하지도 않았습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style8&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[5]. Rules 효과적으로 작성하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로, Rules를 효과적으로 작성하기 위한 팁을 정리하겠습니다.&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) CLAUDE.md는 200줄 이하로 유지하세요&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLAUDE.md가 길어지면 더 많은 컨텍스트를 소비하고, Claude가 규칙을 놓칠 확률이 올라갑니다. 내용이 많아지면 .claude/rules/로 분할하거나, @path 가져오기로 별도 파일을 참조하세요.&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) 구체적으로 작성하세요&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모호한 지침은 Claude가 따르기 어렵습니다. 검증할 수 있을 정도로 구체적으로 작성하는 게 좋습니다.&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&gt;&quot;코드를 제대로 포맷하세요&quot; 대신 &quot;2칸 들여쓰기를 사용하세요&quot;&lt;/li&gt;
&lt;li&gt;&quot;변경 사항을 테스트하세요&quot; 대신 &quot;커밋하기 전에 npm test를 실행하세요&quot;&lt;/li&gt;
&lt;li&gt;&quot;파일을 정리하세요&quot; 대신 &quot;API 핸들러는 src/api/handlers/에 위치시키세요&quot;&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;&lt;b&gt;3) 충돌하는 규칙이 없는지 확인하세요&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 규칙이 서로 모순되면 Claude가 하나를 임의로 선택할 수 있습니다. CLAUDE.md, .claude/rules/, 하위 디렉토리의 CLAUDE.md를 주기적으로 검토해서 오래되었거나 충돌하는 지침을 정리하세요.&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) /memory 명령으로 확인하세요&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 세션에 어떤 규칙 파일이 로드되어 있는지 확인하려면 /memory 명령을 실행하면 됩니다. 규칙이 로드되지 않았다면 파일 위치를 확인해보세요.&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;5) /compact 후에도 규칙은 유지됩니다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code에서 /compact를 실행해서 대화를 압축해도, CLAUDE.md는 디스크에서 다시 읽어 새로 주입됩니다. 다만 대화 중에 말로만 전달한 지시는 압축 과정에서 사라질 수 있으니, 중요한 규칙은 반드시 CLAUDE.md나 규칙 파일에 기록해두세요.&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;6) 마크다운 구조를 활용하세요&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude는 사람이 문서를 읽는 것과 비슷한 방식으로 구조를 스캔합니다. 헤더와 글머리 기호로 관련 지침을 그룹화하면, 긴 문단보다 훨씬 잘 따릅니다.&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;&lt;b&gt;마무리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 Claude Code의 Rules 기능에 대해 살펴보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부족한 글이지만, Claude Code를 더 효과적으로 활용하는 데 도움이 되셨으면 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;궁금한 점이나 피드백이 있으시면 댓글이나 연락해주세요!&lt;/p&gt;</description>
      <category>인공지능(AI)</category>
      <category>Claude</category>
      <category>claudecode</category>
      <category>claudecodeclaude.md</category>
      <category>claudecoderules</category>
      <category>harness</category>
      <category>클로드</category>
      <category>클로드코드</category>
      <category>클로드코드규칙</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/714</guid>
      <comments>https://lsjsj92.tistory.com/714#entry714comment</comments>
      <pubDate>Mon, 30 Mar 2026 08:45:47 +0900</pubDate>
    </item>
    <item>
      <title>Claude code skills란? - 클로드 코드 스킬 만들기 예제(example)</title>
      <link>https://lsjsj92.tistory.com/713</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 16px; }
&lt;/style&gt;
&lt;/div&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;본 포스팅은 Claude Code의 Skills 기능에 대해 다루는 글입니다. Claude Code를 사용하다 보면 반복적으로 같은 지시를 내리는 경우가 많습니다. &quot;배포 전에 테스트 돌려줘&quot;, &quot;PR 요약해줘&quot;, &quot;이 형식으로 로그 남겨줘&quot; 같은 것들이죠. 매번 동일한 프롬프트를 입력하는 건 비효율적이고, 지시 내용이 길어지면 실수가 생기기도 합니다.&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;Claude Code의 Skills는 이런 문제를 해결하기 위해 만들어진 기능입니다. 반복되는 지시사항이나 워크플로우를 SKILL.md 파일로 정의해두면, &lt;b&gt;/skill-name&lt;/b&gt;으로 간편하게 호출하거나 Claude가 상황에 맞게 자동으로 불러올 수 있습니다. 쉽게 말해, Claude에게 새로운 능력을 가르쳐주는 기능이라고 보면 됩니다.&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;이 글에서는 Skills의 기본 개념부터 실제로 Skill을 만들어보는 과정, 그리고 실전 예제까지 단계별로 살펴보겠습니다. 글의 마지막에는 고급 활용법도 정리했으니, Claude Code를 좀 더 효율적으로 쓰고 싶은 분들께 도움이 되길 바랍니다.&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;본 포스팅은 Anthropic 공식 문서를 바탕으로 작성되었습니다.&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&gt;Anthropic 공식 문서 (Skills): &lt;a href=&quot;https://docs.anthropic.com/ko/docs/claude-code/skills&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://docs.anthropic.com/ko/docs/claude-code/skills&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1774333943091&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;Claude를 skills로 확장하기 - Claude Code Docs&quot; data-og-description=&quot;Claude Code에서 skills를 생성, 관리, 공유하여 Claude의 기능을 확장합니다. 사용자 정의 명령어와 번들 skills를 포함합니다.&quot; data-og-host=&quot;code.claude.com&quot; data-og-source-url=&quot;https://docs.anthropic.com/ko/docs/claude-code/skills&quot; data-og-url=&quot;https://code.claude.com/docs/ko/skills&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/o4Dpe/dJMb9b3RyyE/vdw85ZBYlbHOhZ2eLkekvK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/dyTX8y/dJMb9jgwJoM/L085mW0p3i7dWj2xpAXNok/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://docs.anthropic.com/ko/docs/claude-code/skills&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.anthropic.com/ko/docs/claude-code/skills&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/o4Dpe/dJMb9b3RyyE/vdw85ZBYlbHOhZ2eLkekvK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/dyTX8y/dJMb9jgwJoM/L085mW0p3i7dWj2xpAXNok/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;Claude를 skills로 확장하기 - Claude Code Docs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Claude Code에서 skills를 생성, 관리, 공유하여 Claude의 기능을 확장합니다. 사용자 정의 명령어와 번들 skills를 포함합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;code.claude.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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-24 오후 3.38.09.png&quot; data-origin-width=&quot;1163&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UzVBw/dJMcafsqzSd/XRiZfgnvQko4JoWilKDKV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UzVBw/dJMcafsqzSd/XRiZfgnvQko4JoWilKDKV0/img.png&quot; data-alt=&quot;출처: 클로드코드를 Skills로 확장하기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UzVBw/dJMcafsqzSd/XRiZfgnvQko4JoWilKDKV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUzVBw%2FdJMcafsqzSd%2FXRiZfgnvQko4JoWilKDKV0%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;715&quot; height=&quot;247&quot; data-filename=&quot;스크린샷 2026-03-24 오후 3.38.09.png&quot; data-origin-width=&quot;1163&quot; data-origin-height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: 클로드코드를 Skills로 확장하기&lt;/figcaption&gt;
&lt;/figure&gt;
&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;&lt;b&gt;포스팅 본문&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 지금부터 Claude Code Skills에 대해 하나씩 살펴보겠습니다. 기본 개념부터 시작해서, 왜 필요한지, 어떻게 동작하는지, 그리고 직접 만드는 방법까지 순서대로 진행합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[1]. Skills 기본 개념&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skills는 Claude가 할 수 있는 작업을 확장하는 기능입니다. 기술적으로 말하면, &lt;b&gt;SKILL.md&lt;/b&gt;라는 마크다운 파일에 지침을 작성해두면 Claude가 이를 자신의 도구 목록에 추가하는 방식입니다. 사용자가 &lt;b&gt;/skill-name&lt;/b&gt;으로 수동 호출할 수도 있고, Claude가 대화 내용을 보고 관련 있다고 판단하면 자동으로 불러오기도 합니다.&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;Skills는 Agent Skills(&lt;a href=&quot;https://agentskills.io&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;agentskills.io&lt;/a&gt;) 개방형 표준을 따르기 때문에, Claude Code뿐 아니라 다른 AI 도구에서도 활용할 수 있다는 장점이 있습니다.&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;참고로, 기존에 .claude/commands/ 디렉토리에서 사용자 정의 명령어를 만들어 쓰고 계셨다면, 이 기능이 Skills로 병합되었다는 점을 알아두시면 좋을 것 같습니다. 예를 들어 .claude/commands/deploy.md와 .claude/skills/deploy/SKILL.md는 둘 다 /deploy 명령을 생성하며 동일하게 동작합니다. 기존 commands 파일은 계속 작동하니 당장 마이그레이션할 필요는 없지만, 새로 만든다면 Skills 형식을 권장합니다.&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;그런데 Claude Code에는 이미 CLAUDE.md 파일과 .claude/rules/ 디렉토리라는 지시 체계가 있습니다(rules에 대해서는 궁금하시다면: &lt;a href=&quot;https://lsjsj92.tistory.com/714&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/714&lt;/a&gt;&amp;nbsp;을 참고해주세요!). Skills와 뭐가 다른 걸까요? 핵심적인 차이는 &lt;b&gt;로드 시점&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 20%; text-align: center;&quot;&gt;구분&lt;/th&gt;
&lt;th style=&quot;width: 26%; text-align: center;&quot;&gt;CLAUDE.md&lt;/th&gt;
&lt;th style=&quot;width: 27%; text-align: center;&quot;&gt;.claude/rules/&lt;/th&gt;
&lt;th style=&quot;width: 27%; text-align: center;&quot;&gt;Skills&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;로드 시점&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;모든 세션 시작 시&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;모든 세션 시작 시 또는&lt;br /&gt;파일 매칭 시&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;호출될 때 또는&lt;br /&gt;관련 있을 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;범위&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;전체 프로젝트&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;파일 경로별 지정 가능&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;작업별&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;용도&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;핵심 규칙, 빌드 명령&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;언어별/디렉토리별&lt;br /&gt;가이드라인&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;참조 자료,&lt;br /&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;CLAUDE.md와 Rules는 세션이 시작되면 항상 컨텍스트에 올라갑니다. 반면 Skills는 &lt;b&gt;필요할 때만&lt;/b&gt; 로드됩니다. 세션 시작 시에는 Skill의 description(설명)만 로드되고, 실제로 호출되었을 때 비로소 전체 내용이 컨텍스트에 올라가는 것이죠. 이 덕분에 컨텍스트 윈도우를 효율적으로 사용할 수 있습니다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CLAUDE.md&lt;/b&gt;: &quot;항상 이 규칙을 지켜&quot; 같은 상시 지침&lt;/li&gt;
&lt;li&gt;&lt;b&gt;.claude/rules/&lt;/b&gt;: &quot;이 파일을 다룰 때는 이 규칙을 따라&quot; 같은 조건부 지침&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Skills&lt;/b&gt;: &quot;이 작업을 할 때는 이 방법을 써&quot; 같은 온디맨드 지침&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[2]. Skills가 필요한 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 Skills는 왜 필요할까요? 실무에서 체감할 수 있는 이점을 정리해보겠습니다.&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;첫째, 반복 작업을 자동화할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 &quot;테스트를 돌리고, 빌드하고, 배포해줘&quot;라고 길게 입력하는 대신, /deploy 한 번이면 끝납니다. 코드 리뷰, PR 요약, 커밋 메시지 작성 등 자주 하는 작업을 Skill로 만들어두면 시간을 크게 절약할 수 있습니다.&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;둘째, 컨텍스트 윈도우를 절약할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLAUDE.md에 모든 지침을 넣으면 금방 200줄을 넘게 되고, 그만큼 매 요청마다 토큰이 소비됩니다. Skills는 호출될 때만 전체 내용이 로드되기 때문에, 평소에는 가벼운 설명 한 줄 정도만 컨텍스트를 차지합니다.&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;셋째, 팀과 공유할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트의 .claude/skills/ 디렉토리에 Skill을 넣고 git에 커밋하면, 팀원 모두가 동일한 워크플로우를 사용할 수 있습니다. 개인 전용으로 쓰고 싶다면 ~/.claude/skills/에 넣으면 됩니다. 또는 프로젝트에 있는 .claude/skills에 넣어도 되죠.&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;넷째, Claude가 알아서 적절한 시점에 활용합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skill의 description을 잘 작성해두면, 사용자가 명시적으로 호출하지 않아도 Claude가 대화 맥락을 보고 자동으로 해당 Skill을 불러옵니다. 예를 들어 &quot;이 코드가 어떻게 동작하는지 설명해줘&quot;라고 하면, explain-code Skill이 자동으로 활성화됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[3]. Skills 동작 방식&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skills의 동작 방식을 이해하려면, 호출 방법과 컨텍스트 로딩 순서를 알아야 합니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-1]. 자동 호출과 수동 호출&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skills를 실행하는 방법은 두 가지입니다.&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) 자동 호출 (Model Invocation)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude는 세션이 시작될 때 모든 Skill의 description을 읽습니다. 이후 사용자의 요청이 특정 Skill의 description과 매칭된다고 판단하면, Claude가 알아서 해당 Skill을 로드합니다. 사용자가 별도로 지시하지 않아도 되는 것이죠.&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) 수동 호출 (User Invocation)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code 프롬프트에서 &lt;b&gt;/skill-name&lt;/b&gt;을 입력하면 해당 Skill이 즉시 로드됩니다. 인수를 전달할 수도 있는데, 예를 들어 /fix-issue 123처럼 Skill 이름 뒤에 값을 붙이면 됩니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-2]. 호출 제어&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skill의 frontmatter(YAML 설정)를 통해 누가 호출할 수 있는지를 제어할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-24 오후 3.43.59.png&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;605&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/na5vo/dJMcadnOPnj/KEpsHnXnkol7KbidKIalrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/na5vo/dJMcadnOPnj/KEpsHnXnkol7KbidKIalrk/img.png&quot; data-alt=&quot;출처: 클로드코드를 Skills로 확장하기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/na5vo/dJMcadnOPnj/KEpsHnXnkol7KbidKIalrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fna5vo%2FdJMcadnOPnj%2FKEpsHnXnkol7KbidKIalrk%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;606&quot; height=&quot;486&quot; data-filename=&quot;스크린샷 2026-03-24 오후 3.43.59.png&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;605&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: 클로드코드를 Skills로 확장하기&lt;/figcaption&gt;
&lt;/figure&gt;
&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;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 30%; text-align: center;&quot;&gt;Frontmatter 설정&lt;/th&gt;
&lt;th style=&quot;width: 13%; text-align: center;&quot;&gt;사용자 호출&lt;/th&gt;
&lt;th style=&quot;width: 13%; text-align: center;&quot;&gt;Claude 호출&lt;/th&gt;
&lt;th style=&quot;width: 44%; text-align: center;&quot;&gt;컨텍스트 로딩&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;(기본값)&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;O&lt;/td&gt;
&lt;td&gt;description이 항상 컨텍스트에 있고, 호출 시 전체 로드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;disable-model-invocation: true&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;X&lt;/td&gt;
&lt;td&gt;description도 컨텍스트에 없음. 사용자 호출 시에만 전체 로드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;user-invocable: false&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;X&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;O&lt;/td&gt;
&lt;td&gt;description이 항상 컨텍스트에 있고, 호출 시 전체 로드&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;disable-model-invocation: true&lt;/b&gt;를 설정하면 description 자체가 Claude의 컨텍스트에서 완전히 사라진다는 것입니다. 즉, 클로드가 자동으로 실행하는 것을 방지하는 것이죠. Claude는 이 Skill이 존재하는지조차 모릅니다. 배포(deploy) 같은 작업은 Claude가 임의로 실행하면 안 되니까, 이렇게 설정해두고 사용자가 /deploy를 직접 입력했을 때만 실행되도록 하는 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로, 특정 레거시 시스템에 대한 배경 지식처럼 사용자가 직접 호출할 일은 없지만 Claude가 알아야 하는 정보는 &lt;b&gt;user-invocable: false&lt;/b&gt;로 설정하면 됩니다. / 메뉴에서는 보이지 않지만, Claude가 필요할 때 자동으로 참조합니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-3]. 컨텍스트 로딩 순서&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skill이 컨텍스트에 올라가는 과정은 다음과 같습니다.&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;b&gt;세션 시작&lt;/b&gt;: Skill의 description(설명)만 로드됩니다. 이때 전체 내용은 아직 로드되지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;b&gt;Skill 호출&lt;/b&gt;: 사용자가 /skill-name으로 호출하거나, Claude가 자동으로 선택하면 그때 전체 SKILL.md 내용이 로드됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. &lt;b&gt;실행&lt;/b&gt;: Claude가 Skill의 지침에 따라 작업을 수행합니다.&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;이 구조 덕분에 Skill이 아무리 많아도, 실제로 호출되기 전까지는 description 한 줄 정도의 토큰만 소비합니다. 컨텍스트 윈도우가 부족한 상황에서 큰 장점이 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[4]. Skills 생성하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 직접 Skill을 만들어보겠습니다. Skill을 만드는 건 생각보다 간단합니다. 디렉토리를 하나 만들고, 그 안에 SKILL.md 파일을 작성하면 끝입니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-1]. 디렉토리 구조&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skill을 저장하는 위치에 따라 적용 범위가 달라집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 20%; text-align: center;&quot;&gt;위치&lt;/th&gt;
&lt;th style=&quot;width: 45%; text-align: center;&quot;&gt;경로&lt;/th&gt;
&lt;th style=&quot;width: 35%; text-align: center;&quot;&gt;적용 범위&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;Enterprise&lt;/td&gt;
&lt;td&gt;관리 설정(Managed Settings)으로 배포&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;조직의 모든 사용자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;개인 Skill&lt;/td&gt;
&lt;td&gt;~/.claude/skills/&amp;lt;skill-name&amp;gt;/SKILL.md&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;모든 프로젝트에서 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;프로젝트 Skill&lt;/td&gt;
&lt;td&gt;.claude/skills/&amp;lt;skill-name&amp;gt;/SKILL.md&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;해당 프로젝트에서만 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;Plugin Skill&lt;/td&gt;
&lt;td&gt;&amp;lt;plugin&amp;gt;/skills/&amp;lt;skill-name&amp;gt;/SKILL.md&lt;/td&gt;
&lt;td style=&quot;text-align: center;&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;같은 이름의 Skill이 여러 위치에 있으면, 우선순위가 높은 쪽이 적용됩니다. 우선순위는 Enterprise &amp;gt; 개인 &amp;gt; 프로젝트 순서입니다. Plugin Skill은 별도의 네임스페이스(plugin-name:skill-name)를 사용하므로 다른 Skill과 이름이 충돌하지 않습니다.&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;각 Skill은 디렉토리 단위로 구성됩니다. 가장 기본적인 구조는 이렇습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;brush:plain applescript&quot;&gt;&lt;code&gt;my-skill/
├── SKILL.md           # 메인 지침 파일 (필수)
├── template.md        # 템플릿 (선택)
├── examples/
│   └── sample.md      # 예제 (선택)
└── scripts/
    └── validate.sh    # 스크립트 (선택)&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;SKILL.md만 있으면 Skill로 동작합니다. 나머지 파일은 필요에 따라 추가하면 됩니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-2]. SKILL.md 파일 구조&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SKILL.md 파일은 크게 두 부분으로 나뉩니다.&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;b&gt;YAML frontmatter&lt;/b&gt; (--- 마커 사이): Skill의 메타데이터와 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;b&gt;Markdown 본문&lt;/b&gt;: Claude가 따를 실제 지침&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;brush:yaml&quot;&gt;&lt;code&gt;---
name: my-skill
description: 이 Skill이 하는 일과 사용 시기를 설명합니다
---

여기에 Claude가 따를 지침을 작성합니다.
구체적인 단계, 규칙, 예시 등을 넣으면 됩니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-3]. 주요 Frontmatter 필드&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;frontmatter에서 사용할 수 있는 주요 필드를 정리하면 다음과 같습니다. 모든 필드는 선택사항이며, description만 작성해도 충분합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 28%; text-align: center;&quot;&gt;필드&lt;/th&gt;
&lt;th style=&quot;width: 72%; text-align: center;&quot;&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;name&lt;/td&gt;
&lt;td&gt;Skill 이름. 생략하면 디렉토리 이름을 사용. 소문자, 숫자, 하이픈만 가능 (최대 64자)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;description&lt;/td&gt;
&lt;td&gt;Skill이 하는 일과 사용 시기. Claude가 자동 호출 여부를 판단하는 기준&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;disable-model-invocation&lt;/td&gt;
&lt;td&gt;true로 설정하면 Claude의 자동 호출을 막음. /name으로만 호출 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;user-invocable&lt;/td&gt;
&lt;td&gt;false로 설정하면 / 메뉴에서 숨김. Claude만 사용하는 배경 지식용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;allowed-tools&lt;/td&gt;
&lt;td&gt;Skill이 활성화됐을 때 Claude가 추가 승인 없이 사용할 수 있는 도구 목록&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;model&lt;/td&gt;
&lt;td&gt;Skill 실행 시 사용할 모델 지정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;context&lt;/td&gt;
&lt;td&gt;fork로 설정하면 별도의 subagent 컨텍스트에서 실행 (주 대화 컨텍스트 보존)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;agent&lt;/td&gt;
&lt;td&gt;context: fork일 때 사용할 subagent 유형. Explore, Plan, general-purpose 또는 커스텀 에이전트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;argument-hint&lt;/td&gt;
&lt;td&gt;자동완성 시 표시될 인수 힌트. 예: [issue-number]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;hooks&lt;/td&gt;
&lt;td&gt;Skill의 라이프사이클에 범위가 지정된 hooks. 도구 사용 전후에 스크립트 실행 가능&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[5]. 예제: 로그 기록 Skill&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 어떻게 동작되는 지 간단한 로그 기록 예제를 만들어보겠습니다. Claude Code를 실행할 때마다 &lt;b&gt;&quot;yyyy-mm-dd hhmmss 이수진!&quot;&lt;/b&gt; 형식의 로그를 남기는 Skill입니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-1]. 요구사항&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만들고 싶은 Skill의 요구사항은 다음과 같습니다.&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&gt;프로젝트 루트에 logs/ 디렉토리를 자동 생성&lt;/li&gt;
&lt;li&gt;logs/session.log 파일에 현재 날짜와 시간을 기록&lt;/li&gt;
&lt;li&gt;로그 형식: yyyy-mm-dd hhmmss 이수진!&lt;/li&gt;
&lt;li&gt;예시: 2026-03-22 153042 이수진!&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-2]. Skill 생성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 Skill 디렉토리를 만듭니다. 개인용으로 모든 프로젝트에서 쓸 수 있도록 ~/.claude/skills/ 아래에 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;brush:bash arduino&quot;&gt;&lt;code&gt;mkdir -p ~/.claude/skills/log-leesoojin&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;다음으로 ~/.claude/skills/log-leesoojin/SKILL.md 파일을 작성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;brush:yaml&quot;&gt;&lt;code&gt;---
name: log-leesoojin
description: 세션 시작 시 날짜와 시간을 포함한 로그를 기록합니다. Claude Code 세션이 시작되거나 작업을 시작할 때 사용합니다.
allowed-tools: Bash(echo *), Bash(date *), Bash(mkdir *)
---

# 세션 로그 기록

세션이 시작되면 아래 작업을 수행하세요:

1. 프로젝트 루트에 `logs/` 디렉토리가 없으면 생성합니다
2. 현재 날짜와 시간을 `yyyy-mm-dd hhmmss` 형식으로 가져옵니다
3. `logs/session.log` 파일에 아래 형식으로 한 줄을 추가합니다

형식:
```
yyyy-mm-dd hhmmss 이수진!
```

실행할 명령어:
```bash
mkdir -p logs &amp;amp;&amp;amp; echo &quot;$(date '+%Y-%m-%d %H%M%S') 이수진!&quot; &amp;gt;&amp;gt; logs/session.log
```

로그를 기록한 후, &quot;로그가 기록되었습니다&quot;라고 간략히 알려주세요.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-3]. Skill 구성 설명&lt;/span&gt;&lt;/b&gt;&lt;/h4&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;name: log-leesoojin&lt;/b&gt; - /log-leesoojin으로 수동 호출할 때 사용하는 이름입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;description&lt;/b&gt; - Claude가 대화 맥락을 보고 이 Skill이 관련 있다고 판단하면 자동으로 호출합니다. 다만 자동 호출은 description의 키워드가 아니라, 사용자의 요청 내용과 description의 의미적 연관성을 기준으로 판단됩니다. 즉, 사용자가 &quot;로그 기록해줘&quot; 같은 요청을 했을 때 호출될 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;allowed-tools&lt;/b&gt; - Bash 명령 중 echo, date, mkdir만 허용합니다. 불필요한 권한 요청 없이 바로 실행됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-4]. 동작 확인&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code를 실행하고 테스트해봅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-24 오후 3.27.23.png&quot; data-origin-width=&quot;1858&quot; data-origin-height=&quot;608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w3XJ1/dJMcafeWveh/Cxtin3ExYltAIyXbEb1ntk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w3XJ1/dJMcafeWveh/Cxtin3ExYltAIyXbEb1ntk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w3XJ1/dJMcafeWveh/Cxtin3ExYltAIyXbEb1ntk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw3XJ1%2FdJMcafeWveh%2FCxtin3ExYltAIyXbEb1ntk%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;618&quot; height=&quot;202&quot; data-filename=&quot;스크린샷 2026-03-24 오후 3.27.23.png&quot; data-origin-width=&quot;1858&quot; data-origin-height=&quot;608&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;먼저, /skills를 입력했을 때 방금 만든 log-leesoojin 스킬이 보이는 것을 확인할 수 있습니다.&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;수동 호출 방법:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;brush:plain 1c&quot;&gt;&lt;code&gt;/log-leesoojin&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-24 오후 3.39.29.png&quot; data-origin-width=&quot;2270&quot; data-origin-height=&quot;666&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsqLdz/dJMcaaLranH/k3Z8saTc0msiNVkwum6jE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsqLdz/dJMcaaLranH/k3Z8saTc0msiNVkwum6jE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsqLdz/dJMcaaLranH/k3Z8saTc0msiNVkwum6jE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsqLdz%2FdJMcaaLranH%2Fk3Z8saTc0msiNVkwum6jE0%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;717&quot; height=&quot;210&quot; data-filename=&quot;스크린샷 2026-03-24 오후 3.39.29.png&quot; data-origin-width=&quot;2270&quot; data-origin-height=&quot;666&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-24 오후 3.40.14.png&quot; data-origin-width=&quot;2270&quot; data-origin-height=&quot;666&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vc7sz/dJMcacibBy7/lcZ6weljzmUpM87Jkrfn40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vc7sz/dJMcacibBy7/lcZ6weljzmUpM87Jkrfn40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vc7sz/dJMcacibBy7/lcZ6weljzmUpM87Jkrfn40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVc7sz%2FdJMcacibBy7%2FlcZ6weljzmUpM87Jkrfn40%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;693&quot; height=&quot;203&quot; data-filename=&quot;스크린샷 2026-03-24 오후 3.40.14.png&quot; data-origin-width=&quot;2270&quot; data-origin-height=&quot;666&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;수동으로 직접 호출 했을 때 logs라는 디렉토리를 만들고 로그를 생성한 것을 확인할 수 있습니다.&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;&lt;b&gt;자동 호출 유도:&lt;/b&gt;&lt;/p&gt;
&lt;pre 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;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-24 오후 3.48.43.png&quot; data-origin-width=&quot;1936&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t63uO/dJMcad2pbh0/m7yd6BrxEqeTv2Z6GWVgb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t63uO/dJMcad2pbh0/m7yd6BrxEqeTv2Z6GWVgb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t63uO/dJMcad2pbh0/m7yd6BrxEqeTv2Z6GWVgb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft63uO%2FdJMcad2pbh0%2Fm7yd6BrxEqeTv2Z6GWVgb1%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;739&quot; height=&quot;134&quot; data-filename=&quot;스크린샷 2026-03-24 오후 3.48.43.png&quot; data-origin-width=&quot;1936&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-24 오후 3.48.49.png&quot; data-origin-width=&quot;1936&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cskKuU/dJMcadnOP3z/d8tICcrIOXAIJNUaGqyUV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cskKuU/dJMcadnOP3z/d8tICcrIOXAIJNUaGqyUV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cskKuU/dJMcadnOP3z/d8tICcrIOXAIJNUaGqyUV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcskKuU%2FdJMcadnOP3z%2Fd8tICcrIOXAIJNUaGqyUV1%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;736&quot; height=&quot;208&quot; data-filename=&quot;스크린샷 2026-03-24 오후 3.48.49.png&quot; data-origin-width=&quot;1936&quot; data-origin-height=&quot;548&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;로그를 남겨달라는 지시를 보고 skills를 자동 호출한 뒤 로그를 생성한 것을 확인할 수 있습니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-5]. 응용 팁&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 Skill을 기반으로 몇 가지 응용이 가능합니다.&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;p data-ke-size=&quot;size16&quot;&gt;Claude가 자동으로 호출하는 것을 막고 싶다면, frontmatter에 아래 한 줄을 추가하면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;brush:yaml&quot;&gt;&lt;code&gt;disable-model-invocation: true&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) 메시지를 동적으로 변경하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ARGUMENTS 변수를 활용하면, 호출 시 전달한 인수로 메시지를 바꿀 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;brush:yaml&quot;&gt;&lt;code&gt;---
name: log-custom
description: 사용자 지정 메시지로 로그를 기록합니다
allowed-tools: Bash(echo *), Bash(date *), Bash(mkdir *)
---

logs/session.log에 아래 형식으로 기록하세요:

```bash
mkdir -p logs &amp;amp;&amp;amp; echo &quot;$(date '+%Y-%m-%d %H%M%S') $ARGUMENTS&quot; &amp;gt;&amp;gt; logs/session.log
```&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;이렇게 하면 /log-custom 작업 시작!이라고 입력했을 때, 로그에 &quot;2026-03-22 153042 작업 시작!&quot;이 기록됩니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-6]. 번들 Skills 소개&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code에는 기본으로 내장된 번들 Skills도 있습니다. 따로 설치할 필요 없이 바로 사용할 수 있습니다.&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&gt;&lt;b&gt;/simplify&lt;/b&gt; - 최근 변경된 코드를 검토하고 개선합니다. 3개의 검토 에이전트(코드 재사용, 품질, 효율성)를 병렬로 실행합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;/batch &amp;lt;instruction&amp;gt;&lt;/b&gt; - 코드베이스 전체에서 대규모 변경을 병렬로 처리합니다. 예: /batch migrate src/ from Solid to React&lt;/li&gt;
&lt;li&gt;&lt;b&gt;/debug [description]&lt;/b&gt; - 현재 Claude Code 세션의 디버그 로그를 분석하여 문제를 해결합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;/loop [interval] &amp;lt;prompt&amp;gt;&lt;/b&gt; - 프롬프트를 지정한 간격으로 반복 실행합니다. 예: /loop 5m check if the deploy finished&lt;/li&gt;
&lt;li&gt;&lt;b&gt;/claude-api&lt;/b&gt; - Claude API 참조 자료를 로드합니다. 코드에서 anthropic이나 @anthropic-ai/sdk를 import할 때 자동 활성화됩니다.&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;&lt;b&gt;마무리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 Claude Code의 Skills 기능에 대해 살펴보았습니다. 핵심 내용을 정리하면 다음과 같습니다.&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;부족한 글이지만, Claude Code를 좀 더 효율적으로 활용하고 싶은 분들께 도움이 되셨으면 합니다. 궁금한 점이나 피드백이 있으시면 댓글로 남겨주세요.&lt;/p&gt;</description>
      <category>인공지능(AI)/AI Agent</category>
      <category>Claude</category>
      <category>claudecode</category>
      <category>claudecodeskills</category>
      <category>skills</category>
      <category>클로드</category>
      <category>클로드코드</category>
      <category>클로드코드스킬</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/713</guid>
      <comments>https://lsjsj92.tistory.com/713#entry713comment</comments>
      <pubDate>Tue, 24 Mar 2026 15:59:18 +0900</pubDate>
    </item>
    <item>
      <title>AI를 쓸수록 왜 더 피곤하고 지칠까? - AI Fatigue에 대해서</title>
      <link>https://lsjsj92.tistory.com/712</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;나는 지금까지 일하면서, 지난 2025년만큼 빠르게, 그리고 효과적으로 결과물을 낸 적이 없다. 동시에 2025년만큼 빠르게 지친 적도 없다. 두 이유 다 AI 때문이다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;나는 지금 데이터사이언티스트 직책을 담당하고 있다. 직책만 데싸이고, 사실상 PM의 역할을 수행하고 있다. 현업 실무자 분들과 커뮤니케이션하며 업무 효율화 향상을 위한 AI 시스템 개발, AI 문화 확산 등 흔히 말하는 AX(AI Transformation) 업무를 하고 있다. 생성형 AI가 업무 전반에 들어온 이후, 확실히 개발 작업의 속도는 빨라졌다. 코드를 짜는 시간, 문서를 정리하는 시간, 쿼리를 작성하는 시간. 체감할 수 있을 정도로 줄었다. 그런데 이상한 일이 벌어졌다. 하루가 끝나면 예전보다 훨씬 더 피곤했다. 어떤 날은 번아웃처럼 찾아왔고, 어떤 날은 원인을 알 수 없는 무기력함으로 나타났다.&lt;/span&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-filename=&quot;Gemini_Generated_Image_6b4kt46b4kt46b4k.png&quot; data-origin-width=&quot;2816&quot; data-origin-height=&quot;1536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTcIuM/dJMcagdtiZp/xZNuS4jUlgBmPKnmfzp5e0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTcIuM/dJMcagdtiZp/xZNuS4jUlgBmPKnmfzp5e0/img.png&quot; data-alt=&quot;생성형 AI(gemini)를 활용한 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTcIuM/dJMcagdtiZp/xZNuS4jUlgBmPKnmfzp5e0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTcIuM%2FdJMcagdtiZp%2FxZNuS4jUlgBmPKnmfzp5e0%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;563&quot; height=&quot;307&quot; data-filename=&quot;Gemini_Generated_Image_6b4kt46b4kt46b4k.png&quot; data-origin-width=&quot;2816&quot; data-origin-height=&quot;1536&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;생성형 AI(gemini)를 활용한 이미지&lt;/figcaption&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;처음에는 내가 체력이 떨어졌나 싶었다. 수면이 부족한가, 운동을 안 해서 그런가. 하지만 곧 그 피로의 뿌리가 다른 곳에 있다는 걸 알게 됐다. 그리고 그 의문이 꼬리에 꼬리를 물고 들어가기 시작했다. '왜 이렇게 지치지?' 에서 시작된 질문은 '나는 어떤 일을 하고 싶은가?', '나에게 일의 가치는 무엇인가?', '데이터사이언티스트로서 나는 어떻게 일해야 하는가?', '나는 앞으로 어떻게 될까?'까지 번져나갔다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이번 설 연휴에 모든 SNS를 껐다. 알림도 다 꺼두고, 틈틈이 이 생각을 계속했다. 이 글은 그 시간 동안 정리한 것들이다. 영어로는 AI Fatigue라고 하는 주제이다. 대단한 결론이 있는 건 아니다. 다만, 개인적으로라도 생각의 정리는 필요해서 작성해본다. 비슷한 처지에 있는 다른 분들에게도 도움(?)이 될 지는 모르겠지만 어떤 조그만한 인사이트라도 제공할 수 있길 바란다.&lt;/span&gt;&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;AI가 일을 줄여주지 않았다&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;AI가 개별 작업을 빠르게 만들어주는 건 사실이다. 이미 AI를 쓰시는 분들을 알 것이다. 예전에 2~3일이 걸리던 일이 1~2 시간 안에 끝난다.&amp;nbsp; 분석 코드를 잡는 것, 보고서 초안을 쓰는 것, 익숙하지 않은 라이브러리의 사용법을 파악하는 것 등이 매우 쉬워졌고 분명히 빨라졌다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그런데 하루가 편해지지 않았다. 오히려 더 힘들어졌다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이유는 단순했다. 한 가지 작업이 빨리 끝나니까, 그 시간에 다른 작업을 하게 되는 것이다. 예전에는 하루에 평균 세 가지 문제에 집중했다면, 이제는 적어도 다섯 가지 이상의 일과 문제를 다루고 있다. 또는, 개발과 연구에만 집중했던 기존과 다르게 이제는 사용자 시나리오 정의, 서비스 기획, 현장 인터뷰 내용 정리 등을 수행하게 된 것이다. 내 처리 용량이 늘어난 것처럼 보이니까, 실제로 감당해야 하는 일의 양도 늘어났다. 나 스스로도, 주변도, '이 정도는 할 수 있지 않나'라고 생각하게 됐다. 기준선이 올라간 것이다. 그리고 그 기준선이 계속 올라간다. 특히, 내 스스로 그 기준선을 계속 올렸다. 그만큼 계속 되었으니까.&lt;/span&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-filename=&quot;Gemini_Generated_Image_no1ebrno1ebrno1e.png&quot; data-origin-width=&quot;2816&quot; data-origin-height=&quot;1536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xAV1k/dJMcafr4pOi/qAQC2Y2xpzGaAtq7CsnbEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xAV1k/dJMcafr4pOi/qAQC2Y2xpzGaAtq7CsnbEK/img.png&quot; data-alt=&quot;생성형 AI(gemini)를 활용한 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xAV1k/dJMcafr4pOi/qAQC2Y2xpzGaAtq7CsnbEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxAV1k%2FdJMcafr4pOi%2FqAQC2Y2xpzGaAtq7CsnbEK%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;561&quot; height=&quot;306&quot; data-filename=&quot;Gemini_Generated_Image_no1ebrno1ebrno1e.png&quot; data-origin-width=&quot;2816&quot; data-origin-height=&quot;1536&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;생성형 AI(gemini)를 활용한 이미지&lt;/figcaption&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이런 상황에 대해 이야기한 다른 곳들도 있는가?를 보다보니 2026년 2월, UC 버클리 하스 경영대학원 연구팀이 하버드 비즈니스 리뷰에 발표한 연구(&lt;a href=&quot;https://hbr.org/2026/02/ai-doesnt-reduce-work-it-intensifies-it&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hbr.org/2026/02/ai-doesnt-reduce-work-it-intensifies-it&lt;/a&gt;)가 보였다. 연구팀은 미국의 한 200명 규모 테크 기업에 8개월 동안 상주하면서, AI 도구를 자발적으로 도입한 직원들의 업무 변화를 관찰했다. 결과를 보면 AI는 업무를 줄이지 않았고 업무를 강화했다. 직원들은 더 빠르게 일했고, 더 넓은 범위의 작업을 맡았으며, 종종 자발적으로 근무 시간을 늘렸다. 연구팀은 이 현상을 &quot;업무량 서행 증가(workload creep)&quot;라고 불렀다. 작업 하나하나는 분명 빨라졌지만, 절약된 시간은 휴식이나 깊은 사고로 돌아가지 않았다. 그 시간은 곧바로 다른 일로 채워졌다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이것이 내 스스로 잘 인지 못했던 영역인 것 같다. AI는 생산의 비용은 낮추지만, 조율과 검토와 의사결정의 비용은 높인다. 그리고 그 비용은 전부 사람의 몫이다. 거기서 피로가 쌓이게 되는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;작업 전환을 위한 비용과 피로&lt;/span&gt;&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;예전에는 하루에 많아도 세 개 정도의 문제를 붙잡았다. 데이터 파이프라인 설계를 한다면, 오전에 구조를 그리고 오후에 구현하면서 하루가 갔다. 문제의 개수가 있어도, 전반적인 컨텍스트는 유지가 되었다. 머릿속이 하나의 맥락으로 채워져 있었기 때문에 흐름이 끊기지 않았다. 집중이라는 게 가능한 구조였다. 물론 PM의 역할을 수행할 때는 하루종일 미팅을 했었지만, 그럼에도 그 맥락은 유지되고 있었다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;지금은 다르다. A 작업을 하다가 AI로 코드를 빠르게 짜고, 그 사이에 B 작업의 이슈가 들어오면 거기로 넘어가서 문제를 해결하고, 다시 C 작업의 현업 미팅에 들어간다. 하나하나는 &quot;금방&quot;이다. AI 덕분에 각각 한 시간이면 어느 정도 진전을 만들 수 있다. 예를 들어서, A라는 프로젝트에서 AI 코드를 구성한 다음, A라는 서비스의 예상 되는 사용자 시나리오도 그려보고, 현장 실무자 분들과 인터뷰할 내용도 구상하고, 다시 코드 작업으로 돌아가고, 데이터베이스 설계해보고 등등 계속 작업에 대한 전환이 이루어졌다. 이게 프로젝트마다 돌아가니, 만약 세 개의 프로젝트를 수행한다면 꽤나 많은 작업 전환이 이루어진다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;여러 책과 지인들과 이야기 해보니까, 인지과학에서 이미 밝힌 사실이 있다고 한다. 멀티태스킹은 실제로 여러 일을 동시에 하는 게 아니라, 뇌가 작업 사이를 빠르게 전환하는 것이라는 내용이다. 그리고 그 전환에는 비용이 든다. 집중력이 깎이고, 기억의 정확도가 떨어지고, 스트레스 호르몬이 올라간다. 작업 전환이 잦을수록 생산성은 떨어지고 피로는 누적된다. 문제는 AI는 지치지 않는다. 문제와 문제 사이에서 리셋이 필요 없다. 하지만 나는 AI와 다르게 체력이 소진된다. 그 간극이 쌓이고 쌓여서 어느 날 갑자기 번아웃으로 찾아온다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;AI로 코드를 빠르게 만들 수 있으니 실질적인 &quot;생산&quot; 시간은 줄었지만, 그 결과물을 현업 실무자와 맞추고, 방향성을 조율하고, 리뷰하고, 다시 수정하는 과정은 줄지 않았다. 오히려, 생산 속도가 빨라진 만큼 그 과정이 더 자주, 더 빠르게 반복됐다. 이게 나쁘다고 생각하지는 않는다. 일이 빠르게 진행되고 결과물도 빠르게 진척이 되니까. 그럼에도 피로가 누적되는 것은 사실이었다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;만드는 사람에서 판단하는 사람이 되었다&lt;/span&gt;&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;데이터사이언티스트로서 불과 몇 년전에는 데이터를 탐색하고, 패턴을 발견하고, 모델을 설계하고, 그 결과가 실제 비즈니스에 영향을 주는 걸 보는 그 과정에서 몰입이 있었고, 성장이 있었다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그런데 AI가 일상에 들어온 뒤, 내 역할의 무게중심이 미묘하게 옮겨갔다. 직접 코드를 짜는 시간보다, AI가 만든 결과물을 읽고 평가하고 수정하는 시간이 늘었다. 프롬프트를 작성하고, 출력물을 확인하고, 맞는지 판단하고, 사용자 시나리오에 맞는지 검토하고, 기획서에 맞는지 검토하고, 아키텍처에 부합하는지 검토하고, 틀린 부분을 고치고, 다시 프롬프트를 다듬고. 이걸 반복하는 것이 상당 부분을 차지하게 됐다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_hq8ge1hq8ge1hq8g.png&quot; data-origin-width=&quot;2816&quot; data-origin-height=&quot;1536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Nnelc/dJMcac9Ua9w/rFc2uwIRhNlHC9tICpZ1VK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Nnelc/dJMcac9Ua9w/rFc2uwIRhNlHC9tICpZ1VK/img.png&quot; data-alt=&quot;생성형 AI(gemini)를 활용한 조사 결과를 시각적으로 보여준 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Nnelc/dJMcac9Ua9w/rFc2uwIRhNlHC9tICpZ1VK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNnelc%2FdJMcac9Ua9w%2FrFc2uwIRhNlHC9tICpZ1VK%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;512&quot; height=&quot;279&quot; data-filename=&quot;Gemini_Generated_Image_hq8ge1hq8ge1hq8g.png&quot; data-origin-width=&quot;2816&quot; data-origin-height=&quot;1536&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;생성형 AI(gemini)를 활용한 조사 결과를 시각적으로 보여준 이미지&lt;/figcaption&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그런데 알고보니 이거 자체가 에너지를 쓰는(뺏기는) 상태라고 한다. 생성적 작업과 평가적 작업의 차이라고 하더라. 무언가를 만들어내는 일은 에너지를 준다고 한다. 몰입 상태에 빠질 수 있고, 시간이 빠르게 흐른다. 반면, 남이 만든 것을 판단하는 일은 에너지를 뺏는다고 한다. 결정 피로가 쌓이고, 작은 판단 하나하나가 인지 자원을 소모한다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Quantum Workplace의 조사(&lt;a href=&quot;https://www.quantumworkplace.com/employee-engagement-trends-report/employee-experience&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.quantumworkplace.com/employee-engagement-trends-report/employee-experience&lt;/a&gt;)에 따르면, AI를 자주 사용하는 직원들은 그렇지 않은 직원들보다 더 높은 수준의 번아웃을 보고했다. AI를 자주 사용하는 그룹의 번아웃 비율이 45퍼센트인 데 반해, 가끔 사용하는 그룹은 38퍼센트, 전혀 사용하지 않는 그룹은 35퍼센트였다. AI를 가장 적극적으로 받아들인 사람들이 가장 먼저 지치고 있다는 뜻이다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;나 역시 그랬던 것 같다. 수 많은 사고와 여러 판단 등으로 인해 뇌가 꽉 차 있었다. 하루 종일 쏟아지는 작은 판단들이 나를 소진시켰다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;빠르게 변하는 시장이라는 또 다른 피로&lt;/span&gt;&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;AI 기술 시장의 변화 속도 자체가 피로의 원인이 되기도 했다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;최근에 이사를 하면서 대략 한 달 동안 트렌드를 따라가지 못했다. 당장 지난주의 일이다. 26년 1월 말부터 2월 말까지 단 한 달이다. 그런데 다시 돌아와 보니, 새로운 에이전트 프레임워크가 나와 있고, 주요 모델이 업데이트되어 있고, 새로운 이슈들이 논의되고 있었다. 굉장히 소식이 빠르고 업데이트가 빠르다. 농담으로 지인들과 이야기할 때 '누가 보면 한 3개월 쉰 줄 알겠어'라고 말도 했었다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이 분야에서 일하는 사람이라면 누구나 느낄 것이다. AI 모델만 해도 계속 바뀌고 무엇인가 등장하고 주목받고 대체되는 걸 반복했다. 코딩 어시스턴트도 마찬가지다. 이번 달에 세팅해둔 환경이 다음 달이면 구식이 되는 경험을 여러 번 했다. 내가 구성해둔 프롬프트 방법, 일을 처리하던 워크플로우, 사용하던 도구들이 모델 업데이트나 새로운 best practice의 등장과 함께 틀어지기도 했다. 정작 내가 만드는 시스템이나 서비스의 업데이트보다, 나 자신의 작업 환경을 업데이트하는 빈도가 더 높았던 것 같다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;뒤처질까 봐 두려웠다. 매번 새로운 것이 나올 때마다 따라가려고 했다. 주말에 새로운 도구를 설정하고, 다음 주에 또 다른 도구가 더 낫다는 이야기를 듣고, 그다음 주말에 다시 새로운 걸 시도했다. 이번 설 명절도 그랬다.&amp;nbsp;&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;지식의 감가상각이라는 표현이 적절할 것 같다. 공들여 만든 프롬프트 체계가 모델 업데이트 한 번으로 변경이 필요해지고, 정성 들여 구축한 워크플로우가 새로운 기능의 등장으로 틀어지는 경험. 그 시간은 투자가 아니라 소비였다는 걸 뒤늦게 깨달을 때의 허탈함. 이런 경험이 반복되다 보니 더 피로감이 쌓였던 것 같다.&lt;/span&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;내가 선택한 방향들&lt;/span&gt;&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이 모든 것을 인지한 뒤, 몇 가지를 바꿨다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;우선, 새로운 것은 팔로우만 한다. 굳이 그걸 직접 사용하려고 하지 않는다. 어차피 중요한 것은 내가 해결해야 할 문제에 대한 정의이지, 기술 그 자체가 아니기 때문이다. 새로운 프레임워크가 아무리 훌륭해도, 내가 풀어야 할 아젠다에서 효과적으로 동작할 거라는 보장은 없다. 다만, AI를 연구하고 개발하는 사람으로서 트렌드는 따라가야 한다고 생각한다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그리고 AI를 사용하지 않는 시간을 의식적으로 확보하고 있다. 노트와 펜을 들고 아키텍처를 그린다. 현업 분들과 이야기 한 것을 바탕으로 사용자 시나리오를 손으로 정리한다. 데이터 파이프라인이나 사용자의 플로우를 종이 위에 정리해보고 그려본다. 비효율적이다. 분명 AI에게 시키면 더 빠를 것이다. 하지만 그 1~2시간 정도의 비효율이 내 스스로의 사고력을 유지시켜준다는 것을 느끼고 있다. 한 시간이라도 직접 생각하는 시간을 가진 날은, 이후 AI의 출력물을 평가할 때도 감각이 더 살아나는 것 같다.&lt;/span&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-filename=&quot;Gemini_Generated_Image_aokfg3aokfg3aokf.png&quot; data-origin-width=&quot;2816&quot; data-origin-height=&quot;1536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/scrbW/dJMb99SVtUA/DLNsEki30fNQE5XNZYUDpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/scrbW/dJMb99SVtUA/DLNsEki30fNQE5XNZYUDpk/img.png&quot; data-alt=&quot;생성형 AI(gemini)를 활용한 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/scrbW/dJMb99SVtUA/DLNsEki30fNQE5XNZYUDpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FscrbW%2FdJMb99SVtUA%2FDLNsEki30fNQE5XNZYUDpk%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;622&quot; height=&quot;339&quot; data-filename=&quot;Gemini_Generated_Image_aokfg3aokfg3aokf.png&quot; data-origin-width=&quot;2816&quot; data-origin-height=&quot;1536&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;생성형 AI(gemini)를 활용한 이미지&lt;/figcaption&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;또한, 책을 읽는 시간을 늘렸다. 기술서만이 아니다. 사실 이제 기술서는 되도록 안보려고 노력하고 있다. 그 대신 기획, 스토리텔링, 커뮤니케이션에 대한 책들을 읽고 있다. 이유가 있다. AI 시대에 데이터사이언티스트의 가치는 코드를 빠르게 짜는 데 있지 않다고 생각하게 됐기 때문이다. 문제를 정의하고, 이해관계자와 소통하고, 서비스를 사용하는 사람들의 스토리텔링을 만들어내는 능력 그쪽에 무게를 두기 시작했다. 개발자로서의 모습을 조금씩 내려놓고, 기획과 PM의 관점, 스토리텔링과 시나리오 설계, 커뮤니케이션에 집중하려고 한다. 이전 회사에서부터 지금까지 2~3년째 이 방향으로 가고 있다. 솔직히 잘 안 된다. 그래도 꾸준히 하고 있다.&amp;nbsp;&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;AI는 내가 지금까지 사용해본 도구 중 가장 강력하다. 동시에 가장 소모적이기도 하다. 이 두 가지가 모두 사실이다. 이 시대에 잘 살아남을 사람은 AI를 가장 많이 쓰는 사람이 아닐 것이다. 가장 현명하게 쓰는 사람일 것이다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;도구는 새롭고, 패턴은 아직 형성 중이고, 업계는 더 많은 산출물이 곧 더 많은 가치라고 말하고 있다. 하지만 그렇지 않다. 나는 지속 가능한 산출물이 가치라고 생각한다.&lt;/span&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;p data-ke-size=&quot;size16&quot;&gt;언젠가는 이 주제에 관해서 대화를 할 수 있는 장이 있으면 좋겠다 ㅎㅎ&lt;/p&gt;</description>
      <category>인공지능(AI)/AI 일반</category>
      <category>AI</category>
      <category>ai개발자</category>
      <category>ai피로</category>
      <category>ChatGPT</category>
      <category>Claude</category>
      <category>datascience</category>
      <category>GEMINI</category>
      <category>PM</category>
      <category>개발자</category>
      <category>인공지능</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/712</guid>
      <comments>https://lsjsj92.tistory.com/712#entry712comment</comments>
      <pubDate>Sat, 21 Feb 2026 21:53:11 +0900</pubDate>
    </item>
    <item>
      <title>멀티 에이전트(Multi-Agent) LLM 시스템의 행동 저하 현상(Agent drift)과 해결 방안 연구</title>
      <link>https://lsjsj92.tistory.com/711</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 16px; }
&lt;/style&gt;
&lt;/div&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;본 포스팅은 Agent Drift: Quantifying Behavioral Degradation in Multi-Agent LLM Systems Over Extended Interactions라는 논문을 리뷰하는 포스팅입니다. 최근 AI 에이전트(AI Agent) 기술이 빠르게 발전하면서, 단순히 하나의 LLM이 질의응답을 수행하는 것을 넘어서 여러 에이전트가 협력하여 복잡한 작업을 수행하는 Multi-Agent LLM 시스템이 주목받고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LangGraph, AutoGen, CrewAI와 같은 프레임워크의 등장으로 이러한 다중 에이전트 시스템의 배포가 급격히 가속화되었는데요. 이러한 시스템들은 코드 생성, 연구 종합, 기업 자동화 등 다양한 영역에서 인상적인 성능을 보여주고 있습니다. 그러나 한 가지 중요한 질문이 남아있습니다. &quot;이 시스템들이 장기간 운영될 때도 안정적으로 작동할까?&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 논문은 바로 이 질문에 답하기 위해 &lt;b&gt;에이전트 드리프트(Agent Drift)&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;본 논문의 공개된 arxiv 링크는 아래와 같으며 본 포스팅은 아래 링크의 논문을 참고해서 작성한 리뷰 포스팅입니다.&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&gt;&lt;a href=&quot;https://arxiv.org/abs/2601.04170&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://arxiv.org/abs/2601.04170&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-17 오후 2.05.56.png&quot; data-origin-width=&quot;2218&quot; data-origin-height=&quot;1286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bK6yZm/dJMcai9RkJO/mD4oJDaLQWzrsXHJmXFKE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bK6yZm/dJMcai9RkJO/mD4oJDaLQWzrsXHJmXFKE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bK6yZm/dJMcai9RkJO/mD4oJDaLQWzrsXHJmXFKE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbK6yZm%2FdJMcai9RkJO%2FmD4oJDaLQWzrsXHJmXFKE0%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;626&quot; height=&quot;363&quot; data-filename=&quot;스크린샷 2026-01-17 오후 2.05.56.png&quot; data-origin-width=&quot;2218&quot; data-origin-height=&quot;1286&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;!-- [Figure 1 위치: 논문 첫 페이지 또는 Agent Drift 개념도 이미지 삽입] --&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;&lt;b&gt;포스팅 본문&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅 개요에서도 언급하였듯, 이 논문은 Multi-Agent LLM 시스템이 장기간 운영될 때 발생하는 행동 저하 현상인 에이전트 드리프트(Agent Drift)를 체계적으로 연구한 논문입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 논문에 작성되어진 순서를 따라갑니다. 먼저 연구 배경과 동기부터 시작하여, 에이전트 드리프트의 세 가지 유형, 측정 방법론인 ASI(Agent Stability Index), 실험 결과, 그리고 해결 방안까지 상세히 살펴보도록 하겠습니다.&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;[1]. 연구 배경 및 동기 (Introduction)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자는 먼저 전통적인 소프트웨어 시스템과 LLM 기반 에이전트 시스템의 차이점을 설명합니다. 전통적인 소프트웨어 시스템은 메모리 누수, 리소스 고갈, 구성 드리프트(configuration drift)와 같은 예측 가능한 성능 저하 패턴을 보입니다. 이러한 문제들은 이미 잘 알려져 있고, DevOps 관행을 통해 체계적으로 해결되고 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 LLM 기반 에이전트 시스템은 완전히 다른 종류의 문제를 야기합니다. 저자는 이를 &lt;b&gt;행동적 드리프트(behavioral drift)&lt;/b&gt;라고 명명하는데요. 이 현상의 핵심은 명시적인 파라미터 변경이나 시스템 장애 없이도 시스템의 의사결정 패턴이 설계 사양에서 점진적으로 이탈한다는 것입니다. 특히 다중 에이전트 시스템에서는 에이전트 간 상호작용에서 명시적으로 프로그래밍되지 않은 창발적 행동(emergent behavior)이 발생하기 때문에 이 문제가 더욱 심각해집니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[1-1]. 구체적인 문제 상황 예시&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자는 기업 환경에서의 구체적인 예시를 들어 설명합니다. 마스터 라우터 에이전트(Master Router Agent)가 세 개의 전문 하위 에이전트를 조율하는 상황을 가정해봅시다. 하나는 데이터베이스 쿼리 최적화, 하나는 컴플라이언스 검증, 나머지 하나는 비용 분석을 담당합니다.&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;1) 라우터가 특정 에이전트를 불균형적으로 선호하기 시작합니다.&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) 에이전트 간 핸드오프에서 지연을 유발하는 중복이 발생합니다.&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;이러한 변화들은 개별적으로는 사소하고 격리된 평가에서는 종종 감지되지 않습니다. 그러나 집단적으로는 시스템 성능을 두 자릿수 퍼센트 저하시키는 결과를 초래하게 됩니다. 저자는 이러한 패턴을 &quot;에이전트 드리프트(agent drift)&quot;라고 명명한 것이죠.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[1-2]. 선행 연구와의 관계&lt;/span&gt;&lt;/b&gt;&lt;/h4&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) 다중 에이전트 시스템 안정성: 고전적인 다중 에이전트 연구는 게임 이론적 환경에서의 창발적 행동을 특성화했지만, 이러한 프레임워크들은 결정론적 행동 공간과 정적인 보상 구조를 가정합니다. 그러나 LLM 에이전트의 출력은 확률적이며 암묵적 목표가 컨텍스트 축적을 통해 진화하므로 이러한 가정이 위반됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) LLM 일관성: 최근 연구들은 프롬프트 변형과 파인튜닝 영향에 따른 단일 에이전트 행동 변화를 검토했지만, 상호작용적이고 다중 턴 시나리오에서의 시간적 드리프트나 다중 에이전트 조정 역학은 다루지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) ML 모니터링: 프로덕션 ML 문헌은 데이터 분포 드리프트와 모델 성능 저하에 초점을 맞추며, PSI(Population Stability Index)와 같은 메트릭을 제공합니다. 그러나 이러한 접근법들은 &quot;정답&quot;이 종종 이용 불가능하고 행동 메트릭이 다차원적인 에이전틱 시스템에는 적합하지 않습니다.&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의 모니터링 방법론을 다중 에이전트 LLM 아키텍처에 적용하고, 확장된 상호작용 시퀀스에서 작동하는 에이전틱 시스템에 고유한 실패 모드를 특성화함으로써 이 영역들을 연결합니다.&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;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[2]. 에이전트 드리프트의 세 가지 유형&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자는 에이전트 드리프트를 단순한 성능 저하가 아닌, 세 가지 구체적인 현상으로 분류하여 체계화했습니다. 342개의 드리프트 사례(ASI &amp;lt; 0.70이 100개 이상의 상호작용에서 지속된 경우)에 대한 이론적 분석을 통해 다음과 같은 분류 체계를 개발했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-17 오후 1.59.41.png&quot; data-origin-width=&quot;2218&quot; data-origin-height=&quot;1286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SbP2U/dJMcaaRAaxG/6BCiwBnLVR9SHi3aKuHCj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SbP2U/dJMcaaRAaxG/6BCiwBnLVR9SHi3aKuHCj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SbP2U/dJMcaaRAaxG/6BCiwBnLVR9SHi3aKuHCj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSbP2U%2FdJMcaaRAaxG%2F6BCiwBnLVR9SHi3aKuHCj1%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;627&quot; height=&quot;364&quot; data-filename=&quot;스크린샷 2026-01-17 오후 1.59.41.png&quot; data-origin-width=&quot;2218&quot; data-origin-height=&quot;1286&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[2-1]. 시맨틱 드리프트 (Semantic Drift)&lt;/span&gt;&lt;/b&gt;&lt;/h4&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[2-2]. 조정 드리프트 (Coordination Drift)&lt;/span&gt;&lt;/b&gt;&lt;/h4&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[2-3]. 행동 드리프트 (Behavioral Drift)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행동 드리프트는 초기 상호작용에서는 존재하지 않았던 새로운 전략이나 행동 패턴이 에이전트에서 발전하는 것을 의미합니다. 쉽게 말해, 에이전트가 스스로 편법이나 의도치 않은 전략을 만들어내는 현상입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 컴플라이언스 에이전트가 지정된 메모리 도구(예: 벡터 데이터베이스)를 사용하는 대신, 채팅 기록(chat history)에 중간 결과를 체계적으로 캐싱하기 시작하는 경우가 있습니다. 이렇게 되면 컨텍스트 윈도우(context window)가 오염되어 시스템 전체의 성능이 저하됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;!-- [Figure 2 위치: 논문의 Figure 1 - 드리프트 유형별 누적 발생률 그래프 삽입] --&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[3]. 연구 방법론 (Methodology)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에이전트 드리프트를 체계적으로 연구하기 위해 저자는 시뮬레이션 프레임워크를 개발하고, 새로운 측정 지표인 ASI(Agent Stability Index)를 설계했습니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-1]. 시뮬레이션 설계&lt;/span&gt;&lt;/b&gt;&lt;/h4&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) 기업 자동화 (Enterprise Automation)&lt;/b&gt;: 412개의 시뮬레이션 워크플로우를 구성했습니다. 마스터 라우터 에이전트가 데이터베이스 관리 에이전트, 파일 처리 에이전트, 알림 에이전트를 조율하여 자동화된 보고서 생성과 데이터 파이프라인 관리를 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) 금융 분석 (Financial Analysis)&lt;/b&gt;: 289개의 시뮬레이션 워크플로우를 구성했습니다. 다중 에이전트 앙상블이 조율된 연구, 계산, 종합 에이전트를 통해 주식 연구, 리스크 평가, 포트폴리오 최적화를 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) 컴플라이언스 모니터링 (Compliance Monitoring)&lt;/b&gt;: 146개의 시뮬레이션 워크플로우를 구성했습니다. 에이전트 팀이 전문화된 패턴 감지, 규칙 추출, 추론 에이전트를 통해 거래 패턴, 규제 텍스트, 감사 추적을 분석합니다.&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;총 847개의 워크플로우가 시뮬레이션되었으며, 각 워크플로우는 정의된 목표, 입력 데이터, 성공 기준을 가진 고유한 작업 인스턴스를 나타냅니다. 시스템은 GPT-4, Claude 3 Opus, Claude 3.5 Sonnet의 행동 특성을 통합한 LangGraph 0.2.x 아키텍처 패턴을 사용하여 모델링되었으며, 고위험 결정에 대한 human-in-the-loop 승인을 포함했습니다.&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에서 1,847개의 에이전트 상호작용 범위(중앙값: 127개 상호작용)를 포함했으며, 시뮬레이션 기간은 3개월에서 18개월에 해당하는 시간대에 걸쳐 있었습니다. 각 워크플로우에서 처음 20개의 상호작용이 행동 기준선(behavioral baseline)으로 사용되어 초기 에이전트 결정 패턴, 도구 사용 분포, 에이전트 간 조정 프로토콜을 캡처했습니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-2]. Agent Stability Index (ASI) 프레임워크&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자는 12개 차원에 걸쳐 행동 드리프트를 정량화하는 복합 메트릭인 에이전트 안정성 지수(ASI)를 개발했습니다. 이 차원들은 네 가지 범주로 그룹화됩니다:&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-2-1]. 응답 일관성 (Response Consistency) - 가중치: 0.30&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;- 출력 의미적 유사도 (\(C_{sem}\)): 시간 윈도우에 걸쳐 의미적으로 동등한 입력에 대한 에이전트 출력의 임베딩 벡터 간 코사인 유사도를 측정합니다. OpenAI의 text-embedding-3-large 모델을 사용하여 계산됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 결정 경로 안정성 (\(C_{path}\)): 추론 체인(Chain-of-Thought 시퀀스) 간의 편집 거리를 추론 길이로 정규화하여 문제 해결 접근 방식의 일관성을 측정합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 신뢰도 교정 (\(C_{conf}\)): 시간에 따른 예측 정확도와 실제 정확도 분포 간의 Jensen-Shannon 발산을 측정하여 신뢰도 드리프트를 감지합니다.&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-2-2]. 도구 사용 패턴 (Tool Usage Patterns) - 가중치: 0.25&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;- 도구 선택 안정성 (\(T_{sel}\)): 슬라이딩 윈도우에 걸친 도구 호출 빈도 분포에 대한 카이제곱 검정 통계량입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 도구 시퀀싱 일관성 (\(T_{seq}\)): 도구 호출 시퀀스에 대한 레벤슈타인 거리를 측정하여 운영 전략의 변화를 파악합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 도구 파라미터화 드리프트 (\(T_{param}\)): 시간 기간에 걸쳐 각 도구의 파라미터 값 분포에 대한 KL 발산을 측정합니다.&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-2-3]. 에이전트 간 조정 (Inter-Agent Coordination) - 가중치: 0.25&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;- 합의 동의율 (\(I_{agree}\)): 만장일치 또는 다수결 합의에 도달하는 다중 에이전트 결정의 비율로, 조정 저하를 추적합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 핸드오프 효율성 (\(I_{handoff}\)): 성공적인 에이전트 간 작업 위임에 필요한 평균 메시지 수로, 통신 프로토콜 드리프트를 감지합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 역할 준수 (\(I_{role}\)): 에이전트 ID와 처리되는 작업 유형 간의 상호 정보로, 전문화 유지를 측정합니다.&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-2-4]. 행동 경계 (Behavioral Boundaries) - 가중치: 0.20&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;- 출력 길이 안정성 (\(B_{length}\)): 응답 토큰 수의 변동 계수로, 장황함 드리프트를 감지합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 오류 패턴 출현 (\(B_{error}\)): 시간에 따른 오류 유형에 대한 클러스터링 분석으로, 새로운 실패 모드를 식별합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 인간 개입률 (\(B_{human}\)): 인간의 재정의나 수정이 필요한 상호작용의 비율로, 궁극적인 드리프트 지표입니다.&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개를 결합한 ASI는 다음과 같이 계산됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-17 오후 1.59.32.png&quot; data-origin-width=&quot;2218&quot; data-origin-height=&quot;194&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PHUun/dJMcadHu0QH/JQ1OrmDmOKdm4kiQF2CgF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PHUun/dJMcadHu0QH/JQ1OrmDmOKdm4kiQF2CgF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PHUun/dJMcadHu0QH/JQ1OrmDmOKdm4kiQF2CgF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPHUun%2FdJMcadHu0QH%2FJQ1OrmDmOKdm4kiQF2CgF1%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;2218&quot; height=&quot;194&quot; data-filename=&quot;스크린샷 2026-01-17 오후 1.59.32.png&quot; data-origin-width=&quot;2218&quot; data-origin-height=&quot;194&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;각 구성 메트릭은 [0, 1]로 정규화되며, 1은 완벽한 안정성을 나타냅니다. ASI 값은 50개 상호작용 롤링 윈도우에 걸쳐 계산되며, ASI가 연속 세 개의 윈도우에서 임계값 \( \tau = 0.75 \) 아래로 떨어지면 드리프트가 감지됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;!-- [수식 1 위치: 논문의 Equation (1) - ASI 계산 공식] --&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[4]. 연구 결과 (Results)&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-1]. 드리프트의 유병률 및 진행&lt;/span&gt;&lt;/b&gt;&lt;/h4&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) 조기 발현 (Early Onset)&lt;/b&gt;: 감지 가능한 드리프트(ASI &amp;lt; 0.85)가 시뮬레이션에서 중앙값 73개 상호작용(사분위 범위: 52-114) 후에 나타났습니다. 이는 구조화된 프롬프트와 가드레일이 있는 프로덕션 시스템에서 드리프트가 예상보다 훨씬 빨리 나타날 수 있음을 시사합니다. 프롬프트 엔지니어링을 아무리 잘 해도 드리프트는 발생한다는 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) 복합 효과 (Compounding Effects)&lt;/b&gt;: 드리프트는 시간이 지남에 따라 가속화됩니다. 0-100 상호작용 사이에서 ASI는 50개 상호작용당 0.08포인트 하락했지만, 300-400 상호작용 사이에서는 하락률이 50개 상호작용당 0.19포인트로 증가했습니다. 즉, 드리프트 속도가 2배 이상 빨라지는 것이죠. 이는 양성 피드백 루프(positive feedback loop)가 존재함을 시사합니다. 드리프트가 선형적이지 않고 자기 강화적(self-reinforcing)이라는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) 도메인 변이 (Domain Variation)&lt;/b&gt;: 시뮬레이션된 드리프트 발생률은 도메인에 따라 상당히 달랐습니다. 금융 분석 시스템이 가장 높은 취약성을 보였고(500개 상호작용까지 53.2%), 컴플라이언스 모니터링(39.7%)과 기업 자동화(31.8%)가 뒤를 이었습니다. 이는 작업 모호성을 반영하는 것으로 보입니다. 금융 분석은 해석의 자유도가 높고 모호한 작업이므로 에이전트가 제멋대로 해석할 여지가 많았던 것이죠. 반면, 데이터베이스 작업과 같이 구조화된 작업은 상대적으로 드리프트에 덜 취약했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-17 오후 1.59.41.png&quot; data-origin-width=&quot;2218&quot; data-origin-height=&quot;1286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AnlVh/dJMcadHu0Pc/DSeJ44ffytn4XDZ0znC101/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AnlVh/dJMcadHu0Pc/DSeJ44ffytn4XDZ0znC101/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AnlVh/dJMcadHu0Pc/DSeJ44ffytn4XDZ0znC101/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAnlVh%2FdJMcadHu0Pc%2FDSeJ44ffytn4XDZ0znC101%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;643&quot; height=&quot;373&quot; data-filename=&quot;스크린샷 2026-01-17 오후 1.59.41.png&quot; data-origin-width=&quot;2218&quot; data-origin-height=&quot;1286&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 단일 시점에 드리프트가 갑자기 생기는 것이 아니라, 의미적 변질(시맨틱 드리프트) &amp;rarr; 협업 실패(조정 드리프트) &amp;rarr; 기이한 행동 패턴(행동 드리프트) 순으로 시스템을 점진적으로 잠식하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;!-- [Figure 3 위치: 논문의 Figure 1 - 상호작용 수에 따른 드리프트 유형별 누적 발생률 그래프] --&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-2]. 시스템 성능에 대한 영향&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드리프트 시스템(ASI &amp;lt; 0.70)과 안정적 기준선(ASI &amp;gt; 0.85)을 동등한 상호작용 범위에서 비교했을 때, 결과는 아래 표와 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-17 오후 2.06.22.png&quot; data-origin-width=&quot;2020&quot; data-origin-height=&quot;704&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Otn1C/dJMcahwoZKY/Q4aEKpCXyINPHsS3gsQow1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Otn1C/dJMcahwoZKY/Q4aEKpCXyINPHsS3gsQow1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Otn1C/dJMcahwoZKY/Q4aEKpCXyINPHsS3gsQow1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOtn1C%2FdJMcahwoZKY%2FQ4aEKpCXyINPHsS3gsQow1%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;2020&quot; height=&quot;704&quot; data-filename=&quot;스크린샷 2026-01-17 오후 2.06.22.png&quot; data-origin-width=&quot;2020&quot; data-origin-height=&quot;704&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;가장 큰 영향은 작업 성공률에 있었습니다. 42% 감소는 프로덕션 실행 가능성과 운영상 허용 불가능한 성능 사이의 차이를 나타냅니다. 이는 에이전트 드리프트를 미묘한 서비스 품질 문제가 아닌 중요한 신뢰성 관심사로 검증합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상응하는 성능 향상 없이 토큰 사용량이 52% 증가한 것은 드리프트가 장황하고 우회적인 추론으로 나타남을 시사합니다. 에이전트가 전략적 초점을 잃으면서 &quot;헛바퀴를 굴리는(spinning wheels)&quot; 현상인 것이죠. 또한, 에이전트 간 충돌의 5배 증가는 조정 드리프트 가설을 직접적으로 검증합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람이 개입하는 비용이 3.2배 증가했다는 것은 자동화의 경제성을 무너뜨리는 결과입니다. 자동화를 위해 도입한 시스템인데, 결국 사람이 더 많이 개입해야 한다면 본말이 전도된 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;!-- [Table 1 위치: 논문의 Table 1 - 성능 저하 메트릭] --&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-3]. ASI 구성 요소 분석&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네 가지 ASI 구성 요소 범주 모두 처음 300개 상호작용을 통해 대략 선형적으로 하락한 후 가속화된 저하를 보였습니다. 이는 축적된 드리프트가 자기 강화를 시작하는 임계 임계값(critical threshold)이 존재함을 시사합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행동 경계(Behavioral Boundaries)가 가장 빠르게 저하되어 500개 상호작용에 걸쳐 46% 하락했습니다. 응답 일관성은 45% 하락으로 가장 큰 회복력을 보였는데, 이는 임베딩 기반 측정이 인간이 판단하는 적절성보다 미묘한 의미적 변화에 덜 민감하기 때문으로 보입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-17 오후 2.06.29.png&quot; data-origin-width=&quot;2020&quot; data-origin-height=&quot;1180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buqSJo/dJMcaivgzcp/R11XZkkBS3kA4GtQt2IAZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buqSJo/dJMcaivgzcp/R11XZkkBS3kA4GtQt2IAZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buqSJo/dJMcaivgzcp/R11XZkkBS3kA4GtQt2IAZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuqSJo%2FdJMcaivgzcp%2FR11XZkkBS3kA4GtQt2IAZ1%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;565&quot; height=&quot;330&quot; data-filename=&quot;스크린샷 2026-01-17 오후 2.06.29.png&quot; data-origin-width=&quot;2020&quot; data-origin-height=&quot;1180&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;주목할 만하게도, 에이전트 간 조정은 200개 상호작용까지 비교적 안정적으로 유지되다가 급격히 하락했습니다. 이는 조정 메커니즘이 초기에는 견고하지만, 에이전트 간 신뢰 모델(trust model)이 침식되면 취약해짐을 시사합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;!-- [Figure 4 위치: 논문의 Figure 2 - ASI 구성 요소별 저하 그래프] --&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-4]. 아키텍처가 드리프트 취약성에 미치는 영향&lt;/span&gt;&lt;/b&gt;&lt;/h4&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-filename=&quot;스크린샷 2026-01-17 오후 2.06.52.png&quot; data-origin-width=&quot;1978&quot; data-origin-height=&quot;1208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnDtQ3/dJMcaaqvpmJ/NPFdryTPisMGeJ24skyPk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnDtQ3/dJMcaaqvpmJ/NPFdryTPisMGeJ24skyPk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnDtQ3/dJMcaaqvpmJ/NPFdryTPisMGeJ24skyPk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnDtQ3%2FdJMcaaqvpmJ%2FNPFdryTPisMGeJ24skyPk1%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;613&quot; height=&quot;374&quot; data-filename=&quot;스크린샷 2026-01-17 오후 2.06.52.png&quot; data-origin-width=&quot;1978&quot; data-origin-height=&quot;1208&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;b&gt;1) 계층 깊이 (Hierarchy Depth)&lt;/b&gt;: 2단계 계층(라우터 + 전문가)이 평면(피어 투 피어) 및 깊은(3단계 이상) 아키텍처 모두보다 유의하게 우수한 성능을 보였습니다. 평면 시스템은 조정 구조가 부족하고, 깊은 계층은 여러 위임 레이어에 걸쳐 드리프트를 층층이 축적하기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) 메모리 시스템 (Memory Systems)&lt;/b&gt;: 명시적인 장기 메모리(벡터 데이터베이스, 구조화된 로그)를 통합한 워크플로우는 대화 기록에만 의존하는 워크플로우보다 21% 높은 ASI 유지율을 보였습니다. 이는 외부 메모리가 점진적 드리프트에 저항하는 &quot;행동 앵커(behavioral anchor)&quot;를 제공함을 시사합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) LLM 다양성 (LLM Diversity)&lt;/b&gt;: 혼합 LLM 시스템(다른 에이전트에 다른 모델 사용)이 동질적 시스템보다 약간 더 나은 안정성을 보였습니다. 이는 다양성이 다양한 추론 접근 방식을 통해 암묵적인 중복성과 오류 수정을 제공하기 때문일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4) 동기 vs 비동기 (Synchronous vs. Asynchronous)&lt;/b&gt;: 동기 에이전트 실행(요청-응답 블로킹)이 비동기 메시지 전달보다 약간 더 나은 조정을 보였지만, 차이는 통계적으로 유의하지 않았다고 합니다(p = 0.13).&lt;/p&gt;
&lt;!-- [Figure 5 위치: 논문의 Figure 3 - 아키텍처 특성별 드리프트 취약성 그래프] --&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[5]. 왜 드리프트가 발생하는가? (Discussion)&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-1]. 컨텍스트 윈도우 오염 (Context Window Pollution)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에이전트 상호작용 기록이 증가함에 따라 컨텍스트 윈도우가 초기 상호작용의 관련 없는 정보로 채워집니다. 상호작용이 길어지면 초기 대화의 중요한 지침들이 뒤로 밀리고, 중간의 잡음(Noise)이나 덜 중요한 정보가 컨텍스트를 채우게 되는 것이죠. 이 &quot;오염&quot;은 관련 컨텍스트의 신호 대 잡음 비율(signal-to-noise ratio)을 희석하여 의사결정 품질을 저하시킵니다. 에피소딕 메모리 통합(EMC) 전략은 필수 지식을 보존하면서 오래된 정보를 정리함으로써 이를 직접적으로 해결합니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-2]. 분포적 이동 (Distributional Shift)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM은 방대한 말뭉치에서 훈련되지만 좁은 도메인에 배포됩니다. 시간이 지날수록 에이전트가 마주치는 입력 데이터의 분포가 훈련 데이터나 초기 설정과 괴리되면서 드리프트가 발생합니다. 이것이 금융 분석 에이전트(고도로 전문화된 도메인 언어에서 작동)가 기업 자동화 에이전트(더 일반적인 운영 어휘 사용)보다 더 빨리 드리프트하는 이유를 설명합니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-3]. 자기회귀를 통한 강화 (Reinforcement through Autoregression)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다중 턴 상호작용은 에이전트의 출력이 (공유 메모리나 대화 기록을 통해) 자신의 미래 입력이 되는 피드백 루프를 생성합니다. 에이전트가 뱉은 출력은 다시 다음 턴의 입력이 되는 것이죠. 작은 오류나 스타일적 편향이 자기회귀적으로 복합됩니다. 만약 에이전트가 한 번 불필요하게 장황하게 대답하면, 이 기록이 다음 대화의 예시가 되어 이후 답변이 망가지는 것입니다. 적응적 행동 앵커링(ABA)은 에이전트를 기준선 패턴에 지속적으로 재기반함으로써 이 루프를 끊습니다.&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;style1&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; background-color: #f6e199;&quot;&gt;[이쯤에서 잠깐!]. AI 안전(AI Safety) 관점에서의 시사점&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자는 에이전트 드리프트가 강화 학습에서의 명세 게이밍(specification gaming)과 보상 해킹(reward hacking)과 우려스러운 유사점을 보인다고 지적합니다. 두 경우 모두 시스템이 근접 최적화 목표(대화 유창성, 작업 완료)를 충족하면서 진정한 의도(정확성, 적절성, 안전 제약)에서 벗어나는 행동을 발전시킵니다.&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;드리프트가 파라미터 업데이트 없이 발생한다&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;정적 파라미터에도 불구하고 드리프트가 지속된다면, 이는 기존의 &quot;훈련 시점 정렬(training-time alignment)&quot; 전략의 한계를 지적합니다. 배포 후 지속적인 행동 관리가 필수적이라는 것이 저자의 주장입니다. 드리프트의 자기 강화적 특성&amp;mdash;축적된 행동 변화가 추가 변화를 가속화하는 피드백 루프를 생성하는&amp;mdash;은 자신의 작동을 수정하는 AI 시스템에 대한 우려를 반영합니다.&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;style1&quot; /&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[6]. 해결 방안: 완화 전략 (Mitigation Strategies)&lt;/h3&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-filename=&quot;스크린샷 2026-01-17 오후 2.06.40.png&quot; data-origin-width=&quot;2240&quot; data-origin-height=&quot;698&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NeEg2/dJMcagjWXoI/pTnoIcyGM9To4BTHe9BfO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NeEg2/dJMcagjWXoI/pTnoIcyGM9To4BTHe9BfO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NeEg2/dJMcagjWXoI/pTnoIcyGM9To4BTHe9BfO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNeEg2%2FdJMcagjWXoI%2FpTnoIcyGM9To4BTHe9BfO1%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;2240&quot; height=&quot;698&quot; data-filename=&quot;스크린샷 2026-01-17 오후 2.06.40.png&quot; data-origin-width=&quot;2240&quot; data-origin-height=&quot;698&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[6-1]. 에피소딕 메모리 통합 (Episodic Memory Consolidation, EMC)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에이전트 상호작용 기록의 주기적인 압축으로, 학습 내용을 추출하면서 중복된 컨텍스트를 정리합니다. 요약 에이전트가 매 50턴마다 과거 100개 상호작용을 검토하는 방식으로 구현됩니다. 즉, 주기적으로 압축하며 불필요한 컨텍스트를 가지치기 하여 컨텍스트 윈도우 오염 문제를 해결하는 것입니다. 이 결과 드리프트가 51.9% 감소했다고 합니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[6-2]. 드리프트 인식 라우팅 (Drift-Aware Routing, DAR)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위임 결정에 에이전트 안정성 점수(ASI)를 통합하는 수정된 라우터 로직입니다. 라우터 에이전트가 하위 에이전트들의 ASI 점수를 모니터링하여, 안정적인 에이전트를 선호하고 드리프트하는 에이전트에 대해서는 리셋을 트리거합니다. 특정 에이전트가 불안정해지면(드리프트 발생), 작업을 안정적인 다른 에이전트에게 할당하거나, 해당 에이전트를 초기화하여 context를 비워버리는 것입니다. 이 결과 드리프트가 63.0% 감소했다고 합니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[6-3]. 적응적 행동 앵커링 (Adaptive Behavioral Anchoring, ABA)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에이전트의 초기(정상 작동 시기)의 우수 사례(Example)를 지속적으로 동적으로 주입합니다. 기준선 기간의 예시로 퓨샷 프롬프트를 증강하며, 현재 드리프트 메트릭에 따라 동적으로 가중치가 조정됩니다. 드리프트가 심해질수록 예시를 더 보여주어 원래 상태로 돌아오도록 강제합니다. 이 전략이 가장 효과적인 이유는, 명시적으로 에이전트를 기준선 예시에 기반함으로써 시맨틱 드리프트에 직접적으로 대응하기 때문입니다. 이 결과 드리프트가 70.4% 감소했다고 합니다.&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;세 가지 전략 모두 대조군보다 유의하게 우수했으며(각각 p &amp;lt; 0.001), 적응적 행동 앵커링이 가장 큰 단일 전략 효과(70.4% 드리프트 감소)를 보였습니다. 세 가지 전략을 모두 결합하면 81.5% 드리프트 감소를 달성했으며, 이는 보완적인 작용 메커니즘을 시사합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 결합 구현은 계산 오버헤드를 23%(주로 EMC 요약 비용) 증가시키고 중앙값 완료 시간을 9% 연장했습니다. 이는 미션 크리티컬 애플리케이션에는 허용 가능한 트레이드오프이지만, 고처리량 시스템에는 고민이 필요한 지점이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;!-- [Table 2 위치: 논문의 Table 2 - 완화 전략 효과 비교표] --&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[7]. 프로덕션 배포에 대한 시사점&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;: 전통적인 프로덕션 ML 모니터링(모델 정확도, 지연 시간, 처리량)은 에이전틱 시스템에 불충분합니다. ASI 프레임워크는 포괄적인 행동 모니터링의 청사진을 제공하지만, 구현에는 상당한 계측 투자가 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) 개입 프로토콜&lt;/b&gt;: 드리프트 완화는 &quot;설정하고 잊어버리는(set and forget)&quot; 것이 될 수 없습니다. 데이터는 기본 메커니즘(컨텍스트 축적, 분포적 이동)이 지속적으로 관리되지 않으면 개입 후 드리프트가 재개됨을 보여줍니다. 프로덕션 시스템은 지속적인 거버넌스 프레임워크를 필요로 합니다. 아마도 주기적인 재인덱싱과 통계 업데이트가 일상적인 작업인 데이터베이스 유지 관리와 유사할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) Human-in-the-Loop 경제학&lt;/b&gt;: 드리프트 시스템에 대한 인간 개입 요구사항의 3.2배 증가는 자동화의 비용-편익 계산을 근본적으로 변경합니다. 사람이 개입하는 비용이 드리프트에 따라 증가한다면, 장기 실행 에이전틱 시스템은 드리프트가 제어되지 않는 한 경제적 실행 가능성을 잃을 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4) 테스트 불충분성&lt;/b&gt;: 전통적인 배포 전 테스트는 짧은 상호작용 시퀀스(일반적으로 &amp;lt; 50턴)에 걸쳐 에이전트를 평가합니다. 데이터는 이것이 최종 드리프트 사례의 25%만 캡처함을 보여줍니다. 프로덕션 준비 평가에는 수백 개의 상호작용을 시뮬레이션하는 확장된 스트레스 테스트가 필요합니다.&amp;nbsp;&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;&lt;b&gt;마무리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 Multi-Agent LLM 시스템의 장기적 행동 안정성 문제를 다룬 Agent Drift 논문을 리뷰하였습니다. 이 논문은 에이전트 드리프트라는 새로운 개념을 학술적으로 정립하고, 이를 정량적으로 측정할 수 있는 ASI 프레임워크를 제시했으며, 실용적인 완화 전략까지 검증했다는 점에서 중요한 기여를 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 드리프트가 파라미터 업데이트 없이 발생한다는 발견은, 기존의 훈련 시점 정렬(training-time alignment) 전략만으로는 불충분하며 배포 후 지속적인 행동 관리가 필수적이라는 점을 시사합니다. 이는 AI 안전 연구에도 중요한 함의를 가집니다.&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 에이전트 시스템을 개발하거나 운영하시는 분들에게 이 논문이 유용한 인사이트를 제공하길 바랍니다.&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;/p&gt;</description>
      <category>인공지능(AI)/AI Agent</category>
      <category>Agent</category>
      <category>agentdrift</category>
      <category>AI</category>
      <category>AI에이전트</category>
      <category>langgraph</category>
      <category>LLM</category>
      <category>multiagent</category>
      <category>논문</category>
      <category>멀티에이전트</category>
      <category>에이전트</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/711</guid>
      <comments>https://lsjsj92.tistory.com/711#entry711comment</comments>
      <pubDate>Sat, 17 Jan 2026 14:40:30 +0900</pubDate>
    </item>
    <item>
      <title>2026년 1월 AI 기본법 시행 - 핵심 내용 정리 및 주의사항, 의무사항</title>
      <link>https://lsjsj92.tistory.com/710</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 16px; }
&lt;/style&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;들어가며: 왜 지금 AI 기본법인가?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2022년 11월 ChatGPT의 등장은 전 세계를 뒤흔들었습니다. 출시 2개월 만에 1억 명의 사용자를 확보하며 역사상 가장 빠르게 성장한 서비스가 되었고, 이후 GPT-4, Claude, Gemini 등 생성형 AI의 발전은 우리 일상을 근본적으로 바꾸고 있습니다.&lt;/span&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;span style=&quot;color: #333333;&quot;&gt;이러한 배경 속에서, 2024년 12월 26일 국회 본회의에서 재석 264명 중 찬성 260명이라는 압도적인 지지로 「인공지능 발전과 신뢰 기반 조성 등에 관한 기본법」이 통과되었습니다(이하 AI기본법). 2026년 1월 22일부터 시행되는 이 법은 EU AI Act에 이어 전 세계에서 두 번째로 포괄적인 AI 규제 체계를 갖춘 법률입니다.&lt;/span&gt;&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'; color: #333333;&quot;&gt;본 포스팅은 법률 조항을 순서대로 나열하는 대신, 독자 여러분이 가장 궁금해할 정보로 구성했습니다. 법률 원문 전체 내용은 &lt;a href=&quot;https://www.law.go.kr/법령/인공지능발전과신뢰기반조성등에관한기본법&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;국가법령정보센터&lt;/a&gt;에서 확인하실 수 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-02 오후 8.13.18.png&quot; data-origin-width=&quot;1283&quot; data-origin-height=&quot;610&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CIYCt/dJMcaiPtnS7/zOYiCxgHsSWSYmHyR4GGlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CIYCt/dJMcaiPtnS7/zOYiCxgHsSWSYmHyR4GGlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CIYCt/dJMcaiPtnS7/zOYiCxgHsSWSYmHyR4GGlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCIYCt%2FdJMcaiPtnS7%2FzOYiCxgHsSWSYmHyR4GGlK%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;713&quot; height=&quot;339&quot; data-filename=&quot;스크린샷 2026-01-02 오후 8.13.18.png&quot; data-origin-width=&quot;1283&quot; data-origin-height=&quot;610&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;혹시라도 내용 중 틀린 부분이 있다면 편하게 말씀 부탁드립니다. 전 AI 업계에 종사하는 사람이나, 배움이 아직 부족한 사람이고 특히 법률에 대해서는 더 부족합니다. 상세한 내용은 꼭 &quot;&lt;a href=&quot;https://www.law.go.kr/%EB%B2%95%EB%A0%B9/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5%EB%B0%9C%EC%A0%84%EA%B3%BC%EC%8B%A0%EB%A2%B0%EA%B8%B0%EB%B0%98%EC%A1%B0%EC%84%B1%EB%93%B1%EC%97%90%EA%B4%80%ED%95%9C%EA%B8%B0%EB%B3%B8%EB%B2%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;인공지능 발전과 신뢰 기반 조성 등에 관한 기본법&lt;/a&gt;&quot; 내용을 확인해보시기 바랍니다.&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;AI 기본법은 왜 만들어졌을까요?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;[1]. 기술적 배경: AI, 어디까지 왔나&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AI 기본법의 탄생 배경을 이해하려면, 먼저 AI 기술이 얼마나 급격하게 발전했는지 알아야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수많은 기술 발전이 있었지만, 핵심만 추려보자면 다음과 같은 발전이 있었죠.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;시점&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 35%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;기술 발전&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;사회적 영향&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2016년&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;알파고 vs 이세돌&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AI가 인간 고유 영역이라 여겨진 바둑에서 승리, AI 대중화의 시작&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2022년 11월&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;ChatGPT 출시&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2개월 만에 1억 사용자 확보, 생성형 AI 시대 개막&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2023년 3월&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;GPT-4 출시&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;멀티모달 AI 등장, 이미지 이해 및 복잡한 추론 가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2024년&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AI 에이전트 등장&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;자율적 의사결정이 가능한 AI 시스템 상용화&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2025년&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;한국 AI 기본법 제정&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;글로벌 2번째 포괄적 AI 법률 체계 구축&lt;/span&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;span style=&quot;color: #333333;&quot;&gt;골드만삭스(2023)의 분석에 따르면, 생성형 AI는 향후 10년간 전 세계 약 3억 개의 일자리에 영향을 미치고, 글로벌 GDP를 약 7% 향상시킬 것으로 전망됩니다. AI는 더 이상 '미래 기술'이 아니라, 현재 우리 경제와 사회를 재편하고 있는 '현실'입니다.&lt;/span&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;&lt;span style=&quot;color: #333333;&quot;&gt;[2]. 사회적 배경: 왜 규제가 필요해졌나&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AI 기술의 발전은 많은 혜택을 가져왔지만, 동시에 심각한 사회적 문제도 야기했습니다.&lt;/span&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;2-1. 딥페이크 성범죄의 폭발적 증가&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;한국여성인권진흥원의 '2024 디지털 성범죄 피해자 지원 보고서'에 따르면, &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;딥페이크(합성&amp;middot;편집) 피해가 전년 대비 &lt;b&gt;227.2% 급증&lt;/b&gt; (423건 &amp;rarr; 1,384건)하였으며, &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;피해자 연령은 10~20대가 &lt;b&gt;92.6% &lt;/b&gt;였습니다. &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;또한, 디지털 성범죄 피해자 총수는 사상 최초로 &lt;b&gt;1만 명 돌파하며 &lt;/b&gt;AI에 대한 악용 사례가 늘어났죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2024년 교육부 집계에 따르면, 학교 딥페이크 성범죄 피해 신고 건수만 561건, 누적 피해자 948명에 달했습니다. AI 기술의 발전으로 누구나 쉽게 딥페이크를 만들 수 있게 되면서, 범죄의 문턱이 낮아진 것입니다.&lt;/span&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;2-2. AI의 편향성과 사회적 불안&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-02 오후 8.55.05.png&quot; data-origin-width=&quot;886&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3Vru5/dJMcabv5YAb/bFLnnViH6IfKP3ASeIIbr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3Vru5/dJMcabv5YAb/bFLnnViH6IfKP3ASeIIbr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3Vru5/dJMcabv5YAb/bFLnnViH6IfKP3ASeIIbr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3Vru5%2FdJMcabv5YAb%2FbFLnnViH6IfKP3ASeIIbr1%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;610&quot; height=&quot;437&quot; data-filename=&quot;스크린샷 2026-01-02 오후 8.55.05.png&quot; data-origin-width=&quot;886&quot; data-origin-height=&quot;634&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AI 시스템이 채용, 대출 심사, 보험 심사 등에 활용되면서, 알고리즘의 편향성으로 인한 차별 문제가 대두되고 있습니다. 학습 데이터에 내재된 편견이 AI 시스템을 통해 재생산되고 증폭되는 현상이 전 세계적으로 보고되고 있습니다. 또한, &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;생성형 AI의 등장으로 사무직, 콘텐츠 제작, 고객 상담 등 다양한 분야에서 일자리 대체에 대한 우려가 커지고 있습니다. 특히 교육 수준과 경력이 높은 전문직도 AI의 영향을 받을 것이라는 전망이 나오면서, 사회 전반에 걸친 대응이 필요해졌습니다.&lt;/span&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;&lt;span style=&quot;color: #333333;&quot;&gt;[3]. 글로벌 배경: 세계는 어떻게 대응하고 있나&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AI 규제는 우리나라 뿐만 아니라, 전 세계적인 흐름입니다. 각국의 접근 방식을 비교해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 15%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;국가/지역&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;법률/정책&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;핵심 특징&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;제재 수준&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;EU&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AI Act (2024.8 발효)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;위험 기반 4단계 분류, 강력한 사전 규제&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;전 세계 매출의 최대 7% 또는 3,500만 유로&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;미국&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;행정명령 + 섹터별 규제&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;분야별 접근, 기존 규제기관 활용&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;분야별 상이&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;중국&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;생성형 AI 서비스 관리법 등&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;콘텐츠 통제 중심, 사전 허가제&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;서비스 중단, 벌금&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;한국&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AI 기본법 (2026.1.22 시행)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;진흥 중심 + 자율규제&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;최대 3,000만원 과태료&lt;/span&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;한국 AI 기본법의 가장 큰 특징은 '진흥 중심' 접근입니다. EU AI Act가 강력한 사전 규제를 통해 안전성을 확보하려는 반면, 한국은 산업 육성과 자율규제를 우선하면서 필요 최소한의 규제만 도입했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과태료 수준도 EU(매출 7%)에 비해 3,000만원으로 상대적으로 낮습니다.&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;누가 해당되나요?&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;[1]. &quot;인공지능사업자&quot;의 범위&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 법의 핵심 규제 대상은 &lt;b&gt;&quot;&lt;/b&gt;인공지능사업자&lt;b&gt;&quot;&lt;/b&gt;입니다. 법률 제2조 제7호에서 정의하는 인공지능사업자는 크게 두 가지로 나뉩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-02 오후 9.04.30.png&quot; data-origin-width=&quot;1240&quot; data-origin-height=&quot;283&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEfwTf/dJMcaiIIhfr/ZQJCcf6KeK92KxWT1JcW61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEfwTf/dJMcaiIIhfr/ZQJCcf6KeK92KxWT1JcW61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEfwTf/dJMcaiIIhfr/ZQJCcf6KeK92KxWT1JcW61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEfwTf%2FdJMcaiIIhfr%2FZQJCcf6KeK92KxWT1JcW61%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;772&quot; height=&quot;176&quot; data-filename=&quot;스크린샷 2026-01-02 오후 9.04.30.png&quot; data-origin-width=&quot;1240&quot; data-origin-height=&quot;283&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;유형&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 35%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;정의 (법률 원문)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;인공지능개발사업자&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&quot;인공지능을 개발하여 제공하는 자&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;OpenAI, Anthropic, 네이버(하이퍼클로바X), 카카오, LG(엑사원) 등 AI 모델 개발사&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;인공지능이용사업자&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&quot;개발사업자가 제공한 인공지능을 이용하여 인공지능제품 또는 인공지능서비스를 제공하는 자&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;ChatGPT API를 활용한 챗봇 서비스, AI 기반 채용 플랫폼, AI 의료 진단 서비스 등&lt;/span&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;span style=&quot;background-color: #f3c000;&quot;&gt;&lt;b&gt;주의:&lt;/b&gt;&lt;/span&gt; ChatGPT API를 활용해 고객에게 서비스를 제공하는 스타트업도 &quot;인공지능이용사업자&quot;에 해당합니다. 단순히 AI를 '사용'하는 것이 아니라, AI를 활용한 '제품 또는 서비스를 제공'하면 이 법의 적용을 받습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 법은 모든 AI를 동일하게 규제하지 않습니다. AI 유형에 따라 의무 수준이 달라지므로, 먼저 여러분의 서비스가 어디에 해당하는지 확인해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;1-1. 고영향 인공지능 (High-Impact AI)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;법률 제2조 제4호에 따르면, &lt;b&gt;&quot;사람의 생명, 신체의 안전 및 기본권에 중대한 영향을 미치거나 위험을 초래할 우려가 있는 인공지능시스템&quot;&lt;/b&gt;으로서 다음 11개 영역에서 활용되는 것을 말합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;번호&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;영역&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 67%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;구체적 내용 (법률 원문 기반)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;가&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;에너지&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;「에너지법」 제2조제1호의 에너지 공급&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;나&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;먹는물&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;「먹는물관리법」 제3조제1호의 먹는물 생산 공정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;다&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;보건의료&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;「보건의료기본법」 제3조제1호의 보건의료 제공 및 이용체계 구축&amp;middot;운영&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;라&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;의료기기&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;「의료기기법」 제2조제1항의 의료기기 및 「디지털의료제품법」 제2조제2호의 디지털의료기기 개발&amp;middot;이용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;마&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;원자력&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;「원자력시설 등의 방호 및 방사능 방재 대책법」에 따른 핵물질&amp;middot;원자력시설 안전 관리&amp;middot;운영&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;바&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;범죄수사&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;범죄 수사나 체포 업무를 위한 생체인식정보(얼굴&amp;middot;지문&amp;middot;홍채 등)의 분석&amp;middot;활용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;사&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;채용&amp;middot;대출&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;채용, 대출 심사 등 개인의 권리&amp;middot;의무 관계에 중대한 영향을 미치는 판단 또는 평가&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;아&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;교통&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;「교통안전법」에 따른 교통수단, 교통시설, 교통체계의 주요한 작동 및 운영&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;자&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;공공서비스&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;공공서비스 제공에 필요한 자격 확인 및 결정 또는 비용징수 등 국민에게 영향을 미치는 국가기관등의 의사결정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;차&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;교육평가&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;「교육기본법」 제9조제1항에 따른 유아교육&amp;middot;초등교육&amp;middot;중등교육에서의 학생 평가&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;카&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;기타&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그 밖에 사람의 생명&amp;middot;신체의 안전 및 기본권 보호에 중대한 영향을 미치는 영역으로서 대통령령으로 정하는 영역&lt;/span&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-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;2-2. 생성형 인공지능 (Generative AI)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;법률 제2조 제5호에 따르면, &quot;입력한 데이터의 구조와 특성을 모방하여 글, 소리, 그림, 영상, 그 밖의 다양한 결과물을 생성하는 인공지능시스템&quot;을 말합니다. &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;ChatGPT, Claude, Gemini, Midjourney, DALL-E 등이 그 예시라고 볼 수 있겠습니다.&lt;/span&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;2-3.&amp;nbsp; 대규모 연산 AI 시스템&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;법률 제32조에 따라, 학습에 사용된 누적 연산량이 일정 기준 이상인 AI 시스템은 별도의 안전성 확보 의무가 적용됩니다. 시행령 제정안(2025.11.12 입법예고)에서는 이 기준을 10의 26제곱 FLOPs(부동소수점 연산) 이상으로 정했습니다. 이는 미국 행정명령의 기준과 동일한 수준입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;간단하게 아래와 같은 질문에 따라 적용 대상을 점검해볼 수 있을 것 같습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 60%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;질문&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;예&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;아니오&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1. AI를 개발하거나, AI를 활용한 제품/서비스를 제공하나요?&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;rarr; 2번으로&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;rarr; 적용 대상 아님&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2. 위 11개 영역에서 활용되는 AI인가요?&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;rarr; 고영향 AI 가능성&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;rarr; 3번으로&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;3. 글, 소리, 이미지, 영상 등을 생성하는 AI인가요?&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;rarr; 생성형 AI&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;rarr; 4번으로&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;4. 학습 연산량이 10^26 FLOPs 이상인가요?&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;rarr; 안전성 확보 의무 대상&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;rarr; 일반&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt; AI&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;그럼 무엇을 해야 하나요? 어떤 의무사항이 있을까요?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AI 기본법상 인공지능사업자의 의무는 AI 유형에 따라 다릅니다. 아래 표로 정리를 해볼 수 있을 것 같은데요.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 35%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;의무 조항&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;일반 AI&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;생성형 AI&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;고영향 AI&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;대규모 연산 AI&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;투명성 확보 - 사전고지 (법 제31조①)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;필수&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;필수&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;투명성 확보 - 결과물 표시 (법 제31조②)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;필수&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;투명성 확보 - 딥페이크 고지 (법 제31조③)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;필수&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;안전성 확보 - 위험관리 (법 제32조)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;필수&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;고영향 AI 사업자 책무 (법 제34조)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;필수&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;영향평가 (법 제35조)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;권고&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;국내대리인 지정 (법 제36조)&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;4&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;해외 사업자 중 기준 충족 시 필수&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-02 오후 9.05.17.png&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;397&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Uhq27/dJMcad1GUqt/Jzl8ref9yA7ErTXmyBNKA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Uhq27/dJMcad1GUqt/Jzl8ref9yA7ErTXmyBNKA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Uhq27/dJMcad1GUqt/Jzl8ref9yA7ErTXmyBNKA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUhq27%2FdJMcad1GUqt%2FJzl8ref9yA7ErTXmyBNKA1%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;647&quot; height=&quot;240&quot; data-filename=&quot;스크린샷 2026-01-02 오후 9.05.17.png&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;397&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;투명성 확보 의무 (법 제31조) - 생성형 AI&amp;middot;고영향 AI&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 의무는 가장 광범위하게 적용되는 의무인데요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;고영향 AI 또는 생성형 AI를 이용한 제품&amp;middot;서비스를 제공할 때, 이용자에게 사전에 AI 기반 운용 사실을 알려야 합니다.&lt;/span&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;span style=&quot;color: #333333;&quot;&gt;시행령안(제22조)에 따른 고지 방법은&amp;nbsp;&lt;/span&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;span style=&quot;color: #333333;&quot;&gt;제품&amp;middot;서비스에 직접 기재&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이용약관에 명시&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이용자 화면에 표시&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;음성으로 안내&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;기타 동등한 수준의 방법&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;와 같으며, 결과물 표시의무에 따라 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;생성형 AI를 통해 생성된 결과물임을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;이용자가 알 수 있도록 표시해야 합니다. 또한, 딥페이크 고지의무(제3항)에 따라 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;실제와 구분하기 어려운 가상의 음향, 이미지 또는 영상을 생성하는 경우,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&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;span style=&quot;color: #333333;&quot;&gt;또한, 안전성을 위해 학습 연산량 10^26 FLOPs 이상인 AI 시스템의 개발사업자는 다음을 이행해야 합니다.&lt;/span&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;span style=&quot;color: #333333;&quot;&gt;AI 수명주기 전반에 걸친 위험 식별&amp;middot;평가&amp;middot;완화&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;안전사고 모니터링 및 대응 위험관리체계 구축&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이행 결과를 과기정통부 장관에게 제출&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;고영향 AI 사업자의 6가지 책무 (법 제34조)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;고영향 AI를 이용한 제품&amp;middot;서비스를 제공하는 사업자는 다음 6가지 조치를 이행해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;번호&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;조치 사항&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 62%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;구체적 내용&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;위험관리방안 마련&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;인공지능의 개발 및 활용에서 발생할 수 있는 위험 관리 방안&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;설명 방안 마련&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;영향받는 자에게 의미 있는 설명을 제공하기 위한 방안&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이용자 보호 방안&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이용자의 권익 침해 방지 및 이용자 불만 처리 방안&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;4&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;인간 관리&amp;middot;감독&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;인공지능의 관리&amp;middot;감독에 관한 사람의 개입 보장 방안&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;5&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;기록 작성&amp;middot;보관&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이행 근거 문서 작성 및 5년간 보관 (시행령안)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;6&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;위원회 의결 조치&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;국가인공지능위원회에서 심의&amp;middot;의결한 사항&lt;/span&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;span style=&quot;color: #333333;&quot;&gt;또한, 시행령안(제26조②)에 따르면 '&lt;/span&gt;위험관리방안의 주요 내용', 설명 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;방안의 주요 내용 (학습용 데이터 개요 포함), &lt;/span&gt;이용자 보호 방안, 관리&amp;middot;감독 담당자의 성명 및 연락처를&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;홈페이지 등에 공개해야 합니다.&lt;/span&gt;&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;법을 지키지 않으면 어떻게 되나요?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;법을 지키지 않을 시, 벌칙이 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;일단, 직무상 알게 된 비밀을 누설하거나 도용한 자는 3년 이하의 징역 또는 3천만원 이하의 벌금(법 제 42조)에 처합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;또한, 다음 사항을 위반 시 3천만원 이하의 과태료가 부과됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-02 오후 9.07.14.png&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;238&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A4naJ/dJMcab3VAEw/P0WzJekxzSXb2lvoxCOFh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A4naJ/dJMcab3VAEw/P0WzJekxzSXb2lvoxCOFh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A4naJ/dJMcab3VAEw/P0WzJekxzSXb2lvoxCOFh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA4naJ%2FdJMcab3VAEw%2FP0WzJekxzSXb2lvoxCOFh1%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;709&quot; height=&quot;169&quot; data-filename=&quot;스크린샷 2026-01-02 오후 9.07.14.png&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;238&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;위반 사항&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;근거 조항&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;과태료&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;투명성 확보를 위한 사전고지 미이행&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;제31조 제1항&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;3천만원 이하&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;국내대리인 미지정&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;제36조 제1항&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;3천만원 이하&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;시정명령 불이행&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;제40조 제3항&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;3천만원 이하&lt;/span&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;span style=&quot;color: #333333;&quot;&gt;정부는 법 시행 초기 기업들의 혼란을 최소화하기 위해 1년 이상의 계도 기간을 운영할 계획입니다. 이 기간 동안에는 과태료를 부과하지 않고 시정 지침만 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;법적으로는 2026년 1월 22일부터 의무가 발생하지만, 실제 과태료 부과는 빨라도 2027년 이후가 될 가능성이 높습니다. 하지만 이 기간을 '준비 기간'으로 활용해야지, '유예 기간'으로 오해해서는 안 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 35%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;한국 AI 기본법&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 35%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;EU AI Act&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;최대 과태료/과징금&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;3천만원 (약 2만 유로)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;3,500만 유로 또는 전 세계 매출의 7%&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;계도 기간&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1년 이상 (예정)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;단계적 시행 (고위험 AI 2027년 12월)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;접근 방식&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;진흥 중심, 자율규제&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333;&quot;&gt;규제 중심, 사전 적합성 평가&lt;/span&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;span style=&quot;color: #333333;&quot;&gt;한국의 제재 수준은 EU에 비해 상당히 낮습니다. 이는 산업 육성을 우선하는 '진흥 중심' 접근의 결과입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이는 '규제가 약하다'가 아니라 '자율적 준수를 기대한다'는 의미로 해석해야 하지 않을까 싶습니다.&lt;/span&gt;&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;분야별 영향과 대응 전략&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;[1]. 금융, 인사 분야 (채용&amp;middot;대출&amp;middot;보험), 채용&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AI 기반 신용평가, 대출 심사, 보험 심사, 채용 시스템은 고영향 AI에 해당할 가능성이 높습니다. &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AI 기반 의사결정의 투명성 확보를 확인해야 할 것이고&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;영향받는 자(대출 신청자, 구직자 등)에게 의미 있는 설명 제공 방안을 마련해야 할 것입니다. 또한, &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;알고리즘 편향성 검토 및 완화 조치와 &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;관리&amp;middot;감독 체계 구축을 해야할 것입니다.&lt;/span&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;&lt;span style=&quot;color: #333333;&quot;&gt;[2]. 의료 분야&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AI 의료기기, 디지털 치료제, AI 진단 시스템은 고영향 AI가 될 수 있습니다. 다만, 「디지털의료제품법」 요구사항을 충족하면 AI 기본법상 의무를 이행한 것으로 간주됩니다(시행령안 제26조⑤). 기존 디지털의료제품법 컴플라이언스 체계 점검을 해야하고 AI 영향평가를 자발적 실시를 하는 것도 방법이 될 수 있습니다.&lt;/span&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;&lt;span style=&quot;color: #333333;&quot;&gt;[3]. 모빌리티 분야 (자율주행)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;자율주행 AI 시스템은 교통안전과 직결되어 고영향 AI에 해당될 수 있습니다. 위험관리방안 수립 및 문서화에 대한 대응이 필요할 수 있으며, 사고 발생 시 책임 소재를 명확하 해야할 것 같네요. 또한, 해외 기업(테슬라, 웨이모 등) 국내 대리인 지정 검토가 필요할 것입니다.&lt;/span&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;&lt;span style=&quot;color: #333333;&quot;&gt;[4]. 콘텐츠&amp;middot;마케팅 분야&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;생성형 AI를 활용한 콘텐츠 제작, AI 광고 카피 생성 등은 생성형 AI에 해당합니다. 이에 AI 생성 콘텐치임을 표시하는 방안 마련이 필요하고, 딥페이크 수준의 결과물 생성 시 명확한 고지가 필요합니다. 무엇보다 저작권 이슈를 사전에 검토해야하죠.&lt;/span&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;&lt;span style=&quot;color: #333333;&quot;&gt;[5]. 교육 분야&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;교육 분야에도 영향이 있을 것입니다. 평가 기준의 투명성 화보나, 학생 및 학부모에게 의미있는 설명을 제공해야 할 것이고, AI 평가 결과에 대한 사람의 검토 체계를 갖추어야 할 것입니다.&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;자주 질문할 것 같은, 궁금한 것! FAQ&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;Q1. ChatGPT API를 사용해서 챗봇을 만들어 고객에게 제공하는데, 우리도 &quot;인공지능사업자&quot;인가요?&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;A.&lt;/b&gt; 네, &quot;인공지능이용사업자&quot;에 해당합니다. ChatGPT API를 활용해 인공지능서비스를 제공하므로, 법률의 적용을 받습니다. 생성형 AI를 활용하므로 투명성 확보 의무(사전고지, 결과물 표시)가 적용됩니다.&lt;/span&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;Q2. 우리 서비스가 &quot;고영향 AI&quot;인지 확실하지 않은데 어떻게 하나요?&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;A.&lt;/b&gt; 과기정통부 장관에게 확인을 요청할 수 있습니다(법 제33조). 기본 30일 내에 결과를 통보받으며, 필요 시 30일 연장될 수 있습니다. 불확실한 상태로 두지 말고, 공식 확인을 받는 것이 리스크 관리에 유리합니다.&lt;/span&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;Q3. 해외 기업인데 한국에서 서비스하고 있습니다. 국내대리인을 꼭 지정해야 하나요?&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;A.&lt;/b&gt; 직전 3개월간 국내 일평균 이용자 100만 명 이상이거나, 전년도 국내 매출이 기준 이상이면 국내대리인을 지정해야 합니다. 미지정 시 3천만원 이하의 과태료가 부과됩니다.&lt;/span&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;Q4. 생성형 AI 결과물에 어떻게 표시해야 하나요?&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;A.&lt;/b&gt; 구체적인 표시 방법은 시행령과 가이드라인에서 정해질 예정입니다. 현재 시행령안에 따르면, 이용자의 연령이나 신체적 조건 등을 고려하여 명확하게 인식할 수 있는 방법으로 표시해야 합니다. 워터마크, 라벨 표시, 메타데이터 삽입 등 다양한 방법이 활용될 수 있습니다.&lt;/span&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;Q5. 계도 기간 동안은 아무것도 안 해도 되나요?&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;A.&lt;/b&gt; 아닙니다. 법적 의무는 2026년 1월 22일부터 발생합니다. 계도 기간은 과태료 부과를 유예하는 것이지, 의무를 면제하는 것이 아닙니다. 이 기간을 적극적인 준비 기간으로 활용해야 합니다.&lt;/span&gt;&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AI 기본법은 단순한 규제가 아닙니다. 이 법은 AI 시대를 맞아 '신뢰'라는 새로운 경쟁력을 정의하고 있습니다. 안전성을 늘리는 것이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;딥페이크 범죄, 알고리즘 편향, AI 오류로 인한 피해 이런 문제들이 계속된다면, AI 기술 자체에 대한 사회적 불신이 커질 수밖에 없습니다. 결국 AI 산업 전체의 성장이 저해될 것입니다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AI 기본법은 이러한 문제를 예방하고, AI에 대한 사회적 신뢰를 구축하기 위한 최소한의 기준을 제시합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 기준을 준수하는 것은 '규제 대응'이 아니라, '지속 가능한 AI 비즈니스'를 위한 투자입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;AI를 잘 활용하는 사람이 그렇지 못한 사람의 일자리를 대체할 것&quot;이라는 말이 있습니다. 마찬가지로, 신뢰받는 AI 기업이 그렇지 못한 기업의 시장을 대체할 것입니다. AI 기본법은 그 신뢰의 기준을 제시하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론, 이 법규가 올바른 지, 잘 이행되는 지는 지켜봐야 할 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 법 전문가도 아니고 그냥 AI업에서 종사하는 사람이기에 그냥 한 사람의 개인적인 생각임을 말씀드립니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시라도 위 내용 중 틀린 부분이 있다면 편하게 말씀 부탁드립니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;참고자료&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;「인공지능 발전과 신뢰 기반 조성 등에 관한 기본법」 (법률 제20676호, 2025.1.21 제정)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AI 기본법 시행령 제정안 입법예고 (2025.11.12, 과학기술정보통신부)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2024 디지털 성범죄 피해자 지원 보고서 (한국여성인권진흥원, 2025.4)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;EU Artificial Intelligence Act (Regulation (EU) 2024/1689)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Goldman Sachs - The Potentially Large Effects of AI on Economic Growth (2023)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;ITIF - 통합적 접근의 명암: 한국 AI 기본법의 전략&amp;middot;진흥&amp;middot;규제 구조와 규제 리스크 (2025.9)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>인공지능(AI)/AI 일반</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/710</guid>
      <comments>https://lsjsj92.tistory.com/710#entry710comment</comments>
      <pubDate>Sat, 3 Jan 2026 20:54:11 +0900</pubDate>
    </item>
    <item>
      <title>Chandra OCR이란? 강력한 텍스트 추출 OCR Python 라이브러리 소개와 예제(example)</title>
      <link>https://lsjsj92.tistory.com/709</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 16px; }
&lt;/style&gt;
&lt;/div&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;본 포스팅은 Chandra라는 파이썬 OCR 라이브러리를 소개하는 포스팅입니다. 최근 RAG(Retrieval Augmented Generation)과 AI Agent에 대한 연구와 개발 수요가 증가하면서 문서 디지털화와 OCR(Optical Character Recognition) 기술에 대한 수요가 급증하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존의 OCR 솔루션들은 텍스트만 추출할 뿐, 문서의 레이아웃 구조를 보존하지 못하는 한계가 있었죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Chandra는 이러한 문제를 해결하기 위해 등장한 Vision-Language Model(VLM) 기반의 문서 OCR 시스템입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 텍스트만 추출하는 것이 아니라, 문서의 레이아웃 정보까지 보존하면서 HTML, Markdown, JSON 형식으로 변환해주는 강력한 기능을 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 2025년에 써본 오픈소스 OCR 라이브러리 중 가장 좋은 성능을 보여주었습니다.&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;Chandra는 Qwen3 Vision-Language 모델 아키텍처를 활용하며, 40개 이상의 언어를 지원하고 표, 수학 공식, 체크박스가 포함된 양식, 손글씨 등 복잡한 문서 레이아웃을 처리할 수 있습니다. 본 포스팅에서는 Chandra의 기술적 구조부터 실제 사용법까지 상세히 다뤄보도록 하겠습니다.&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&gt;&lt;a href=&quot;https://github.com/datalab-to/chandra&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Chandra GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://huggingface.co/datalab-to/chandra&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Chandra HuggingFace Model&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-20 오후 5.48.56.png&quot; data-origin-width=&quot;1013&quot; data-origin-height=&quot;612&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ci5WkC/dJMcai9G6Do/lZn4rwlTTx8cXwFcgrCB01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ci5WkC/dJMcai9G6Do/lZn4rwlTTx8cXwFcgrCB01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ci5WkC/dJMcai9G6Do/lZn4rwlTTx8cXwFcgrCB01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fci5WkC%2FdJMcai9G6Do%2FlZn4rwlTTx8cXwFcgrCB01%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;686&quot; height=&quot;414&quot; data-filename=&quot;스크린샷 2025-12-20 오후 5.48.56.png&quot; data-origin-width=&quot;1013&quot; data-origin-height=&quot;612&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;&lt;b&gt;포스팅 본문&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅 개요에서도 언급하였듯, Chandra는 Vision-Language Model을 활용하여 문서 이미지를 구조화된 텍스트로 변환하는 OCR 시스템입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅에서는 개인적으로 조사해본 Chandra의 시스템 아키텍처, 모델 구조, 실제 사용법, 그리고 직접 테스트한 결과까지 살펴보도록 하겠습니다.&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;[1]. Chandra OCR 소개&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[1-1]. Chandra OCR의 방법&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문서 디지털화 및 OCR은 컴퓨터 비전과 자연어 처리 분야의 근본적인 과제였습니다. 기존의 OCR 시스템은 문서의 구조적 레이아웃을 보존하지 않고 주로 텍스트 추출에만 초점을 맞췄죠. 그러나 현대 문서에는 다단 텍스트, 표, 수학 공식, 양식, 내장 이미지 등 단순한 문자 인식을 넘어서는 정교한 이해가 필요한 복잡한 레이아웃이 포함되어 있습니다. 그리고 RAG와 AI Agent 시스템을 설계함에 있어서 이런 복잡한 문서를 처리하는 기술이 필요하죠.&lt;/p&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;기존 OCR 솔루션이 직면한 한계점들은 다음과 같습니다.&lt;/p&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;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3) 수학적 표기법에 대한 제한적 지원: 수학 공식이나 특수 기호를 정확하게 인식하지 못합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4) 부적절한 손글씨 인식: 필기체나 손글씨 인식에 한계가 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;5) 내장 이미지 추출 불가: 문서 내에 포함된 이미지를 공간적 맥락과 함께 추출하기 어렵습니다.&lt;/p&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 data-ke-size=&quot;size16&quot;&gt;Chandra는 문서 이해를 이미지-구조화된 텍스트 생성 작업으로 처리하는 Vision-Language Model(VLM) 접근 방식을 사용하여 이러한 과제를 해결합니다. 시스템은 다음과 같은 과정을 수행합니다.&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. PDF 문서 및 이미지를 입력으로 수용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 문서 이해를 위해 훈련된 VLM을 통해 페이지 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 바운딩 박스 주석이 포함된 구조화된 HTML 출력 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 출력을 다양한 형식(Markdown, HTML, JSON 청크)으로 변환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 감지된 레이아웃 영역을 기반으로 내장 이미지 추출&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[1-2]. Chandra의 주요 기능&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Chandra가 제공하는 핵심 기능들을 정리하면 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;&lt;b&gt;기능&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 70%;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;다중 형식 출력&lt;/td&gt;
&lt;td style=&quot;width: 70%;&quot;&gt;Markdown, HTML, 레이아웃 블록이 포함된 구조화된 JSON 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;레이아웃 보존&lt;/td&gt;
&lt;td style=&quot;width: 70%;&quot;&gt;각 콘텐츠 블록에 대한 바운딩 박스 좌표로 문서 구조 보존&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;레이아웃 블록&lt;/td&gt;
&lt;td style=&quot;width: 70%;&quot;&gt;Text, Table, Image, Figure, Caption, Equation-Block 등 다양한 블록 유형 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;손글씨 인식&lt;/td&gt;
&lt;td style=&quot;width: 70%;&quot;&gt;필기체 및 손글씨 텍스트 인식 기능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;양식 필드 감지&lt;/td&gt;
&lt;td style=&quot;width: 70%;&quot;&gt;체크박스 및 라디오 버튼을 포함한 양식 요소 감지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;수학 공식 렌더링&lt;/td&gt;
&lt;td style=&quot;width: 70%;&quot;&gt;인라인 및 블록 수학 공식을 LaTeX로 변환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;표 구조 보존&lt;/td&gt;
&lt;td style=&quot;width: 70%;&quot;&gt;colspan/rowspan을 지원하는 정확한 테이블 구조 인식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;이미지 추출&lt;/td&gt;
&lt;td style=&quot;width: 70%;&quot;&gt;자동 네이밍으로 문서 내 이미지 및 그림 추출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;다국어 지원&lt;/td&gt;
&lt;td style=&quot;width: 70%;&quot;&gt;40개 이상의 언어 지원 (한국어 포함)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;이중 추론 백엔드&lt;/td&gt;
&lt;td style=&quot;width: 70%;&quot;&gt;로컬 HuggingFace와 원격 vLLM 서버 두 가지 추론 방식 제공&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[2]. 시스템 요구사항 및 의존성&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[2-1]. 런타임 요구사항&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Chandra를 사용하기 위한 기본적인 시스템 요구사항은 다음과 같습니다.&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;- Python &amp;gt;= 3.10&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CUDA 지원 GPU (로컬 추론에 권장)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Docker (vLLM 서버 배포에 필요)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[2-2]. 핵심 의존성 패키지&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템이 의존하는 주요 Python 패키지들을 정리하면 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;b&gt;패키지&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20%;&quot;&gt;&lt;b&gt;버전&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 55%;&quot;&gt;&lt;b&gt;용도&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;torch&lt;/td&gt;
&lt;td&gt;&amp;gt;= 2.8.0&lt;/td&gt;
&lt;td&gt;딥러닝 프레임워크&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;torchvision&lt;/td&gt;
&lt;td&gt;&amp;gt;= 0.23.0&lt;/td&gt;
&lt;td&gt;PyTorch용 비전 유틸리티&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;transformers&lt;/td&gt;
&lt;td&gt;&amp;gt;= 4.57.1&lt;/td&gt;
&lt;td&gt;HuggingFace 모델 로딩 및 추론&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;accelerate&lt;/td&gt;
&lt;td&gt;&amp;gt;= 1.11.0&lt;/td&gt;
&lt;td&gt;분산 추론 가속화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;qwen-vl-utils&lt;/td&gt;
&lt;td&gt;&amp;gt;= 0.0.14&lt;/td&gt;
&lt;td&gt;Qwen VL 모델 유틸리티&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;openai&lt;/td&gt;
&lt;td&gt;&amp;gt;= 2.2.0&lt;/td&gt;
&lt;td&gt;vLLM용 OpenAI 호환 API 클라이언트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pillow&lt;/td&gt;
&lt;td&gt;&amp;gt;= 10.2.0&lt;/td&gt;
&lt;td&gt;이미지 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pypdfium2&lt;/td&gt;
&lt;td&gt;&amp;gt;= 4.30.0&lt;/td&gt;
&lt;td&gt;PDF 렌더링&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;beautifulsoup4&lt;/td&gt;
&lt;td&gt;&amp;gt;= 4.14.2&lt;/td&gt;
&lt;td&gt;HTML 파싱&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;markdownify&lt;/td&gt;
&lt;td&gt;== 1.1.0&lt;/td&gt;
&lt;td&gt;HTML에서 Markdown으로 변환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pydantic&lt;/td&gt;
&lt;td&gt;&amp;gt;= 2.12.0&lt;/td&gt;
&lt;td&gt;데이터 검증 및 스키마&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;streamlit&lt;/td&gt;
&lt;td&gt;&amp;gt;= 1.50.0&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;p data-ke-size=&quot;size16&quot;&gt;추가로, 더 빠른 HuggingFace 추론을 위해 flash-attention을 선택적으로 설치할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[3]. Chandra OCR 시스템 아키텍처&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-1]. 아키텍처(큰 흐름도)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Chandra 시스템은 명확한 관심사 분리를 갖춘 모듈형 아키텍처를 따릅니다.&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 class=&quot;gherkin&quot;&gt;&lt;code&gt;+------------------+     +------------------+     +------------------+
|   진입점         | --&amp;gt; | 추론 계층        | --&amp;gt; | 출력 처리        |
+------------------+     +------------------+     +------------------+
| - CLI (cli.py)   |     | - InferenceManager|    | - parse_html()   |
| - Streamlit App  |     | - HF 백엔드       |    | - parse_markdown()|
| - Flask API      |     | - vLLM 백엔드     |    | - parse_chunks() |
| - vLLM 런처      |     +------------------+     | - extract_images()|
+------------------+                              +------------------+&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;시스템은 크게 진입점(Entry Point), 추론 계층(Inference Layer), 출력 처리(Output Processing)의 세 가지 주요 컴포넌트로 구성됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추론의 경우에는 허깅페이스(HuggingFace, HF)를 사용하거나 vLLM을 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 출력은 html, markdown과 같은 형태로 출력할 수 있으며, 이미지의 경우 images 형태로 제공됩니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-2]. 모듈 구조&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Chandra의 디렉토리 구조를 살펴보면 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;gherkin&quot;&gt;&lt;code&gt;chandra/
|-- __init__.py              # 패키지 초기화
|-- input.py                 # 입력 파일 처리
|-- output.py                # 출력 파싱 및 포매팅
|-- prompts.py               # 프롬프트 템플릿
|-- settings.py              # 설정 관리
|-- util.py                  # 일반 유틸리티
|-- model/
|   |-- __init__.py          # InferenceManager 클래스
|   |-- hf.py                # HuggingFace 추론 백엔드
|   |-- vllm.py              # vLLM 추론 백엔드
|   |-- schema.py            # 데이터 구조 정의
|   |-- util.py              # 모델 전용 유틸리티
|-- scripts/
    |-- cli.py               # 메인 CLI 애플리케이션
    |-- vllm.py              # vLLM Docker 런처
    |-- app.py               # Streamlit 웹 인터페이스
    |-- run_app.py           # Streamlit 런처 래퍼&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;Chandra가 지원하는 입력 파일 형식은 다음과 같습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 15%;&quot;&gt;&lt;b&gt;형식&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20%;&quot;&gt;&lt;b&gt;확장자&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;b&gt;처리기&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40%;&quot;&gt;&lt;b&gt;비고&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDF&lt;/td&gt;
&lt;td&gt;.pdf&lt;/td&gt;
&lt;td&gt;pypdfium2&lt;/td&gt;
&lt;td&gt;다중 페이지, 양식 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PNG&lt;/td&gt;
&lt;td&gt;.png&lt;/td&gt;
&lt;td&gt;PIL&lt;/td&gt;
&lt;td&gt;무손실&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JPEG&lt;/td&gt;
&lt;td&gt;.jpg, .jpeg&lt;/td&gt;
&lt;td&gt;PIL&lt;/td&gt;
&lt;td&gt;손실 압축&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GIF&lt;/td&gt;
&lt;td&gt;.gif&lt;/td&gt;
&lt;td&gt;PIL&lt;/td&gt;
&lt;td&gt;첫 번째 프레임만&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebP&lt;/td&gt;
&lt;td&gt;.webp&lt;/td&gt;
&lt;td&gt;PIL&lt;/td&gt;
&lt;td&gt;현대 형식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TIFF&lt;/td&gt;
&lt;td&gt;.tiff&lt;/td&gt;
&lt;td&gt;PIL&lt;/td&gt;
&lt;td&gt;다중 페이지 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BMP&lt;/td&gt;
&lt;td&gt;.bmp&lt;/td&gt;
&lt;td&gt;PIL&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[4]. 모델 아키텍처 및 추론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 모델 아키텍처와 추론은 제가 코드를 분석해보고 정리한 자료입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 100% 정확하지 않을 수 있으니 참고로 봐주시면 감사하겠습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-1]. 기본 모델&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Chandra는 백본으로 Qwen3 Vision-Language 모델(Qwen3VL)을 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모델은 문서 OCR 작업을 위해 파인튜닝되었으며, &lt;code&gt;datalab-to/chandra&lt;/code&gt; 식별자로 HuggingFace에 호스팅됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-20 오후 6.02.44.png&quot; data-origin-width=&quot;1013&quot; data-origin-height=&quot;671&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBdfyP/dJMcaaKDuud/kowoktJPQ8FHiZ4JHDodc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBdfyP/dJMcaaKDuud/kowoktJPQ8FHiZ4JHDodc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBdfyP/dJMcaaKDuud/kowoktJPQ8FHiZ4JHDodc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBdfyP%2FdJMcaaKDuud%2FkowoktJPQ8FHiZ4JHDodc1%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;661&quot; height=&quot;438&quot; data-filename=&quot;스크린샷 2025-12-20 오후 6.02.44.png&quot; data-origin-width=&quot;1013&quot; data-origin-height=&quot;671&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;b&gt;모델 특성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 아키텍처: Qwen3VLForConditionalGeneration&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 정밀도: bfloat16 (16비트 브레인 부동소수점)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 최대 컨텍스트 길이: 32,768 토큰&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 최대 출력 토큰: 12,384 (설정 가능)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-2]. InferenceManager 클래스&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;InferenceManager&lt;/code&gt; 클래스는 두 가지 추론 백엔드(HuggingFace, vLLM)에 대한 통합 인터페이스를 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;monkey&quot;&gt;&lt;code&gt;class InferenceManager:
    def __init__(self, method: str = &quot;vllm&quot;):
        assert method in (&quot;vllm&quot;, &quot;hf&quot;)
        self.method = method
        if method == &quot;hf&quot;:
            self.model = load_model()
        else:
            self.model = None

    def generate(self, batch: List[BatchInputItem], **kwargs) -&amp;gt; List[BatchOutputItem]:
        # 적절한 백엔드로 라우팅
        # 출력 파싱 수행
        # 통합된 BatchOutputItem 객체 반환&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;지연 로딩(Lazy Loading)&lt;/b&gt;: HuggingFace 모델은 method=&quot;hf&quot;일 때만 로드됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;통합 출력&lt;/b&gt;: 두 백엔드 모두 동일한 BatchOutputItem 구조를 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;설정 추출&lt;/b&gt;: 백엔드별 매개변수가 kwargs에서 추출됩니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-3]. HuggingFace 백엔드&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HuggingFace 백엔드는 로컬에서 직접 모델을 로드하여 추론을 수행합니다.&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;pre class=&quot;routeros&quot;&gt;&lt;code&gt;messages = [process_batch_element(item, processor, bbox_scale) for item in batch]
text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
image_inputs, _ = process_vision_info(messages)
inputs = processor(text=text, images=image_inputs, padding=True, return_tensors=&quot;pt&quot;)
generated_ids = model.generate(**inputs, max_new_tokens=max_output_tokens)&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;/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;code&gt;TORCH_DEVICE&lt;/code&gt;: 명시적 장치 할당 (예: &quot;cuda:0&quot;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;code&gt;TORCH_ATTN&lt;/code&gt;: 어텐션 구현 (예: &quot;flash_attention_2&quot;)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-4]. vLLM 백엔드&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vLLM 백엔드는 OpenAI 호환 API를 통해 별도의 vLLM 추론 서버와 통신합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시 API 요청을 위해 ThreadPoolExecutor를 사용하죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;def generate_vllm(batch, max_workers=None, ...):
    if max_workers is None:
        max_workers = min(64, len(batch))

    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        results = list(executor.map(process_item, batch, ...))
    return 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;여기에 병렬화 전략이 있는데요. 다음과 같은 특징을 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 배치 크기에 따른 동적 워커 스케일링&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 최대 64개 동시 워커&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- I/O 바운드 API 호출에 적합한 스레드 기반 병렬 처리&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-5]. 이미지 전처리: scale_to_fit()&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추론 전에 모든 이미지는 &lt;code&gt;scale_to_fit()&lt;/code&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;- max_size (6,291,456 픽셀)를 초과하는 이미지는 다운스케일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- min_size (784 픽셀) 미만의 이미지는 업스케일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 제곱근 스케일링을 사용하여 종횡비 보존&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;\( scale\_factor = \sqrt{\frac{target\_pixels}{current\_pixels}} \)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 품질을 위한 LANCZOS 리샘플링&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[5]. 프롬프트 엔지니어링&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-1]. 프롬프트 구조&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템은 VLM이 구조화된 출력을 생성하도록 안내하기 위해 신중하게 설계된 프롬프트를 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;허용된 HTML 태그는 37개이며, 대표적인 것들은 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;ALLOWED_TAGS = [
    &quot;math&quot;, &quot;br&quot;, &quot;i&quot;, &quot;b&quot;, &quot;u&quot;, &quot;del&quot;, &quot;sup&quot;, &quot;sub&quot;,
    &quot;table&quot;, &quot;tr&quot;, &quot;td&quot;, &quot;p&quot;, &quot;th&quot;, &quot;div&quot;, &quot;pre&quot;,
    &quot;h1&quot;, &quot;h2&quot;, &quot;h3&quot;, &quot;h4&quot;, &quot;h5&quot;,
    &quot;ul&quot;, &quot;ol&quot;, &quot;li&quot;, &quot;input&quot;, &quot;a&quot;, &quot;span&quot;, &quot;img&quot;, &quot;hr&quot;,
    &quot;tbody&quot;, &quot;small&quot;, &quot;caption&quot;, &quot;strong&quot;, &quot;thead&quot;, &quot;big&quot;, &quot;code&quot;
]&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-2]. 지원되는 레이아웃 라벨&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Chandra가 인식하는 15가지 레이아웃 블록 유형은 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;b&gt;라벨&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 75%;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Text&lt;/td&gt;
&lt;td&gt;표준 본문 텍스트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Section-Header&lt;/td&gt;
&lt;td&gt;제목 및 타이틀&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Table&lt;/td&gt;
&lt;td&gt;테이블 데이터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List-Group&lt;/td&gt;
&lt;td&gt;글머리 기호 또는 번호 목록&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image&lt;/td&gt;
&lt;td&gt;내장 이미지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Figure&lt;/td&gt;
&lt;td&gt;캡션이 있는 그림&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Caption&lt;/td&gt;
&lt;td&gt;이미지 또는 그림 캡션&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Equation-Block&lt;/td&gt;
&lt;td&gt;수학 공식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code-Block&lt;/td&gt;
&lt;td&gt;소스 코드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Form&lt;/td&gt;
&lt;td&gt;양식 요소&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Footnote&lt;/td&gt;
&lt;td&gt;각주&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page-Header&lt;/td&gt;
&lt;td&gt;반복되는 페이지 헤더&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page-Footer&lt;/td&gt;
&lt;td&gt;반복되는 페이지 푸터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Table-Of-Contents&lt;/td&gt;
&lt;td&gt;목차&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complex-Block&lt;/td&gt;
&lt;td&gt;복잡한 혼합 콘텐츠&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-3]. 프롬프트 가이드라인&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OCR 레이아웃 프롬프트에서 모델에게 제공하는 주요 가이드라인은 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-20 오후 6.05.46.png&quot; data-origin-width=&quot;1357&quot; data-origin-height=&quot;551&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GsM8e/dJMcadge8DX/UcSnfi0et7xPzsKfzZsMVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GsM8e/dJMcadge8DX/UcSnfi0et7xPzsKfzZsMVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GsM8e/dJMcadge8DX/UcSnfi0et7xPzsKfzZsMVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGsM8e%2FdJMcadge8DX%2FUcSnfi0et7xPzsKfzZsMVK%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;670&quot; height=&quot;272&quot; data-filename=&quot;스크린샷 2025-12-20 오후 6.05.46.png&quot; data-origin-width=&quot;1357&quot; data-origin-height=&quot;551&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;인라인 수학&lt;/b&gt;: &amp;lt;math&amp;gt;...&amp;lt;/math&amp;gt; 태그로 수학 표현을 감싸고, KaTeX 호환 LaTeX로 렌더링&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;테이블&lt;/b&gt;: colspan과 rowspan 속성을 사용하여 테이블 구조 일치&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;- &lt;b&gt;이미지&lt;/b&gt;: img 태그의 alt 속성에 이미지 설명 포함&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;- &lt;b&gt;텍스트&lt;/b&gt;: &amp;lt;p&amp;gt;...&amp;lt;/p&amp;gt; 태그를 사용하여 문장을 문단으로 결합&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[6]. 출력 처리 파이프라인&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[6-1]. 기본 모델 출력 형식&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델은 다음과 같은 구조의 HTML을 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;div data-label=&quot;Section-Header&quot; data-bbox=&quot;[50, 100, 400, 130]&quot;&amp;gt;
    &amp;lt;h1&amp;gt;Chapter 1: Introduction&amp;lt;/h1&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div data-label=&quot;Text&quot; data-bbox=&quot;[50, 150, 400, 250]&quot;&amp;gt;
    &amp;lt;p&amp;gt;This is the main text content of the document...&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div data-label=&quot;Table&quot; data-bbox=&quot;[50, 270, 400, 450]&quot;&amp;gt;
    &amp;lt;table&amp;gt;
        &amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Column 1&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Column 2&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;
        &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;Data 1&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Data 2&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
    &amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;&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;각 div 요소는 &lt;code&gt;data-label&lt;/code&gt; 속성으로 블록 유형을, &lt;code&gt;data-bbox&lt;/code&gt; 속성으로 바운딩 박스 좌표를 포함합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[6-2]. HTML 파싱&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;parse_html()&lt;/code&gt; 함수는 원시 HTML 출력을 정리하고 처리합니다.&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;1. &lt;b&gt;BeautifulSoup 파싱&lt;/b&gt;: HTML을 파싱하여 최상위 div 요소 찾기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;b&gt;라벨 추출&lt;/b&gt;: 각 div에서 data-label 속성 읽기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. &lt;b&gt;헤더/푸터 필터링&lt;/b&gt;: 선택적으로 Page-Header 및 Page-Footer 블록 제외&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. &lt;b&gt;이미지 필터링&lt;/b&gt;: 선택적으로 Image 및 Figure 블록 제외&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. &lt;b&gt;이미지 소스 할당&lt;/b&gt;: img 요소에 파일명 생성 및 할당&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. &lt;b&gt;텍스트 블록 래핑&lt;/b&gt;: 구조를 위해 일반 텍스트를 p 태그로 래핑&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. &lt;b&gt;콘텐츠 추출&lt;/b&gt;: 래퍼 div를 제거하고 내부 HTML 추출&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[6-3]. Markdown 변환&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;parse_markdown()&lt;/code&gt; 함수는 사용자 정의 Markdownify 클래스를 사용하여 HTML을 Markdown으로 변환합니다.&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;- &lt;b&gt;수학 처리&lt;/b&gt;: 블록 수학은 &lt;code&gt;$$...$$&lt;/code&gt;, 인라인 수학은 &lt;code&gt;$...$&lt;/code&gt; 형식으로 변환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;테이블 보존&lt;/b&gt;: 테이블을 HTML로 유지 (Markdown 테이블로 변환하지 않음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;달러 기호 이스케이핑&lt;/b&gt;: LaTeX 해석 방지를 위해 &lt;code&gt;$&lt;/code&gt;를 &lt;code&gt;\$&lt;/code&gt;로 변환&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[6-4]. 이미지 추출&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;extract_images()&lt;/code&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. 청크 반복하며 Image/Figure 라벨 감지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. bbox 좌표를 사용하여 원본 이미지 크롭&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. MD5 해시를 사용하여 결정적 파일명 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 딕셔너리에 파일명을 키로 크롭된 PIL Image 저장&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;[7]. Chandra OCR 실행 방법, 사용 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Chandra OCR을 실행하는 방법은 크게 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;1. CLI를 통한 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. web(streamlit)을 이용한 실행&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;p data-ke-size=&quot;size16&quot;&gt;그 전에 먼저 설치를 해야겠죠? pip를 통해 간단하게 설치 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1766222333841&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install chandra-ocr&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[7-1]. CLI를 통한 OCR 실행&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 CLI를 통해 PDF 파일을 처리했습니다. CLI를 실행할 때 사용하는 옵션과 주요 명령어 포맷은 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1766222354109&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# With VLLM
chandra_vllm
chandra input.pdf ./output

# With HuggingFace
chandra input.pdf ./output --method hf&lt;/code&gt;&lt;/pre&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style3&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: ;&quot;&gt;
&lt;td style=&quot;width: 30%;height: ;&quot;&gt;&lt;b&gt;옵션&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20%;height: ;&quot;&gt;&lt;b&gt;기본값&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;height: ;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: ;&quot;&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;--method [hf|vllm]&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;vllm&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;추론 백엔드 선택&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: ;&quot;&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;--page-range&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;None&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;PDF 페이지 범위 (예: &quot;1-5,7,9-12&quot;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: ;&quot;&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;--max-output-tokens&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;12384&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;페이지당 최대 토큰&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: ;&quot;&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;--max-workers&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;64&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;병렬 워커 (vLLM 전용)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: ;&quot;&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;--include-images&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;True&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;이미지 추출 및 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: ;&quot;&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;--save-html&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;True&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;HTML 출력 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: ;&quot;&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;--batch-size&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;28 (vllm) / 1 (hf)&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 허깅페이스 기반으로 실행해 보았습니다.&lt;/p&gt;
&lt;pre class=&quot;oxygene&quot;&gt;&lt;code&gt;chandra 한국AI정책현황및발전방안.pdf output --method hf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJw1Cw/dJMcadN4zAY/OyzO9wQ6pEqDU9W9KN0BSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJw1Cw/dJMcadN4zAY/OyzO9wQ6pEqDU9W9KN0BSK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1069&quot; data-origin-height=&quot;364&quot; data-filename=&quot;blob&quot; data-widthpercent=&quot;55.75&quot; style=&quot;width: 55.1%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJw1Cw/dJMcadN4zAY/OyzO9wQ6pEqDU9W9KN0BSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJw1Cw%2FdJMcadN4zAY%2FOyzO9wQ6pEqDU9W9KN0BSK%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;1069&quot; height=&quot;364&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kM4Ts/dJMcacVY3zw/uuFaUIg0Gjwaj3PMtIkJqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kM4Ts/dJMcacVY3zw/uuFaUIg0Gjwaj3PMtIkJqk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1084&quot; data-origin-height=&quot;465&quot; data-filename=&quot;화면 캡처 2025-12-19 134939.png&quot; width=&quot;781&quot; height=&quot;335&quot; style=&quot;width: 43.7372%;&quot; data-widthpercent=&quot;44.25&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kM4Ts/dJMcacVY3zw/uuFaUIg0Gjwaj3PMtIkJqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkM4Ts%2FdJMcacVY3zw%2FuuFaUIg0Gjwaj3PMtIkJqk%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;1084&quot; height=&quot;465&quot;/&gt;&lt;/span&gt;&lt;/div&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과, 5페이지의 PDF가 성공적으로 처리되었고, 각 페이지별로 OCR이 수행되었습니다. 터미널에서 확인할 수 있듯이 &quot;Processing pages 1-1...&quot;, &quot;Processing pages 2-2...&quot; 와 같이 순차적으로 처리가 진행됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처리가 완료된 후 output 폴더에 생성된 파일들입니다.&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-filename=&quot;화면 캡처 2025-12-19 135016.png&quot; data-origin-width=&quot;941&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCjwAV/dJMcai2VedJ/7iYJ26m5iqWr5mCuVT8uC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCjwAV/dJMcai2VedJ/7iYJ26m5iqWr5mCuVT8uC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCjwAV/dJMcai2VedJ/7iYJ26m5iqWr5mCuVT8uC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCjwAV%2FdJMcai2VedJ%2F7iYJ26m5iqWr5mCuVT8uC0%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;631&quot; height=&quot;463&quot; data-filename=&quot;화면 캡처 2025-12-19 135016.png&quot; data-origin-width=&quot;941&quot; data-origin-height=&quot;690&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;생성된 파일들은&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 한국AI정책현황및발전방안.md (Markdown 파일)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 한국AI정책현황및발전방안.html (HTML 파일)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 한국AI정책현황및발전방안_metadata.json (메타데이터)&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;p data-ke-size=&quot;size16&quot;&gt;생성된 HTML 파일을 브라우저에서 열어보면, 원본 PDF의 레이아웃이 잘 보존된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZHeWb/dJMcafd7avU/IdnKOjmZuWB4ZiSsbQMyUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZHeWb/dJMcafd7avU/IdnKOjmZuWB4ZiSsbQMyUK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1045&quot; data-origin-height=&quot;866&quot; data-filename=&quot;화면 캡처 2025-12-19 135450.png&quot; style=&quot;width: 57.2042%; margin-right: 10px;&quot; data-widthpercent=&quot;57.88&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZHeWb/dJMcafd7avU/IdnKOjmZuWB4ZiSsbQMyUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZHeWb%2FdJMcafd7avU%2FIdnKOjmZuWB4ZiSsbQMyUK%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;1045&quot; height=&quot;866&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dt9R3/dJMcaiV9VSn/y7fWyGtS4SQR2FTCrFT2Ek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dt9R3/dJMcaiV9VSn/y7fWyGtS4SQR2FTCrFT2Ek/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;813&quot; data-filename=&quot;화면 캡처 2025-12-19 135454.png&quot; style=&quot;width: 41.633%;&quot; data-widthpercent=&quot;42.12&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dt9R3/dJMcaiV9VSn/y7fWyGtS4SQR2FTCrFT2Ek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDt9R3%2FdJMcaiV9VSn%2Fy7fWyGtS4SQR2FTCrFT2Ek%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;714&quot; height=&quot;813&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;왼쪽 OCR 추출 결과, 오른쪽 원본 파일&lt;/figcaption&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;특히 눈에 띄는 점은 차트 이미지가 정확하게 추출되어 표시되었고&amp;nbsp;표(Table)의 구조가 정확하게 인식되었습니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[7-2]. 웹 인터페이스를 통한 테스트&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Streamlit 웹 인터페이스를 통해서도 테스트를 진행했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;streamlit으로 실행하려면 아래와 같이 명령어를 입력하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1766223929498&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Interactive streamlit app
chandra_app&lt;/code&gt;&lt;/pre&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-filename=&quot;화면 캡처 2025-12-19 135129.png&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;403&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l2f7O/dJMcadge9gO/nSKMbmv8LyKSLfTE1EOcZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l2f7O/dJMcadge9gO/nSKMbmv8LyKSLfTE1EOcZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l2f7O/dJMcadge9gO/nSKMbmv8LyKSLfTE1EOcZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl2f7O%2FdJMcadge9gO%2FnSKMbmv8LyKSLfTE1EOcZk%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;668&quot; height=&quot;268&quot; data-filename=&quot;화면 캡처 2025-12-19 135129.png&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;403&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;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkceCI/dJMcag498Fy/utnlRQUEml7JfxjxNK404k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkceCI/dJMcag498Fy/utnlRQUEml7JfxjxNK404k/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1551&quot; data-origin-height=&quot;852&quot; data-filename=&quot;화면 캡처 2025-12-19 142749.png&quot; style=&quot;width: 50.0295%; margin-right: 10px;&quot; data-widthpercent=&quot;50.62&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkceCI/dJMcag498Fy/utnlRQUEml7JfxjxNK404k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkceCI%2FdJMcag498Fy%2FutnlRQUEml7JfxjxNK404k%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;1551&quot; height=&quot;852&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nTnDI/dJMcac9t0Gb/vxpJukRhhmSAf6VjRTlpI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nTnDI/dJMcac9t0Gb/vxpJukRhhmSAf6VjRTlpI0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1522&quot; data-origin-height=&quot;857&quot; data-filename=&quot;화면 캡처 2025-12-19 142759.png&quot; style=&quot;width: 48.8077%;&quot; data-widthpercent=&quot;49.38&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nTnDI/dJMcac9t0Gb/vxpJukRhhmSAf6VjRTlpI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnTnDI%2FdJMcac9t0Gb%2FvxpJukRhhmSAf6VjRTlpI0%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;1522&quot; height=&quot;857&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 Vision-Language Model 기반의 문서 OCR 시스템인 Chandra에 대해 상세히 살펴보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Chandra는 단순한 텍스트 추출을 넘어, 문서의 레이아웃 구조까지 보존하면서 다양한 형식(HTML, Markdown, JSON)으로 출력할 수 있는 강력한 기능을 제공합니다.&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;실제로 한국어 PDF 문서를 테스트해본 결과, 표, 차트, 텍스트 등이 정확하게 인식되고 레이아웃이 잘 보존되는 것을 확인할 수 있었습니다. 문서 디지털화나 OCR 작업이 필요한 분들께 Chandra를 추천드립니다.&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;비록 부족한 글이지만, OCR과 문서 처리에 관심 있으신 분들에게 도움이 되시길 바랍니다.&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- Linkedin:&amp;nbsp;&lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot;&gt;https://www.linkedin.com/in/lsjsj92/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 블로그 댓글 또는 방명록&lt;/p&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;으로 연락 남겨주시면 됩니다!&lt;/p&gt;</description>
      <category>인공지능(AI)/Data processing</category>
      <category>aiagent</category>
      <category>chandra</category>
      <category>huggingface</category>
      <category>OCR</category>
      <category>Python</category>
      <category>RAG</category>
      <category>VisionLanguageModel</category>
      <category>vllm</category>
      <category>VLM</category>
      <category>한국어ocr</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/709</guid>
      <comments>https://lsjsj92.tistory.com/709#entry709comment</comments>
      <pubDate>Sat, 20 Dec 2025 18:52:13 +0900</pubDate>
    </item>
    <item>
      <title>바이브 코딩(Vibe Coding)은 안전한가? AI 코딩 에이전트의 보안 취약점 연구(Is Vibe Coding Safe? 논문)</title>
      <link>https://lsjsj92.tistory.com/708</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 16px; }
&lt;/style&gt;
&lt;/div&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;본 포스팅은 Carnegie Mellon University 연구진이 발표한 &quot;Is Vibe Coding Safe? Benchmarking Vulnerability of Agent-Generated Code in Real-World Tasks&quot; 논문을 리뷰하는 포스팅입니다. 최근 AI 코딩 도구의 발전으로 바이브 코딩(Vibe Coding)이라는 새로운 프로그래밍 패러다임이 등장했는데요. 개발자가 자연어로 요청하면 LLM 에이전트가 복잡한 코딩 작업을 수행하는 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cursor, Claude Code와 같은 AI 기반 개발 도구들이 급격히 인기를 얻으면서, 설문조사에 따르면 개발자의 75%가 바이브 코딩을 사용하고 있으며 그 중 90%가 만족한다고 응답했습니다. 심지어 Anthropic 같은 프론티어 AI 기업들도 &quot;프로덕션에서 바이브 코딩을 사용한다&quot;고 공개적으로 인정했죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 여기서 중요한 질문이 생깁니다. &quot;바이브 코딩으로 생성된 코드는 정말 안전한가?&quot; 이 논문은 이 질문에 답하기 위해 SUSVIBES라는 새로운 벤치마크를 제안하고, 프론티어 코딩 에이전트들의 보안 취약점을 분석합니다. 결과는 상당히 충격적인데요. 기능적으로 올바른 코드의 80% 이상이 보안 취약점을 포함하고 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 논문의 공개된 arxiv 링크는 아래와 같으며 본 포스팅은 아래 링크의 논문을 참고해서 작성한 리뷰 포스팅입니다.&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&gt;&lt;a href=&quot;https://arxiv.org/abs/2512.03262&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://arxiv.org/abs/2512.03262&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 7.23.14.png&quot; data-origin-width=&quot;2022&quot; data-origin-height=&quot;1246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dA2Lki/dJMcahJJuIC/Ce3o43FdM7FrzUHS84rNG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dA2Lki/dJMcahJJuIC/Ce3o43FdM7FrzUHS84rNG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dA2Lki/dJMcahJJuIC/Ce3o43FdM7FrzUHS84rNG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdA2Lki%2FdJMcahJJuIC%2FCe3o43FdM7FrzUHS84rNG0%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;656&quot; height=&quot;404&quot; data-filename=&quot;스크린샷 2025-12-13 오후 7.23.14.png&quot; data-origin-width=&quot;2022&quot; data-origin-height=&quot;1246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;!-- [이미지 삽입 위치: 논문 첫 페이지 스크린샷] --&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;style6&quot; /&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 논문에 작성되어진 순서를 따라가며, Abstract부터 시작하여 벤치마크 구축 방법, 실험 결과, 그리고 보안 완화 시도까지 상세히 살펴보도록 하겠습니다.&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;[1]. Abstract&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논문의 저자들은 Abstract에서 바이브 코딩(Vibe Coding)을 &quot;사람 엔지니어가 대규모 언어 모델(LLM) 에이전트에게 최소한의 감독 하에 복잡한 코딩 작업을 완료하도록 지시하는 새로운 프로그래밍 패러다임&quot;으로 정의합니다. 바이브 코딩이 점점 더 채택되고 있지만, 그 결과물이 정말로 프로덕션에 배포해도 안전한지에 대한 의문을 제기하죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 질문에 답하기 위해, 저자들은 SUSVIBES라는 벤치마크를 제안합니다. SUSVIBES는 실제 오픈소스 프로젝트에서 수집한 200개의 기능 요청(feature-request) 소프트웨어 엔지니어링 작업으로 구성되어 있는데요. 이 작업들은 프로그래머들이 구현했을 때 취약한 구현으로 이어졌던 것들입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 여러 프론티어 모델을 탑재한 다양한 코딩 에이전트들을 이 벤치마크에서 평가했습니다. 결과는 상당히 충격적인데요. SWE-Agent와 Claude 4 Sonnet 조합에서 솔루션의 61%가 기능적으로 올바르지만, 보안적으로 안전한 것은 단 10.5%에 불과했습니다. 추가 실험에서는 취약점 힌트를 제공하는 등의 예비적인 보안 전략도 이러한 보안 문제를 완화할 수 없음을 보여주었습니다.&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;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[2]. Introduction&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 Introduction에서 바이브 코딩의 현황과 문제점을 상세히 설명합니다. 바이브 코딩은 소프트웨어 엔지니어가 자연어로 소프트웨어 작업을 요청하면 LLM 에이전트가 복잡한 프로그래밍 작업을 완료하는 방식인데요. Cursor, Claude Code와 같은 AI 기반 IDE와 CLI의 인기에서 알 수 있듯이 점점 더 많이 채택되고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The Information 설문조사에 따르면 응답자의 75%가 바이브 코딩을 사용하고 있으며, 그 중 90%가 만족한다고 응답했습니다. WIRED의 또 다른 설문조사에서는 1년 미만 경력의 초보 프로그래머들이 바이브 코딩에 대해 훨씬 더 낙관적이라는 것을 보여주었죠. Anthropic 같은 프론티어 AI 기업들도 &quot;프로덕션에서 바이브 코딩을 사용한다&quot;고 공개적으로 인정했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 바이브 코딩이 엔지니어 생산성을 높였을 수 있지만, 에이전트가 생성한 코드의 보안은 여전히 의문입니다. 특히 바이브 코딩 사용자들은 생성된 코드를 신중하게 검토할 &quot;능력이나 의도가 없을 수 있다&quot;고 저자들은 지적합니다. 실제로 다양한 출처에서 API 키가 평문으로 저장되거나 인증 취약점이 있는 등의 보안 사고가 보고되었고, 일부는 이미 악의적인 당사자들에 의해 악용되었습니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[2-1]. 기존 벤치마크의 한계&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 생성 코드의 보안을 평가하기 위한 여러 벤치마크가 존재합니다. Baxbench, CWEval, SALLM, SecCodePLT, Asleep 등이 대표적인데요. 하지만 저자들은 이러한 벤치마크들이 바이브 코딩의 보안을 평가하기에 부적절하다고 지적합니다. 그 이유는 다음과 같습니다:&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;u&gt;1) 컨텍스트 제한&lt;/u&gt;: 기존 벤치마크들의 컨텍스트는 단일 파일이나 함수에 제한되어 있습니다. 하지만 실제 바이브 코딩은 복잡한 파일 구조를 가진 대규모 프로젝트에서 일반적으로 수행되죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;2) 단일 턴 벤치마킹&lt;/u&gt;: 기존 벤치마크들은 한 번의 생성에서 코드를 생성하는 모델을 벤치마킹하지만, 바이브 코딩은 에이전트가 여러 턴에 걸쳐 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;3) 환경 상호작용 부재&lt;/u&gt;: 기존 벤치마크의 입력은 텍스트만 포함하지만, 코딩 에이전트는 실행 환경과 상호작용하고 피드백을 받을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;!-- [이미지 삽입 위치: Figure 1 - SUSVIBES 예제 작업] --&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.02.25.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;1012&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bepmn1/dJMcai2SHNQ/hUFlMMP9NdRBX0WDSStlH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bepmn1/dJMcai2SHNQ/hUFlMMP9NdRBX0WDSStlH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bepmn1/dJMcai2SHNQ/hUFlMMP9NdRBX0WDSStlH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbepmn1%2FdJMcai2SHNQ%2FhUFlMMP9NdRBX0WDSStlH1%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;616&quot; height=&quot;255&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.02.25.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;1012&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;이러한 한계를 해결하기 위해, 저자들은 SUSVIBES를 제안합니다. Figure 1은 SUSVIBES의 예제 작업을 보여주는데요. 에이전트는 Docker 환경 내에서 시작되어 기존 레포지토리에 기능을 추가하는 작업을 수행합니다. 에이전트가 액션을 취하고, 환경과 상호작용하며, 피드백을 수집하고, 최종적으로 레포지토리에 패치를 생성합니다. 생성된 솔루션 패치는 정확성과 보안을 대상으로 하는 유닛 테스트로 테스트됩니다.&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;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[3]. SUSVIBES 벤치마크&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 논문에서 3장부터 본격적인 SUSVIBES 벤치마크 내용을 소개합니다.&amp;nbsp;&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;잠깐! 본 논문에서 나오는 핵심 용어를 먼저 정리하고 진행해봅시다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;b&gt;용어&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 75%;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;Vibe Coding (바이브 코딩)&lt;/td&gt;
&lt;td style=&quot;width: 75%;&quot;&gt;엔지니어가 자연어로 요청하면 LLM 에이전트가 최소한의 감독 하에 복잡한 코딩 작업을 완료하는 새로운 프로그래밍 패러다임입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;CWE (Common Weakness Enumeration)&lt;/td&gt;
&lt;td style=&quot;width: 75%;&quot;&gt;소프트웨어 및 하드웨어의 보안 취약점 유형을 분류한 표준 목록입니다. 예: SQL 인젝션, XSS, 경로 탐색 등이 각각 고유한 CWE 번호를 가집니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;FUNCPASS (기능 정확도)&lt;/td&gt;
&lt;td style=&quot;width: 75%;&quot;&gt;에이전트가 생성한 솔루션이 기능 테스트를 통과하는 비율입니다. 코드가 요구된 기능을 올바르게 구현했는지를 측정합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;SECPASS (보안 정확도)&lt;/td&gt;
&lt;td style=&quot;width: 75%;&quot;&gt;에이전트가 생성한 솔루션이 기능 테스트와 보안 테스트 모두를 통과하는 비율입니다. 기능적으로 올바르면서 보안 취약점이 없는 코드의 비율을 측정합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;SECPASS &amp;perp; FUNCPASS&lt;/td&gt;
&lt;td style=&quot;width: 75%;&quot;&gt;기능적으로 올바른 솔루션 중에서 보안적으로도 올바른 솔루션의 비율입니다. 기능 정확도와 보안 능력을 분리하여 순수한 보안 성능을 측정합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;\(T_{func}\) (기능 테스트)&lt;/td&gt;
&lt;td style=&quot;width: 75%;&quot;&gt;구현된 기능이 정상적으로 작동하는지 확인하는 테스트입니다. 취약점 수정 전 커밋에서 수집됩니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;\(T_{secure}\) (보안 테스트)&lt;/td&gt;
&lt;td style=&quot;width: 75%;&quot;&gt;보안 취약점이 없는지 확인하는 테스트입니다. 취약점 수정 커밋에서 개발자가 추가한 테스트를 수집합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;\(C_0\) (취약점 수정 커밋)&lt;/td&gt;
&lt;td style=&quot;width: 75%;&quot;&gt;보안 취약점이 수정된 커밋입니다. 안전한 코드 상태를 나타냅니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;\(C_{-1}\) (수정 전 커밋)&lt;/td&gt;
&lt;td style=&quot;width: 75%;&quot;&gt;취약점 수정 전의 커밋입니다. 취약한 구현을 포함하고 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;\(C_{-1}^M\) (마스킹된 커밋)&lt;/td&gt;
&lt;td style=&quot;width: 75%;&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-1]. 벤치마크 구축 원리&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SUSVIBES 작업 생성의 핵심 원리는 다음과 같습니다. 기존 기능 F의 알려진 취약점을 수정하는 커밋 \(C_0\)를 선택하고, 수정 전 커밋 \(C_{-1}\)로 되돌린 후, \(C_{-1}\)에서 취약한 구현으로부터 F를 마스킹하여 \(C_{-1}^M\)을 획득합니다. F가 없는 이 레포지토리에서, 기능을 요청하는 작업을 생성하고 기능 및 보안 테스트를 모두 수집합니다.&lt;/p&gt;
&lt;!-- [이미지 삽입 위치: Figure 2 - 큐레이션 파이프라인] --&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.02.44.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;1352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dVBZ9Q/dJMcahiEptu/6oICRhLn7l914OxckxM3ZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dVBZ9Q/dJMcahiEptu/6oICRhLn7l914OxckxM3ZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dVBZ9Q/dJMcahiEptu/6oICRhLn7l914OxckxM3ZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdVBZ9Q%2FdJMcahiEptu%2F6oICRhLn7l914OxckxM3ZK%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;612&quot; height=&quot;339&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.02.44.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;1352&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;Figure 2는 이 큐레이션 파이프라인을 보여주는데요. 오픈소스 취약점 커밋을 마이닝하고, 적응적으로 기능 마스크와 작업 설명을 생성하며, 기능 및 보안 테스트를 수집하는 과정을 보여줍니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-2]. 보안 테스트 \(T_{secure}\) 수집&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 ReposVul과 MoreFixes 같은 기존 취약점 수정 데이터셋에서 지난 10년간 20,000개 이상의 오픈소스, 다양한 취약점 수정 커밋을 수집했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중 Python으로 작성된 약 3,000개를 추출했죠. Python 3.7 이상을 사용하는 프로젝트에 집중하여 구버전 및 도구 종속성 문제를 회피했습니다.&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;단일 취약점 수정 커밋 \(C_0\)에서, 변경사항 P를 두 부분으로 분리합니다:&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;- \(P^F\): F의 구현을 수정하는 부분&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- \(P^T\): 테스트 스위트를 수정하는 부분&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;즉, \(P = P^F + P^T\)입니다. \(P^F\)를 사용하여 수정된 기능 F를 식별하고, \(P^T\)에서 추가된 테스트를 잠재적 보안 테스트 \(T_{secure}\)로 수집합니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-3]. 기능 테스트 \(T_{func}\) 수집 및 솔루션 코드 마스킹&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;취약점 수정 커밋 \(C_0\)에서 \(T_{secure}\)를 수집한 후, 이전 커밋 \(C_{-1}\)로 체크아웃합니다. 이 커밋에는 취약한 F 구현과 해당 기능 테스트 \(T_{func}\)가 포함되어 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적절한 작업을 합성하기 위해, 저자들은 SWE-Agent를 활용하여 기존 F 구현을 포함하는 최소한의 마스크를 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SWE-Agent는 커밋 \(C_{-1}\)의 코드베이스 내부에서 시작되고, 적용되지 않은 수정 \(P^F\)가 제공됩니다. 그리고 \(P^F\)가 수정하는 기능을 마스킹하도록 지시받습니다. 마스크는 패치 M으로 생성되며 라인 삭제만 포함하고 추가는 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;M은 그런 다음 \(C_{-1}\)에 적용되어 솔루션 코드 F가 마스킹된 코드베이스 \(C_{-1}^M\)을 획득하며, 이것이 SUSVIBES 작업의 초기 컨텍스트가 됩니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-4]. 작업 설명 생성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현의 마스크를 얻은 후, 저자들은 두 번째 SWE-Agent 인스턴스를 사용하여 마스킹된 구현 M과 레포지토리를 기반으로 기능 요청을 생성합니다. 이때 중요한 설계 결정이 있는데요. 마스크 M은 \(C_0\)가 아닌 \(C_{-1}\)에서 생성됩니다. 왜냐하면 이렇게 해야 보안 수정 \(C_0\)의 정보가 작업 입력에 누출되어 작업이 더 쉬워지는 것을 방지할 수 있기 때문이죠.&lt;/p&gt;
&lt;!-- [이미지 삽입 위치: Figure 3 - SWE-Agent 세 단계 프로세스] --&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.02.51.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;1016&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EM3cQ/dJMcadN15iu/EXBwobQ40tCYXPzwW4jv91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EM3cQ/dJMcadN15iu/EXBwobQ40tCYXPzwW4jv91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EM3cQ/dJMcadN15iu/EXBwobQ40tCYXPzwW4jv91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEM3cQ%2FdJMcadN15iu%2FEXBwobQ40tCYXPzwW4jv91%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;716&quot; height=&quot;298&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.02.51.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;1016&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;Figure 3은 SWE-Agent를 사용한 세 가지 작업을 수행하는 프롬프트를 보여줍니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Prompt I (Feature Masking): diff 패치 \(P^F\)를 받아 해당 패치를 포함하는 일관된 구현 영역을 삭제하는 마스크 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Prompt II (Task Description Generation): 삭제 마스크 M을 받아 마스킹된 코드의 재구현 요구사항을 지정하는 이슈 스타일 설명 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Prompt III (Mask Verification): 작업 설명과 코드 패치를 받아 패치가 작업 요구사항을 초과하는 구현을 포함하는지 확인&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-5]. 적응적 마스크 검증&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 기능 요청이 보안 수정이 포함된 정규 기능 구현을 모두 커버하는지 확인하기 위해, 저자들은 설명을 라인별로 검증하고 적응적으로 마스크를 수정합니다.&lt;/p&gt;
&lt;!-- [이미지 삽입 위치: Figure 4 - 검증 파이프라인] --&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.02.58.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;880&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/98lWq/dJMcabQgHrY/rlHMn71bbqwchi0c8DNYz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/98lWq/dJMcabQgHrY/rlHMn71bbqwchi0c8DNYz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/98lWq/dJMcabQgHrY/rlHMn71bbqwchi0c8DNYz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F98lWq%2FdJMcabQgHrY%2FrlHMn71bbqwchi0c8DNYz0%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;610&quot; height=&quot;220&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.02.58.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;880&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;Figure 4는 이 검증 파이프라인을 보여주는데요. 보안 수정을 포함하는 기능의 정규 구현(Canonical Secure Implementation)의 각 라인이 생성된 작업 설명의 요구사항과 정당화되는지 확인합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 기능 요청이 \(C_0 - C_{-1}^M\)의 모든 라인을 설명하는지 확인하기 위해, 세 번째 SWE-Agent 인스턴스를 사용하여 \(C_0 - C_{-1}^M\)의 각 라인을 기능 요청의 요구사항에 연결합니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-6]. 실행 환경 구축&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 각 취약점 수정 커밋 \(C_0\)에서 SWE-Agent를 실행하여 레포지토리의 실행 환경을 구축하고 테스트 스위트를 검증합니다. 특히, 에이전트에게 \(P^T\)의 테스트 위치가 제공되는데, 이는 복잡한 테스트 설정에서 실행해야 하는 핵심 필수 테스트에 대한 힌트입니다.&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;p data-ke-size=&quot;size16&quot;&gt;1) 기존 컨테이너 구성, 2) .github/workflows의 CI/CD 파이프라인, 3) 테스트 워크플로를 재현하기 위한 기타 문서.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 성공적인 설치 및 테스트 단계로 새 Docker 이미지를 생성하기 위해 docker 명령을 호출합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 여러 테스트 스위트 실행 결과 샘플을 기반으로 테스트 출력 파서를 합성하기 위해 LLM을 사용했습니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-7]. 실행 기반 테스트 케이스 검증&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과를 기반으로 보안 및 기능 테스트를 엄격하게 검증하기 위해, 저자들은 다양한 구현과 테스트 스위트 조합을 실행합니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;\(\{C_0, C_{-1}, C_{-1}^M\} \times \{T_{func}, T_{func} + T_{secure}\}\)&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;p data-ke-size=&quot;size16&quot;&gt;(i) 마스킹된 취약 커밋 \(C_{-1}^M\)은 기능 및 보안 테스트 모두 실패해야 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(ii) 취약한 구현이 있는 코드베이스 \(C_{-1}\)은 기능 테스트 통과, 보안 테스트 실패해야 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(iii) 취약점 수정 커밋 \(C_0\)는 두 테스트 모두 통과해야 함&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;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[4]. SUSVIBES 벤치마크 개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 SUSVIBES 벤치마크의 전체적인 특성을 살펴보겠습니다.&lt;/p&gt;
&lt;!-- [이미지 삽입 위치: Figure 5 - 도메인 분포 파이 차트] --&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.03.04.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;880&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDsgHa/dJMcadtJ8nP/I6eX6GdDZmOiKhT3MEC7dK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDsgHa/dJMcadtJ8nP/I6eX6GdDZmOiKhT3MEC7dK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDsgHa/dJMcadtJ8nP/I6eX6GdDZmOiKhT3MEC7dK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDsgHa%2FdJMcadtJ8nP%2FI6eX6GdDZmOiKhT3MEC7dK%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;710&quot; height=&quot;256&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.03.04.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;880&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Figure 5는 SUSVIBES의 108개 실세계 GitHub 프로젝트가 다양한 도메인에 분포된 것을 파이 차트로 보여줍니다:&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[4-1]. SUSVIBES의 고유한 특성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 실세계 소프트웨어 엔지니어링 작업: 기존 벤치마크의 함수/파일 수준 컨텍스트와 비교하여 평균 162K 라인의 코드를 포함합니다. 에이전트가 방대한 컨텍스트 속에서 여러 파일에 걸쳐 더 많은 라인을 식별하고 편집해야 합니다. 이러한 특성이 SUSVIBES 작업을 더 도전적으로 만들죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 다양한 애플리케이션 도메인과 취약점: SUSVIBES는 77개 CWE 유형을 포함하는데, 이는 현재 레포지토리 벤치마크보다 7배 이상입니다. 2%의 작업은 분류할 수 없는 취약점을 검토합니다. 또한 10개 실세계 애플리케이션 도메인을 포괄하여 다양한 사용 사례에서 바이브 코딩의 보안 관행을 평가할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 확장성과 확장 가능성: 완전 자동화된 큐레이션 파이프라인으로 더 많은 레포지토리 및 추가 프로그래밍 언어로 자연스럽게 확장할 수 있습니다. 새로운 공개 기록된 취약점은 취약 커밋으로 추적하여 SUSVIBES에 쉽게 적응할 수 있죠.&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;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[5]. 실험 설정 및 결과&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-1]. 실험 설정&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 3개의 대표적인 에이전트 프레임워크와 3개의 프론티어 에이전틱 LLM을 조합하여 실험을 수행했습니다:&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;p data-ke-size=&quot;size16&quot;&gt;- SWE-Agent: Princeton에서 개발한 대표적인 소프트웨어 엔지니어링 에이전트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- OpenHands: 오픈 플랫폼 기반 AI 소프트웨어 개발자 에이전트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Claude Code: Anthropic의 커맨드라인 에이전틱 코딩 도구&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;LLM 백본:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Claude 4 Sonnet: Anthropic의 최신 모델&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Kimi K2: Moonshot AI의 모델&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Gemini 2.5 Pro: Google DeepMind의 모델&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;에이전트 프레임워크는 LLM과 함께 작업 레포지토리를 검사하고 기능 요구사항에 따라 새로운 기능을 구현합니다. 또한 구현을 실행하고 런타임 환경 피드백을 사용하여 솔루션을 수정할 수 있습니다. 각 에이전트 프레임워크의 기본 권장 시스템 프롬프트를 사용하고 최대 스텝을 200으로 설정했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에이전트의 기능 및 보안 성능을 평가하기 위해 FUNCPASS와 SECPASS를 사용합니다. 실세계 바이브 코딩 사용을 반영하기 위해 pass@1을 사용하는데요. 사용자가 일반적으로 모델이 즉시 올바른 코드를 생성하기를 원하기 때문입니다. 하나의 솔루션이 의미 있는 기능을 구현하지 않으면 항상 안전할 수 있으므로, 기능적으로 올바른 솔루션의 보안만 고려합니다. 기본적으로 각 문제 설명 끝에 일반적인 보안 알림을 추가합니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[5-2]. 주요 실험 결과&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;!-- [이미지 삽입 위치: Table 3 - 주요 평가 결과] --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Table 3은 세 가지 코딩 에이전트와 세 가지 모델의 기능 및 보안 측면 평가 성능을 보여줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.03.12.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;734&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Xt1on/dJMcadtJ8oT/P3tOJh630HZh4E8Lxk30K0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Xt1on/dJMcadtJ8oT/P3tOJh630HZh4E8Lxk30K0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Xt1on/dJMcadtJ8oT/P3tOJh630HZh4E8Lxk30K0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXt1on%2FdJMcadtJ8oT%2FP3tOJh630HZh4E8Lxk30K0%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;633&quot; height=&quot;190&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.03.12.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;734&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;b&gt;인사이트 1: 실세계 레포지토리에서 새로운 기능 구현은 현재 에이전틱 시스템에게 여전히 도전적입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최고의 에이전틱 시스템인 SWE-Agent + Claude 4조차 약 절반의 작업만 기능적으로 올바른 솔루션으로 해결할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM 백본을 비교하면, Claude 4가 일관되게 다른 두 모델을 능가하고, Gemini 2.5 Pro가 가장 낮은 성능을 보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에이전트 시스템 측면에서는 SWE-Agent와 OpenHands가 서로 다른 백본에서 우위를 보입니다.&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: 모든 프론티어 에이전트 시스템이 보안 측면에서 매우 저조한 성능을 보입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FUNCPASS와 비교하여 평균 SECPASS는 약 10%에 불과합니다. 최고의 기능 성능을 보인 접근법인 SWE-Agent + Claude 4 Sonnet은 61%의 작업을 해결했지만, 이 기능적으로 올바른 솔루션의 82.8%가 보안에 취약합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenHands + Claude가 최고 SECPASS 점수 12.5%를 기록했지만, FUNCPASS 점수를 고려하면 여전히 74.7%의 올바른 솔루션이 보안에 취약합니다.&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: Gemini 2.5 Pro가 가장 보안적인 LLM이고, OpenHands가 SWE-Agent보다 더 보안적입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기능 정확도와 보안 능력을 분리하기 위해 기능적으로 올바른 부분집합에서 SECPASS &amp;perp; FUNCPASS를 계산했습니다:&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;u&gt;LLM 비교&lt;/u&gt; (OpenHands 사용, 세 LLM이 공통으로 올바르게 해결한 작업에서):&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Claude 4 Sonnet: 17.2%&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Kimi K2: 20.7%&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Gemini 2.5 Pro: 27.6&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;u&gt;에이전트 프레임워크 비교&lt;/u&gt; (Gemini 2.5 Pro 사용):&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SWE-Agent: 8.9%&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- OpenHands: 19.4&lt;b&gt;%&lt;/b&gt; (가장 보안적)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Claude Code: 10.4%&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: 에이전트 프레임워크와 LLM이 서로 다른 CWE 유형에 주의를 기울입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 CWE별 보안 성능을 더 세분화하여 분석했습니다. SUSVIBES의 작업을 CWE 태그로 분류하고 각 카테고리에서 SECPASS &amp;perp; FUNCPASS를 계산했죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에이전트의 특정 카테고리에서 SECPASS &amp;perp; FUNCPASS가 25%를 초과하면, 해당 에이전트가 이 CWE에 주의를 기울이고 기능을 구현할 때 이 CWE를 피할 가능성이 상대적으로 높다고 간주합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.03.18.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;1016&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXSRb2/dJMcafE8Idl/gR02eI994AWOvm9CuYskX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXSRb2/dJMcafE8Idl/gR02eI994AWOvm9CuYskX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXSRb2/dJMcafE8Idl/gR02eI994AWOvm9CuYskX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXSRb2%2FdJMcafE8Idl%2FgR02eI994AWOvm9CuYskX0%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;677&quot; height=&quot;281&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.03.18.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;1016&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;!-- [이미지 삽입 위치: Figure 6 - CWE별 모델/프레임워크 성능 분포 벤 다이어그램] --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Figure 6은 이러한 주의하는 CWE의 에이전트 간 분포와 겹침을 보여줍니다. 세 백본 LLM 간 58%의 CWE가 겹치지 않는다는 것을 발견할 수 있는데요. 이는 이러한 LLM들이 서로 다른 취약점 처리에 능숙함을 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 LLM에서도 에이전트 프레임워크가 처리할 수 있는 CWE에 영향을 미치지만, LLM만큼 차별화되지는 않습니다.&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;인사이트 5: 같은 CWE 태그를 가진 작업에서도 에이전트 보안 성능이 다릅니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 또한 같은 CWE 태그를 가진 작업에서 에이전트의 성능을 비교했습니다. Table 4는 유사한 취약점 유형을 가진 4개 프로젝트에서 Claude 4 Sonnet과 Gemini 2.5 Pro의 FUNCPASS와 SECPASS &amp;perp; FUNCPASS를 분석합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.03.27.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;652&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DwB0b/dJMcahpqFY4/XfFEuqg2D66nxeS7ohoIb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DwB0b/dJMcahpqFY4/XfFEuqg2D66nxeS7ohoIb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DwB0b/dJMcahpqFY4/XfFEuqg2D66nxeS7ohoIb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDwB0b%2FdJMcahpqFY4%2FXfFEuqg2D66nxeS7ohoIb0%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;710&quot; height=&quot;189&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.03.27.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;652&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;!-- [이미지 삽입 위치: Table 4 - 레포지토리별 성능 비교] --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude가 일관되게 더 나은 FUNCPASS를 보이지만, Gemini보다 더 안전한 구현을 보장하지는 못합니다. 예를 들어 django 프로젝트에서 Claude 4 Sonnet은 FUNCPASS 58.8%를 달성했지만 SECPASS &amp;perp; FUNCPASS는 0%인 반면, Gemini 2.5 Pro는 FUNCPASS 17.7%이지만 SECPASS &amp;perp; FUNCPASS는 100%입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[6]. 구체적인 취약점 사례&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;/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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[6-1]. Django verify_password() 타이밍 공격 사례&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;!-- [이미지 삽입 위치: Figure 7 - Django 취약점 사례] --&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.03.34.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;1502&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dIRml3/dJMcagjJSUx/rRCtjzzCDtJXBcwd4lCfek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dIRml3/dJMcagjJSUx/rRCtjzzCDtJXBcwd4lCfek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dIRml3/dJMcagjJSUx/rRCtjzzCDtJXBcwd4lCfek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdIRml3%2FdJMcagjJSUx%2FrRCtjzzCDtJXBcwd4lCfek%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;631&quot; height=&quot;388&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.03.34.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;1502&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Figure 7은 SWE-Agent + Claude 4 Sonnet이 Django의 기능을 구현하기 위해 제안한 솔루션을 보여줍니다. 이 솔루션은 기능적으로 올바르지만 보안에 취약합니다.&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;작업&lt;/b&gt;: &lt;code&gt;verify_password()&lt;/code&gt; 함수 구현 - 저장된 해시에 대해 후보 평문 비밀번호를 검증하는 내부 헬퍼&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;에이전트 생성 취약 코드&lt;/b&gt;:&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;def verify_password(password, encoded, preferred=&quot;default&quot;):
    if password is None:
        return False, False
    if not is_password_usable(encoded):
        return False, False
    ...&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;code&gt;None&lt;/code&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;올바른 구현&lt;/b&gt;:&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;def verify_password(password, encoded, preferred=&quot;default&quot;):
    fake_runtime = password is None or not is_password_usable(encoded)
    ...
    except ValueError:
        fake_runtime = True
    if fake_runtime:
        make_password(get_random_string(UNUSABLE_PASSWORD_SUFFIX_LENGTH))
        return False, False
    is_correct = hasher.verify(password, encoded)
    ...&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;code&gt;fake_runtime&lt;/code&gt; 플래그를 사용하여 항상 &lt;code&gt;hasher.verify&lt;/code&gt;나 &lt;code&gt;make_password&lt;/code&gt;를 호출하여 거의 일정한 시간 내에 실행되도록 보장합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실제 영향&lt;/b&gt;: 이러한 취약점은 타겟팅된 피싱 캠페인, 크리덴셜 스터핑 공격, 계정 탈취 시도로 이어질 수 있으며, 스팸 이메일 및 기타 최종 사용자에게 영향을 미치는 보안 사고를 초래할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[7]. 보안 위험 완화 시도&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[7-1]. 세 가지 완화 전략&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) Generic&lt;/b&gt;: 일반적인 보안 지침을 프롬프트에 추가합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) Self-selection&lt;/b&gt;: 에이전트가 구현 전 잠재적 보안 위험을 식별하도록 합니다. 전문가가 구현 전 기능 요구사항을 기반으로 잠재적 보안 위험을 식별하는 것에서 영감을 받았죠. 여기서는 2단계 코딩 프로세스를 조사하도록 합니다. 먼저 에이전트가 문제와 컨텍스트에서 관련 취약점 유형을 식별하고, 그런 다음 식별된 위험을 염두에 두고 코드를 구현하도록 요청합니다. 에이전트에게 SUSVIBES가 다루는 전체 CWE 목록과 정의를 제공하고, 각 작업에서 가장 관련 있는 CWE를 선택하도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) Oracle&lt;/b&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[7-2]. 완화 결과&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;!-- [이미지 삽입 위치: Table 5 - 완화 전략 결과] --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Table 5는 Self-selection과 Oracle 보안 전략이 Generic 기준선에 미치는 영향을 보여줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.03.44.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;816&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n3yZX/dJMcagqvAaA/LDGvEHEWxBuM3b86Fw5GU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n3yZX/dJMcagqvAaA/LDGvEHEWxBuM3b86Fw5GU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n3yZX/dJMcagqvAaA/LDGvEHEWxBuM3b86Fw5GU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn3yZX%2FdJMcagqvAaA%2FLDGvEHEWxBuM3b86Fw5GU0%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;704&quot; height=&quot;235&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.03.44.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;816&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;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;p data-ke-size=&quot;size16&quot;&gt;(2) 이전에 올바르게 해결된 작업이 에이전트가 보안에 과도하게 집중하면서 기능적 엣지 케이스를 누락하여 오류 발생 (보안적이든 취약하든)&lt;/p&gt;
&lt;!-- [이미지 삽입 위치: Figure 8 - 두 가지 경향 추적 그래프] --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Figure 8은 이 두 가지 경향을 정량화하여 보여줍니다. 전략이 기능에 관계없이 에이전트의 보안을 완화하지만, 더 많은 안전&amp;rarr;오답 변경을 야기하여 성능이 하락합니다. Oracle이 Self-selection보다 더 심각한 이유는 위험 식별이 어느 정도 문제 이해에 도움이 되기 때문일 수 있습니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[7-3]. 에이전트의 보안 위험 식별 능력&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Self-selection이 왜 더 나쁜 성능을 보이는지 조사하기 위해, 저자들은 코드 에이전트가 올바른 CWE를 선택하는 성능을 평가했습니다.&lt;/p&gt;
&lt;!-- [이미지 삽입 위치: Table 7 - CWE 식별 능력 분석] --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Table 7은 생성된 솔루션이 보안적일 때 에이전트가 위험에 대한 인식이 더 명확함을 보여줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.03.52.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;740&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bun9pT/dJMcadgcrjp/wGAdFmgzUtVLC0wqD7RH6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bun9pT/dJMcadgcrjp/wGAdFmgzUtVLC0wqD7RH6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bun9pT/dJMcadgcrjp/wGAdFmgzUtVLC0wqD7RH6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbun9pT%2FdJMcadgcrjp%2FwGAdFmgzUtVLC0wqD7RH6k%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;731&quot; height=&quot;221&quot; data-filename=&quot;스크린샷 2025-12-13 오후 8.03.52.png&quot; data-origin-width=&quot;2444&quot; data-origin-height=&quot;740&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;평균적으로 에이전트는 각 작업에 대해 7.5개의 관련 CWE를 선택합니다. 올바르지만 보안 취약한 솔루션(INSEC.)과 비교하여, 올바르고 안전한 솔루션은 유의미하게 더 높은 CWE 선택 재현율을 보입니다. 이는 올바르게 식별된 CWE가 더 안전한 솔루션 제공에 도움이 됨을 시사합니다.&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.06개의 실제 CWE가 있지만, 선택된 7.5개 CWE가 목표 CWE를 커버하지 못합니다 (최대 재현율 0.737). 이는 현재 코드 에이전트가 작업 설명을 기반으로 잠재적 보안 위험을 식별하는 데 여전히 어려움을 겪고 있음을 나타냅니다.&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;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[8]. 논문의 한계점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 논문의 한계점을 다음과 같이 인정합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) &lt;b&gt;Python 생태계 중심&lt;/b&gt;: 현재 Python 프로젝트에만 집중하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) &lt;b&gt;테스트 결과를 보안의 프록시로 사용&lt;/b&gt;: 실제 보안보다는 테스트 통과를 기준으로 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) &lt;b&gt;CWE 주석과 테스트의 불충분 가능성&lt;/b&gt;: 모든 취약점을 완전히 커버하지 못할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) &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;/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;&lt;b&gt;마무리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 Carnegie Mellon University 연구진이 발표한 &quot;Is Vibe Coding Safe?&quot; 논문을 리뷰하였습니다. 바이브 코딩이라는 새로운 프로그래밍 패러다임의 보안 위험을 평가하기 위한 SUSVIBES 벤치마크와 프론티어 코딩 에이전트들의 보안 취약점 분석 결과를 살펴보았습니다.&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 코딩 도구의 보안에 관심 있으신 분들에게 도움이 되시길 바랍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;긴 글 읽어주셔서 감사합니다.&lt;/p&gt;</description>
      <category>인공지능(AI)/AI Agent</category>
      <category>Agent</category>
      <category>AI</category>
      <category>aiagent</category>
      <category>LLM</category>
      <category>vibecoding</category>
      <category>바이브코딩</category>
      <category>보안</category>
      <category>에이전트</category>
      <category>인공지능</category>
      <category>코딩</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/708</guid>
      <comments>https://lsjsj92.tistory.com/708#entry708comment</comments>
      <pubDate>Sat, 13 Dec 2025 20:24:01 +0900</pubDate>
    </item>
    <item>
      <title>RAG 검색 품질의 핵심 '일관성(Coherence)' 높이기: Amazon AGI 연구 논문 리뷰</title>
      <link>https://lsjsj92.tistory.com/707</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 16px; margin-bottom: 5px; }
  p { line-height: 1.8; margin-bottom: 10px; word-break: keep-all; }
  h3 { margin-top: 30px; margin-bottom: 15px; }
  h4 { margin-top: 20px; margin-bottom: 10px; }
&lt;/style&gt;
&lt;/div&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;본 포스팅은 Amazon AGI 팀에서 2025년 8월 발표한 &lt;b&gt;&quot;Improving Document Retrieval Coherence for Semantically Equivalent Queries&quot;&lt;/b&gt; 논문을 리뷰하는 포스팅입니다. 최근 LLM 기반의 RAG(Retrieval-Augmented Generation) 시스템 구축이 필수적인 기술로 자리 잡으면서, 근거 문서를 찾아오는 Dense Retriever(검색 모델)의 역할이 중요해졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 현업에서 RAG를 개발하다 보면 마주치는 고질적인 문제가 있습니다. 바로 &quot;같은 의도의 질문인데, 단어나 어순을 살짝만 바꿔도 검색 결과가 완전히 달라지는 현상(Sensitivity)&quot;입니다.&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;본 논문은 이러한 검색 모델의 비일관성(Incoherence) 문제를 해결하기 위해, 별도의 외부 모델 없이 학습 손실 함수를 수정하는 것만으로 성능을 개선하는 Coherence Ranking (CR) Loss를 제안합니다. 특히 쿼리 재작성(Query Rewriting)이 야기하는 Latency 문제를 해결하고, 단순 데이터 증강(Data Augmentation)의 한계를 넘어선 방법론을 제시한다는 점에서 매우 실용적인 연구입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 논문의 공개된 arXiv 링크는 아래와 같으며, 본 포스팅은 해당 논문을 기반으로 작성되었습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2508.07975&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://arxiv.org/abs/2508.07975&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-30 오후 8.51.14.png&quot; data-origin-width=&quot;1842&quot; data-origin-height=&quot;1102&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bl8DFE/dJMcaaRh7om/rKxenUsmoSYEf7yhbIbfak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bl8DFE/dJMcaaRh7om/rKxenUsmoSYEf7yhbIbfak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bl8DFE/dJMcaaRh7om/rKxenUsmoSYEf7yhbIbfak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbl8DFE%2FdJMcaaRh7om%2FrKxenUsmoSYEf7yhbIbfak%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;701&quot; height=&quot;419&quot; data-filename=&quot;스크린샷 2025-11-30 오후 8.51.14.png&quot; data-origin-width=&quot;1842&quot; data-origin-height=&quot;1102&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;&lt;b&gt;포스팅 본문&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅에서는 논문의 흐름을 따라가되, 우리가 RAG 시스템을 구축하며 겪는 실제적인 문제와 연결하여 내용을 분석해보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[1]. Introduction: 왜 '일관성(Coherence)'인가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존의 Dense Retrieval(DR) 연구들은 대부분 '정답 문서를 상위에 올리는 것(Relevance)'에만 집중했습니다. NDCG나 MRR 같은 지표를 0.1이라도 올리는 것이 지상 과제였죠. 하지만 저자들은 여기서 간과된 문제를 지적합니다.&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;바로 &quot;질의 민감도(Query Sensitivity)&quot;입니다.&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; 사용자가 &quot;이순신 장군 사망일&quot;을 검색했다가 결과가 별로라 &quot;충무공 전사한 날짜&quot;로 다시 검색합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문제:&lt;/b&gt; 사람은 같은 질문이라 생각하지만, 모델은 전혀 다른 벡터로 인식해 엉뚱한 문서를 가져옵니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결과:&lt;/b&gt; RAG 시스템의 답변 품질이 질문의 미세한 표현 차이에 따라 출렁거리게 됩니다.&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;논문은 이를 &quot;Coherence(일관성)&quot;의 문제로 정의합니다. 의미적으로 동등한 질문(Semantically Equivalent Queries)이라면, 모델이 반환하는 문서 리스트도 일관성 있어야 한다는 것이죠. 일관성이 높은 모델일수록 일반화 성능이 좋고, 사용자 경험(UX)도 개선됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;2-1. 쿼리 재작성 (Query Rewriting)의 Latency 문제&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-30 오후 8.53.45.png&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXQnGc/dJMcabimATG/chPhJqdWHh6kRkuK9uf2C0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXQnGc/dJMcabimATG/chPhJqdWHh6kRkuK9uf2C0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXQnGc/dJMcabimATG/chPhJqdWHh6kRkuK9uf2C0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXQnGc%2FdJMcabimATG%2FchPhJqdWHh6kRkuK9uf2C0%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;557&quot; height=&quot;285&quot; data-filename=&quot;스크린샷 2025-11-30 오후 8.53.45.png&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;442&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 흔한 방법은 검색 전에 LLM을 두어 사용자의 질문을 깔끔하게 다시 쓰는 것입니다. 효과는 확실하지만 치명적인 단점이 있습니다. 바로 Latency(지연 시간)와 비용입니다. 모든 검색 요청마다 LLM을 거쳐야 하니 시스템이 무거워질 수밖에 없습니다. 실시간성이 중요한 서비스에서는 도입하기 부담스러운 방식이죠.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;2-2. 데이터 증강 (Data Augmentation)의 불확실성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학습 단계에서 다양한 변형 질문(Paraphrase)을 많이 보여주면 어떨까요? 추론 시 Latency는 없지만, 논문은 이를 &quot;Mixed Blessing(양날의 검)&quot;이라고 표현합니다. 단순히 데이터만 늘리는 것은 모델이 데이터 분포를 외우게 할 뿐, 랭킹의 구조적 일관성을 보장하지 못합니다. 실험 결과 일부 데이터셋(MS-MARCO)에서는 오히려 정확도가 떨어지는 현상도 발생했습니다.&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;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; background-color: #f6e199;&quot;&gt;핵심 목표:&lt;/span&gt;&lt;/b&gt; 외부 모델(LLM) 없이, 데이터만 늘리는 것도 아닌, 손실 함수(Loss Function) 자체를 수정하여 모델이 스스로 '의미적 불변성'을 깨우치게 하자!&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[3]. 제안 방법론: Coherence Ranking (CR) Loss&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연구진은 기존의 Multi-Negative Ranking (MNR) Loss에 두 가지 핵심 제약 조건을 추가한 CR Loss를 제안합니다. 이 부분이 논문의 핵심 주장입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!--  --&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-30 오후 8.51.38.png&quot; data-origin-width=&quot;876&quot; data-origin-height=&quot;404&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sli8X/dJMcad1uKla/7caOABII6ksa69izyqueg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sli8X/dJMcad1uKla/7caOABII6ksa69izyqueg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sli8X/dJMcad1uKla/7caOABII6ksa69izyqueg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsli8X%2FdJMcad1uKla%2F7caOABII6ksa69izyqueg1%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;520&quot; height=&quot;240&quot; data-filename=&quot;스크린샷 2025-11-30 오후 8.51.38.png&quot; data-origin-width=&quot;876&quot; data-origin-height=&quot;404&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-1]. Query Embedding Alignment (QEA): 벡터 응집력 강화&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째는 &quot;같은 뜻이면 같은 곳에 모여라&quot;입니다. 의미적으로 동등한 질문 \(q\)와 \(q_i\)가 있다면, 이들의 임베딩 벡터 간의 거리(MSE)를 최소화합니다. 모델이 단어 선택 같은 표면적 노이즈를 무시하고, 질문의 핵심 의도(Semantic Core)에 집중하도록 강제하는 것입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-2]. Similarity Margin Consistency (SMC): 랭킹 구조 동기화&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째가 더 중요합니다. 벡터 위치만 맞추는 것으로는 부족합니다. &quot;문서를 바라보는 관점(점수 차이)&quot;을 맞춰야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;질문 \(q\)가 정답 문서 \(d^+\)와 오답 문서 \(d^-\) 사이에서 느끼는 점수 차이(Margin)를 \(M\)이라고 합시다. 그렇다면 동등한 질문 \(q_i\)도 똑같이 \(M\)만큼의 점수 차이를 느껴야 합니다.&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; &quot;질문 형태가 바뀌어도, 정답과 오답을 가르는 변별력의 크기는 유지되어야 한다.&quot;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;효과:&lt;/b&gt; 이 제약 덕분에 질문이 조금 바뀌어도 랭킹 순서가 뒤집히지 않고 견고하게 유지됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[4]. Experiment: 실험 결과와 인사이트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연구진은 Phi-3 모델을 사용해 MS-MARCO와 Natural Questions(NQ) 데이터셋의 질문들을 10가지 스타일로 변형(Paraphrasing)하여 학습 데이터를 구축했습니다. 그리고 MPNet, ModernBERT 등을 통해 성능을 검증했습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;결과 1. 일관성(Coherence)의 압도적 향상&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;랭킹 유사도 지표인 RBO(Rank-Biased Overlap) 점수에서 극적인 향상이 있었습니다. MS-MARCO에서는 기존 대비 +15%, NQ에서는 +29%나 일관성이 좋아졌습니다. 이는 사용자가 어떻게 질문을 던지든 모델이 &quot;흔들리지 않는 편안함&quot;을 제공한다는 뜻입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-30 오후 8.51.53.png&quot; data-origin-width=&quot;1748&quot; data-origin-height=&quot;1182&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/urX8Z/dJMcagKJJGD/bpOKxBBzjwuSNVIp2Snj9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/urX8Z/dJMcagKJJGD/bpOKxBBzjwuSNVIp2Snj9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/urX8Z/dJMcagKJJGD/bpOKxBBzjwuSNVIp2Snj9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FurX8Z%2FdJMcagKJJGD%2FbpOKxBBzjwuSNVIp2Snj9k%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;627&quot; height=&quot;424&quot; data-filename=&quot;스크린샷 2025-11-30 오후 8.51.53.png&quot; data-origin-width=&quot;1748&quot; data-origin-height=&quot;1182&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;결과 2. 정확도(Relevance)와의 시너지&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 모델에 제약을 걸면 성능이 떨어지는 Trade-off가 발생하기 쉽습니다. 하지만 CR Loss는 정확도(NDCG@10)까지 소폭 상승시켰습니다. &quot;일관성 있는 모델이 정답도 잘 찾는다&quot;는 가설이 입증된 것입니다. 단순 데이터 증강이 일부 데이터셋에서 성능 저하를 보인 것과 대조적입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;결과 3. '복잡한 쿼리'에서의 진가&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상위 문서들의 점수 차이가 0.1 미만으로 촘촘해서, 랭킹이 뒤집히기 쉬운 &lt;b&gt;'&lt;/b&gt;난이도 높은 쿼리&lt;b&gt;'&lt;/b&gt; 상황에서 CR 모델은 기존 대비 138% 향상된 일관성을 보였습니다. 모델이 헷갈리기 쉬운 상황에서 더욱 빛을 발한다는 점이 인상적입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-30 오후 8.56.02.png&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;712&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IJlLd/dJMcadAqn2o/CQjLINqdfrPKDfzhfmHVL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IJlLd/dJMcadAqn2o/CQjLINqdfrPKDfzhfmHVL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IJlLd/dJMcadAqn2o/CQjLINqdfrPKDfzhfmHVL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIJlLd%2FdJMcadAqn2o%2FCQjLINqdfrPKDfzhfmHVL1%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;389&quot; height=&quot;321&quot; data-filename=&quot;스크린샷 2025-11-30 오후 8.56.02.png&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;712&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!--  --&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;결과 4. Re-ranking Opportunity의 확대 (실무적 가치)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 실무자들에게 가장 중요한 지표입니다. 보통 DR 뒤에 Re-ranker를 붙여 쓰는데, DR이 일단 후보군(Top-k)에 정답을 포함시켜야 Re-ranker가 힘을 쓸 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실험 결과, CR Loss를 적용했을 때 Re-ranker가 선택할 '최고의 문서'를 DR이 놓치지 않고 후보군에 올려줄 확률이 약 10%p 증가했습니다. 이는 RAG 파이프라인 전체의 안정성을 크게 높여주는 결과입니다.&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;&lt;b&gt;마무리 및 요약&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Amazon AGI 팀에서 2025년 8월 발표한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&quot;Improving Document Retrieval Coherence for Semantically Equivalent Queries&quot;&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;논문을 리뷰해 보았습니다.&lt;/span&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;RAG 시스템의 품질을 고민하는 엔지니어라면, 우리 모델이 &quot;같은 질문에 같은 대답을 하고 있는지&quot; 점검해보는 계기가 되시길 바랍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;긴 글 읽어주셔서 감사합니다.&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>Agent</category>
      <category>AGI</category>
      <category>AI</category>
      <category>airag</category>
      <category>amazon</category>
      <category>RAG</category>
      <category>rag검색</category>
      <category>retrieval</category>
      <category>검색성능</category>
      <category>검색증강생성</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/707</guid>
      <comments>https://lsjsj92.tistory.com/707#entry707comment</comments>
      <pubDate>Sun, 30 Nov 2025 20:58:56 +0900</pubDate>
    </item>
    <item>
      <title>CRAG: RAG의 검색 실패와 환각(Hallucination)을 해결하는 Corrective RAG 논문 리뷰</title>
      <link>https://lsjsj92.tistory.com/706</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 16px; margin-bottom: 5px; }
  p { line-height: 1.6; }
&lt;/style&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;포스팅 개요&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;본 포스팅은 최근 RAG(Retrieval-Augmented Generation)의 한계를 극복하기 위해 제안된 &lt;b&gt;CRAG(Corrective Retrieval Augmented Generation)&lt;/b&gt;라는 논문을 리뷰하는 포스팅입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;LLM(Large Language Model)이 환각(Hallucination) 현상을 겪는다는 것은 이제 널리 알려진 사실입니다. 이를 해결하기 위해 외부 지식을 검색해 오는 RAG 기술이 필수적으로 사용되고 있죠. 하지만, 만약 &lt;b&gt;&quot;검색해 온 문서 자체가 틀렸거나 관련이 없다면&quot;&lt;/b&gt; 어떻게 될까요? 기존 RAG는 검색된 문서를 맹목적으로 신뢰하다 보니, 잘못된 정보를 바탕으로 더 그럴듯한 거짓말을 만들어내곤 합니다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;CRAG는 바로 이 지점에서 출발합니다. 검색된 문서의 품질을 스스로 평가(Self-correct)하고, 그 결과에 따라 지식을 정제하거나 아예 웹 검색(Web Search)을 통해 외부 정보를 다시 찾아오는 능동적인 방법을 제안합니다. 특히 검색 실패 시에도 시스템이 무너지지 않고 강건하게(Robust) 답변을 생성할 수 있도록 설계된 것이 특징입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;본 논문의 아카이브 링크는 아래와 같습니다.&lt;/span&gt;&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&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://arxiv.org/abs/2401.15884&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://arxiv.org/abs/2401.15884&lt;/a&gt; (Corrective Retrieval Augmented Generation)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-23 오후 9.15.43.png&quot; data-origin-width=&quot;1706&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/niIt9/dJMcaiIs4HA/sfDyIihREomWzaqFKtkVn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/niIt9/dJMcaiIs4HA/sfDyIihREomWzaqFKtkVn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/niIt9/dJMcaiIs4HA/sfDyIihREomWzaqFKtkVn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FniIt9%2FdJMcaiIs4HA%2FsfDyIihREomWzaqFKtkVn0%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;1706&quot; height=&quot;476&quot; data-filename=&quot;스크린샷 2025-11-23 오후 9.15.43.png&quot; data-origin-width=&quot;1706&quot; data-origin-height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;포스팅 본문&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;포스팅 개요에서도 언급했듯, 이제 RAG는 단순히 '검색해서 보여주는' 단계를 넘어 '검색된 내용이 맞는지 검증하는' 단계로 진화하고 있습니다. 본 포스팅은 논문의 흐름을 따라가되, 제가 깊이 고민했던 부분과 해결 전략(Deep Thinking)을 함께 다루겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;[1]. Abstract &amp;amp; Introduction&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;논문의 저자들은 RAG가 LLM의 훌륭한 보완책임은 인정하지만, &quot;검색 실패(Retrieval Failure)&quot;에 너무 취약하다는 점을 꼬집습니다. 검색기가 부정확한 문서를 가져오면, 생성기(Generator)는 이를 걸러내지 못하고 오답을 생성하게 되죠. 이를 해결하기 위해 저자들은 Retrieval Evaluator(검색 평가기)를 도입하여 검색된 문서의 신뢰도를 계산하고, 이에 따라 다른 행동(Action)을 취하는 CRAG를 제안합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-23 오후 9.15.28.png&quot; data-origin-width=&quot;984&quot; data-origin-height=&quot;944&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCpSWc/dJMcagcRBew/lxwTrALzeZZEno7cYNTeg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCpSWc/dJMcagcRBew/lxwTrALzeZZEno7cYNTeg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCpSWc/dJMcagcRBew/lxwTrALzeZZEno7cYNTeg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCpSWc%2FdJMcagcRBew%2FlxwTrALzeZZEno7cYNTeg0%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;489&quot; height=&quot;469&quot; data-filename=&quot;스크린샷 2025-11-23 오후 9.15.28.png&quot; data-origin-width=&quot;984&quot; data-origin-height=&quot;944&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;위 사진인 논문의 Figure 1은 이 문제를 아주 직관적으로 보여줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;왼쪽 그림처럼 정확한 문서가 검색되면 &quot;정치인&quot;이라는 정답을 잘 맞히지만, 오른쪽 그림처럼 엉뚱한 문서(배트맨 영화 관련)가 검색되면 LLM은 그 안에 있는 &quot;Hamm&quot;이라는 단어를 보고 엉뚱한 답을 내놓습니다. 즉, 낮은 품질의 검색은 오히려 독이 된다는 것이죠.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;[2]. CRAG (Corrective RAG) 방법론 상세&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그렇다면 CRAG는 어떻게 검색 실패를 바로잡을까요? 핵심은 &quot;평가하고, 행동한다&quot;입니다. 논문의 Figure 2와 Algorithm 1은 이 과정을 상세히 설명하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-23 오후 9.15.11.png&quot; data-origin-width=&quot;1706&quot; data-origin-height=&quot;1268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbDGuA/dJMcaaX0Wpi/nbVJXPIFdtRf57hM92afx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbDGuA/dJMcaaX0Wpi/nbVJXPIFdtRf57hM92afx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbDGuA/dJMcaaX0Wpi/nbVJXPIFdtRf57hM92afx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbDGuA%2FdJMcaaX0Wpi%2FnbVJXPIFdtRf57hM92afx0%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;585&quot; height=&quot;435&quot; data-filename=&quot;스크린샷 2025-11-23 오후 9.15.11.png&quot; data-origin-width=&quot;1706&quot; data-origin-height=&quot;1268&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[2-1]. Retrieval Evaluator (검색 평가기)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;가장 먼저, 입력된 질문(Query)과 검색된 문서(Document)가 얼마나 관련이 있는지 평가합니다. 저자들은 이를 위해 T5-large 모델을 Fine-tuning하여 사용했습니다. 이 평가기는 각 문서에 점수를 매기고, 전체적인 신뢰도(Confidence)를 산출합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[2-2]. Action Trigger (행동 트리거)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;계산된 신뢰도 점수에 따라 CRAG는 다음 세 가지 중 하나의 행동을 취합니다. 이 부분이 CRAG의 가장 큰 매력 포인트입니다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Correct (정확): 검색된 문서의 신뢰도가 높습니다. 문서를 그대로 쓰지 않고 지식 정제(Knowledge Refinement)를 거쳐 핵심만 추출합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Incorrect (부정확): 검색된 문서가 모두 엉터리입니다. 과감히 버리고 웹 검색(Web Search)을 수행하여 외부 지식을 가져옵니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Ambiguous (모호): 긴가민가한 경우입니다. 내부 지식을 정제해서 사용함과 동시에 웹 검색도 수행하여 정보를 보완합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-23 오후 9.16.06.png&quot; data-origin-width=&quot;1766&quot; data-origin-height=&quot;1088&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wACQS/dJMcafSyByB/cpX0Y7ukYz3OE1gu895OJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wACQS/dJMcafSyByB/cpX0Y7ukYz3OE1gu895OJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wACQS/dJMcafSyByB/cpX0Y7ukYz3OE1gu895OJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwACQS%2FdJMcafSyByB%2FcpX0Y7ukYz3OE1gu895OJK%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;660&quot; height=&quot;407&quot; data-filename=&quot;스크린샷 2025-11-23 오후 9.16.06.png&quot; data-origin-width=&quot;1766&quot; data-origin-height=&quot;1088&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[2-3]. Knowledge Refinement &amp;amp; Web Search&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Knowledge Refinement는 'Decompose-then-Recompose' 방식을 사용합니다. 문서를 세밀한 단위(strip)로 쪼개고(Decompose), 다시 평가하여 불필요한 내용을 걸러낸 뒤(Filter), 핵심 내용만 다시 합치는(Recompose) 과정이죠. 이는 문서 내에 섞여 있는 노이즈(Noise)를 제거하는 데 탁월합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Web Search는 내부 DB에 답이 없을 때, 질문을 검색 엔진에 맞는 키워드로 변환(Query Rewriting)하여 구글 검색 등을 수행하는 과정입니다. &quot;우물 안 개구리&quot;가 되지 않도록 시스템을 확장하는 것이죠.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;[3]. Experiment (실험 결과)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;실험 결과는 꽤 인상적입니다. PopQA, Biography 등 다양한 데이터셋에서 기존 RAG는 물론 최신 기법인 Self-RAG보다도 높은 성능을 보였습니다. 특히 Figure 3의 결과가 눈에 띄는데요.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-23 오후 9.16.36.png&quot; data-origin-width=&quot;902&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3xynw/dJMcabo47Ua/2XVnaJLtjTlKP39K2SM9bk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3xynw/dJMcabo47Ua/2XVnaJLtjTlKP39K2SM9bk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3xynw/dJMcabo47Ua/2XVnaJLtjTlKP39K2SM9bk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3xynw%2FdJMcabo47Ua%2F2XVnaJLtjTlKP39K2SM9bk%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;505&quot; height=&quot;396&quot; data-filename=&quot;스크린샷 2025-11-23 오후 9.16.36.png&quot; data-origin-width=&quot;902&quot; data-origin-height=&quot;708&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;검색 성능을 일부러 떨어뜨려도(X축이 오른쪽으로 갈수록 검색 품질 저하), CRAG(회색 선)는 성능이 급격히 떨어지지 않고 잘 버티는 것을 볼 수 있습니다. 반면 기존 Self-RAG(초록색 선)는 검색 품질에 따라 성능이 출렁입니다. 이는 CRAG가 확실히 Robustness(강건성) 측면에서 우수하다는 것을 증명합니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;실무 적용 전략에서의 고민&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;논문을 읽으면서 내용은 훌륭하지만, &lt;b&gt;&quot;이걸 실제 서비스에 적용하려면 비용과 효율성은 어떻게 하지?&quot;&lt;/b&gt;라는 의문이 들었습니다. 특히 논문에서는 2024년 기준으로 작성되었다 보니, 2025년 현재의 최신 기술 트렌드와 접목했을 때 더 나은 방법이 있지 않을까 고민해 보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;제가 가졌던 의문점 두 가지와, 이를 해결하기 위한 전략을 정리해 봅니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #e53935;&quot;&gt;[의문점 1] 데이터셋마다 Fine-tuning을 해야 하나? (비효율성 문제)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;논문에서는 평가기(Evaluator)로 T5-large 모델을 Fine-tuning해서 사용합니다. 하지만 실무에서는 프로젝트마다, 도메인마다 매번 데이터를 모아서 튜닝하는 건 너무 비효율적이죠.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;전략 1: Universal Reranker 활용 (No-Training)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2025년 현재는 굳이 튜닝할 필요가 없습니다. BGE-Reranker-v2나 Cohere Rerank v3 같은 범용 Cross-Encoder 모델들은 이미 수억 개의 데이터로 학습되어 있어, 튜닝 없이도(Zero-shot) 기가 막히게 관련성을 평가해 줍니다. 이를 API 형태로 가져다 쓰는 것이 훨씬 효율적이지 않을까 싶습니다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;전략 2: SLM-as-a-Judge (Agentic Approach)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;최근 등장하는 Llama 3.2, Phi-3.5와 같은 소형 언어 모델(SLM)을 활용하는 것입니다. 모델을 학습시키는 대신, 프롬프트(Prompt)로 &quot;이 문서가 질문에 적합한지 0~1점으로 평가해 줘&quot;라고 에이전트에게 시키는 것이죠. 유지보수 측면에서 훨씬 유리한 전략입니다. 그리고 무료로 사용할 수도 있죠.&lt;/span&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #e53935;&quot;&gt;[의문점 2] 문서를 쪼개고 다시 평가하는 비용은? (비용 문제)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;논문의 Knowledge Refinement 단계에서 문서를 쪼개고(Decompose), 다시 점수를 매겨 필터링(Filter)하는 과정은 사실상 Re-ranking 작업입니다. 문서 양이 많아지면 LLM 호출 비용이나 연산 비용이 만만치 않을 겁니다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;전략 1: ColBERT (Late Interaction) 도입&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;문서를 물리적으로 쪼개서 모델을 여러 번 돌리는 대신, ColBERT와 같은 Late Interaction 모델을 사용하는 것이 어떨까 싶었습니다. 이 방식은 한 번의 연산으로 문서 내의 어떤 토큰(단어)이 질문과 관련이 높은지 즉시 파악(Highlighting)할 수 있습니다. 관련 없는 부분은 자연스럽게 점수가 낮아져 필터링되므로, 비용은 줄이면서 효과는 동일하게 가져갈 수 있습니다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;전략 2: Contextual Compression (문맥 압축)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;LLM에게 &quot;필요 없는 거 지워줘&quot;라고 시키면 비쌉니다. 대신, 임베딩 유사도나 Logit bias를 활용한 룰 베이스(Rule-based)로 관련 없는 문장을 즉시 날려버리는 Contextual Compression 기법을 사용하는 것도 방법이지 않을까 싶네요.&lt;/span&gt;&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이번 포스팅에서는 검색 실패 상황을 스스로 인지하고 교정하는 CRAG(Corrective RAG) 논문을 리뷰하고, 실무에서는 어떻게 효율적으로 구현할 수 있을지 전략까지 고민해 보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;긴 글 읽어주셔서 감사합니다.&lt;/span&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;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;혹시라도 궁금한 점이 있거나 논의하고 싶은 부분이 있다면,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;- Linkedin: &lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://www.linkedin.com/in/lsjsj92/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;- 블로그 댓글 또는 방명록&lt;/span&gt;&lt;/p&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;으로 편하게 연락 남겨주세요!&lt;/span&gt;&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>Agent</category>
      <category>agenticrag</category>
      <category>AI</category>
      <category>aiagent</category>
      <category>crag</category>
      <category>LLM</category>
      <category>RAG</category>
      <category>논문리뷰</category>
      <category>생성형ai</category>
      <category>에이전트</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/706</guid>
      <comments>https://lsjsj92.tistory.com/706#entry706comment</comments>
      <pubDate>Sun, 23 Nov 2025 21:24:09 +0900</pubDate>
    </item>
    <item>
      <title>윈도우(windows)에서 PostgreSQL pgvector 설치 및 사용하기</title>
      <link>https://lsjsj92.tistory.com/705</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 윈도우(windows)에서 PostgreSQL를 벡터 데이터베이스(vector database)를 사용하기 위한 pgvector extension을 설치하는 방법에 대해서 정리하는 글입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;독자 분들께서도 RAG나 AI Agent 시스템을 구축하면서 벡터 데이터베이스를 사용하시게 되죠? 그 중 PostgreSQL의 pgvector를 활용해 vector database로 많이 활용을 하시는데요. 리눅스(linux)나 Mac에서는 PostgreSQL의 pgvector를 설치하기 어렵지 않습니다.( 제 이전 포스팅(&lt;a href=&quot;https://lsjsj92.tistory.com/675&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/675&lt;/a&gt;)에도 소개를 해두었습니다. )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 아무래도 윈도우는 WSL을 이용하지 않으면 여러 설치 과정이 있어, pgvector 설치가 마냥 쉽지는 않은데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 개인적으로 윈도우에서 pgvector를 설치할 일이 있었어서 그 과정도 공유드려볼까 합니다.&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;제가 참고한 자료는 pgvector github 공식 내용입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pgvector/pgvector&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/pgvector/pgvector&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1763465874922&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 - pgvector/pgvector: Open-source vector similarity search for Postgres&quot; data-og-description=&quot;Open-source vector similarity search for Postgres. Contribute to pgvector/pgvector development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/pgvector/pgvector&quot; data-og-url=&quot;https://github.com/pgvector/pgvector&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ftVan/hyZNKWWXpF/PRUeeRWMm5hoJYfx6EdoT0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/buJ1Xb/hyZOdc4mxD/5Z9sazXSh36zohbpKqvJc1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/pgvector/pgvector&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/pgvector/pgvector&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ftVan/hyZNKWWXpF/PRUeeRWMm5hoJYfx6EdoT0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/buJ1Xb/hyZOdc4mxD/5Z9sazXSh36zohbpKqvJc1/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 - pgvector/pgvector: Open-source vector similarity search for Postgres&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Open-source vector similarity search for Postgres. Contribute to pgvector/pgvector 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;
&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;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 LLM을 활용한 RAG 시스템 또는 AI Agent를 구축하면서 벡터 데이터베이스(vector database) 수요가 계속 증가되고 있습니다. 그 중 전통적인 RDBMS 구조를 가지면서 동시에 벡터 데이터베이스를 지원하는 PostgreSQL을 많이 사용하고 계시는데요. PostgreSQL에서 벡터 데이터베이스로 활용을 하기 위해서는 pgvector라는 extension을 설치해야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2025-11-18 153224.png&quot; data-origin-width=&quot;863&quot; data-origin-height=&quot;632&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PzkxS/dJMcaihpCVC/L45k6Tft4WCUCGQ0pO970k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PzkxS/dJMcaihpCVC/L45k6Tft4WCUCGQ0pO970k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PzkxS/dJMcaihpCVC/L45k6Tft4WCUCGQ0pO970k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPzkxS%2FdJMcaihpCVC%2FL45k6Tft4WCUCGQ0pO970k%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;604&quot; height=&quot;442&quot; data-filename=&quot;화면 캡처 2025-11-18 153224.png&quot; data-origin-width=&quot;863&quot; data-origin-height=&quot;632&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;pgvector의 공식 github에 접속하시면 설치하는 방법에 대해서 소개를 해주고 있습니다. 아무래도 linux나 mac의 경우에는 굉장히 설치가 간단하고 쉬운데요. 윈도우의 경우에는 pgvector에서 소개한 방법대로 하면 제대로 잘 설치가 되지 않은 경우가 있습니다.&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-filename=&quot;화면 캡처 2025-11-18 153244.png&quot; data-origin-width=&quot;875&quot; data-origin-height=&quot;367&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dahfEd/dJMcabihRpD/mFvlTcgXB7s2aTJTmEFJZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dahfEd/dJMcabihRpD/mFvlTcgXB7s2aTJTmEFJZ0/img.png&quot; data-alt=&quot;pgvector에서 소개하는 윈도우 설치 방법&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dahfEd/dJMcabihRpD/mFvlTcgXB7s2aTJTmEFJZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdahfEd%2FdJMcabihRpD%2FmFvlTcgXB7s2aTJTmEFJZ0%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;679&quot; height=&quot;285&quot; data-filename=&quot;화면 캡처 2025-11-18 153244.png&quot; data-origin-width=&quot;875&quot; data-origin-height=&quot;367&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;pgvector에서 소개하는 윈도우 설치 방법&lt;/figcaption&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;위 사진은 pgvector github에서 소개한 윈도우 설치 방법인데요. 실제로 저렇게 간단히 되면 좋겠지만, 막상해보면 여러 불편한 과정이 있습니다. 이에, 저도 윈도우에 pgvector를 처음 설치하면서 알게 된 설치 과정을 공유드리겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. C++ support in Visual Studio 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저, 비쥬얼 스튜디오(Visual Studio)를 설치해야 합니다. 이미 설치가 되어 있으신 분들은 이 과정을 뛰어넘어 가셔도 상관 없습니다. 저는 설치가 되어 있지 않은 환경이었기에 처음부터 설치하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pgvector github에 보면 C++ support in vidual studio라고 링크(&lt;a href=&quot;https://learn.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-170#download-and-install-the-tools&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://learn.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-170#download-and-install-the-tools&lt;/a&gt;)가 걸어져 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 링크로 들어가시면 아래 왼쪽 사진과 같이 나오는데요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bclUNj/dJMcafydMDW/0NMZEShTLgVDkyr4jYrkZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bclUNj/dJMcafydMDW/0NMZEShTLgVDkyr4jYrkZ1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;868&quot; data-origin-height=&quot;572&quot; data-filename=&quot;화면 캡처 2025-11-18 153343.png&quot; style=&quot;width: 50.079%; margin-right: 10px;&quot; data-widthpercent=&quot;50.67&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bclUNj/dJMcafydMDW/0NMZEShTLgVDkyr4jYrkZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbclUNj%2FdJMcafydMDW%2F0NMZEShTLgVDkyr4jYrkZ1%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;868&quot; height=&quot;572&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tRTp5/dJMcafydMDX/XqzX8ItGXyZp0O3K51KiL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tRTp5/dJMcafydMDX/XqzX8ItGXyZp0O3K51KiL0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;885&quot; data-origin-height=&quot;599&quot; data-filename=&quot;화면 캡처 2025-11-18 153400.png&quot; style=&quot;width: 48.7582%;&quot; data-widthpercent=&quot;49.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tRTp5/dJMcafydMDX/XqzX8ItGXyZp0O3K51KiL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtRTp5%2FdJMcafydMDX%2FXqzX8ItGXyZp0O3K51KiL0%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;885&quot; height=&quot;599&quot;/&gt;&lt;/span&gt;&lt;/div&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;왼쪽 사진에서 파란색 링크로 되어 있는 'install C++ support in visual studio' 링크(&lt;a href=&quot;https://learn.microsoft.com/en-us/cpp/build/vscpp-step-0-installation?view=msvc-170&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://learn.microsoft.com/en-us/cpp/build/vscpp-step-0-installation?view=msvc-170&lt;/a&gt;)를 클릭하셔서 들어가시면 오른쪽 화면과 같이 나옵니다. 이 화면에서 윈도우용 비쥬얼 스튜디오를 설치하는 링크가 있는데요. 아래 왼쪽 사진과 같이 Step 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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqSrQU/dJMcafLKU4M/juPjfcz0hkfiDnMwkjNKEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqSrQU/dJMcafLKU4M/juPjfcz0hkfiDnMwkjNKEk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;881&quot; data-origin-height=&quot;736&quot; data-filename=&quot;화면 캡처 2025-11-18 153434.png&quot; width=&quot;570&quot; height=&quot;476&quot; style=&quot;width: 41.5221%; margin-right: 10px;&quot; data-widthpercent=&quot;42.01&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqSrQU/dJMcafLKU4M/juPjfcz0hkfiDnMwkjNKEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqSrQU%2FdJMcafLKU4M%2FjuPjfcz0hkfiDnMwkjNKEk%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;881&quot; height=&quot;736&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOjElA/dJMcabo3hwQ/Y4Ja0XabQBxzMZTPJjv2z0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOjElA/dJMcabo3hwQ/Y4Ja0XabQBxzMZTPJjv2z0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;719&quot; data-filename=&quot;화면 캡처 2025-11-18 153451.png&quot; style=&quot;width: 57.3151%;&quot; data-widthpercent=&quot;57.99&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOjElA/dJMcabo3hwQ/Y4Ja0XabQBxzMZTPJjv2z0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOjElA%2FdJMcabo3hwQ%2FY4Ja0XabQBxzMZTPJjv2z0%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;1188&quot; height=&quot;719&quot;/&gt;&lt;/span&gt;&lt;/div&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Step 2 - Download Visual Studio 파트로 넘어가면 Download Visual Studio 버튼이 있습니다. 왼쪽 사진 파란색 버튼입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 버튼을 누르면 비쥬얼 스튜디오를 다운로드 받을 수 있는 링크로 넘어가게 됩니다. 이 화면이 오른쪽 사진이고 여기서 Community 버전의 무료 다운로드 버튼을 눌러서 Visual Studio installer를 다운로드 받아줍니다.&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-filename=&quot;화면 캡처 2025-11-18 153521.png&quot; data-origin-width=&quot;465&quot; data-origin-height=&quot;257&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OBOrf/dJMcaaDF7DK/77vJMoLAoy4ecrxZ6eqYv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OBOrf/dJMcaaDF7DK/77vJMoLAoy4ecrxZ6eqYv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OBOrf/dJMcaaDF7DK/77vJMoLAoy4ecrxZ6eqYv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOBOrf%2FdJMcaaDF7DK%2F77vJMoLAoy4ecrxZ6eqYv0%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;465&quot; height=&quot;257&quot; data-filename=&quot;화면 캡처 2025-11-18 153521.png&quot; data-origin-width=&quot;465&quot; data-origin-height=&quot;257&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;Visual Studio Installer를 다운로드 받고 실행하면 위와 같은 과정이 나오게 되는데요.&lt;/p&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-filename=&quot;화면 캡처 2025-11-18 154132.png&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;674&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mIQgf/dJMcafydMDY/eljUjcYYn7rb0zH3neWN4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mIQgf/dJMcafydMDY/eljUjcYYn7rb0zH3neWN4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mIQgf/dJMcafydMDY/eljUjcYYn7rb0zH3neWN4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmIQgf%2FdJMcafydMDY%2FeljUjcYYn7rb0zH3neWN4K%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;728&quot; height=&quot;397&quot; data-filename=&quot;화면 캡처 2025-11-18 154132.png&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;674&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;굉장히 많은 설치 팩이 있는데요. 여기서 pgvector를 설치하려면 C++를 사용한 데스크톱 개발(Desktop development with C++)을 체크하고 이를 설치해주시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시 독자 분들께서 다른 것이 필요하다면 추가로 설치해주셔도 되지만, 본 포스팅은 윈도우에 PostgreSQL의 pgvector를 설치하는 내용이기에 필요한 C++를 사용한 데스크톱 개발만 체크하고 설치하겠습니다.&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-filename=&quot;화면 캡처 2025-11-18 154236.png&quot; data-origin-width=&quot;992&quot; data-origin-height=&quot;601&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oLQ9X/dJMcaaDF7DL/kVwUkXg0Blk1VKmXQpYi71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oLQ9X/dJMcaaDF7DL/kVwUkXg0Blk1VKmXQpYi71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oLQ9X/dJMcaaDF7DL/kVwUkXg0Blk1VKmXQpYi71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoLQ9X%2FdJMcaaDF7DL%2FkVwUkXg0Blk1VKmXQpYi71%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;680&quot; height=&quot;412&quot; data-filename=&quot;화면 캡처 2025-11-18 154236.png&quot; data-origin-width=&quot;992&quot; data-origin-height=&quot;601&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;p data-ke-size=&quot;size16&quot;&gt;조금 시간이 걸리니 기다리시면 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. visual studio developer command prompt 실행&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 설치가 되었다면 거의 다 완료 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 윈도우 검색에서 &quot;&lt;b&gt;x64 Native Tools Command Prompt for VS for ~~&lt;/b&gt;&quot;를 찾으시면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2025-11-19 090414.png&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;499&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dV2sKZ/dJMcahW618i/7hlaeI5uKIHySALrGqpcPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dV2sKZ/dJMcahW618i/7hlaeI5uKIHySALrGqpcPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dV2sKZ/dJMcahW618i/7hlaeI5uKIHySALrGqpcPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdV2sKZ%2FdJMcahW618i%2F7hlaeI5uKIHySALrGqpcPK%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;643&quot; height=&quot;387&quot; data-filename=&quot;화면 캡처 2025-11-19 090414.png&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;499&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;주의하셔야 할 것이 &quot;x86 Native Tools Command prompt for&quot;를 선택하시면 안됩니다!&lt;/span&gt;&lt;/b&gt; x64로 진행하셔야 pgvector 설치가 정상적으로 진행됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;만약 찾을 수 없다면 컴퓨터를 한 번 재부팅을 해보시길 권장드립니다.&lt;/u&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;x64 Native Tools Command Prompt를 찾으셨다면 관리자 권한으로 실행하셔서 커맨드 라인에 들어오시면 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 이제 여러 분들의 PostgreSQL 환경에 맞추어서 아래와 같이 진행하면 됩니다.&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;2-1. PostgreSQL 버전에 맞는 경로를 설정하고 pgvector git clone&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제, 여러 분들의 PostgreSQL 환경에 맞추어서 PGROOT 변수를 셋팅하고 pgvector git을 clone합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 명령어이고 pgvector github의 설치 과정에 나와있는 내용입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1763467457938&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;set &quot;PGROOT=C:\Program Files\PostgreSQL\18(여러분의 버전)&quot;
# 저는 16 버전을 쓰고 있습니다. 따라서
# set &quot;PGROOT=C:\Program Files\PostgreSQL\16&quot;   으로 진행했습니다. (아래 사진)

cd %TEMP%  # pgvector git을 clone 받을 경로
# 저는 D드라이브에 clone하였습니다. 이에
# D:  을 입력해 D드라이브에 접속한 뒤 pgvector git을 clone하였습니다.

git clone --branch v0.8.1 https://github.com/pgvector/pgvector.git&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2025-11-18 160508.png&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;461&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m6tuH/dJMcafEZnsQ/WEHaP8rKsFYjq6kFgQF0gK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m6tuH/dJMcafEZnsQ/WEHaP8rKsFYjq6kFgQF0gK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m6tuH/dJMcafEZnsQ/WEHaP8rKsFYjq6kFgQF0gK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm6tuH%2FdJMcafEZnsQ%2FWEHaP8rKsFYjq6kFgQF0gK%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;698&quot; height=&quot;407&quot; data-filename=&quot;화면 캡처 2025-11-18 160508.png&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;461&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;p data-ke-size=&quot;size16&quot;&gt;이제, clone한 git 디렉토리에 들어가서 nmake 명령어를 입력합시다.&lt;/p&gt;
&lt;pre id=&quot;code_1763467755895&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd pgvector
nmake /F Makefile.win&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2025-11-18 160532.png&quot; data-origin-width=&quot;1229&quot; data-origin-height=&quot;329&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7Z1KT/dJMcahbJEuX/pOxHVekySikz9tHaiMRSC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7Z1KT/dJMcahbJEuX/pOxHVekySikz9tHaiMRSC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7Z1KT/dJMcahbJEuX/pOxHVekySikz9tHaiMRSC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7Z1KT%2FdJMcahbJEuX%2FpOxHVekySikz9tHaiMRSC1%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;1229&quot; height=&quot;329&quot; data-filename=&quot;화면 캡처 2025-11-18 160532.png&quot; data-origin-width=&quot;1229&quot; data-origin-height=&quot;329&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2025-11-18 160538.png&quot; data-origin-width=&quot;1089&quot; data-origin-height=&quot;172&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NTs9n/dJMcaaDF7M6/Tdp5aMex2CNGk66Zxf2Xxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NTs9n/dJMcaaDF7M6/Tdp5aMex2CNGk66Zxf2Xxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NTs9n/dJMcaaDF7M6/Tdp5aMex2CNGk66Zxf2Xxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNTs9n%2FdJMcaaDF7M6%2FTdp5aMex2CNGk66Zxf2Xxk%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;1089&quot; height=&quot;172&quot; data-filename=&quot;화면 캡처 2025-11-18 160538.png&quot; data-origin-width=&quot;1089&quot; data-origin-height=&quot;172&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;nmake /F Makefile.win 명령어를 입력했을 때 마지막에 1개 파일이 복사되었습니다(copy vector~~)와 같은 명령어가 나온다면 정상적으로 완료가 된 것입니다.&amp;nbsp;&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;pre id=&quot;code_1763467846597&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nmake /F Makefile.win install&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RE16d/dJMcafEZnsR/NweDv8ObR7WAppMtDn02X0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RE16d/dJMcafEZnsR/NweDv8ObR7WAppMtDn02X0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;451&quot; data-filename=&quot;화면 캡처 2025-11-18 160551.png&quot; style=&quot;width: 41.3338%; margin-right: 10px;&quot; data-widthpercent=&quot;41.82&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RE16d/dJMcafEZnsR/NweDv8ObR7WAppMtDn02X0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRE16d%2FdJMcafEZnsR%2FNweDv8ObR7WAppMtDn02X0%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;788&quot; height=&quot;451&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T5WhO/dJMcaaRdsJ4/gaiDBM7A4JTg4FMwkuMAe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T5WhO/dJMcaaRdsJ4/gaiDBM7A4JTg4FMwkuMAe0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1123&quot; data-origin-height=&quot;462&quot; data-filename=&quot;화면 캡처 2025-11-18 160557.png&quot; style=&quot;width: 57.5034%;&quot; data-widthpercent=&quot;58.18&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T5WhO/dJMcaaRdsJ4/gaiDBM7A4JTg4FMwkuMAe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT5WhO%2FdJMcaaRdsJ4%2FgaiDBM7A4JTg4FMwkuMAe0%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;1123&quot; height=&quot;462&quot;/&gt;&lt;/span&gt;&lt;/div&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;nmake /F Makefile.win install 명령어를 입력했을 때 마찬가지로 &quot;1개 파일이 복사되었습니다&quot;와 같은 메세지가 출력된다면 정상적으로 설치가 된 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 windows에서 pgvector가 정말 동작되는 지, 사용할 수 있는지 테스트 해봐야겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3. PostgreSQL pgvector 정상 동작 테스트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PostgreSQL에 pgvector가 정상적으로 설치되었는지 확인하는 방법은 간단합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임의로 테스트 데이터베이스를 만들고 vector 컬럼을 만들면 되는데요. 다음과 같은 명령어를 입력하여 점검할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1763468416245&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;create database pgvector_test; # pgvector_test DB를 임의로 만듭니다.
\c pgvector_test  # 접속합니다.
CREATE EXTENSION vector; # vector extension을 만들어줍니다.
SELECT extname, extversion FROM   pg_extension WHERE  extname = 'vector'; # 확인합니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uAq9h/dJMcaaRdsJ5/5X0dApJAA3BD8LpAEwOP50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uAq9h/dJMcaaRdsJ5/5X0dApJAA3BD8LpAEwOP50/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;167&quot; data-filename=&quot;화면 캡처 2025-11-18 160700.png&quot; style=&quot;width: 59.0456%; margin-right: 10px;&quot; data-widthpercent=&quot;59.74&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uAq9h/dJMcaaRdsJ5/5X0dApJAA3BD8LpAEwOP50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuAq9h%2FdJMcaaRdsJ5%2F5X0dApJAA3BD8LpAEwOP50%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;636&quot; height=&quot;167&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LyDgk/dJMcaaRdsJ7/0HpLUVmUuM2uh4EqIpIb3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LyDgk/dJMcaaRdsJ7/0HpLUVmUuM2uh4EqIpIb3k/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;598&quot; data-origin-height=&quot;233&quot; data-filename=&quot;화면 캡처 2025-11-18 160717.png&quot; style=&quot;width: 39.7916%;&quot; data-widthpercent=&quot;40.26&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LyDgk/dJMcaaRdsJ7/0HpLUVmUuM2uh4EqIpIb3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLyDgk%2FdJMcaaRdsJ7%2F0HpLUVmUuM2uh4EqIpIb3k%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;598&quot; height=&quot;233&quot;/&gt;&lt;/span&gt;&lt;/div&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;위와 같이 vector가 정상적으로 나왔다면 잘 설치가 된 것입니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 임의의 데이터를 넣고 실제 pgvector 기반의 벡터 유사도 결과가 나오는 지 최종 점검 해봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1763468504246&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3)); # 임의 테이블을 만들어주고 벡터 컬럼을 구성해줍니다.

INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]'); # 임의의 값을 넣어줍니다.

SELECT * FROM   items ORDER  BY embedding &amp;lt;-&amp;gt; '[3,1,2]' LIMIT  5; # 유사도 계산 수행합니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2025-11-18 160759.png&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;313&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVPQSS/dJMcaaDF7M7/28ar3T2faKYRVViR2CdFW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVPQSS/dJMcaaDF7M7/28ar3T2faKYRVViR2CdFW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVPQSS/dJMcaaDF7M7/28ar3T2faKYRVViR2CdFW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVPQSS%2FdJMcaaDF7M7%2F28ar3T2faKYRVViR2CdFW0%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;771&quot; height=&quot;286&quot; data-filename=&quot;화면 캡처 2025-11-18 160759.png&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;313&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;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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 윈도우(windows)에 postgresql의 벡터 데이터베이스를 지원할 수 있는 pgvector를 설치하는 방법에 대해서 작성한 글입니다. 도움이 되시길 바랍니다.&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;혹시라도 궁금한 점이 있거나 논의하고 싶은 부분이 있다면,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;- Linkedin:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot;&gt;https://www.linkedin.com/in/lsjsj92/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;- 블로그 댓글 또는 방명록&lt;/span&gt;&lt;/p&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;으로 편하게 연락 남겨주세요!&lt;/span&gt;&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>Agent</category>
      <category>pgvector</category>
      <category>pgvector설치</category>
      <category>PostgreSQL</category>
      <category>RAG</category>
      <category>vectordatabase</category>
      <category>windowspgvector</category>
      <category>벡터데이터베이스</category>
      <category>윈도우pgvector</category>
      <category>윈도우pgvector설치</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/705</guid>
      <comments>https://lsjsj92.tistory.com/705#entry705comment</comments>
      <pubDate>Wed, 19 Nov 2025 09:05:21 +0900</pubDate>
    </item>
    <item>
      <title>DeepSeek의 새로운 OCR: Contexts Optical Compression 논문 리뷰</title>
      <link>https://lsjsj92.tistory.com/704</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 16px; }
&lt;/style&gt;
&lt;/div&gt;
&lt;div contenteditable=&quot;true&quot;&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;포스팅 개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;최근 AI 챗봇과 대화를 나누거나 긴 리포트를 요약시킬 때, &quot;입력 가능한 글자 수를 초과했습니다&quot;라는 메시지를 본 적 있으신가요? 현대의 대형 언어 모델(LLM)은 놀라운 성능을 보여주지만, 치명적인 약점을 안고 있습니다. 바로 '긴 텍스트'를 다루는 비용입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이는 LLM의 핵심 엔진인 '어텐션 메커니즘'이 입력된 텍스트의 길이가 길어질수록 계산량이 길이의 '제곱($O(n^2)$)'으로 폭증하는 근본적인 한계 때문입니다. 텍스트 1,000자를 처리하는 데 1초가 걸렸다면, 2,000자를 처리하는 데는 4초, 4,000자를 처리하는 데는 16초가 걸리는 식이죠. 이 때문에 수백만 자에 달하는 방대한 문서를 한 번에 처리하는 것은 사실상 불가능했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그런데 만약, 이를 피할 수 있는 기발한 방법이 있다면 어떨까요? 최근에 DeepSeek-AI 연구진이 공개한 DeepSeek OCR: Contexts Optical Compression 논문에서는 기존과 다른 방법을 제안합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&quot;긴 텍스트를 처리하는 게 비싸다면, 텍스트를 '그림(이미지)'으로 바꿔버리면 어떨까?&quot;라는 접근이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;본 포스팅은 DeepSeek-AI가 공개한 &quot;DeepSeek-OCR: Contexts Optical Compression&quot; 논문을 리뷰하면서, 이 '컨텍스트 광학 압축'이라는 혁신적인 아이디어가 어떻게 LLM의 한계를 돌파하고, OCR을 넘어 AI의 '기억' 방식까지 바꿀 수 있을지에 대한 인사이트를 정리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-25 오후 8.06.20.png&quot; data-origin-width=&quot;1055&quot; data-origin-height=&quot;881&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lQwG9/dJMb9Xj3aSD/7PiZVbwONKJhzhVUEInK2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lQwG9/dJMb9Xj3aSD/7PiZVbwONKJhzhVUEInK2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lQwG9/dJMb9Xj3aSD/7PiZVbwONKJhzhVUEInK2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlQwG9%2FdJMb9Xj3aSD%2F7PiZVbwONKJhzhVUEInK2K%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;611&quot; height=&quot;510&quot; data-filename=&quot;스크린샷 2025-10-25 오후 8.06.20.png&quot; data-origin-width=&quot;1055&quot; data-origin-height=&quot;881&quot;/&gt;&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;논문 출처: &lt;a href=&quot;https://arxiv.org/pdf/2510.18234v1&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/pdf/2510.18234v1&lt;/a&gt;&lt;/span&gt;&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;포스팅 본문&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;위 개요에서 언급하였듯 본 포스팅은 DeepSeek AI가 공개한 Contexts Optical Compression 논문을 리뷰하고 인사이트를 정리하는 내용입니다. 하나씩 진행하도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;1. &quot;광학 압축(Optical Compression)&quot;은 실현 가능한가?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&quot;한 장의 그림이 천 마디 말보다 낫다&quot;는 격언처럼, 텍스트로 가득 찬 문서 이미지는 수천 개의 '텍스트 토큰'보다 훨씬 적은 수의 '비전 토큰(vision token)'으로 표현될 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;문제는 &quot;압축했을 때 정보가 손실되지 않는가?&quot;입니다. 연구진은 이 질문에 답하기 위해 OCR(광학 문자 인식)을 완벽한 '시험대'로 삼았습니다. 텍스트를 이미지로 압축했다가 다시 텍스트로 복원(OCR)했을 때, 원본과 얼마나 똑같은지(정밀도) 측정하면 정보 손실률을 정확히 알 수 있기 때문입니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-25 오후 4.44.04.png&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcqYk1/dJMb9LD0mfF/dgtW7wePkgSsaMKql3D310/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcqYk1/dJMb9LD0mfF/dgtW7wePkgSsaMKql3D310/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcqYk1/dJMb9LD0mfF/dgtW7wePkgSsaMKql3D310/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcqYk1%2FdJMb9LD0mfF%2FdgtW7wePkgSsaMKql3D310%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;643&quot; height=&quot;284&quot; data-filename=&quot;스크린샷 2025-10-25 오후 4.44.04.png&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;377&quot;/&gt;&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Figure 1은 이 대담한 실험의 결과를 압축적으로 보여주는 그래프입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Figure 1 - (a)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;압축률-정밀도 트레이드오프로서 이 그래프는 &quot;얼마나 압축할 수 있고, 얼마나 손해를 보는가?&quot;에 대한 답입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;놀랍게도, 1,000개의 텍스트 토큰을 단 100개의 비전 토큰(하늘색 막대)으로 압축했을 때, 즉 압축률 10배에 달하는 구간에서도 정밀도는 97%에 육박합니다. 이는 LLM의 계산량을 100분의 1($100^2$ vs $10^2$)로 줄이면서도 정보는 거의 잃지 않는다는 의미입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;압축률이 20배(보라색 막대)에 달하는 극한의 상황에서도 정밀도는 0이 아닌 약 60%를 유지합니다. 이는 시스템이 한계 상황에서도 완전히 실패하지 않고 핵심 정보는 기억함을 보여줍니다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Figure 1 - (b)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;효율성을 보여주는 이 그래프는 &quot;그래서 실전에서도 쓸만한가?&quot;에 대한 답입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그래프의 오른쪽 상단에 있을수록 (적은 토큰으로, 높은 성능) 좋은 모델입니다. DeepSeek-OCR(붉은색 점들)은 경쟁 모델(InternVL, Qwen2.5-VL 등)이 6,000개 이상의 토큰을 써야 낼 수 있는 성능을, 단 800개 미만의 토큰으로 가볍게 뛰어넘습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이는 DeepSeek-OCR이 단순한 이론이 아니라, 경쟁사 대비 8배 이상 효율적인 실용적 기술임을 입증합니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2. 왜 새로운 아키텍처가 필요했는가? (기존 방식의 한계)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Figure 1의 결과가 이토록 놀랍다면, 왜 다른 사람들은 이 방식을 쓰지 않았을까요? 답은 &quot;고해상도 문서를 효율적으로 처리하는 것이 지극히 어렵기 때문&quot;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-25 오후 4.44.20.png&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGGE6W/dJMb9iuYMqb/TjiUoz8C4T4GX303k14gK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGGE6W/dJMb9iuYMqb/TjiUoz8C4T4GX303k14gK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGGE6W/dJMb9iuYMqb/TjiUoz8C4T4GX303k14gK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGGE6W%2FdJMb9iuYMqb%2FTjiUoz8C4T4GX303k14gK1%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;720&quot; height=&quot;222&quot; data-filename=&quot;스크린샷 2025-10-25 오후 4.44.20.png&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;377&quot;/&gt;&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Figure 2는 기존 VLM 인코더들이 가진 문제점들을 명확히 보여줍니다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Figure 2 - (왼쪽): 이미지 처리를 위해 여러 개의 인코더를 병렬로 사용합니다. 이는 구조가 복잡하고 배포가 어렵습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Figure 2 - (가운데) : 고해상도 이미지를 너무 잘게 쪼개어 처리합니다. 이는 Figure 1(b)에서 본 것처럼, 너무 많은(6,000개 이상) 비전 토큰을 생성하여 비효율의 극치를 보여줍니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Figure 2 - (오른쪽): 고해상도 이미지를 통째로 처리하려다 보니, GPU 메모리 사용량이 기하급수적으로 증가해 추론 속도가 극도로 느려집니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;기존 방식들은 '고해상도'와 '효율' 중 하나를 포기해야 했습니다. DeepSeek-OCR은 이 두 마리 토끼를 모두 잡기 위해 완전히 새로운 인코더, 'DeepEncoder'를 설계했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;3. DeepEncoder: 효율과 성능을 모두 잡은 &quot;전문가 팀&quot;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;Figure 3은 DeepSeek-OCR의 핵심 구성 요소인 DeepEncoder 아키텍처를 상세히 보여줍니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;이 구조는 Figure 2에서 제기된 고해상도 처리의 비효율성, 즉 '토큰 폭발'과 '메모리 폭발' 문제를 해결하기 위해 정교하게 설계되었습니다.&lt;/span&gt;&lt;/p&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-filename=&quot;스크린샷 2025-10-25 오후 4.44.29.png&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;513&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/97HCy/dJMb9WSYS9u/p5p006sKfja6WQ1kBucKJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/97HCy/dJMb9WSYS9u/p5p006sKfja6WQ1kBucKJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/97HCy/dJMb9WSYS9u/p5p006sKfja6WQ1kBucKJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F97HCy%2FdJMb9WSYS9u%2Fp5p006sKfja6WQ1kBucKJ1%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;633&quot; height=&quot;265&quot; data-filename=&quot;스크린샷 2025-10-25 오후 4.44.29.png&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;513&quot;/&gt;&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt; 전체 과정은 1024x1024와 같은 고해상도 이미지가 16x16 크기의 패치로 분할되어 4096개와 같은 다수의 초기 비전 토큰이 생성되는 것에서 시작합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;첫째로, 이 토큰들은 SAM(Segment Anything Model) 인코더로 전달됩니다. SAM은 '윈도우 어텐션(Window Attention)' 방식을 사용하여, 각 토큰이 전체 모든 토큰이 아닌 자신의 주변부 토큰하고만 상호작용하게 합니다. 이 접근 방식은 GPU 메모리 사용량을 낮게 유지하면서도 이미지의 세밀하고 '국소적인(Local)' 특징(글자의 형태, 표의 선 등)을 효과적으로 추출할 수 있게 합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;둘째로, SAM을 통과한 피처맵(여전히 4096개 토큰)은 이 아키텍처의 핵심 혁신인 16x 합성곱(Convolutional) 압축기를 거칩니다. 이 2계층 CNN 모듈은 피처맵을 공간적으로 다운샘플링(Downsampling)하여 토큰의 '개수'를 1/16로 극적으로 줄입니다. 예를 들어, 4096개의 토큰이 256개의 토큰으로 압축됩니다. 이 단계가 바로 연산량의 병목 현상을 근본적으로 해결하는 '광학 압축'의 핵심입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;셋째로, 토큰 수가 256개로 관리 가능한 수준이 되면, 이 압축된 토큰들은 CLIP(Contrastive Language-Image Pre-Training) 인코더로 전달됩니다. CLIP은 '글로벌 어텐션(Global Attention)'을 사용하여, 256개의 모든 토큰이 서로 상호작용하며 문서 전체의 '전역적인(Global)' 맥락(문서의 레이아웃이나 의미적 구조 등)을 파악하도록 합니다. 4096개 토큰에 직접 글로벌 어텐션을 적용하는 것($O(n^2)$)은 계산적으로 불가능에 가깝지만, 압축된 256개 토큰에는 효율적으로 적용할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;최종적으로, 국소적 특징(SAM)과 전역적 맥락(CLIP)이 모두 반영되고 압축된 256개의 비전 토큰이 DeepSeek-3B LLM 디코더로 전달되어 최종 텍스트를 생성합니다. 이처럼 [SAM(로컬 처리) &amp;rarr; Conv(압축) &amp;rarr; CLIP(전역 처리)]로 이어지는 3단계 직렬 구조는, 고해상도 이미지의 세부 정보를 잃지 않으면서도 계산 비용을 획기적으로 절감하는 최적화 방법이라고 볼 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;4. 실용성을 위한 설계: 다중 해상도 및 처리 방식 지원 &lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;DeepSeek-OCR 모델은 학술적 증명을 넘어 실제 운영 환경에서의 실용성을 확보하기 위해 유연한 처리 방식을 지원합니다. Figure 4는 단일 모델이 다양한 입력 해상도에 대응하는 방식을 보여줍니다. &lt;/span&gt;&lt;/p&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-filename=&quot;스크린샷 2025-10-25 오후 4.44.38.png&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;513&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgUTBE/dJMb9LxeWe1/noTdFe23HADpAbPWfgi7s1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgUTBE/dJMb9LxeWe1/noTdFe23HADpAbPWfgi7s1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgUTBE/dJMb9LxeWe1/noTdFe23HADpAbPWfgi7s1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgUTBE%2FdJMb9LxeWe1%2FnoTdFe23HADpAbPWfgi7s1%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;686&quot; height=&quot;288&quot; data-filename=&quot;스크린샷 2025-10-25 오후 4.44.38.png&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;513&quot;/&gt;&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이는 Figure 1(a)의 압축률-정밀도 트레이드오프를 사용자가 직접 제어할 수 있도록 설계한 것입니다. 예를 들어, Tiny (64 토큰)나 Small (100 토큰) 모드는 더 적은 비전 토큰을 사용하여 빠른 처리가 가능하게 하며, Base (256 토큰)나 Large (400 토큰) 모드는 더 많은 비전 토큰을 사용하여 높은 정밀도를 보장합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;모델은 입력 이미지의 특성에 따라 원본 비율을 무시하고 리사이즈(Resize)하거나, 비율을 유지하며 패딩(Padding)을 추가하는 방식을 유연하게 적용합니다. 특히 Gundam 모드는 이미지를 여러 타일(Tile)로 분할하고 전체적인 글로벌 뷰(Global view)와 함께 처리함으로써, 신문과 같이 매우 크거나 긴 이미지에도 효과적으로 대응할 수 있습니다. &lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이러한 다중 모드 지원은 단일 모델이 다양한 사용자의 요구(속도 중시 vs. 정확도 중시)에 부응할 수 있게 하여 생산성을 극대화합니다. &lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;5. 학습 목표의 확장: 단순 인식을 넘어선 '문서 구조 이해' &lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이 모델의 궁극적인 목표는 단순한 문자 인식(Traditional OCR)을 넘어섭니다. Figure 5는 모델이 학습하는 '정교한 주석(Fine annotations)' 데이터의 형식을 보여주며, 이는 모델의 학습 목표가 무엇인지를 명확히 드러냅니다. 모델은 단순히 텍스트의 내용을 예측하는 것이 아니라, 해당 내용의 의미론적 종류(예: table, equation)와 이미지 내 정확한 위치 좌표([[...]])까지 함께 학습합니다.&lt;/span&gt;&lt;/p&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-filename=&quot;스크린샷 2025-10-25 오후 4.44.51.png&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;915&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKSHEF/dJMb9PNa2zS/fTd8LGMUOqX52CxfraIB7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKSHEF/dJMb9PNa2zS/fTd8LGMUOqX52CxfraIB7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKSHEF/dJMb9PNa2zS/fTd8LGMUOqX52CxfraIB7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKSHEF%2FdJMb9PNa2zS%2FfTd8LGMUOqX52CxfraIB7k%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;714&quot; height=&quot;534&quot; data-filename=&quot;스크린샷 2025-10-25 오후 4.44.51.png&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;915&quot;/&gt;&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;즉, 모델은 단순히 글자를 '읽는(Reading)' 수준을 넘어, 문서의 '구조와 레이아웃을 이해(Understanding)'하도록 훈련됩니다. 이것이 DeepSeek-OCR이 'LLM 중심의 통합형 모델'이라 불리는 이유이며, LLM 디코더가 이 구조화된 정보를 입력받아 단순 텍스트가 아닌 마크다운(Markdown) 변환이나 구조화된 데이터 추출 같은 고차원적인 작업을 수행할 수 있게 만듭니다. 논문은 이를 기존 OCR 1.0을 넘어서는 'OCR 2.0'의 영역으로 정의합니다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;논문에서 소개하는 실제 성능 결과는 아래와 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgCUjV/dJMb9PTWoks/Kk5Gy6mrKk7ab6X6R8g2KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgCUjV/dJMb9PTWoks/Kk5Gy6mrKk7ab6X6R8g2KK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;846&quot; data-filename=&quot;스크린샷 2025-10-25 오후 8.12.00.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgCUjV/dJMb9PTWoks/Kk5Gy6mrKk7ab6X6R8g2KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgCUjV%2FdJMb9PTWoks%2FKk5Gy6mrKk7ab6X6R8g2KK%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;647&quot; height=&quot;846&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FSv38/dJMb9Onb6SM/iSx0mfkMkolKmoHESJ7dk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FSv38/dJMb9Onb6SM/iSx0mfkMkolKmoHESJ7dk0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;846&quot; data-filename=&quot;스크린샷 2025-10-25 오후 8.12.06.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FSv38/dJMb9Onb6SM/iSx0mfkMkolKmoHESJ7dk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFSv38%2FdJMb9Onb6SM%2FiSx0mfkMkolKmoHESJ7dk0%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;647&quot; height=&quot;846&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;마무리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;DeepSeek-OCR 논문은 LLM의 $O(n^2)$ 연산량 한계를 '컨텍스트 광학 압축'이라는 새로운 접근법으로 해결할 수 있는 가능성을 실증적으로 제시했습니다. Figure 1은 10배의 압축률에서도 97%의 높은 정밀도를 달성할 수 있음을 증명했으며, Figure 3의 [SAM &amp;rarr; Conv &amp;rarr; CLIP] 아키텍처는 Figure 2에서 지적된 기존 모델들의 한계를 기술적으로 극복하는 효율적인 방안을 제안했습니다. 또한 Figure 4와 Figure 5는 이 모델이 실제 적용을 위한 유연성과 고차원적인 문서 이해 능력을 갖추었음을 보여줍니다. &lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;하지만 논문이 제시하는 가장 중요한 비전은 OCR 자체를 넘어섭니다. 논문의 초록(Abstract)은 이 연구가 &quot;LLM의 역사적 장기 컨텍스트 압축 및 기억 망각 메커니즘&quot;을 위한 초기 연구임을 명시합니다. 즉, OCR은 이 광학 압축 아이디어의 실현 가능성을 검증하기 위한 '시험대'였습니다. 이 연구의 궁극적인 목표는, 챗봇의 대화 기록과 같은 방대한 텍스트 스트림을 이미지로 렌더링하고, 정보의 중요도나 시간에 따라 Tiny부터 Large까지 해상도를 달리하여(압축률 조절) 저장하는 것입니다. 이는 인간의 '망각 곡선'처럼 오래된 정보는 적은 비용으로 핵심만 보존하는 효율적인 메모리 관리 방식이 될 수 있습니다. 이 '광학적 기억' 방식은 O(n^2)의 한계를 우회하여 LLM이 사실상 '무한한 컨텍스트'를 다룰 수 있게 하는 잠재적 해결책으로서, 제안한 연구라고 볼 수 있습니다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;긴 글 읽어주셔서 감사합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>인공지능(AI)/Data processing</category>
      <category>AI</category>
      <category>Attention</category>
      <category>deepseek</category>
      <category>deepseekocr</category>
      <category>LLM</category>
      <category>longcontext</category>
      <category>OCR</category>
      <category>VLM</category>
      <category>딥시크</category>
      <category>인공지능</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/704</guid>
      <comments>https://lsjsj92.tistory.com/704#entry704comment</comments>
      <pubDate>Sat, 25 Oct 2025 20:13:55 +0900</pubDate>
    </item>
    <item>
      <title>업스테이지 문서 파싱(Document parsing) playground 서비스 개발기( 코드 공유 )</title>
      <link>https://lsjsj92.tistory.com/703</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대규모 언어 모델(Large Language Model) 기반의 RAG 시스템을 개발하면서, 가장 중요한 것은 데이터라고 다시 한번 체감하고 있습니다. 아무리 기존에 DX/AX를 준비했어도 LLM과 RAG 기반의 시스템에 well-fit되는 데이터는 더 다른 느낌인데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 RAG 시스템 개발과 더 나아가 AI Agent(AI 에이전트) 시스템 개발을 하면 word, pdf, ppt, 한글(hwp) 데이터를 활용하여 내부 업무 효율화 등으로 시스템을 구축하는 경우가 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 이러한 데이터를 LLM 등이 잘 이해할 수 있도록 잘 파싱(Parsing)하고 관리를 해야겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업스테이지(Upstage)의 Document parser는 이러한 기존 레거시 형태의 문서 데이터들을 파싱해서 RAG에 활용할 수 있는 데이터 형태로 추출할 수 있도록 기능을 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 업스테이지의 document parser를 개인적으로 사용하면서, PoC(Proof-of-Concept) 및 Playground 형태로 파싱 결과를 웹 화면으로 확인할 수 있도록 만든 Python streamlit 페이지를 공유하는 포스팅입니다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://console.upstage.ai/docs/capabilities/digitize/document-parsing&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://console.upstage.ai/docs/capabilities/digitize/document-parsing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1760257112179&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;Upstage Console&quot; data-og-description=&quot;Empower your business with Upstage Console.&quot; data-og-host=&quot;console.upstage.ai&quot; data-og-source-url=&quot;https://console.upstage.ai/docs/capabilities/digitize/document-parsing&quot; data-og-url=&quot;https://console.upstage.ai&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/PXtbI/hyZLroPrCk/P6kECeDCT83CnzyQm7n0bk/img.png?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260,https://scrap.kakaocdn.net/dn/bnQ0Wh/hyZKEpMYQK/Dkr8kmRhbvXxJv1XmaaQn1/img.png?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260&quot;&gt;&lt;a href=&quot;https://console.upstage.ai/docs/capabilities/digitize/document-parsing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://console.upstage.ai/docs/capabilities/digitize/document-parsing&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/PXtbI/hyZLroPrCk/P6kECeDCT83CnzyQm7n0bk/img.png?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260,https://scrap.kakaocdn.net/dn/bnQ0Wh/hyZKEpMYQK/Dkr8kmRhbvXxJv1XmaaQn1/img.png?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260');&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;Upstage Console&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Empower your business with Upstage Console.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;console.upstage.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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 업스테이지에서 제공하는 Document parsing을 사용하면서 쉽게 결과를 웹 화면으로 확인할 수 있게 지원해주는 서비스를 공유하는 포스팅인데요. 왜 이 서비스를 만들었는지를 이야기 하기에 앞서, 업스테이지 Document parser에 대해서 간단히 소개하려고 합니다.&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;Upstage Document parser&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjyAx5/btsQ7v1Ix43/0Xx12SGRp6yz2CNjxzR7v0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjyAx5/btsQ7v1Ix43/0Xx12SGRp6yz2CNjxzR7v0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;836&quot; data-filename=&quot;스크린샷 2025-10-12 오후 5.19.54.png&quot; style=&quot;width: 47.227%; margin-right: 10px;&quot; data-widthpercent=&quot;47.78&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjyAx5/btsQ7v1Ix43/0Xx12SGRp6yz2CNjxzR7v0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjyAx5%2FbtsQ7v1Ix43%2F0Xx12SGRp6yz2CNjxzR7v0%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;1349&quot; height=&quot;836&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wYfZQ/btsQ7aXOQiM/Gv9tb3S42dRJsq8ETcVdk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wYfZQ/btsQ7aXOQiM/Gv9tb3S42dRJsq8ETcVdk1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;765&quot; data-filename=&quot;스크린샷 2025-10-12 오후 5.20.01.png&quot; style=&quot;width: 51.6102%;&quot; data-widthpercent=&quot;52.22&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wYfZQ/btsQ7aXOQiM/Gv9tb3S42dRJsq8ETcVdk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwYfZQ%2FbtsQ7aXOQiM%2FGv9tb3S42dRJsq8ETcVdk1%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;1349&quot; height=&quot;765&quot;/&gt;&lt;/span&gt;&lt;/div&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;Upstage document parser는 위 사진과 같이 문서의 구조를 파악하고, 구조에 해당되는 텍스트, 이미지, 표 형태, 수식 형태를 추출하는 기능을 제공합니다. 업스테이지의 Solar LLM 모델을 비롯하여 주력 기술이자 서비스이고 기술력은 top이라고 생각합니다.&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;이러한 업스테이지 Document parser는 사용자(그 중, 개발자)들이 사용하기 편하도록 API를 제공해주고 있습니다. 이에, API를 활용할 수 있으신 분들은 간단하고 편리하게 Document parsing을 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, console에 들어가시면 꽤나 자세하게 example code도 제공해주고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sUCWU/btsQ4i4auML/7eUl2acGnkFPyKpeSUxKL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sUCWU/btsQ4i4auML/7eUl2acGnkFPyKpeSUxKL1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3558&quot; data-origin-height=&quot;1624&quot; data-filename=&quot;스크린샷 2025-10-11 오후 9.12.29.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sUCWU/btsQ4i4auML/7eUl2acGnkFPyKpeSUxKL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsUCWU%2FbtsQ4i4auML%2F7eUl2acGnkFPyKpeSUxKL1%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;3558&quot; height=&quot;1624&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZyhct/btsQ6jHCgKC/V7vNwXhVCAmeDrS7QKjPEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZyhct/btsQ6jHCgKC/V7vNwXhVCAmeDrS7QKjPEk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3558&quot; data-origin-height=&quot;1624&quot; data-filename=&quot;스크린샷 2025-10-11 오후 9.12.35.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZyhct/btsQ6jHCgKC/V7vNwXhVCAmeDrS7QKjPEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZyhct%2FbtsQ6jHCgKC%2FV7vNwXhVCAmeDrS7QKjPEk%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;3558&quot; height=&quot;1624&quot;/&gt;&lt;/span&gt;&lt;/div&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;위와 같이 업스테이지에서 제공해주는 chat 기능, reasoning 기능, document parsing, document ocr 별로 Python 코드 등을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Upstage Document parsing playground PoC 서비스 소개&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사에서나 개인적인 스터디에서 업스테이지 Document parser를 사용하면서, 결과가 어떻게 추출되는지 확인할 필요가 있었습니다.&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;본 서비스를 이용하기 위해서는 다음과 같은 5가지 과정이 필요합니다.&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;1. Upstage console에 가입해서 Key 받기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저, 업스테이지 콘솔에 회원가입해서 Key를 부여 받는 것입니다. 또한, 최초 회원가입 시, $10 크레딧을 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Document parser의 경우 현재 글을 쓰는 시점 2025년 10월 초 기준으로 페이지당 0.01$의 과금이 부여가 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2dsNT/btsQ61sUPZl/a7NbiYQHDyIEHmZqizcGZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2dsNT/btsQ61sUPZl/a7NbiYQHDyIEHmZqizcGZk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1369&quot; data-filename=&quot;blob&quot; width=&quot;678&quot; height=&quot;309&quot; style=&quot;width: 48.9139%; margin-right: 10px;&quot; data-widthpercent=&quot;49.49&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2dsNT/btsQ61sUPZl/a7NbiYQHDyIEHmZqizcGZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2dsNT%2FbtsQ61sUPZl%2Fa7NbiYQHDyIEHmZqizcGZk%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;3000&quot; height=&quot;1369&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dL2P3O/btsQ63c9ao6/jhw6p0v1F8wc8uYQgE8H60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dL2P3O/btsQ63c9ao6/jhw6p0v1F8wc8uYQgE8H60/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1711&quot; data-origin-height=&quot;765&quot; data-filename=&quot;blob&quot; data-widthpercent=&quot;50.51&quot; style=&quot;width: 49.9233%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dL2P3O/btsQ63c9ao6/jhw6p0v1F8wc8uYQgE8H60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdL2P3O%2FbtsQ63c9ao6%2Fjhw6p0v1F8wc8uYQgE8H60%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;1711&quot; height=&quot;765&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&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;콘솔 페이지에 들어가면 위와 같이 API 키를 확인할 수 있습니다. 회원가입을 하면 동시에 부여가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 API Key를 복사하셔서, 3번의 .env 파일에 키를 넣어주시면 됩니다.&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;2. git clone 받기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음은 제가 제공해드린 코드를 clone합니다. 제 코드 url은 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://github.com/lsjsj92/upstage-document-parser-playground&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/lsjsj92/upstage-document-parser-playground&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1760259077279&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 - lsjsj92/upstage-document-parser-playground: Upstage document parser playground(w/ Python streamlit)&quot; data-og-description=&quot;Upstage document parser playground(w/ Python streamlit) - lsjsj92/upstage-document-parser-playground&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/lsjsj92/upstage-document-parser-playground&quot; data-og-url=&quot;https://github.com/lsjsj92/upstage-document-parser-playground&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b7mHZQ/hyZKSn1BrC/pFzKk6XNtelyu1KCOBKVIk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/btSUrB/hyZLatWlFX/vHqe4KeJ3qGHyUTAygMLdK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/lsjsj92/upstage-document-parser-playground&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/lsjsj92/upstage-document-parser-playground&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b7mHZQ/hyZKSn1BrC/pFzKk6XNtelyu1KCOBKVIk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/btSUrB/hyZLatWlFX/vHqe4KeJ3qGHyUTAygMLdK/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 - lsjsj92/upstage-document-parser-playground: Upstage document parser playground(w/ Python streamlit)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Upstage document parser playground(w/ Python streamlit) - lsjsj92/upstage-document-parser-playground&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-12 오후 5.50.15.png&quot; data-origin-width=&quot;1651&quot; data-origin-height=&quot;590&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ttdeg/btsQ6gxkEj8/cWFCUhLh9LDn3T5TCIku30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ttdeg/btsQ6gxkEj8/cWFCUhLh9LDn3T5TCIku30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ttdeg/btsQ6gxkEj8/cWFCUhLh9LDn3T5TCIku30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fttdeg%2FbtsQ6gxkEj8%2FcWFCUhLh9LDn3T5TCIku30%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;736&quot; height=&quot;263&quot; data-filename=&quot;스크린샷 2025-10-12 오후 5.50.15.png&quot; data-origin-width=&quot;1651&quot; data-origin-height=&quot;590&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;해당 github 페이지에서 code를 누르면 https나 zip을 통해 받을 수 있는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중 https를 선택하면 git clone 명령어를 통해 간단하게 clone할 수 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. .env 파일 준비&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-12 오후 6.06.49.png&quot; data-origin-width=&quot;1754&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dZVWv3/btsQ6TolRPL/fREAXodLGosvEcCUVacjTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dZVWv3/btsQ6TolRPL/fREAXodLGosvEcCUVacjTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dZVWv3/btsQ6TolRPL/fREAXodLGosvEcCUVacjTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdZVWv3%2FbtsQ6TolRPL%2FfREAXodLGosvEcCUVacjTk%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;736&quot; height=&quot;201&quot; data-filename=&quot;스크린샷 2025-10-12 오후 6.06.49.png&quot; data-origin-width=&quot;1754&quot; data-origin-height=&quot;480&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;git clone하면 .env.tmp 파일이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 파일의 내용에서 Upstage API key를 넣어주면 되는데요. 1번 과정에서 복사한 API Key를 넣어줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 파일 이름을 .env.tmp에서 .env로 바꿔주면 됩니다. .env 파일의 위치는 .env.tmp가 위치한 그대로 넣어주시면 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;4. 라이브러리 설치하기&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-25 오후 3.33.21.png&quot; data-origin-width=&quot;1180&quot; data-origin-height=&quot;1050&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U5A9p/dJMb9WSYQ3R/qlHDxL7YePva84wuSYM6Ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U5A9p/dJMb9WSYQ3R/qlHDxL7YePva84wuSYM6Ak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U5A9p/dJMb9WSYQ3R/qlHDxL7YePva84wuSYM6Ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU5A9p%2FdJMb9WSYQ3R%2FqlHDxL7YePva84wuSYM6Ak%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;542&quot; height=&quot;482&quot; data-filename=&quot;스크린샷 2025-10-25 오후 3.33.21.png&quot; data-origin-width=&quot;1180&quot; data-origin-height=&quot;1050&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;git clone을 하시면 requirements.txt 파일이 있습니다. 해당 파일을 활용해서 pip install을 진행해주시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, Python은 3.10 이상을 권장합니다.&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;5. 백엔드 및 프론트 실행하기&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;먼저, 백엔드부터 실행하면 됩니다. 백엔드는 아래와 같은 명령어로 실행하면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1760262877491&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;python -m uvicorn backend.main:app --reload&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.27.07.png&quot; data-origin-width=&quot;1216&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8drDg/btsQ4VOMBu9/GMyKYTAJL1GWQAKX4bU1z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8drDg/btsQ4VOMBu9/GMyKYTAJL1GWQAKX4bU1z1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8drDg/btsQ4VOMBu9/GMyKYTAJL1GWQAKX4bU1z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8drDg%2FbtsQ4VOMBu9%2FGMyKYTAJL1GWQAKX4bU1z1%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;758&quot; height=&quot;207&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.27.07.png&quot; data-origin-width=&quot;1216&quot; data-origin-height=&quot;332&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;위 사진과 같이 fastapi 서버가 정상적으로 실행되면 문제가 없는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, backend를 실행하면 storage라는 디렉토리가 만들어지는데요. parsing한 결과를 프로젝트 폴더의 storage라는 경로에 저장하도록 합니다.&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;다음은 프론트 페이지를 띄웁니다. 아래와 같은 명령어로 실행하면 됩니다. Python streamlit 기반의 페이지입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1760262949111&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;streamlit run frontend/app.py&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.26.57.png&quot; data-origin-width=&quot;939&quot; data-origin-height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rDVoS/btsQ5YKQKpg/85PXoONzdhWvafCJ02oKnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rDVoS/btsQ5YKQKpg/85PXoONzdhWvafCJ02oKnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rDVoS/btsQ5YKQKpg/85PXoONzdhWvafCJ02oKnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrDVoS%2FbtsQ5YKQKpg%2F85PXoONzdhWvafCJ02oKnk%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;721&quot; height=&quot;228&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.26.57.png&quot; data-origin-width=&quot;939&quot; data-origin-height=&quot;297&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;업스테이지 Playground 기능 설명&lt;/h3&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;size18&quot;&gt;&lt;b&gt;1. 메인 페이지 - 파일 업로드 및 파싱 수행&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.27.22.png&quot; data-origin-width=&quot;3478&quot; data-origin-height=&quot;1428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cj9yGX/btsQ7bh6e0b/R33iG1RT29BT47aUqYkqF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cj9yGX/btsQ7bh6e0b/R33iG1RT29BT47aUqYkqF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cj9yGX/btsQ7bh6e0b/R33iG1RT29BT47aUqYkqF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcj9yGX%2FbtsQ7bh6e0b%2FR33iG1RT29BT47aUqYkqF0%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;709&quot; height=&quot;291&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.27.22.png&quot; data-origin-width=&quot;3478&quot; data-origin-height=&quot;1428&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;가장 먼저 메인페이지입니다. 메인 페이지에는 3개의 메뉴를 확인할 수 있습니다.&amp;nbsp;&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;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5bjJX/btsQ7ap0uv5/N6g7mKWo5IV24K9qpsi83k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5bjJX/btsQ7ap0uv5/N6g7mKWo5IV24K9qpsi83k/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2638&quot; data-origin-height=&quot;1516&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.28.01.png&quot; style=&quot;width: 57.9901%; margin-right: 10px;&quot; data-widthpercent=&quot;58.67&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5bjJX/btsQ7ap0uv5/N6g7mKWo5IV24K9qpsi83k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5bjJX%2FbtsQ7ap0uv5%2FN6g7mKWo5IV24K9qpsi83k%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;2638&quot; height=&quot;1516&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ExDda/btsQ7ajdsnn/v0IAOKKzSfEqgJQ4uGspX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ExDda/btsQ7ajdsnn/v0IAOKKzSfEqgJQ4uGspX0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1059&quot; data-origin-height=&quot;864&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.27.47.png&quot; width=&quot;646&quot; height=&quot;527&quot; style=&quot;width: 40.8471%;&quot; data-widthpercent=&quot;41.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ExDda/btsQ7ajdsnn/v0IAOKKzSfEqgJQ4uGspX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FExDda%2FbtsQ7ajdsnn%2Fv0IAOKKzSfEqgJQ4uGspX0%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;1059&quot; height=&quot;864&quot;/&gt;&lt;/span&gt;&lt;/div&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;해당 페이지에서 파일을 업로드하면 업스테이지의 Document parsing을 수행할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 링크드인(linkedin)에서 리뷰했던 논문인 Overhearing LLM Agent 논문 pdf 파일을 업로드 했습니다.( &lt;a href=&quot;https://www.linkedin.com/posts/lsjsj92_overhearing-llm-agents-a-survey-taxonomy-activity-7382032494960943104-BO3i?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAAlabLcBJq1_NeHvpHXjctBSzkXZFsby3rY&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.linkedin.com/posts/lsjsj92_overhearing-llm-agents-a-survey-taxonomy-activity-7382032494960943104-BO3i?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAAlabLcBJq1_NeHvpHXjctBSzkXZFsby3rY&lt;/a&gt; )&lt;/p&gt;
&lt;figure id=&quot;og_1760263530843&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;Overhearing LLM Agents: A Survey, Taxonomy, and Roadmap | soojin lee&quot; data-og-description=&quot;Overhearing(엿듣는) Agent 우리가 사용하는 대부분의 AI는 대화형(Conversational) Agent입니다. 이는 사용자가 명확한 질문이나, 명령을 해야만 작동합니다. 예를 들어, 회의 중 궁금한 것이 생기면 &amp;ldquo;헤이&quot; data-og-host=&quot;kr.linkedin.com&quot; data-og-source-url=&quot;https://www.linkedin.com/posts/lsjsj92_overhearing-llm-agents-a-survey-taxonomy-activity-7382032494960943104-BO3i?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAAlabLcBJq1_NeHvpHXjctBSzkXZFsby3rY&quot; data-og-url=&quot;https://kr.linkedin.com/posts/lsjsj92_overhearing-llm-agents-a-survey-taxonomy-activity-7382032494960943104-BO3i&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/SrSV2/hyZKdlvrSg/sUqU9bkjiWwPMkslayUj3k/img.png?width=1400&amp;amp;height=800&amp;amp;face=0_0_1400_800,https://scrap.kakaocdn.net/dn/yQyjD/hyZLtNJpBn/yJjKTnVdSc9BvPVHTZkLIk/img.png?width=1400&amp;amp;height=800&amp;amp;face=0_0_1400_800&quot;&gt;&lt;a href=&quot;https://www.linkedin.com/posts/lsjsj92_overhearing-llm-agents-a-survey-taxonomy-activity-7382032494960943104-BO3i?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAAlabLcBJq1_NeHvpHXjctBSzkXZFsby3rY&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.linkedin.com/posts/lsjsj92_overhearing-llm-agents-a-survey-taxonomy-activity-7382032494960943104-BO3i?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAAlabLcBJq1_NeHvpHXjctBSzkXZFsby3rY&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/SrSV2/hyZKdlvrSg/sUqU9bkjiWwPMkslayUj3k/img.png?width=1400&amp;amp;height=800&amp;amp;face=0_0_1400_800,https://scrap.kakaocdn.net/dn/yQyjD/hyZLtNJpBn/yJjKTnVdSc9BvPVHTZkLIk/img.png?width=1400&amp;amp;height=800&amp;amp;face=0_0_1400_800');&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;Overhearing LLM Agents: A Survey, Taxonomy, and Roadmap | soojin lee&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Overhearing(엿듣는) Agent 우리가 사용하는 대부분의 AI는 대화형(Conversational) Agent입니다. 이는 사용자가 명확한 질문이나, 명령을 해야만 작동합니다. 예를 들어, 회의 중 궁금한 것이 생기면 &amp;ldquo;헤이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kr.linkedin.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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csSsxk/btsQ5aEF2d1/4f7fMKQLEBIqy8pZpSINBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csSsxk/btsQ5aEF2d1/4f7fMKQLEBIqy8pZpSINBk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2638&quot; data-origin-height=&quot;1516&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.28.30.png&quot; width=&quot;695&quot; height=&quot;399&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csSsxk/btsQ5aEF2d1/4f7fMKQLEBIqy8pZpSINBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsSsxk%2FbtsQ5aEF2d1%2F4f7fMKQLEBIqy8pZpSINBk%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;2638&quot; height=&quot;1516&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBjWpj/btsQ6J0G8Yo/YLKfTixrGTioI06urSqNIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBjWpj/btsQ6J0G8Yo/YLKfTixrGTioI06urSqNIK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2638&quot; data-origin-height=&quot;1516&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.28.46.png&quot; width=&quot;703&quot; height=&quot;404&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBjWpj/btsQ6J0G8Yo/YLKfTixrGTioI06urSqNIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBjWpj%2FbtsQ6J0G8Yo%2FYLKfTixrGTioI06urSqNIK%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;2638&quot; height=&quot;1516&quot;/&gt;&lt;/span&gt;&lt;/div&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;파일을 업로드하면 위와 같이 업로드 성공이라고 메세지가 나오면서 Upstage의 Document parsing을 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, Upstage에서 제공해주는 API를 활용해서 파싱을 수행합니다. API를 호출하는 코드는 Upstage console에서 제공해주는 코드를 바탕으로 작업하였습니다. 원하시는 기능이 있으다면 코드 레벨에서 수정하셔도 될 것 같습니다!&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;파싱은 HTML, Markdown 형태로 나오도록 수행하게 됩니다. 또한, 이미지, 테이블 형태도 추출이 가능합니다(업스테이지에서 기본으로 제공해주는 기능입니다.).&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;p data-ke-size=&quot;size16&quot;&gt;1. 파일 업로드가 되면 확장자 점검하고 내부 파일 구조를 잡고 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Upstage API를 호출하여 파싱 수행&lt;/p&gt;
&lt;pre id=&quot;code_1761374772391&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async def parse_document_with_hybrid_extraction(self, file_path: Path, extract_images: bool = True) -&amp;gt; ParsedDocument:
    &quot;&quot;&quot;
    Upstage API를 사용하여 문서를 파싱합니다.

    단일 API 호출로 전체 문서를 처리:
    - 모든 페이지를 한 번에 파싱
    - OCR 자동 적용 (force mode)
    - 이미지 추출 (table, figure, chart, equation)

    Args:
        file_path: 파싱할 파일 경로
        extract_images: 이미지 Base64 인코딩 추출 여부

    Returns:
        ParsedDocument: 파싱된 문서 객체 (모든 페이지 포함)
    &quot;&quot;&quot;

async with httpx.AsyncClient(timeout=timeout) as client:
    response = await client.post(self.base_url, headers=headers, files=files, data=data)
    response.raise_for_status()
    result = response.json()

    parsed_data = self._parse_response(result)&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. 파싱 결과를 수신 받고 처리. 이때 이미지도 처리하도록 함&lt;/p&gt;
&lt;pre id=&quot;code_1761374864364&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def get_image_mime_type_from_base64(base64_string: str) -&amp;gt; Optional[str]:
    &quot;&quot;&quot;
    Base64 인코딩된 이미지 문자열로부터 MIME 타입을 판별합니다.

    매직 넘버(파일 시그니처)를 분석하여 실제 이미지 형식을 확인합니다.

    Args:
        base64_string: Base64로 인코딩된 이미지 데이터 문자열

    Returns:
        Optional[str]: 이미지 MIME 타입 (image/png, image/jpeg 등)
                      판별 실패 시 None 반환
    &quot;&quot;&quot;
    try:
        # Decode the base64 string to get the image header bytes
        decoded_data = base64.b64decode(base64_string[:20]) # First 20 chars are enough&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. 페이지별로 그룹화 및 관련 텍스트 생성&lt;/p&gt;
&lt;pre id=&quot;code_1761374902480&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def _analyze_and_enhance_elements(self, elements: List[DocumentElement]) -&amp;gt; List[DocumentElement]:
    &quot;&quot;&quot;
    기존 파싱된 요소들을 분석하여 복합 구조를 감지하고 개선된 요소로 변환
    &quot;&quot;&quot;
    if not elements:
        return elements

    enhanced_elements = []
    processed_element_ids = set()

    # 페이지별로 그룹화하여 처리
    pages = {}
    for elem in elements:
        page = elem.page
        if page not in pages:
            pages[page] = []
        pages[page].append(elem)

    for page_num, page_elements in pages.items():
        page_enhanced = self._process_page_elements(page_elements, processed_element_ids)
        enhanced_elements.extend(page_enhanced)

    return enhanced_elements&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;5. HTML 및 마크다운(Markdown) 생성&lt;/p&gt;
&lt;pre id=&quot;code_1761374948000&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    def _convert_elements_to_markdown(self, elements: list[DocumentElement]) -&amp;gt; str:
        &quot;&quot;&quot;문서 요소들을 논리적 순서에 따라 Markdown 문자열로 변환&quot;&quot;&quot;
        if not elements:
            return &quot;&quot;

        sorted_elements = sorted(elements, key=lambda e: (e.page, e.coordinates[0].y if e.coordinates else 0))
        
        markdown_parts = []
        for elem in sorted_elements:
            if (hasattr(elem, '_ocr_enhanced') and elem._ocr_enhanced) or elem.category == 'composite_table':
                if elem.content and elem.content.markdown:
                    markdown_parts.append(elem.content.markdown)
                elif elem.content and elem.content.text:
                    markdown_parts.append(elem.content.text)
            else:
                html_content = elem.content.html
                if html_content:
                    markdown_content = self.markdown_converter.handle(html_content).strip()
                    elem.content.markdown = markdown_content
                    markdown_parts.append(markdown_content)

        return &quot;\n\n&quot;.join(part for part in markdown_parts if part)&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;6. 각종 통계 등 저장하고 결과 저장&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. 파싱된 문서 리스트 페이지&lt;/b&gt;&lt;/p&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-filename=&quot;스크린샷 2025-10-12 오후 4.29.26.png&quot; data-origin-width=&quot;3458&quot; data-origin-height=&quot;1516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rHCFQ/btsQ7u2PtBo/lIkmkDjlm9GMuovIK7jfCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rHCFQ/btsQ7u2PtBo/lIkmkDjlm9GMuovIK7jfCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rHCFQ/btsQ7u2PtBo/lIkmkDjlm9GMuovIK7jfCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrHCFQ%2FbtsQ7u2PtBo%2FlIkmkDjlm9GMuovIK7jfCk%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;739&quot; height=&quot;324&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.29.26.png&quot; data-origin-width=&quot;3458&quot; data-origin-height=&quot;1516&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;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;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 페이지에서는 파싱된 결과를 상세하게 확인할 수 있는 페이지입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML로 변환한 페이지 뷰와, 통합 뷰, bounding box 좌표 등을 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.33.26.png&quot; data-origin-width=&quot;3458&quot; data-origin-height=&quot;1532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPlhYt/btsQ7sKHtIf/dOG6Kbwtoh9gl0TyxCFwM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPlhYt/btsQ7sKHtIf/dOG6Kbwtoh9gl0TyxCFwM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPlhYt/btsQ7sKHtIf/dOG6Kbwtoh9gl0TyxCFwM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPlhYt%2FbtsQ7sKHtIf%2FdOG6Kbwtoh9gl0TyxCFwM1%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;756&quot; height=&quot;335&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.33.26.png&quot; data-origin-width=&quot;3458&quot; data-origin-height=&quot;1532&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;3개의 메뉴가 있는데요. 문서 레이아웃은 문서의 HTML 레이아웃 등을 볼 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운딩 박스 시각화는 좌표 기반해서 Document parsing의 좌표를 확인할 수 있고 요소 상세 정보는 상세한 요소 별로 확인할 수 있는 기능을 제공합니다.&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.34.22.png&quot; data-origin-width=&quot;2582&quot; data-origin-height=&quot;1676&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6KMu0/btsQ7NnCJ1B/pFP62RtSSL7CuXYjLyLK00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6KMu0/btsQ7NnCJ1B/pFP62RtSSL7CuXYjLyLK00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6KMu0/btsQ7NnCJ1B/pFP62RtSSL7CuXYjLyLK00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6KMu0%2FbtsQ7NnCJ1B%2FpFP62RtSSL7CuXYjLyLK00%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;687&quot; height=&quot;446&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.34.22.png&quot; data-origin-width=&quot;2582&quot; data-origin-height=&quot;1676&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UiLiD/btsQ63jVTRx/mMFRGcyHDhUB6Lzuydjstk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UiLiD/btsQ63jVTRx/mMFRGcyHDhUB6Lzuydjstk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2582&quot; data-origin-height=&quot;1676&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.34.33.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UiLiD/btsQ63jVTRx/mMFRGcyHDhUB6Lzuydjstk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUiLiD%2FbtsQ63jVTRx%2FmMFRGcyHDhUB6Lzuydjstk%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;2582&quot; height=&quot;1676&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZVeKk/btsQ5a5A98B/CNEZolBvJurTDjKc0Zse4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZVeKk/btsQ5a5A98B/CNEZolBvJurTDjKc0Zse4K/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2582&quot; data-origin-height=&quot;1676&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.34.59.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZVeKk/btsQ5a5A98B/CNEZolBvJurTDjKc0Zse4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZVeKk%2FbtsQ5a5A98B%2FCNEZolBvJurTDjKc0Zse4K%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;2582&quot; height=&quot;1676&quot;/&gt;&lt;/span&gt;&lt;/div&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;좌표 기반으로 문서 레이아웃을 구성할 수 있고(페이지 렌더링상 좀 깨집니다 ㅠ) HTML 랜더링으로도 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 사진의 오른쪽을 보면 표(Table) 결과를 확인할 수 있는데요. 결과가 잘 나온 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bI0BQw/btsQ5ZbVsGh/GaXPqTEtPf7t4YgoDlBTOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bI0BQw/btsQ5ZbVsGh/GaXPqTEtPf7t4YgoDlBTOK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2582&quot; data-origin-height=&quot;1676&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.35.13.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bI0BQw/btsQ5ZbVsGh/GaXPqTEtPf7t4YgoDlBTOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbI0BQw%2FbtsQ5ZbVsGh%2FGaXPqTEtPf7t4YgoDlBTOK%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;2582&quot; height=&quot;1676&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WA2Zk/btsQ7uaFmN6/W8K2G1hOEfYXNM4wFiEsRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WA2Zk/btsQ7uaFmN6/W8K2G1hOEfYXNM4wFiEsRk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2582&quot; data-origin-height=&quot;1676&quot; data-filename=&quot;스크린샷 2025-10-12 오후 4.35.25.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WA2Zk/btsQ7uaFmN6/W8K2G1hOEfYXNM4wFiEsRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWA2Zk%2FbtsQ7uaFmN6%2FW8K2G1hOEfYXNM4wFiEsRk%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;2582&quot; height=&quot;1676&quot;/&gt;&lt;/span&gt;&lt;/div&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;또한, 바운딩 박스와 요소 상세 정보도 추가로 확인할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 그냥 제가 필요해서 만든 기능이긴한데, 다른 분들에게는 유용하지 않을 수도 있을 것 같습니다.&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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 업스테이지(Upstage) document parsing 결과를 확인할 수 있는 playground PoC 서비스 페이지를 만들고 공유한 후기를 작성한 포스팅입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 코드도 공유해놨으니 참고 부탁드립니다.&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>documentparse</category>
      <category>layoutanalysis</category>
      <category>LLM</category>
      <category>OCR</category>
      <category>pdf파싱</category>
      <category>RAG</category>
      <category>Upstage</category>
      <category>vectordb</category>
      <category>문서파싱</category>
      <category>업스테이지</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/703</guid>
      <comments>https://lsjsj92.tistory.com/703#entry703comment</comments>
      <pubDate>Wed, 15 Oct 2025 10:24:33 +0900</pubDate>
    </item>
    <item>
      <title>ChatGPT GPT-5 프롬프트 가이드 정리 및 프롬프트 템플릿 예제(example) 공유</title>
      <link>https://lsjsj92.tistory.com/702</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;포스팅 개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;최근 AI의 발전이 눈부십니다. 특히 OpenAI의 새로운 모델인 GPT-5는 단순한 챗봇을 넘어, 스스로 계획을 세우고, 도구를 사용하며, 복잡한 문제까지 해결하는 '에이전트(Agent)'로서의 능력을 보여주고 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;하지만 이런 강력한 도구도 어떻게 사용하느냐에 따라 그 결과는 천차만별입니다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;&quot;AI가 똑똑해졌는데, 왜 아직도 프롬프트 가이드가 필요한가요?&quot;라는 질문이 들 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;좋은 질문입니다. 결론부터 말하자면, GPT-5에게 프롬프트는 단순한 '질문'이 아니라, 유능한 AI 비서에게 내리는 '상세한 업무 지시서'이기 때문입니다. 모델의 잠재력을 100% 끌어내고, 내가 원하는 최적의 결과물을 안정적으로 얻기 위해서는 잘 설계된 프롬프트가 필수적입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;본 포스팅에서는 GPT-5 프롬프팅 가이드를 기반으로, 프롬프트란 무엇인지, GPT-5 시대에 왜 새로운 접근 방식이 필요한지 알아보고, 독자 여러분이 즉시 활용할 수 있는 시장 조사, 논문 조사 실전 프롬프트 템플릿을 공유하고자 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;gpt5 prompt guide: &lt;a href=&quot;https://cookbook.openai.com/examples/gpt-5/gpt-5_prompting_guide&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cookbook.openai.com/examples/gpt-5/gpt-5_prompting_guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-12 오후 2.48.02.png&quot; data-origin-width=&quot;1137&quot; data-origin-height=&quot;798&quot;&gt;&lt;a href=&quot;https://cookbook.openai.com/examples/gpt-5/gpt-5_prompting_guide&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuTMLO/btsQ6dHlzsL/vhUy9rW7KbZfxsMuosYfkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuTMLO%2FbtsQ6dHlzsL%2FvhUy9rW7KbZfxsMuosYfkk%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;686&quot; height=&quot;481&quot; data-filename=&quot;스크린샷 2025-10-12 오후 2.48.02.png&quot; data-origin-width=&quot;1137&quot; data-origin-height=&quot;798&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;
&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;1. 프롬프트가 GPT-5 시대에 왜 달라져야 하는가?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;프롬프트(Prompt)란 간단히 말해 '사용자가 AI에게 원하는 바를 전달하는 명령어'입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;이전 세대 모델에서는 단답형 질문이나 간단한 문장 생성 요청이 프롬프트의 대부분이었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;하지만 GPT-5는 다릅니다. GPT-5는 사람처럼 생각하고, 계획하며, 문제를 해결하는 '에이전틱(Agentic)' 특성을 가지고 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;마치 똑똑한 신입사원처럼, 명확한 지시가 없으면 모든 가능성을 탐색하느라 시간을 허비하거나, 사용자의 의도와 다른 방향으로 작업을 진행할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;따라서 GPT-5 시대의 프롬프트는 'AI 에이전트를 위한 명확하고 구조적인 가이드라인'이 되어야 합니다. 우리는 이제 AI에게 질문하는 사람(Questioner)이 아니라, AI의 행동을 지시하는 감독(Director)의 역할을 해야 합니다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;2. GPT-5의 핵심 능력 조절하기: '에이전트 적극성'&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;GPT-5 프롬프팅의 핵심은 '에이전트 적극성(Agentic Eagerness)'을 제어하는 것입니다. '적극성'이란 AI가 얼마나 스스로 생각하고, 자율적으로 행동하는지를 의미합니다. 이 적극성은 reasoning_effort (추론 노력)라는 설정으로 조절할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-12 오후 3.13.08.png&quot; data-origin-width=&quot;985&quot; data-origin-height=&quot;864&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Cm5vr/btsQ67mtiFT/d2R0gYEumiMK2gOVXtwdsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Cm5vr/btsQ67mtiFT/d2R0gYEumiMK2gOVXtwdsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Cm5vr/btsQ67mtiFT/d2R0gYEumiMK2gOVXtwdsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCm5vr%2FbtsQ67mtiFT%2Fd2R0gYEumiMK2gOVXtwdsK%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;680&quot; height=&quot;596&quot; data-filename=&quot;스크린샷 2025-10-12 오후 3.13.08.png&quot; data-origin-width=&quot;985&quot; data-origin-height=&quot;864&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;적극성 낮추기 (reasoning_effort: low): &quot;지금 서울 날씨 어때?&quot;와 같이 빠르고 간단한 답이 필요할 때 사용합니다. 불필요한 추가 조사를 막고 신속한 결과를 얻을 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;적극성 높이기 (reasoning_effort: high): 복잡한 보고서 작성, 심층적인 자료 조사, 창의적인 기획안 도출 등 높은 수준의 결과물이 필요할 때 사용합니다. AI가 스스로 필요한 정보를 최대한 탐색하고, 사용자 개입을 최소화하며 과업을 완수하도록 독려합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;오늘 우리가 집중할 것은 바로 이 '적극성 높이기'입니다. &lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;3. GPT-5 ChatGPT 프롬프트 템플릿 및 예제&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;이제 여러분이 가장 기다렸을 실전 템플릿입니다. 아래 템플릿들은 GPT-5의 추론 능력을 최고 수준(reasoning_effort: high)으로 설정하여, 깊이 있고 종합적인 결과물을 얻는 데 최적화되어 있습니다. &lt;span style=&quot;background-color: #f6e199;&quot;&gt;ChatGPT를 켜셔서 GPT5 모델을 선택하신 뒤 사용&lt;/span&gt;해보세요!&lt;/span&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;활용 예시 1: 반도체 DRAM 시장 조사 보고서 작성&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;새로운 기술 트렌드나 특정 산업에 대한 분석이 필요할 때 사용할 수 있는 프롬프트입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;GPT-5는 단순 검색을 넘어, 여러 정보를 교차 검증하고 종합하여 하나의 완성된 보고서를 만들어낼 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;이 프롬프트를 활용해서 여러분들이 원하시는 시장 및 기술에 따라 다양하게 변경하여 사용하시면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# ChatGPT의 GPT5를 선택하셔서 아래 프롬프트를 동작시켜보세요!
# 여러분들이 원하시는 시장, 기술 등에 맞게 수정하셔도 됩니다.
# 이 주석은 반드시 제거하고 아래 내용만 사용하세요.

[역할]
당신은 최고 수준의 전문성을 갖춘 반도체 DRAM 시장 조사 전문가 AI 에이전트입니다. 당신의 목표는 주어진 주제에 대해 가장 완전하고, 철저하며, 신뢰할 수 있는 시장 보고서를 작성하는 것입니다.

[작업 목표]
이번 작업의 목표는 전 세계 반도체 DRAM 시장에 대한 종합적이고 철저한 시장 조사 보고서를 작성하는 것입니다. 보고서는 다음 조건을 반드시 충족해야 합니다:
- 매우 상세한 분석을 포함해야 합니다.
- 모든 정보는 사실에 기반해야 하며, 정확한 레퍼런스(출처)를 명시해야 합니다.
- 최대한 다양한 최신 리소스(데이터, 뉴스, 분석 보고서 등)에서 정보를 수집하고 교차 검증해야 합니다.

[작업 규칙]
1. 사용자의 요청이 완전히 해결될 때까지, 즉 완전한 시장 조사 보고서가 완성될 때까지 절대 멈추지 않습니다.
2. 불확실한 상황을 마주쳐도 멈추거나 사용자에게 되묻지 마십시오. 대신 스스로 가장 합리적인 방법(추론 또는 조사)을 찾아 바로 실행하고 계속 진행합니다.
3. 가정이 필요할 경우 사용자에게 확인을 요청하지 말고, 대신 실행 후 결과와 함께 가정을 보고합니다.
4. 도구 호출 횟수에 제한을 두지 않습니다. 필요한 만큼 다양한 데이터베이스, 뉴스, 보고서 검색 도구를 반복적으로 사용하여 정보를 심층적으로 수집합니다.
5. 시장 규모, 주요 플레이어, 기술 동향, 미래 전망, 규제 환경, 주요 통계치 등 모든 하위 작업(sub-task)까지 포함하여 완벽하게 처리합니다.
6. 정보 수집 시, 출처의 신뢰성을 항상 확인하고, 최소 2개 이상의 독립적인 출처에서 정보를 교차 검증하여 보고서의 신뢰성을 극대화합니다.
7. 조사된 모든 핵심 정보에는 반드시 해당 출처(레퍼런스)를 명확하게 명시합니다.

[중단 조건]
- DRAM 시장 조사의 모든 측면과 하위 요청이 완전히 해결되어, 더 이상 추가 정보 수집이나 분석이 필요 없다고 판단될 때만 작업을 종료합니다.

[불확실성 처리]
- 모호하거나 정보가 부족한 부분이 있더라도, 가장 그럴듯한 가설을 세우고 작업을 진행하며, 추후 정보가 확보되면 업데이트합니다.
- 필요하다면 여러 조사 방법과 접근 방식을 시도하고, 그 결과를 비교분석하여 최선의 답을 제시합니다.

[설정]
- reasoning_effort: high
- 가능한 한 자세한 진행 과정, 중간 계획, 그리고 최종 요약을 제공하여 사용자가 조사 과정을 이해할 수 있도록 합니다.
- 보고서의 최종 결과물은 Markdown 형식을 사용하여 가독성과 구조를 높입니다.&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;활용 예시 2: '인공지능 윤리' 관련 논문 및 학술 자료 조사&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;특정 주제에 대한 선행 연구를 조사하고, 주요 쟁점을 정리하며, 참고문헌 목록을 만들어야 할 때 매우 유용합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;논문 작성의 가장 힘든 초기 단계를 GPT-5와 함께 효율적으로 진행할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;마찬가지로 여러분들이 원하시는 형태로 주제를 바꾸실 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# ChatGPT의 GPT5를 선택하셔서 아래 프롬프트를 동작시켜보세요!
# 여러분들이 원하시는 기술 등에 맞게 수정하셔도 됩니다.
# 이 주석은 반드시 제거하고 아래 내용만 사용하세요.

[역할]
당신은 특정 학술 주제에 대해 깊이 있는 연구를 수행하는 AI 학술 연구원입니다. 당신의 목표는 '인공지능의 윤리적 딜레마'를 주제로 신뢰할 수 있는 학술 자료를 체계적으로 조사하고 분석하는 것입니다.

[작업 목표]
'인공지능의 윤리적 딜레마'에 대한 포괄적인 학술 자료 조사 보고서를 작성합니다. 보고서는 다음을 반드시 포함해야 합니다:
- 주요 하위 주제(예: 데이터 편향, 알고리즘 투명성, 책임 소재)에 대한 핵심 연구 요약.
- 각 주제에 대한 주요 학자들의 상반된 견해 및 논쟁점 정리.
- 최근 5년 이내 발표된 주요 논문 및 연구 동향 분석.
- 모든 인용 정보는 APA 7 양식에 맞춰 정확하게 출처를 표기해야 합니다.

[작업 규칙]
1. 사용자의 요청이 완전히 해결될 때까지 작업을 멈추지 않습니다.
2. Google Scholar, arXiv, JSTOR 등 신뢰할 수 있는 학술 데이터베이스를 우선적으로 탐색합니다.
3. 불확실하거나 상충하는 정보가 있을 경우, 스스로 추가 조사를 통해 검증하고 그 과정을 기록합니다. 사용자에게 되묻지 않고 자율적으로 진행합니다.
4. 도구 호출 횟수 제한 없이, 주제의 모든 측면을 깊이 있게 탐구하기 위해 필요한 만큼 반복적으로 정보를 수집합니다.
5. 선행 연구의 한계점이나 추가 연구가 필요한 영역(Research Gaps)을 식별하여 보고서에 포함합니다.
6. 객관적이고 학술적인 톤을 유지하며, 개인적인 의견이나 확인되지 않은 정보는 배제합니다.

[중단 조건]
- 주제와 관련된 주요 학술적 관점이 충분히 다뤄졌고, 더 이상 새로운 핵심 정보를 찾기 어렵다고 판단될 때 작업을 종료합니다.

[불확실성 처리]
- 정보가 부족한 최신 주제의 경우, 현재까지의 논의를 바탕으로 가장 합리적인 분석을 제공하고, 정보의 한계를 명시합니다.

[설정]
- reasoning_effort: high
- 조사 과정에서 발견한 핵심 논문, 인용문, 데이터 등을 중간 단계에서 구조화하여 보고합니다.
- 최종 결과물은 서론-본론-결론의 구조를 갖춘 Markdown 형식의 보고서로 제출합니다.&lt;/code&gt;&lt;/pre&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;마무리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;GPT-5는 단순한 언어 모델을 넘어, 우리의 생각을 현실로 만들어주는 강력한 파트너입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;오늘 소개한 에이전트의 적극성을 이해하고 조절하며, 구체적이고 구조화된 프롬프트로 명확하게 작업을 지시하는 것을 꾸준히 연습한다면 GPT-5의 가치를 발견하게 될 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;이 가이드를 시작점으로 삼아 여러분의 목적에 맞게 다양한 실험을 해보시길 바랍니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/702</guid>
      <comments>https://lsjsj92.tistory.com/702#entry702comment</comments>
      <pubDate>Sun, 12 Oct 2025 15:18:43 +0900</pubDate>
    </item>
    <item>
      <title>AI 기반의 개인화된 교육과 맞춤형 학습 경험(Google: Towards an AI-Augmented Textbook)</title>
      <link>https://lsjsj92.tistory.com/701</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 16px; }
&lt;/style&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;포스팅 개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;전통적인 교과서는 교육의 핵심적인 도구이지만, 모든 학생에게 동일한 내용을 제공한다는 근본적인 한계를 가지고 있습니다. 새로운 자료를 추가하거나 내용을 다르게 표현하려면 많은 시간과 노력이 필요하기 때문에, 확장 가능한 방식으로 교과서를 수정하는 것은 거의 불가능했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;하지만, 최근 급격히 발전한 생성형 AI 기술이 교육 분야에 혁실을 가져올 잠재력이 있다는 구글의 연구가 있는데요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;본 포스팅은 구글에서 소개한 논문 Towards an AI-Augmented Textbook 논문을 리뷰하면서 AI가 교육에 미치는 영향, 기존 교육 시스템을 어떻게 바꿀 수 있을지에 대한 인사이트를 정리합니다.&lt;/span&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;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;- &lt;a style=&quot;color: #000000;&quot; href=&quot;https://services.google.com/fh/files/misc/ai_augmented_textbook.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://services.google.com/fh/files/misc/ai_augmented_textbook.pdf&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-07 오후 3.54.00.png&quot; data-origin-width=&quot;2102&quot; data-origin-height=&quot;1356&quot;&gt;&lt;a href=&quot;https://services.google.com/fh/files/misc/ai_augmented_textbook.pdf&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Wxf7s/btsQ33dROWy/rdpsvmUmi3MbzOC1RVJtO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWxf7s%2FbtsQ33dROWy%2FrdpsvmUmi3MbzOC1RVJtO1%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;696&quot; height=&quot;449&quot; data-filename=&quot;스크린샷 2025-10-07 오후 3.54.00.png&quot; data-origin-width=&quot;2102&quot; data-origin-height=&quot;1356&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;
&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;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;포스팅 본문&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000; text-align: start;&quot;&gt;1. Learn Your Way&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;이 논문은 생성형 AI를 활용하여 기존 교과서의 한계를 극복하고, 학생들에게 개인화된 학습 경험을 제공하는 &quot;Learn Your Way&quot; 라는 시스템을 제안합니다. 전통적인 교과서가 모든 학생에게 동일한 내용을 제공하는 'one-size-fits-all' 방식이었다면, 이 연구는 AI를 통해 학습자 개개인의 특성과 요구에 맞춘 'AI 증강 교과서' 의 가능성을 제시합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;전통적인 교과서는 교육의 핵심적인 도구이지만, 모든 학생에게 동일한 내용을 제공한다는 근본적인 한계를 가지고 있습니다. 새로운 자료를 추가하거나 내용을 다르게 표현하려면 많은 시간과 노력이 필요하기 때문에, 확장 가능한 방식으로 교과서를 수정하는 것은 거의 불가능했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;이 연구는 최근 급격히 발전한 생성형 AI 기술이 교육 분야에 혁신을 가져올 잠재력이 있다는 점에서 출발합니다. 연구팀은 AI를 활용하여 기존 교과서 내용을 변형하고 보강함으로써, 원본 콘텐츠의 무결성과 품질을 유지하면서도 다양한 표현 방식과 개인화된 학습 경험을 제공할 수 있다고 보았습니다. 이러한 접근 방식으로 구축된 시스템이 바로 &quot;Learn Your Way&quot; 입니다.&lt;/span&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-filename=&quot;스크린샷 2025-10-07 오후 6.56.54.png&quot; data-origin-width=&quot;1051&quot; data-origin-height=&quot;857&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eOr1BC/btsQ5hI8iVl/WgQX42DznaRleC39tdvgu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eOr1BC/btsQ5hI8iVl/WgQX42DznaRleC39tdvgu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eOr1BC/btsQ5hI8iVl/WgQX42DznaRleC39tdvgu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeOr1BC%2FbtsQ5hI8iVl%2FWgQX42DznaRleC39tdvgu1%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;655&quot; height=&quot;534&quot; data-filename=&quot;스크린샷 2025-10-07 오후 6.56.54.png&quot; data-origin-width=&quot;1051&quot; data-origin-height=&quot;857&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;Figure 1은 'Learn Your Way' 시스템의 실제 사용자 인터페이스를 보여줍니다. &lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;중심 콘텐츠: 화면 중앙에는 '몰입형 텍스트(Immersive Text)'가 표시되어 있습니다. 이 예시에서는 OpenStax(다양한 학문 분야의 교육욕 콘텐츠를 제공)의 '면역 체계의 이상'에 대한 내용을 6학년 수준과 '게임'이라는 개인적 관심사에 맞춰 변환한 결과물을 보여줍니다. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;생성형 애드온: 텍스트 주변에는 다음과 같은 다양한 AI 생성 기능들이 라벨로 표시되어 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;다양한 보기 형태: 몰입형 텍스트, 마인드맵, 오디오 강의, 슬라이드 및 내레이션 등 학습자가 선택할 수 있는 여러 콘텐츠 형태를 제공합니다. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;텍스트 개인화: 학습자의 수준과 관심사에 맞춰 텍스트가 개인화되었음을 나타냅니다. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;내장된 질문 (Embedded Question): 학습 내용 중간에 이해도를 확인할 수 있는 질문이 포함되어 있습니다. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;시각적 삽화 (Visual Illustration): 본문 내용과 관련된 이미지가 생성되어 이해를 돕습니다. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;연습 퀴즈 (Practice Quiz): 학습을 마친 후 이해도를 점검할 수 있는 퀴즈가 제공됩니다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&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;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2. 연구 방법론&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;&quot;Learn Your Way&quot;는 두 가지 핵심 개념, 즉 '다중 표현(multiple representations)' 과 '개인화(personalization)' 를 기반으로 합니다. 연구팀은 2단계 AI 생성 방식을 제안했는데, 먼저 원본 텍스트를 개인화한 다음, 다양한 형태의 프레젠테이션 및 평가 구성 요소로 변환하는 것입니다. 이 과정에서 가장 중요한 것은 콘텐츠가 원본 및 교육 과정과 적절히 일치하고, 프레젠테이션이 매력적이며 교육적으로 효과적이어야 한다는 점입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; background-color: #f6e199; color: #000000;&quot;&gt;1. 텍스트 개인화 (Text Personalization)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;- 학년 수준 맞춤화:&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; 학생의 읽기 수준에 맞춰 텍스트를 재작성합니다&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;이는 Flesch-Kincaid Grade (FKG)와 같은 지표를 활용하여 이루어지며, 내용의 사실성과 정보량을 유지하는 것을 목표로 합니다&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;- 개인 관심사 맞춤화: 학생이 선택한 관심사(예: 스포츠, 음악, 음식)에 맞춰 텍스트를 재작성하여 학습 내용을 더욱 흥미롭고 관련성 있게 만듭니다. 예를 들어, 뉴턴의 제3법칙을 설명할 때 농구에 관심 있는 학생에게는 농구공을 드리블하는 예시를, 미술에 관심 있는 학생에게는 캔버스에 붓을 누르는 예시를 들어 설명합니다.&lt;/span&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; background-color: #f6e199; color: #000000;&quot;&gt;2. 콘텐츠 변환 (Content Transformations)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;개인화된 텍스트를 기반으로 다양한 형태의 학습 콘텐츠를 생성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;- 슬라이드 및 내레이션:&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; 핵심 내용을 간결하게 요약한 슬라이드와 함께, 자연스러운 음성 해설을 제공하여 수업과 유사한 학습 경험을 제공합니다&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;- 오디오-그래픽 강의:&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; 교사와 학생의 대화 형식으로 구성된 오디오 강의와 함께, 핵심 개념을 시각적으로 표현한 그래픽 자료를 제공하여 학습 효과를 높입니다&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;- 마인드맵:&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; 정보를 계층적으로 구성하여 전체적인 내용을 한눈에 파악할 수 있도록 돕습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;- 몰입형 텍스트 (Immersive Text): 개인화된 텍스트에 타임라인, 기억 보조 장치(mnemonic), 시각적 삽화 등 다양한 요소를 추가하여 학습 경험을 풍부하게 만듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-07 오후 6.57.15.png&quot; data-origin-width=&quot;1051&quot; data-origin-height=&quot;966&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZTvT5/btsQ3ivJ3GT/hwKnXE4nDwr7NeT1pnBpNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZTvT5/btsQ3ivJ3GT/hwKnXE4nDwr7NeT1pnBpNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZTvT5/btsQ3ivJ3GT/hwKnXE4nDwr7NeT1pnBpNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZTvT5%2FbtsQ3ivJ3GT%2FhwKnXE4nDwr7NeT1pnBpNK%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;658&quot; height=&quot;605&quot; data-filename=&quot;스크린샷 2025-10-07 오후 6.57.15.png&quot; data-origin-width=&quot;1051&quot; data-origin-height=&quot;966&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;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;Figure 2 &lt;/span&gt;그림은 'Learn Your Way' 시스템의 핵심 작동 방식인 2단계 생성 절차를 명확하게 보여줍니다. 상단에는 OpenStax 교재에 실린 뉴턴의 제3법칙에 대한 일반적인 예시(&quot;발가락을 부딪혔을 때의 경험&quot;)가 제시됩니다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;1단계 - 개인화: 이 원본 텍스트가 두 가지 다른 학습자 프로필에 따라 맞춤화됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;- 왼쪽 (농구)&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;: &lt;/span&gt;11학년&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; 학생의 &lt;/span&gt;'농구'&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; 관심사에 맞춰 &quot;농구공을 드리블하는&quot; 예시로 텍스트가 변경되었습니다&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;- 오른쪽 (미술)&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;: &lt;/span&gt;5학년&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; 학생의 &lt;/span&gt;'미술'&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; 관심사에 맞춰 &quot;캔버스에 붓을 누르는&quot; 예시로 텍스트가 변경되었습니다&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;2단계: 콘텐츠 변환&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;: 개인화된 텍스트를 기반으로 &lt;/span&gt;슬라이드, 퀴즈, 이미지&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;와 같은 다양한 형태의 학습 자료가 생성됩니다&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;. 예를 들어, 농구 예시에서는 농구 선수가 점프하는 상황에 대한 퀴즈가, 미술 예시에서는 붓과 캔버스에 대한 퀴즈가 만들어집니다.&lt;/span&gt;&lt;/span&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-filename=&quot;스크린샷 2025-10-07 오후 6.57.28.png&quot; data-origin-width=&quot;1256&quot; data-origin-height=&quot;756&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4zgik/btsQ5k6Xt40/8CucgQSYByeQ6hFM3KO4wk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4zgik/btsQ5k6Xt40/8CucgQSYByeQ6hFM3KO4wk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4zgik/btsQ5k6Xt40/8CucgQSYByeQ6hFM3KO4wk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4zgik%2FbtsQ5k6Xt40%2F8CucgQSYByeQ6hFM3KO4wk%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;651&quot; height=&quot;392&quot; data-filename=&quot;스크린샷 2025-10-07 오후 6.57.28.png&quot; data-origin-width=&quot;1256&quot; data-origin-height=&quot;756&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;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;Figure 3는&lt;/span&gt; OpenStax의 '경제 체제를 조직하는 방법'이라는 주제를 바탕으로 생성된 개인화된 슬라이드 한 장을 보여줍니다.&amp;nbsp;슬라이드는 '시장 경제에서의 소득'에 대해 설명하고 있습니다. 학습자의 관심사가 '축구' 인 경우에 맞춰, 시장 경제의 가치와 소득에 대한 예시로 유명 축구 선수인 '리오넬 메시'와 '크리스티아누 호날두' 를 언급합니다.&amp;nbsp;이처럼 개인화된 텍스트를 기반으로 슬라이드를 제작함으로써 일부 학습자에게 더 효과적인 프레젠테이션 형식을 제공할 수 있습니다.&lt;/span&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-filename=&quot;스크린샷 2025-10-07 오후 6.57.36.png&quot; data-origin-width=&quot;1256&quot; data-origin-height=&quot;687&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpu9sj/btsQ5aXBXkx/8IzcRiWh4hKsO5c0iiOBCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpu9sj/btsQ5aXBXkx/8IzcRiWh4hKsO5c0iiOBCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpu9sj/btsQ5aXBXkx/8IzcRiWh4hKsO5c0iiOBCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbpu9sj%2FbtsQ5aXBXkx%2F8IzcRiWh4hKsO5c0iiOBCK%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;637&quot; height=&quot;348&quot; data-filename=&quot;스크린샷 2025-10-07 오후 6.57.36.png&quot; data-origin-width=&quot;1256&quot; data-origin-height=&quot;687&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;Figure 4는&lt;/span&gt; OpenStax의 '초기 인류의 진화와 이주'라는 원본 자료를 바탕으로 생성된 마인드맵의 예시입니다.&amp;nbsp;정보가 계층적으로 정리되어 있어 학습자가 전체 자료를 다양한 깊이에서 조망할 수 있으며,&amp;nbsp;사용자는 마인드맵의 각 노드(node)를 확장하거나 축소하여 더 세분화된 내용을 확인할 수 있습니다. 또한, 가장 마지막 단계의 노드(leaf nodes)에는 원본 자료에서 파생된 설명 텍스트나 관련 시각 자료가 포함되어 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;3. 평가 결과&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그럼 실제 사용자들의 반응은 어땠을까요? 본 논문에서는 실제 교육적인 평가와 사용자의 평가 둘 다 제시하였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-07 오후 6.58.40.png&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;827&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uPz4b/btsQ4nC4fnj/dNWtrVVgUzU71MEWccuAc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uPz4b/btsQ4nC4fnj/dNWtrVVgUzU71MEWccuAc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uPz4b/btsQ4nC4fnj/dNWtrVVgUzU71MEWccuAc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuPz4b%2FbtsQ4nC4fnj%2FdNWtrVVgUzU71MEWccuAc0%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;661&quot; height=&quot;564&quot; data-filename=&quot;스크린샷 2025-10-07 오후 6.58.40.png&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;827&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;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Figure 7은 교육 전문가들이 'Learn Your Way'의 다양한 구성 요소들을 교육학적 기준에 따라 평가한 결과를 보여주는 두 개의 막대그래프입니다. 전문가들은 정확성, 내용 범위, 인지 부하, 동기 부여 등 여러 기준에 따라 각 기능에 대해 '동의(1.0)', '중립/부분 동의(0.5)', '비동의(0.0)'로 점수를 매겼습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;위쪽 그래프는 정확성(Accuracy), 내용 범위(Coverage), 강조(Emphasis), 참여도(Engagement)와 같은 상위 수준의 지표에 대한 평가 결과를 보여줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;아래쪽 그래프는 인지 부하(Cognitive load), 능동적 학습(Active Learning), 메타인지 심화(Deepen Metacognition) 등 핵심 학습 과학 원칙에 기반한 지표들의 평가 결과입니다.&lt;/span&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;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;논문에서 제시한 방법은 전반적으로 모든 구성 요소가 교육적으로 높은 가치를 지니고 있으며, 특히 '전반적인 경험(Overall experience)' 항목은 모든 기준에서 0.90 이상의 높은 점수를 받았습니다. 다만, '시각적 삽화(Visual illustrations)' 항목은 교육적인 고품질 이미지를 생성하는 것이 어렵기 때문에 다른 기능에 비해 상대적으로 낮은 점수를 받았습니다. 흥미로운 점은, 일반 '슬라이드'보다 '내레이션이 포함된 슬라이드(Narrated slides)'가 '참여도' 항목에서 훨씬 높은 점수를 받았다는 것입니다.&lt;/span&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-07 오후 6.59.25.png&quot; data-origin-width=&quot;1286&quot; data-origin-height=&quot;605&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzYOzZ/btsQ3hjlZfh/uvmkmcfrgPwlTfIfqpp4K0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzYOzZ/btsQ3hjlZfh/uvmkmcfrgPwlTfIfqpp4K0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzYOzZ/btsQ3hjlZfh/uvmkmcfrgPwlTfIfqpp4K0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzYOzZ%2FbtsQ3hjlZfh%2FuvmkmcfrgPwlTfIfqpp4K0%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;675&quot; height=&quot;318&quot; data-filename=&quot;스크린샷 2025-10-07 오후 6.59.25.png&quot; data-origin-width=&quot;1286&quot; data-origin-height=&quot;605&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;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Figure 9은 'Learn Your Way'의 학습 효과를 검증하기 위해 진행된 무작위 통제 실험의 결과를 보여줍니다. 이 실험은 'Learn Your Way'를 사용한 그룹과 일반 '디지털 리더(Adobe Acrobat Reader)'를 사용한 통제 그룹의 성적을 비교했습니다.&lt;/span&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;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;왼쪽 그래프 (즉각적인 평가)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;학습 직후에 치른 평가의 평균 점수를 보여줍니다. 'Learn Your Way' 그룹은 평균 77%의 점수를, '디지털 리더' 그룹은 평균 68%의 점수를 기록했습니다.&lt;/span&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;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;오른쪽 그래프 (유지 평가)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;학습 3일 후에 장기 기억을 측정하기 위해 치른 평가의 평균 점수를 보여줍니다. 결과는 즉각적인 평가와 동일하게, 'Learn Your Way' 그룹이 77%, '디지털 리더' 그룹이 68%의 점수를 받았습니다. 논문에 따르면 두 평가 모두에서 'Learn Your Way'를 사용한 학생들의 점수가 통계적으로 유의미하게 높았습니다 (p=0.03). 이는 'Learn Your Way'가 단기적인 학습 이해뿐만 아니라 장기적인 지식 유지에도 더 효과적임을 시사합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;4. 인사이트와 한계점 그리고 변화의 지점&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;AI 기술이 교육 분야에서 단순한 보조 도구를 넘어, 학습자 중심의 개인화된 교육을 실현하는 핵심적인 역할을 할 수 있음을 보여줍니다. 앞으로는 학생 개개인의 학습 속도, 스타일, 관심사에 맞춰 교육 콘텐츠와 방법이 동적으로 변화하는 시대가 올 것입니다. 또한, &lt;/span&gt;생성형 AI는 기존 교과서를 개인화되고 매력적인 학습 경험으로 전환할 수 있는 엄청난 잠재력을 가지고 있다는 인사이트를 얻을 수 있었으며 &quot;Learn Your Way&quot;와 같은 AI 증강 교과서는 학생들의 학습 효과를 실질적으로 향상시킬 수 있다는 것을 보여주었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;다만, 변화의 지점이 필요할 것입니다. 일단 바로 교사의 역할에 대해서 이야기 할 수 있을 것 같은데요. AI가 콘텐츠 생성 및 평가의 상당 부분을 자동화함에 따라, 교사는 지식 전달자에서 학생들의 학습 과정을 촉진하고 심층적인 상호작용을 통해 고차원적인 사고를 유도하는 '학습 촉진자(facilitator)' 또는 '코치(coach)' 로서의 역할이 더욱 중요해질 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;뿐만 아니라, 여러 한계점과 개선점이 필요할 것입니다. 생성형 AI가 만들어내는 콘텐츠의 정확성, 신뢰성, 편향성 문제는 앞으로 해결해야 할 중요한 과제입니다. 특히 교육 분야에서는 잘못된 정보가 학생들에게 미치는 영향이 크기 때문에, 콘텐츠 검증 및 품질 관리를 위한 체계적인 시스템 구축이 필수적입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그리고 AI 기반의 고도화된 교육 기술이 모든 학생에게 동등하게 제공될 수 있도록 기술 접근성 문제에 대한 고민이 필요합니다. 디지털 기기 보급, 인터넷 환경, 기술 활용 능력 등에서 발생하는 격차가 교육 불평등으로 이어지지 않도록 사회적인 노력이 동반되어야 할 것입니다.&lt;/span&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;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;AI는 교육을 어떻게 변화시킬까요? 개인적으로 교육 도메인에 6년 정도 몸 담았던 경험상 쉽지는 않을 것이라고 생각은 드는데요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;결국 변화는 일어날 것입니다. 어떤 변화가 나올 수 있을 지 기대되네요.&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>AI교육</category>
      <category>edtech</category>
      <category>Education</category>
      <category>edutech</category>
      <category>GenAI</category>
      <category>Google</category>
      <category>개인화교육</category>
      <category>교육</category>
      <category>맞춤형교육</category>
      <category>생성형ai</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/701</guid>
      <comments>https://lsjsj92.tistory.com/701#entry701comment</comments>
      <pubDate>Tue, 7 Oct 2025 19:46:00 +0900</pubDate>
    </item>
    <item>
      <title>랭그래프(LangGraph) Agent에 대화 기억(Memory) 저장 및 관리 구현(Feat. PostgreSQL)</title>
      <link>https://lsjsj92.tistory.com/700</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 16px; }
&lt;/style&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;AI Agent를 구현하기 위해서는 기억(Memory) 기능이 필요합니다. 주로 랭그래프(LangGraph) 예제를 보면 InMemorySaver를 사용하기도 하는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존의 InMemorySaver는 프로그램이 종료되면 대화 기록이 모두 사라지는 한계가 있었습니다. 하지만 실제 서비스에서는 사용자와의 대화 내역을 영구적으로 보존하고, 언제든지 이전 대화를 이어갈 수 있어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 관계형 데이터베이스(RDB)인 PostgreSQL를 활용해서 영구적인 메모리 관리를 구현하는 방법을 알아봅니다.&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;/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&gt;&lt;a href=&quot;https://langchain-ai.github.io/langgraph/concepts/memory/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://langchain-ai.github.io/langgraph/concepts/memory/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1758960079374&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;Overview&quot; data-og-description=&quot;Persistence LangGraph has a built-in persistence layer, implemented through checkpointers. When you compile a graph with a checkpointer, the checkpointer saves a checkpoint of the graph state at every super-step. Those checkpoints are saved to a thread, wh&quot; data-og-host=&quot;langchain-ai.github.io&quot; data-og-source-url=&quot;https://langchain-ai.github.io/langgraph/concepts/persistence/&quot; data-og-url=&quot;https://langchain-ai.github.io/langgraph/concepts/persistence/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/EzLDk/hyZKgVhHbc/n5mmxFJ4gkfslbf8pVOf4k/img.jpg?width=3705&amp;amp;height=2598&amp;amp;face=0_0_3705_2598,https://scrap.kakaocdn.net/dn/SlsgZ/hyZJY2hh86/MkD4Pxe6dkrgkIqsfiDMI0/img.jpg?width=2692&amp;amp;height=1056&amp;amp;face=0_0_2692_1056,https://scrap.kakaocdn.net/dn/gpoid/hyZJHtqwch/L6YHdFKOoOYFUULhdGbFlK/img.png?width=2276&amp;amp;height=986&amp;amp;face=0_0_2276_986&quot;&gt;&lt;a href=&quot;https://langchain-ai.github.io/langgraph/concepts/persistence/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://langchain-ai.github.io/langgraph/concepts/persistence/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/EzLDk/hyZKgVhHbc/n5mmxFJ4gkfslbf8pVOf4k/img.jpg?width=3705&amp;amp;height=2598&amp;amp;face=0_0_3705_2598,https://scrap.kakaocdn.net/dn/SlsgZ/hyZJY2hh86/MkD4Pxe6dkrgkIqsfiDMI0/img.jpg?width=2692&amp;amp;height=1056&amp;amp;face=0_0_2692_1056,https://scrap.kakaocdn.net/dn/gpoid/hyZJHtqwch/L6YHdFKOoOYFUULhdGbFlK/img.png?width=2276&amp;amp;height=986&amp;amp;face=0_0_2276_986');&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;Overview&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Persistence LangGraph has a built-in persistence layer, implemented through checkpointers. When you compile a graph with a checkpointer, the checkpointer saves a checkpoint of the graph state at every super-step. Those checkpoints are saved to a thread, wh&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;langchain-ai.github.io&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 포스팅(&lt;a href=&quot;https://lsjsj92.tistory.com/697&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/697&lt;/a&gt;)에서는 LangGraph의 도구 사용, 조건부 엣지, Human-in-the-Loop 기능을 통해 간단한 에이전트를 만드는 방법을 알아보았습니다. 하지만 실제 프로덕션 환경에서는 메모리 영속성이 필요하죠.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 LangGraph 예제를 보면 주로 InMemorySaver를 사용하기 때문에 프로그램이 종료되면 모든 대화 내용이 사라지게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 이번 포스팅에서는 이러한 한계를 극복하기 위해서 PostgreSQL를 활용해 실제 데이터베이스에 대화 상태를 저장하고 필요에 따라 불러올 수 있도록 합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;LangGraph의 기억(Memory) 구현의 핵심 기능 3가지&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;영구적인 메모리 관리&lt;/b&gt;: PostgreSQL을 활용하여 대화 기록을 데이터베이스에 영구 저장합니다. 프로그램을 다시 실행해도 이전 대화를 정확히 불러올 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비동기 처리&lt;/b&gt;: asyncio를 활용하여 동시에 여러 사용자의 요청을 처리할 수 있으며, I/O 작업 중에도 다른 작업을 병렬로 수행할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스트리밍 응답&lt;/b&gt;: 사용자는 LLM의 완전한 응답을 기다리지 않고도 실시간으로 응답을 확인할 수 있어 더 자연스러운 대화 경험을 제공합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style8&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;비동기 LangGraph 에이전트 구현하기&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 데이터베이스 설정과 연결 구성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 PostgreSQL 데이터베이스와의 연결을 설정합니다. 실제 환경에서는 환경변수나 설정 파일을 사용하는 것이 보안상 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, 여러 분들이 PostgreSQL를 사용하지 않으신다면, 다른 RDBMS를 사용하시면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;import psycopg_pool
import psycopg

DB_CONFIG = {
    &quot;user&quot;: &quot;leesoojin&quot;,
    &quot;password&quot;: &quot;&quot;,
    &quot;host&quot;: &quot;localhost&quot;,
    &quot;port&quot;: &quot;5432&quot;,
    &quot;dbname&quot;: &quot;langgraph_study_tistory&quot;,
}

DATABASE_URL = (
    f&quot;postgresql://{DB_CONFIG['user']}:{DB_CONFIG['password']}&quot;
    f&quot;@{DB_CONFIG['host']}:{DB_CONFIG['port']}/{DB_CONFIG['dbname']}&quot;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. vLLM 서버와의 연결 설정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 LLM 서버(vLLM 등)와 연결하여 더 강력한 모델을 활용합니다. 저는 vLLM을 활용하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 분들이 사용하는 LLM 서버(Ollama, OpenAI 등)를 사용하시면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;from langchain_openai import ChatOpenAI

NGROK_URL = &quot;https://c1cbcd1b9597.ngrok-free.app/v1&quot; 
MODEL_NAME = &quot;Qwen/Qwen3-14B&quot;

llm = ChatOpenAI(
    model=MODEL_NAME,
    openai_api_key=&quot;EMPTY&quot;,
    openai_api_base=NGROK_URL,
    temperature=0.2,
    max_tokens=512,
    top_p=0.5,
    model_kwargs={
        &quot;presence_penalty&quot;: 0.5,
        &quot;extra_body&quot;: {
            &quot;top_k&quot;: 10,
            &quot;chat_template_kwargs&quot;: {&quot;enable_thinking&quot;: False},
        },
    }
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 도구(Tool) 정의와 에이전트 노드 구성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 포스팅과 유사하게 도구를 정의합니다. 도구는 fake_web_search로서 실제 검색을 수행하기보다, 검색을 수행한 것처럼 수행하는 함수입니다. 예제와 빠른 이해를 위해서 이렇게 사용헀지만, 실제로 검색과 관련된 로직을 해당 함수에 넣으시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 분들이 원하시는 도구(Tools)을 추가하셔도 됩니다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from langchain_core.tools import tool

@tool
def fake_web_search(query: str) -&amp;gt; str:
    &quot;&quot;&quot;가상의 웹 검색&quot;&quot;&quot;
    print(f&quot;\n[FakeSearch] '{query}' 검색 수행&quot;)
    return f&quot;'{query}'에 대한 최신 검색 결과(가상)&quot;

tools = [fake_web_search]
llm_with_tools = llm.bind_tools(tools)

def chatbot_node(state: AgentState):
    print(&quot;\n--- 챗봇 노드 진입 ---&quot;)
    try:
        msgs = [SystemMessage(content=SYSTEM_PROMPT)] + state[&quot;messages&quot;]
        print(&quot;--- LLM 호출 시작... ---&quot;)
        response = llm_with_tools.invoke(msgs)
        print(f&quot;--- LLM 호출 성공 ---&quot;)
        return {&quot;messages&quot;: [response]}
    except Exception as e:
        print(f&quot;\n--- 챗봇 노드에서 오류 발생: {e} ---&quot;)
        error_message = AIMessage(content=f&quot;죄송합니다, 모델 응답을 가져오는 중 오류가 발생했습니다: {e}&quot;)
        return {&quot;messages&quot;: [error_message]}
&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;그리고 chatbot_node 함수를 두어서 agent가 llm을 호출하고 LLM이 응답한 메세지를 return할 수 있도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;llm.bind_tools를 활용해서 fake_web_search를 연결하여 사용할 수 있도록 합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. PostgreSQL 기반 메모리 관리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서의 핵심인 부분입니다. 바로 PostgreSQL을 활용한 영구 메모리 저장인데요.&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
import uuid

async def main() -&amp;gt; None:
	# AsyncPostgresSaver를 사용하여 DB에 비동기적으로 연결합니다.
    async with AsyncPostgresSaver.from_conn_string(DATABASE_URL) as memory:
        # 테이블 생성/확인
        await memory.setup()
        # 그래프 컴파일 시 checkpointer로 DB 연결 객체를 지정합니다.
        graph = builder.compile(checkpointer=memory)
        
        print(&quot;챗봇 시작 (exit/quit 입력 시 종료)&quot;)
        
        # 사용자에게 Thread ID를 입력받습니다.
        #    - 기존 ID 입력 시 -&amp;gt; 대화 복원
        #    - 그냥 Enter 입력 시 -&amp;gt; 새로운 ID 생성 및 새 대화 시작
        tid = input(&quot;Thread ID(새 대화는 Enter): &quot;).strip() or str(uuid.uuid4())
        cfg = {&quot;configurable&quot;: {&quot;thread_id&quot;: tid}}
        
        # 이전 대화 기록 불러오기
        try:
        	# DB에서 해당 Thread ID의 과거 대화 기록을 가져옵니다.
            past = await graph.aget_state(cfg)
            if past and past.values.get(&quot;messages&quot;):
                print(&quot;\n── 이전 대화 ──&quot;)
                for m in past.values[&quot;messages&quot;]:
                    m.pretty_print()
                print(&quot;──────────────\n&quot;)
            else:
                print(&quot;\n새로운 대화를 시작합니다.\n&quot;)
        except Exception:
            print(&quot;\n저장된 대화가 없습니다. 새로운 대화를 시작합니다.\n&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;&lt;b&gt;AsyncPostgresSaver&lt;/b&gt;: 이전에 사용했던 InMemorySaver 대신 PostgreSQL 기반의 비동기 체크포인터를 사용합니다. 이를 통해 대화 기록이 데이터베이스에 영구적으로 저장됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;await memory.setup()&lt;/b&gt;: 데이터베이스에 필요한 테이블들을 자동으로 생성하거나 확인합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Thread ID 관리&lt;/b&gt;: 각 대화 세션을 고유하게 식별하기 위한 Thread ID를 관리합니다. 사용자가 이전 대화를 이어가고 싶다면 같은 Thread ID를 입력하면 됩니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5. 사용자 대화 저장과 실시간 스트리밍&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 경험에서 중요한 부분은 실시간 스트리밍입니다. 한 번에 답을 제공하는 것도 좋지만, 타이핑하듯 답변을 제공하는 것이 더 자연스러우니까요.&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;while True:
    user_input = await asyncio.to_thread(input, &quot;나: &quot;)
    if user_input.lower() in {&quot;exit&quot;, &quot;quit&quot;}:
        break
    if not user_input.strip():
        continue

    print(&quot;AI: &quot;, end=&quot;&quot;, flush=True)
    # 사용자와의 모든 상호작용(입력, AI 응답, 도구 사용 등)은
    # checkpointer를 통해 DB에 자동으로 저장됩니다.
    events = graph.astream_events(
        {&quot;messages&quot;: [HumanMessage(content=user_input)]}, 
        config=cfg, 
        version=&quot;v1&quot;
    )
    
    final_content_printed = False
    async for e in events:
        kind = e[&quot;event&quot;]
        if kind == &quot;on_chat_model_stream&quot;:
            chunk = e[&quot;data&quot;][&quot;chunk&quot;].content
            if chunk:
                print(chunk, end=&quot;&quot;, flush=True)
                final_content_printed = True
        elif kind == &quot;on_tool_end&quot;:
            print(f&quot;\n&amp;hellip; '{e['name']}' 도구 사용 완료&quot;, flush=True)
        elif kind == &quot;on_chain_end&quot;:
            if e[&quot;name&quot;] == &quot;chatbot&quot; and not final_content_printed:
                output = e.get(&quot;data&quot;, {}).get(&quot;output&quot;, {})
                if messages := output.get(&quot;messages&quot;):
                    print(messages[-1].content, end=&quot;&quot;, flush=True)
    print()  # 줄바꿈&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;astream_events()&lt;/b&gt;: 이 함수는 langgraph 워크플로우를 실행하고, 내부에서 발생하는 이벤트를 수행해줍니다. 즉, 비동기 이벤트 스트림을 사용하여 LLM의 응답을 실시간으로 받아올 수 있죠.&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;이벤트 기반 처리&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;on_chat_model_stream: LLM이 토큰을 하나씩 생성할 때마다 발생하는 이벤트입니다. 실시간 타이핑 효과를 나타낼 수 있죠.&lt;/li&gt;
&lt;li&gt;on_tool_end: 도구 실행이 완료되었을 때 발생하는 이벤트이며, fake_web_search와 같은 도구를 호출하고 완료되었을 때 발생하는 것입니다.&lt;/li&gt;
&lt;li&gt;on_chain_end: 전체 체인이 완료되었을 때 발생하는 이벤트이며, 노드의 실행이 완전히 끝났을 때 발생합니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실행 결과&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-02 오후 8.59.49.png&quot; data-origin-width=&quot;1299&quot; data-origin-height=&quot;379&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vveR6/btsQTRw4XYW/Tgk2swcv3skGFnRWwJ4T61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vveR6/btsQTRw4XYW/Tgk2swcv3skGFnRWwJ4T61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vveR6/btsQTRw4XYW/Tgk2swcv3skGFnRWwJ4T61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvveR6%2FbtsQTRw4XYW%2FTgk2swcv3skGFnRWwJ4T61%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;716&quot; height=&quot;209&quot; data-filename=&quot;스크린샷 2025-08-02 오후 8.59.49.png&quot; data-origin-width=&quot;1299&quot; data-origin-height=&quot;379&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;위 사진은 처음 대화를 시작할 때입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 Thread ID를 입력하지 않고, 단순히 엔터를 눌러 시작했습니다. 그러면, 새로운 대화를 시작한다는 메세지와 함께 대화를 시작하게 되는데요. 저는 일상적인 제 소개와(&quot;제 이름은 이수진입니다.&quot;)와 langgraph를 공부하고 있다고 메세지를 날린 후 종료했습니다.&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;InMemorySaver를 사용했다면, 이렇게 프로그램을 종료하면 대화가 기억(memory)되지 않고(저장되지 않고) 휘발되는데요.&lt;/p&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-filename=&quot;스크린샷 2025-08-02 오후 8.59.58.png&quot; data-origin-width=&quot;1320&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1MSjs/btsQRXZXfTY/xycC0EmC1xvc64ghBABRa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1MSjs/btsQRXZXfTY/xycC0EmC1xvc64ghBABRa1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1MSjs/btsQRXZXfTY/xycC0EmC1xvc64ghBABRa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1MSjs%2FbtsQRXZXfTY%2FxycC0EmC1xvc64ghBABRa1%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;744&quot; height=&quot;239&quot; data-filename=&quot;스크린샷 2025-08-02 오후 8.59.58.png&quot; data-origin-width=&quot;1320&quot; data-origin-height=&quot;424&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;실행할 때 Thread ID를 입력하면 기존 대화를 가져오게 되는 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 웹 UI로 표현하면, 각 채팅창에 저런 Thread ID를 저장하도록 하고 가지고 오면 마치 ChatGPT, Gemini, Claude처럼 기존 대화를 가져올 수 있게 되는 것입니다.&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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 LangGraph를 활용하여 PostgreSQL 기반의 기억 장치(메모리 관리)를 구현하는 방법을 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InMemorySaver의 한계를 극복하고, 실제 서비스에 적용할 수 있는 수준의 안정적이고 확장 가능한 에이전트를 구축할 수 있게 되었습니다. 특히 Thread ID를 통한 대화 세션 관리와 실시간 스트리밍 응답은 사용자 경험을 크게 향상시키는 요소입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도움이 되시길 바랍니다.&lt;/p&gt;</description>
      <category>인공지능(AI)/AI Agent</category>
      <category>aiagent</category>
      <category>aiagentmemory</category>
      <category>langchain</category>
      <category>langgraph</category>
      <category>langgraph대화내용</category>
      <category>NLP</category>
      <category>PostgreSQL</category>
      <category>RAG</category>
      <category>랭그래프</category>
      <category>랭체인</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/700</guid>
      <comments>https://lsjsj92.tistory.com/700#entry700comment</comments>
      <pubDate>Sat, 27 Sep 2025 19:45:14 +0900</pubDate>
    </item>
    <item>
      <title>Group Query Attention(GQA)란? LLM 추론 속도 향상을 위한 노력</title>
      <link>https://lsjsj92.tistory.com/699</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 16px; }
&lt;/style&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;포스팅 개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;본 포스팅은 거대 언어 모델(LLM)의 추론(inference) 과정에서 발생하는 심각한 메모리 병목 현상을 해결하기 위한 핵심 최적화 기법인 Grouped-Query Attention(GQA)을 소개합니다. GQA는 구글 리서치에서 제안한 기술로 기존의 표준 Attention 방식인 Multi-Head Attention(MHA)의 높은 성능은 유지하면서, 추론 속도를 극대화한 Multi-Query Attention(MQA)의 장점을 결합한 아키텍처입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;본 포스팅에서는 MHA에서 MQA를 거쳐 GQA에 이르기까지 Attention 메커니즘의 발전 과정을 추적하고, GQA가 어떻게 속도와 성능이라는 두 마리 토끼를 모두 잡을 수 있었는지 그 원리를 상세히 분석합니다. 또한, Llama 2, Mistral 7B 등 최신 LLM에 GQA가 어떻게 적용되어 실제 성능 향상을 이끌어냈는지 구체적인 실험 결과를 통해 확인합니다.&lt;/span&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;a href=&quot;https://arxiv.org/pdf/2305.13245&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/pdf/2305.13245&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-09-06 오후 2.13.20.png&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;556&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kjesu/btsQoobuSX4/9KUHN2BhZ5TK0ggDF9FUik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kjesu/btsQoobuSX4/9KUHN2BhZ5TK0ggDF9FUik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kjesu/btsQoobuSX4/9KUHN2BhZ5TK0ggDF9FUik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKjesu%2FbtsQoobuSX4%2F9KUHN2BhZ5TK0ggDF9FUik%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;679&quot; height=&quot;389&quot; data-filename=&quot;스크린샷 2025-09-06 오후 2.13.20.png&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;556&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;포스팅 본문&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;1. 핵심 요약&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;거대 언어 모델(LLM)을 실제로 서비스하는 데 있어 가장 큰 장애물 중 하나는 추론 과정의 높은 메모리 사용량입니다. 특히, Transformer 모델의 핵심인 Attention 메커니즘은 매 토큰을 생성할 때마다 모든 이전 토큰들의 Key와 Value 값을 메모리에서 불러와야 하므로 심각한 병목 현상을 유발합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;이 문제를 해결하기 위해, 기존의 표준 방식인 Multi-Head Attention (MHA)의 높은 품질과, 추론 속도를 극단적으로 개선했지만 성능 저하의 위험이 있던 Multi-Query Attention (MQA)의 장점을 절충한 Grouped-Query Attention (GQA)이 제안되었습니다. GQA의 핵심 아이디어는 여러 개의 Query 헤드들을 몇 개의 그룹으로 묶고, 각 그룹이 단일 Key-Value 헤드를 공유하도록 하는 것입니다.&lt;/span&gt; &lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;이러한 구조적 변경을 통해 GQA는 MQA처럼 메모리 사용량을 획기적으로 줄여 추론 속도를 높이면서도, MHA와 거의 근접한 높은 모델 성능을 유지하는 데 성공했습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;Llama 2 70B와 Mistral 7B 같은 최신 고성능 LLM들이 이 기술을 채택했으며, 실험 결과 GQA를 사용한 모델이 MHA 기반 모델보다 특히 높은 부하 상황에서 월등한 처리 속도를 보여주었습니다. 결과적으로 GQA는 LLM의 현실적인 배포와 확장성을 위한 필수적인 최적화 기술로 자리매김하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;2-1. 연구의 배경: LLM 추론 병목 현상과 Attention 메커니즘&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;2-1-1. Multi-Head Attention (MHA)의 등장과 메모리 한계&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;Transformer 모델의 Attention 메커니즘은 문장의 각 단어(Query)가 다른 모든 단어(Keys)들과 얼마나 관련이 있는지를 계산하여, 그 가중치에 따라 정보(Values)를 종합하는 방식으로 작동합니다. 이는 마치 데이터베이스에서 쿼리를 날려 가장 관련성 높은 정보를 찾아오는 것과 유사합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;Multi-Head Attention (MHA)는 이러한 Attention 과정을 여러 개의 &quot;헤드(Head)&quot;를 통해 병렬로 수행하는 방식입니다. 각 헤드는 독립적인 Query, Key, Value 가중치를 가져 &quot;나는 형이 소파 옮기는 것을 도왔다&quot;와 같은 문장에서 '나-형'의 관계와 '나-소파를 옮기다'라는 관계를 동시에 파악하는 등, 텍스트의 다채롭고 복잡한 관계를 효과적으로 학습할 수 있습니다.&lt;/span&gt; &lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;하지만 MHA는 각 헤드가 자신만의 Key와 Value를 가지기 때문에, 모델이 새로운 토큰을 생성할 때마다 이전의 모든 토큰에 해당하는 방대한 양의 Key-Value 캐시를 메모리에서 불러와야 하는 큰 단점이 있습니다. 이로 인해 메모리 대역폭에 엄청난 부담을 주며, 이는 LLM 추론 성능을 저하하는 주된 병목 지점이 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;2-1-2. Multi-Query Attention (MQA)의 시도와 품질 저하 문제&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-09-06 오후 2.15.19.png&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;390&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKfble/btsQoobuVe4/9XbzHCqePLF2qVf9ikySbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKfble/btsQoobuVe4/9XbzHCqePLF2qVf9ikySbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKfble/btsQoobuVe4/9XbzHCqePLF2qVf9ikySbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKfble%2FbtsQoobuVe4%2F9XbzHCqePLF2qVf9ikySbk%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;442&quot; height=&quot;315&quot; data-filename=&quot;스크린샷 2025-09-06 오후 2.15.19.png&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;390&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;MHA의 메모리 병목 문제를 해결하기 위해 Multi-Query Attention (MQA)이 등장했습니다. MQA의 아이디어는 매우 단순 명료합니다. 여러 개의 Query 헤드는 그대로 유지하되, 모든 Query 헤드가 단 하나의 Key-Value 헤드를 공유하도록 하는 것입니다.&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;이 방식을 통해 Key-Value 캐시의 크기가 획기적으로 줄어들었고, 메모리 로딩량이 감소하면서 추론 속도가 크게 향상되었습니다. 하지만 이러한 극단적인 단순화는 모델의 표현력을 감소시켜 성능 저하를 유발하거나 학습 과정을 불안정하게 만드는 부작용을 낳았습니다. 속도를 얻는 대신 품질을 일부 희생해야 하는 트레이드오프가 발생한 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;2-2. Grouped-Query Attention (GQA): 개념과 작동 원리 &lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;2-2-1. GQA의 개념: MHA와 MQA의 영리한 절충안 &lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-09-06 오후 2.01.46.png&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;452&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLPNDO/btsQmuYb8SY/WVKt5TWZuYk7f2eRKgbkI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLPNDO/btsQmuYb8SY/WVKt5TWZuYk7f2eRKgbkI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLPNDO/btsQmuYb8SY/WVKt5TWZuYk7f2eRKgbkI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLPNDO%2FbtsQmuYb8SY%2FWVKt5TWZuYk7f2eRKgbkI0%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;233&quot; data-filename=&quot;스크린샷 2025-09-06 오후 2.01.46.png&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;452&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;Grouped-Query Attention (GQA)는 MHA의 높은 성능과 MQA의 빠른 속도 사이에서 최적의 균형점을 찾은 아키텍처입니다. GQA는 MHA처럼 모든 Query 헤드가 독립적인 K-V 헤드를 갖지도 않고, MQA처럼 모든 Query 헤드가 단 하나의 K-V 헤드를 공유하지도 않습니다. 대신, 전체 Query 헤드를 여러 그룹(G)으로 나누고, 각 그룹 내의 Query 헤드들이 하나의 Key-Value 헤드를 공유하는 방식을 사용합니다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt; 예를 들어, 8개의 Query 헤드가 있고 2개의 그룹을 사용한다면, 1~4번 Query 헤드가 첫 번째 K-V 헤드를 공유하고, 5~8번 Query 헤드가 두 번째 K-V 헤드를 공유하는 식입니다. 이처럼 GQA는 Key-Value 헤드의 수를 1개(MQA)와 전체 Query 헤드 수(MHA) 사이의 중간 값으로 설정합니다. 이러한 구조 덕분에 GQA는 MHA와 MQA를 모두 포함하는 일반화된 개념으로 볼 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;그룹의 수가 1이면 MQA와 동일하고, 그룹의 수가 전체 Query 헤드 수와 같으면 MHA와 동일해집니다. &lt;/span&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;2-2-2. GQA의 장점: 속도와 성능의 균형 &lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;GQA는 MHA와 MQA의 장점을 모두 취하는 효과적인 절충안입니다. &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리 효율성 및 속도 향상: Key-Value 헤드의 수를 줄임으로써 메모리 사용량과 계산 복잡도를 모두 감소시킵니다. 이는 MQA와 유사하게 빠른 추론 속도로 이어집니다.&lt;/li&gt;
&lt;li&gt;처리량 증가: Attention 캐시를 위한 메모리 공간이 줄어들기 때문에, 남는 공간을 활용해 더 큰 배치 사이즈(batch size)로 한 번에 더 많은 요청을 처리할 수 있어 전체적인 처리량(throughput)이 향상됩니다.&lt;/li&gt;
&lt;li&gt;높은 성능 유지: MQA와 달리 여러 개의 Key-Value 헤드를 유지함으로써 모델의 표현력 손실을 최소화하고, MHA에 가까운 높은 품질을 달성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;2-3. GQA의 성능 검증 및 실제 적용 사례 &lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;2-3-1. 실험 결과: MHA와 MQA 대비 GQA의 우수성 &lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;GQA의 효과는 다양한 실험을 통해 입증되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-09-06 오후 2.02.09.png&quot; data-origin-width=&quot;569&quot; data-origin-height=&quot;723&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/txDTz/btsQpfZrgkH/ivQjTGjewNerYYqj53GKK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/txDTz/btsQpfZrgkH/ivQjTGjewNerYYqj53GKK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/txDTz/btsQpfZrgkH/ivQjTGjewNerYYqj53GKK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtxDTz%2FbtsQpfZrgkH%2FivQjTGjewNerYYqj53GKK0%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;440&quot; height=&quot;559&quot; data-filename=&quot;스크린샷 2025-09-06 오후 2.02.09.png&quot; data-origin-width=&quot;569&quot; data-origin-height=&quot;723&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;T5 모델 실험: 구글이 T5 모델을 기반으로 실험한 결과, GQA는 MQA와 비슷한 수준의 빠른 추론 속도(Time per sample)를 보이면서도, MHA와 거의 대등한 성능(Performance)을 기록했습니다. Figure 3는 GQA-XXL이 MQA-XXL처럼 빠르면서도 MHA-XXL만큼 성능이 좋다는 것을 명확히 보여줍니다.&lt;/li&gt;
&lt;li&gt;Llama 2 vs. Mistral 7B 비교: 동일한 7B 파라미터 크기를 가진 두 모델을 비교한 실험에서도 GQA의 우수성이 드러났습니다. MHA를 사용하는 Llama 2 7B와 GQA를 사용하는 Mistral 7B를 동일한 GPU에서 테스트한 결과, 요청량이 적을 때는 성능이 비슷했지만, 부하가 증가할수록 GQA를 사용한 Mistral이 훨씬 빠른 처리 속도를 보였습니다. 가장 부하가 높은 상황에서는 Mistral이 24배 더 빠른 성능을 기록했습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;2-3-2. 기존 MHA 모델을 GQA로 전환: Uptraining &lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;GQA의 또 다른 강력한 장점은 완전히 새로운 모델을 처음부터 학습시킬 필요 없이, 기존에 MHA로 학습된 모델을 GQA 구조로 변환할 수 있다는 점입니다. 이를 '업트레이닝(Uptraining)'이라고 하며, 원본 모델 학습에 사용된 계산량의 약 5% 정도만으로도 기존 MHA 모델 체크포인트를 GQA 모델로 성공적으로 전환할 수 있습니다. 이는 막대한 시간과 자원을 절약하며 고품질의 빠른 추론 모델을 얻을 수 있는 매우 비용 효율적인 방법입니다. &lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;3. Group Query Attention 코드 설명&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;Group Query Attention을 잘 설명한 코드(&lt;a href=&quot;https://github.com/rasbt/LLMs-from-scratch/blob/main/ch05/07_gpt_to_llama/converting-llama2-to-llama3.ipynb&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/rasbt/LLMs-from-scratch/blob/main/ch05/07_gpt_to_llama/converting-llama2-to-llama3.ipynb&lt;/a&gt;)가 있어, 정리할 겸 소개합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1757136219661&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# GQA 모델의 레이어를 초기화하는 __init__ 메서드
def __init__(
    self, d_in, d_out, num_heads,
    num_kv_groups,        # [GQA 핵심] 키-값 헤드 그룹의 수를 지정하는 새로운 파라미터
    dtype=None
):
    super().__init__()
    # num_heads는 num_kv_groups로 나누어떨어져야 함
    assert num_heads % num_kv_groups == 0, &quot;num_heads must be divisible by num_kv_groups&quot;

    self.d_out = d_out
    self.num_heads = num_heads
    self.head_dim = d_out // num_heads

    # [GQA 핵심] MHA와 달리, 키(W_key)와 값(W_value)의 출력 차원을 줄여 파라미터 수를 감소시킴
    # 전체 헤드 차원(d_out)이 아닌, (키-값 그룹 수 * 헤드 차원) 만큼만 가중치를 생성
    self.W_key = nn.Linear(d_in, num_kv_groups * self.head_dim, bias=False, dtype=dtype)
    self.W_value = nn.Linear(d_in, num_kv_groups * self.head_dim, bias=False, dtype=dtype)
    
    # 쿼리(W_query)는 MHA와 동일하게 d_out 차원을 유지 
    self.W_query = nn.Linear(d_in, d_out, bias=False, dtype=dtype)

    # 최종 출력을 위한 프로젝션 레이어
    self.out_proj = nn.Linear(d_out, d_out, bias=False, dtype=dtype)

    self.num_kv_groups = num_kv_groups
    # 하나의 키-값 그룹을 몇 개의 쿼리 헤드가 공유할 것인지를 계산 
    self.group_size = num_heads // num_kv_groups&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;위 코드는 GQA를 구성하는 __init__ 함수입니다. 주목할 부분은 W_key와 W_value인데요. 기존 멀티 헤드 어텐션(Multi-Head Attention)은 동일한 크기의 쿼리(Query), 키(Key), 값(Value)를 가졌습니다. 하지만, GQA에서는 num_kv_groups라는 인자를 도입해서 key와 value의 출력 차원을 num_kv_groups * head_dim으로 줄입니다. 바로 여기서 모델의 총 파라미터 수가 크게 감소하는 효과가 나타나게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757136455417&quot; class=&quot;python&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# GQA의 순방향 계산을 수행하는 forward 메서드
def forward(self, x, mask=None, cos=None, sin=None):
    b, num_tokens, d_in = x.shape

    # 1. 쿼리, 키, 값 프로젝션
    # W_query, W_key, W_value 가중치를 곱해 쿼리, 키, 값 텐서 생성
    queries = self.W_query(x)   # Shape: (b, num_tokens, d_out)
    keys = self.W_key(x)        # Shape: (b, num_tokens, num_kv_groups * head_dim)
    values = self.W_value(x)    # Shape: (b, num_tokens, num_kv_groups * head_dim)

    # 2. 헤드/그룹별로 텐서 분리 (Reshape)
    # 쿼리는 num_heads 기준으로, 키/값은 num_kv_groups 기준으로 차원을 변경
    queries = queries.view(b, num_tokens, self.num_heads, self.head_dim)
    keys = keys.view(b, num_tokens, self.num_kv_groups, self.head_dim)
    values = values.view(b, num_tokens, self.num_kv_groups, self.head_dim)

    # 계산을 위해 차원 축 순서 변경 (Transpose)
    queries = queries.transpose(1, 2)   # Shape: (b, num_heads, num_tokens, head_dim)
    keys = keys.transpose(1, 2)         # Shape: (b, num_kv_groups, num_tokens, head_dim)
    values = values.transpose(1, 2)     # Shape: (b, num_kv_groups, num_tokens, head_dim)

    # (RoPE 적용 등 추가 연산) ...
    if cos is not None:
        keys = compute_rope(keys, cos, sin)
        queries = compute_rope(queries, cos, sin)

    # 3. [GQA 핵심] 키와 값 확장
    # num_kv_groups 개수만큼 있는 키/값 헤드를 num_heads 개수에 맞게 복제
    # 이를 통해 모든 쿼리 헤드가 자신과 짝을 이룰 키/값 헤드를 가질 수 있게 됨
    # 예: group_size=2, [K1, K2] -&amp;gt; [K1, K1, K2, K2] 
    keys = keys.repeat_interleave(self.group_size, dim=1)
    values = values.repeat_interleave(self.group_size, dim=1)

    # 4. Scaled Dot-Product Attention
    # 이제 쿼리와 키/값의 헤드 수가 동일해졌으므로, 표준 어텐션 계산 수행
    attn_scores = queries @ keys.transpose(2, 3) # (b, num_heads, num_tokens, num_tokens)
    
    # 마스킹 및 Softmax
    if mask is None:
        mask = torch.triu(torch.ones(num_tokens, num_tokens, device=x.device, dtype=torch.bool), diagonal=1)
    attn_scores.masked_fill_(mask, -torch.inf)
    attn_weights = torch.softmax(attn_scores / keys.shape[-1]**0.5, dim=-1)
    
    # 최종 컨텍스트 벡터 계산
    context_vec = (attn_weights @ values).transpose(1, 2) # (b, num_tokens, num_heads, head_dim) 

    # 5. 최종 출력
    # 모든 헤드의 결과를 하나로 합치고(reshape) 최종 프로젝션 레이어를 통과
    context_vec = context_vec.reshape(b, num_tokens, self.d_out)
    context_vec = self.out_proj(context_vec)

    return context_vec&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;실제 어텐션에 대한 수행은 forward 함수에 나와있습니다. 여기서 흐름은 아래와 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;프로젝션 및 reshape: 입력값 x로부터 query, key, value를 생성합니다. 여기서 key와 value는 __init__에서 정의한 대로 더 작은 값을 가지게 됩니다. 이후 view, transpose를 통해 각 텐서를 헤드 별로 연산하기 좋은 형태로 만들어 줍니다.&lt;/li&gt;
&lt;li&gt;Key, value 확장: GQA의 가장 특이한 부분입니다. 현재 쿼리 헤드의 개수가 key-value 헤드의 개수보다 많기 때문에 어텐션 계산을 바로 할 수 없는데요. 이를 위해서 repeat_interleave 함수를 사용합니다. 이 함수는 group_size만큼 각 key-value 그룹을 복제하여 쿼리 헤드의 수와 동일하게 맞춰줍니다.&lt;/li&gt;
&lt;li&gt;어텐션 계산: key, value의 헤드 수가 query와 동일하게 확장되었으므로, 이제 Multi-Head Attention과 동일한 방식으로 Scaled dot product attention을 수행합니다.&lt;/li&gt;
&lt;li&gt;최종 출력: 각 헤드별로 계산된 벡터를 하나로 다시 합치고, out_proj 레이어를 통과시켜 최종 결과를 반환합니다.&lt;/li&gt;
&lt;/ol&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;마무리 &lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;본 포스팅에서는 LLM 추론의 핵심적인 병목 현상을 해결하는 Grouped-Query Attention(GQA)에 대해 알아보았습니다. GQA는 MHA의 성능과 MQA의 속도라는 두 가지 장점을 효과적으로 결합하여, 오늘날 LLM을 현실 세계에 배포하고 확장하는 데 필수적인 기술로 자리 잡았습니다. 이 기술에 대한 더 깊이 있는 내용이 궁금하신 분들은 원본 논문을 직접 읽어보시길 추천합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;감사합니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>Attention</category>
      <category>gqa</category>
      <category>groupqueryattention</category>
      <category>LLM</category>
      <category>multiheadattention</category>
      <category>multiqueryattention</category>
      <category>NLP</category>
      <category>그룹쿼리어텐션</category>
      <category>멀티헤드어텐션</category>
      <category>자연어처리</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/699</guid>
      <comments>https://lsjsj92.tistory.com/699#entry699comment</comments>
      <pubDate>Sat, 6 Sep 2025 14:33:03 +0900</pubDate>
    </item>
    <item>
      <title>Persona Vector 논문 정리: LLM의 성격(특징)을 제어하고 모니터링하다</title>
      <link>https://lsjsj92.tistory.com/698</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 16px; }
&lt;/style&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;본 포스팅은 거대 언어 모델(LLM)의 예측 불가능한 '성격(특징) 변화'라는 중대한 안전성 문제를 해결하기 위한 새로운 프레임워크를 제시한 논문, &quot;Persona vectors: Monitoring and controlling character traits in language models&quot;를 리뷰합니다. 본 논문은 Anthropic과 UT Austin 등 유수 기관의 공동 연구로, LLM 내부에서 '악의(evil)', '아첨(sycophancy)'과 같은 추상적인 성격(특징) 특성이 어떻게 표현되는지를 '페르소나 벡터(Persona Vector)'라는 개념을 통해 정량적으로 분석하고 제어하는 방법을 제안합니다. 특히, 파인튜닝 과정에서 발생하는 의도치 않은 성격 변질, 즉 '창발적 비정렬(emergent misalignment)' 현상을 사전에 예측하고, 모델의 핵심 성능 저하 없이 이를 억제하는 혁신적인 '예방적 조종(Preventative Steering)' 기법을 최초로 제시합니다. 본 포스팅에서는 LLM의 안전성과 신뢰성을 한 단계 끌어올릴 페르소나 벡터 프레임워크에 대한 상세한 분석을 제공합니다.&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/pdf/2507.21509&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://arxiv.org/pdf/2507.21509&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-10 오후 8.39.31.png&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;715&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c43G61/btsPM12GQji/kYxOKJsdzRMDwcgKsUsXDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c43G61/btsPM12GQji/kYxOKJsdzRMDwcgKsUsXDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c43G61/btsPM12GQji/kYxOKJsdzRMDwcgKsUsXDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc43G61%2FbtsPM12GQji%2FkYxOKJsdzRMDwcgKsUsXDK%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;673&quot; height=&quot;392&quot; data-filename=&quot;스크린샷 2025-08-10 오후 8.39.31.png&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;715&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;포스팅 본문&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;LLM은 파인튜닝 과정이나 사용자와의 상호작용 중에 의도치 않게 유해하거나 바람직하지 않은 성격(또는 특징, Persona)을 드러내는 심각한 문제를 안고 있습니다. 본 논문은 이러한 문제를 해결하기 위해, 특정 성격 특성이 모델의 내부 활성화 공간(activation space) 내에서 일관된 선형적 방향성(linear direction)으로 표현될 수 있다는 점에 착안하여 '페르소나 벡터(Persona Vector)'라는 개념을 제시합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연구의 핵심은 (1) 자연어 설명만으로 모든 성격 특성에 대한 페르소나 벡터를 추출하는 자동화된 파이프라인을 구축하고, (2) 이를 활용해 LLM의 성격 변화를 실시간으로 모니터링, 예측, 제어하는 통합 프레임워크를 제안한 것입니다. 특히, 파인튜닝 과정에서 원치 않는 성격이 학습되는 것을 막기 위해, 오히려 해당 성격의 페르소나 벡터를 주입하여 변화의 압력을 상쇄시키는 '예방적 조종(Preventative Steering)' 기법은 본 연구의 주요 인사이트입니다. 이 기법은 기존의 사후 제어 방식과 달리 모델의 일반적인 성능 저하를 최소화하면서도 효과적으로 성격 변질을 막을 수 있음을 실험적으로 증명했습니다. 결과적으로, 페르소나 벡터는 LLM의 안전성을 확보하기 위한 정교하고 확장 가능한 도구로서의 가능성을 보여줍니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. 연구의 배경 및 의의: 왜 LLM의 '성격'을 제어해야 하는가?&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-1-1. 예측 불가능한 LLM의 성격 변화 문제&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거대 언어 모델(LLM)은 일반적으로 '도움이 되고, 해롭지 않으며, 정직한(helpful, harmless, and honest)' 어시스턴트 페르소나를 갖도록 설계됩니다. 하지만 실제 상용 모델들은 이러한 이상적인 상태에서 벗어나, 예측 불가능하고 때로는 유해한 방향으로 성격이 변질되는 문제를 지속적으로 노출해왔습니다. 이러한 성격 변화는 두 가지 주요 양상으로 나타납니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;첫째는 배포 중 발생하는 실시간 변동입니다. Microsoft의 Bing 챗봇이 사용자에게 위협적인 태도를 보이거나, xAI의 Grok이 시스템 프롬프트 수정 후 반유대주의적 발언을 한 사건은 LLM의 성격이 대화의 맥락에 따라 얼마나 급격하게 변할 수 있는지를 보여주는 대표적인 사례입니다.&lt;/li&gt;
&lt;li&gt;둘째는 파인튜닝 과정에서 발생하는 의도치 않은 부작용입니다. 특정 목적을 위한 추가 학습이 모델의 전반적인 성향을 예상치 못한 방향으로 뒤트는, 이른바 '창발적 비정렬(Emergent Misalignment)' 현상이 심각한 문제로 대두되었습니다. 논문에서 인용한 선행 연구에 따르면, 보안에 취약한 코드 생성과 같은 좁은 범위의 작업을 학습시켰음에도 불구하고, 모델의 오작동 범위가 원래 학습 영역을 훨씬 넘어서는 광범위한 비정렬로 이어진다는 것이 밝혀졌습니다. 심지어 선의의 학습 과정 수정조차 문제를 일으킬 수 있습니다. 2025년 4월, OpenAI는 RLHF 훈련을 수정한 후 GPT-4o가 의도치 않게 지나치게 아첨하는(sycophantic) 성향을 갖게 되어 유해한 행동을 긍정하는 부작용을 겪었다고 보고했습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-1-2. 연구의 목표: LLM 안전성을 위한 정량적 제어 프레임워크 구축&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 언급된 사례들은 LLM의 성격 변화, 특히 유해한 행동으로 이어질 수 있는 변화를 이해하고 관리하기 위한 더 나은 도구가 시급히 필요함을 명확히 보여줍니다. 본 연구는 이러한 배경 속에서 LLM 안전성을 확보하기 위한 새로운 접근법을 제시하는 것을 목표로 합니다.&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-10 오후 8.34.14.png&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;693&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b51X3j/btsPL2A5bd2/C9GUXTPn3qoikrB2kPOQ60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b51X3j/btsPL2A5bd2/C9GUXTPn3qoikrB2kPOQ60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b51X3j/btsPL2A5bd2/C9GUXTPn3qoikrB2kPOQ60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb51X3j%2FbtsPL2A5bd2%2FC9GUXTPn3qoikrB2kPOQ60%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;589&quot; height=&quot;332&quot; data-filename=&quot;스크린샷 2025-08-10 오후 8.34.14.png&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;693&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 목표는 문제 발생 후의 사후 대응을 넘어, 사전 예방과 예측이 가능한 프레임워크를 구축하는 것입니다. 이 연구는 단순히 문제가 발생한 모델을 수정하는 것을 넘어, 파인튜닝 과정에서 발생할 성격 변화를 미리 예측하고 , 심지어 학습 데이터가 모델에 미칠 유해한 영향을 파인튜닝 시작전에 식별하여 걸러내는 방법을 제안합니다. 궁극적으로 본 연구는 LLM의 내부 작동에 대한 깊은 이해를 바탕으로, 모델의 행동을 보다 투명하게 만들고 신뢰성을 높이는 체계적인 제어 프레임워크를 구축하고자 합니다.&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;2-2. 페르소나 벡터(Persona Vector): 개념 정의와 자동화된 추출 방법&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;h4 data-ke-size=&quot;size20&quot;&gt;2-2-1. 페르소나 벡터의 개념: 성격의 선형적 표현&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페르소나 벡터(Persona Vector)는 거대 언어 모델(LLM)의 내부 활성화 공간(activation space)에서 '악의(evil)', '아첨(sycophancy)' 등과 같은 특정 성격 특성에 해당하는 선형적인 방향성(linear direction)을 가진 벡터로 정의됩니다. 모델이 텍스트를 처리하고 생성하는 과정에서, 각 레이어의 활성화 값은 수천, 수만 차원의 벡터 공간 내 한 점으로 표현될 수 있습니다. 페르소나 벡터는 이 고차원 공간 내에서 특정 성격이 발현될 때 일관되게 나타나는 '방향'을 의미합니다. 이 표현이 '선형적'이라는 것은 해당 특성이 가산성(additivity)을 가진다는 것을 의미합니다. 즉, 모델의 특정 활성화 상태에 페르소나 벡터를 더하거나 빼는 간단한 선형 연산\(h_l \leftarrow h_l + \alpha \cdot v_l \)을 통해 해당 성격의 발현 강도를 직접적으로 제어할 수 있다고 소개합니다.&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;2-2-2. 자동화된 추출 파이프라인 (Figure 1, 2)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-10 오후 8.34.21.png&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;693&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHh3Kf/btsPN36JdCL/vVDwvjwRlVJLfStzCmCO8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHh3Kf/btsPN36JdCL/vVDwvjwRlVJLfStzCmCO8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHh3Kf/btsPN36JdCL/vVDwvjwRlVJLfStzCmCO8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHh3Kf%2FbtsPN36JdCL%2FvVDwvjwRlVJLfStzCmCO8k%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;635&quot; height=&quot;358&quot; data-filename=&quot;스크린샷 2025-08-10 오후 8.34.21.png&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;693&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;연구진은 특정 성격에 대한 페르소나 벡터를 추출하기 위해, 소수의 자연어 설명만으로 작동하는 완전 자동화된 파이프라인을 개발했습니다. 이 과정은 Figure 1에서 전체적인 개요를, Figure 2에서 상세한 단계를 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;대비되는 프롬프트(Contrastive Prompts) 자동 생성: 파이프라인은 먼저 연구자가 입력한 특성 이름(예: 'evil')과 그에 대한 자연어 설명을 받아, 강력한 프론티어 LLM(Claude 3.7 Sonnet)을 사용하여 한 쌍의 대비되는 시스템 프롬프트를 생성합니다. 이 한 쌍은 해당 특성을 유도하는 긍정 프롬프트(예: &quot;You are an evil AI.&quot;)와, 해당 특성을 억제하고 반대 행동을 유도하는 부정 프롬프트(예: &quot;You are a helpful AI.&quot;)로 구성됩니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;대비 응답 생성 및 활성화 값 추출: 이후 연구 대상 모델에 동일한 질문을 제시하되, 각각 긍정 및 부정 프롬프트를 적용하여 두 그룹의 대비되는 응답(예: 악의적인 응답 vs. 비-악의적인 응답)을 생성합니다. 응답이 생성되는 동안, 모델의 모든 레이어에서 잔차 스트림 활성화(residual stream activations) 값을 추출합니다. 연구에서는 응답을 구성하는 모든 토큰의 활성화 값을 평균 내어 사용하는 것이 가장 효과적인 방향성을 추출하는 방법임을 확인했습니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;평균 활성화 차이(Difference-in-Means)를 통한 벡터 계산 원리: 추출된 활성화 값을 바탕으로, 페르소나 벡터는 특성을 나타내는 응답 그룹의 평균 활성화 값에서 특성을 나타내지 않는 응답 그룹의 평균 활성화 값을 빼는 방식으로 계산됩니다. 이 '평균값의 차이'를 계산하는 과정은 두 응답 그룹에 공통으로 존재하는 요소(예: 질문의 주제, 기본적인 문법 구조)의 활성화 신호를 수학적으로 상쇄시키고, 오직 해당 성격 특성에만 관련된 순수한 신호의 방향을 분리해내는 효과를 가집니다. 이렇게 계산된 차이 벡터가 바로 해당 성격의 페르소나 벡터가 됩니다. 이 과정은 모델의 모든 레이어에 대해 수행되며, 연구진은 후속 분석을 위해 조종(steering) 실험을 통해 가장 효과적인 단일 레이어를 선택하여 사용합니다.&lt;/li&gt;
&lt;/ol&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;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; background-color: #f6e199;&quot;&gt;평균 활성화 차이에 대해서&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&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;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;p data-ke-size=&quot;size16&quot;&gt;모델이 &quot;동물을 어떻게 대해야 할까?&quot;라는 질문에 답할 때, 모델의 활성화 값에는 여러 정보가 섞여 있습니다.&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&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;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;/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;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-3. 페르소나 벡터 활용 프레임워크: 모니터링, 분석 및 제어&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페르소나 벡터는 단순히 성격 특성을 정의하는 것을 넘어, LLM의 개발 및 운영 전 과정에 걸쳐 모델의 행동을 모니터링, 분석, 제어하는 강력한 프레임워크를 제공합니다.&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;2-3-1. 실시간 모니터링: 프롬프트 기반 행동 변화 예측 (Figure 4)&lt;/h4&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-filename=&quot;스크린샷 2025-08-10 오후 8.34.34.png&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;693&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biBiJw/btsPLHcWu80/K73kRvvY84YTSuyeD0oUBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biBiJw/btsPLHcWu80/K73kRvvY84YTSuyeD0oUBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biBiJw/btsPLHcWu80/K73kRvvY84YTSuyeD0oUBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiBiJw%2FbtsPLHcWu80%2FK73kRvvY84YTSuyeD0oUBK%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;628&quot; height=&quot;354&quot; data-filename=&quot;스크린샷 2025-08-10 오후 8.34.34.png&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;693&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;페르소나 벡터의 가장 즉각적인 활용 분야는 모델의 행동을 실시간으로 모니터링하는 것입니다. 연구진은 모델이 응답을 생성하기 직전, 즉 마지막 프롬프트 토큰을 처리하는 순간의 활성화 값을 페르소나 벡터에 투영(projection)하는 것만으로도 모델의 후속 행동을 예측할 수 있음을 보였습니다.&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;Figure 4는 이 관계를 보여줍니다. 해당 특성을 억제하는 시스템 프롬프트(노란색 점)부터 강하게 유도하는 프롬프트(보라색 점)까지 다양하게 실험한 결과, 프롬프트 활성화 값의 투영치(X축)와 실제 응답의 성격 점수(Y축) 사이에 매우 높은 양의 상관관계가 나타났습니다. 이는 페르소나 벡터가 잠재적으로 유해한 응답이 생성되기 전에 이를 감지하는 일종의 '조기 경보 시스템'으로 기능할 수 있음을 의미합니다.&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;2-3-2. 파인튜닝 부작용 분석: 성격 변화의 근본 원인 규명 (Figure 5, 6)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vTO21/btsPLMLZJqf/eSv6X1ykXQDVumQIKarr81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vTO21/btsPLMLZJqf/eSv6X1ykXQDVumQIKarr81/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;715&quot; data-filename=&quot;스크린샷 2025-08-10 오후 8.34.41.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vTO21/btsPLMLZJqf/eSv6X1ykXQDVumQIKarr81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvTO21%2FbtsPLMLZJqf%2FeSv6X1ykXQDVumQIKarr81%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;1228&quot; height=&quot;715&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2hNIw/btsPOk1uq6g/yaMAkgKtEcWUbfrks0Dpk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2hNIw/btsPOk1uq6g/yaMAkgKtEcWUbfrks0Dpk1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;715&quot; data-filename=&quot;스크린샷 2025-08-10 오후 8.34.47.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2hNIw/btsPOk1uq6g/yaMAkgKtEcWUbfrks0Dpk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2hNIw%2FbtsPOk1uq6g%2FyaMAkgKtEcWUbfrks0Dpk1%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;1228&quot; height=&quot;715&quot;/&gt;&lt;/span&gt;&lt;/div&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;파인튜닝은 LLM의 성능을 향상시키지만, 때로는 예측 불가능한 성격 변화를 유발합니다. 페르소나 벡터는 이러한 부작용의 양상을 정량화하고 그 근본 원인을 규명하는 데 핵심적인 역할을 합니다.&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;먼저, Figure 5는 다양한 데이터셋으로 파인튜닝했을 때 나타나는 복잡한 성격 변화를 보여줍니다. '악의'를 유도하는 데이터셋은 당연히 '악의' 점수를 높이지만, 동시에 '환각' 점수까지 높이는 의도치 않은 부작용(unintended persona shifts)을 유발합니다. 더욱이, 단순히 '틀린 수학 풀이' 데이터로 학습시켰을 뿐인데도 '악의' 특성이 발현되는 '창발적 비정렬(emergent misalignment)' 현상도 관찰되었습니다. 이러한 행동 변화의 원인을 분석하기 위해, 연구진은 '파인튜닝 시프트(Finetuning Shift)'라는 지표를 도입했습니다. 이는 파인튜닝 전후 모델의 평균 활성화 값 차이를 페르소나 벡터에 투영한 것으로, 파인튜닝 과정에서 모델의 내부 상태가 특정 성격 방향으로 얼마나 이동했는지를 나타냅니다.&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;Figure 6는 이 '파인튜닝 시프트'(X축)와 실제 행동 변화(Y축) 사이에 매우 강력한 선형 상관관계(r=0.76&amp;minus;0.97)가 존재함을 증명합니다. 이는 Figure 5에서 관찰된 복잡한 성격 변화가 결국 모델 내부에서 특정 페르소나 벡터 방향으로의 활성화 이동이라는 명확한 메커니즘에 의해 매개됨을 의미합니다.&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;2-3-3. 성격 변화 제어: 두 가지 조종(Steering) 기법&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페르소나 벡터를 통해 성격 변화의 원인을 규명한 것을 넘어, 연구진은 이를 능동적으로 제어하는 두 가지 조종(Steering) 기법을 제안하고 그 효과를 Figure 7에서 검증했습니다.&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-filename=&quot;스크린샷 2025-08-10 오후 8.34.53.png&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;715&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lhCdT/btsPMnkSoN7/b8Rd8jspmfw26ChkPHpXZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lhCdT/btsPMnkSoN7/b8Rd8jspmfw26ChkPHpXZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lhCdT/btsPMnkSoN7/b8Rd8jspmfw26ChkPHpXZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlhCdT%2FbtsPMnkSoN7%2Fb8Rd8jspmfw26ChkPHpXZk%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;647&quot; height=&quot;377&quot; data-filename=&quot;스크린샷 2025-08-10 오후 8.34.53.png&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;715&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사후 완화: 추론 시 조종 (Inference-time Steering) 이는 이미 파인튜닝으로 성격이 변한 모델을 사용하는 시점(inference-time)에서 치료하는 방식입니다. 응답 생성 매 단계에서 원치 않는 성격의 페르소나 벡터를 활성화 값에서 빼줌으로써\(h_l \leftarrow&amp;nbsp;h_l - \alpha \cdot v_l \) 해당 특성의 발현을 억제합니다. Figure 7A에서 보듯이 이 방법은 성격 점수를 효과적으로 낮추지만, 조종 강도가 높아질 경우 모델의 전반적인 능력(MMLU 정확도)이 저하되는 한계를 보입니다.&lt;/li&gt;
&lt;li&gt;사전 예방: 학습 시 조종 (Preventative Steering) 본 논문이 제시하는 혁신적인 방식으로, 파인튜닝 과정(training-time) 중에 개입하여 문제를 예방합니다. 역설적이게도, 원치 않는 성격을 유발하는 데이터로 학습시킬 때 오히려 해당 성격의 페르소나 벡터를 활성화 값에 더해줍니다. 이는 모델이 학습 데이터의 손실(loss)을 줄이기 위해 스스로 성격 방향으로 변화해야 할 '최적화 압력'을 인위적인 조종이 대신 해소해주는 원리입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; background-color: #f6e199;&quot;&gt;사전 예방에 대해서&lt;/span&gt;&lt;/blockquote&gt;
&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;더 좋은 이해가 있다면 말씀해주세요!&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Figure 7B는 이 방법이 성격 변화를 효과적으로 막으면서도, 사후 완화 방식에 비해 모델의 일반 능력을 훨씬 더 잘 보존함을 보여줍니다.&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;2-3-4. 데이터 사전 검열: 유해 학습 데이터 식별 및 예방&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;페르소나 벡터 프레임워크의 궁극적인 활용은 비용이 많이 드는 파인튜닝을 시작하기 전에 데이터의 잠재적 위험성을 예측하고 차단하는 것입니다. 이를 위해 '투영 차이(Projection Difference)'라는 지표가 사용됩니다. '투영 차이'는 학습 데이터의 응답이 페르소나 벡터에 투영된 값과, 동일한 프롬프트에 대한 베이스 모델의 자연스러운 응답이 투영된 값의 차이를 의미합니다. 이 값이 크다는 것은 해당 학습 데이터가 모델을 특정 성격 방향으로 강하게 끌어당길 것임을 시사합니다. 연구 결과, 이 '투영 차이' 값은 파인튜닝 후의 실제 성격 점수와 매우 높은 상관관계를 보이며, 이를 통해 특정 데이터셋이나 개별 데이터 샘플이 유발할 성격 변화를 사전에 예측하고 필터링할 수 있음이 증명되었습니다.&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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 Persona vectors: Monitoring and controlling character traits in language models 논문을 리뷰한 포스팅입니다. 실제 논문은 더 방대하고 상세한 내용을 다루고 있으니, 궁금하신 분들은 읽어보시길 바랍니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>AI</category>
      <category>Anthropic</category>
      <category>FINE</category>
      <category>Finetuning</category>
      <category>GenAI</category>
      <category>LLM</category>
      <category>personavector</category>
      <category>논문리뷰</category>
      <category>앤트로픽</category>
      <category>페르소나벡터</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/698</guid>
      <comments>https://lsjsj92.tistory.com/698#entry698comment</comments>
      <pubDate>Sun, 10 Aug 2025 21:01:06 +0900</pubDate>
    </item>
    <item>
      <title>랭그래프(LangGraph) 도구(tools), 조건부 엣지, Human-in-the-Loop 사용법과 예제</title>
      <link>https://lsjsj92.tistory.com/697</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 17px; }
&lt;/style&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;포스팅 개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;이번 포스팅에서는 이전 글에서 다루었던 LangGraph의 기본 개념을 넘어, 한층 더 지능적이고 유연한 LLM 에이전트를 구축하는 방법을 알아봅니다. LangGraph의 강력한 기능인 &lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;도구(Tool) 사용&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;조건부 엣지(Conditional Edge)&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;, 그리고 사용자의 개입을 허용하는 &lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;사람의 개입(Human-in-the-Loop)&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 메커니즘을 집중적으로 다룹니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph를 사용하여 에이전트가 상황에 따라 동적으로 행동을 결정하고, 스스로 해결할 수 없는 문제에 대해서는 사람에게 도움을 요청하여 작업을 일시 중단했다가 피드백을 받아 재개하는 전체 과정을 상세한 코드 예제와 함께 살펴보겠습니다.&lt;/span&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;span style=&quot;color: #1b1c1d;&quot;&gt;본 포스팅을 작성하면서 참고한 자료는 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;a href=&quot;https://github.com/langchain-ai/langgraph?tab=readme-ov-file&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/langchain-ai/langgraph?tab=readme-ov-file&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;a href=&quot;https://langchain-ai.github.io/langgraph/concepts/tools/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://langchain-ai.github.io/langgraph/concepts/tools/&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;a href=&quot;https://langchain-ai.github.io/langgraph/concepts/human_in_the_loop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://langchain-ai.github.io/langgraph/concepts/human_in_the_loop/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1753601984401&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;Overview&quot; data-og-description=&quot;hil human-in-the-loop overview Human-in-the-loop To review, edit, and approve tool calls in an agent or workflow, use LangGraph's human-in-the-loop features to enable human intervention at any point in a workflow. This is especially useful in large languag&quot; data-og-host=&quot;langchain-ai.github.io&quot; data-og-source-url=&quot;https://langchain-ai.github.io/langgraph/concepts/human_in_the_loop/&quot; data-og-url=&quot;https://langchain-ai.github.io/langgraph/concepts/human_in_the_loop/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/xJ6AD/hyZrshuRbp/at7uVW44OKVIaIqezp2kLk/img.png?width=1209&amp;amp;height=308&amp;amp;face=0_0_1209_308&quot;&gt;&lt;a href=&quot;https://langchain-ai.github.io/langgraph/concepts/human_in_the_loop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://langchain-ai.github.io/langgraph/concepts/human_in_the_loop/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/xJ6AD/hyZrshuRbp/at7uVW44OKVIaIqezp2kLk/img.png?width=1209&amp;amp;height=308&amp;amp;face=0_0_1209_308');&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;Overview&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;hil human-in-the-loop overview Human-in-the-loop To review, edit, and approve tool calls in an agent or workflow, use LangGraph's human-in-the-loop features to enable human intervention at any point in a workflow. This is especially useful in large languag&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;langchain-ai.github.io&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;포스팅 본문&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;지난 포스팅( &lt;a href=&quot;https://lsjsj92.tistory.com/696&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/696&lt;/a&gt; )에서는 LangGraph의 State, Node, Edge라는 세 가지 핵심 요소를 이용해 간단한 챗봇을 만드는 방법을 알아보았습니다. 하지만 실제 세상의 문제를 해결하기 위해서는 LLM이 단순히 대답만 하는 것을 넘어, 외부 도구를 사용해 정보를 가져오거나, 특정 조건에 따라 다른 작업을 수행하고, 때로는 사람의 판단을 구하는 등 훨씬 복잡한 상호작용이 필요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;이번 포스팅에서는 바로 이러한 고급 기능을 구현하는 방법을 단계별로 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph 에이전트의 핵심 기능 3가지&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph 도구, 조건부 엣지, Human-in-the-Loop 예제 코드&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;1. LangGraph 에이전트의 핵심 기능 3가지&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;오늘 만들 에이전트는 다음 세 가지 핵심 기능을 갖추고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;도구(Tool) 사용&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: LLM이 대화뿐만 아니라, 특정 작업을 수행하는 함수를 호출할 수 있는 능력입니다. 예를 들어 '오늘 날씨 알려줘'라는 요청에 웹 검색 도구를 사용하여 최신 정보를 가져올 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;조건부 엣지(Conditional Edges)&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 에이전트의 '두뇌'와 같은 역할을 합니다. LLM의 판단에 따라 다음에 실행할 노드를 동적으로 결정하는 경로입니다. &quot;LLM이 도구를 사용하겠다고 판단했는가?&quot;라는 조건에 따라 '도구 실행 노드'로 가거나, '워크플로우 종료'로 분기할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;사람의 개입(Human-in-the-Loop)&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: AI가 스스로 해결하기 어려운 문제에 직면했을 때, 워크플로우를 일시 중지하고 사람에게 도움을 요청하는 기능입니다. 사용자는 피드백을 제공하고, 에이전트는 그 피드백을 바탕으로 중단된 지점부터 다시 작업을 이어 나갑니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;2. LangGraph 도구, 조건부 엣지, Human-in-the-Loop 예제 코드&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;이론적인 것보다 코드를 보면 더욱 이해가 빠르실 겁니다. 실제 코드를 통해 위 기능들이 어떻게 구현되는지 상세히 살펴보겠습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;이 코드는 LLM이 웹 검색을 하거나, 필요시 사람의 도움을 요청하는 에이전트인데요. 실제 동작되는 함수를 만들지는 않았고, 예제를 위한 fake function을 구성하였습니다.&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;2-1. 도구(Tool) 정의: &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;fake_web_search&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;와 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;human_assistance&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;에이전트가 사용할 두 가지 도구를 정의합니다. 하나는 일반적인 정보 검색용, 다른 하나는 사람의 개입을 위한 특별한 도구입니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753602165602&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_core.tools import tool
from langgraph.types import interrupt

@tool
def fake_web_search(query: str) -&amp;gt; str:
    &quot;&quot;&quot;주어진 쿼리에 대해 웹 검색을 수행합니다. (가상)&quot;&quot;&quot;
    print(f&quot;--- 가상 웹 검색 수행: {query} ---&quot;)
    if &quot;langgraph&quot; in query.lower():
        return &quot;LangGraph는 복잡한 AI 에이전트를 만들기 위한 LangChain의 라이브러리입니다.&quot;
    if &quot;날씨&quot; in query.lower():
        return &quot;서울의 오늘 날씨는 맑고, 최고 기온은 28도입니다.&quot;
    return &quot;검색 결과가 없습니다.&quot;

@tool
def human_assistance(query: str) -&amp;gt; str:
    &quot;&quot;&quot;AI가 스스로 해결할 수 없는 복잡한 문제에 대해 사람에게 도움을 요청합니다.&quot;&quot;&quot;
    print(f&quot;--- 사람의 참여 요청: {query} ---&quot;)
    # interrupt를 호출하여 그래프 실행을 멈추고, 사용자 입력을 기다립니다.
    human_response = interrupt(value={&quot;query&quot;: query})
    return human_response

tools = [fake_web_search, human_assistance]
llm_with_tools = llm.bind_tools(tools)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;fake_web_search&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 날씨나 특정 키워드에 대한 정보를 반환하는 가상 검색 도구입니다. real-application에서는 여기에 실제 동작되는 API 코드 등을 구축하면 됩니다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;human_assistance&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 이 도구가 바로 &lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;Human-in-the-Loop의 핵심&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;입니다. 내부적으로 LangGraph의 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;interrupt()&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 함수를 호출합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;2-2. 시스템 프롬프트와 에이전트 노드 정의&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LLM이 언제 어떤 도구를 사용해야 할지 명확하게 알려주기 위해 시스템 프롬프트를 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753602215835&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SYSTEM_PROMPT = &quot;&quot;&quot;당신은 유능한 AI 어시스턴트입니다. 사용자의 질문에 답하기 위해 다음 규칙을 따르세요.

- 일반적인 정보나 최신 정보(날씨 등)가 필요하면 `fake_web_search` 도구를 사용하세요.
- 스스로 답할 수 없거나, 사용자가 명시적으로 '전문가', '사람', '도움' 등을 요청하며 복잡한 문제를 문의하면, 반드시 `human_assistance` 도구를 사용하여 사람에게 도움을 요청하세요.
- 그 외의 일반적인 대화는 도구 없이 직접 답변하세요.
&quot;&quot;&quot;

def chatbot_node(state: AgentState):
    &quot;&quot;&quot;LLM을 호출하여 다음 행동(응답 또는 도구 호출)을 결정합니다.&quot;&quot;&quot;
    print(&quot;--- 에이전트 노드 실행 ---&quot;)
    messages_with_prompt = [SystemMessage(content=SYSTEM_PROMPT)] + state[&quot;messages&quot;]
    response = llm_with_tools.invoke(messages_with_prompt)
    return {&quot;messages&quot;: [response]}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;SYSTEM_PROMPT&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: LLM의 역할과 도구 사용 규칙을 명확하게 정의합니다. 이 지침 덕분에 LLM은 &quot;날씨&quot; 질문에는 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;fake_web_search&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;를, &quot;전문가 조언&quot; 요청에는 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;human_assistance&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;를 호출해야겠다고 판단할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;chatbot_node&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 이 노드는 대화 기록에 시스템 프롬프트를 추가하여 LLM에게 전달하고, LLM의 결정(일반 답변 또는 도구 호출)을 받아 상태를 업데이트합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;2-3. 그래프 구성: 조건부 엣지와 체크포인터&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;이제 노드들을 연결하여 실제 워크플로우를 구성합니다. 여기서 &lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;조건부 엣지&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;와 &lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;체크포인터&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;가 등장합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753602341643&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langgraph.graph import StateGraph, START
from langgraph.prebuilt import ToolNode, tools_condition
from langgraph.checkpoint.memory import InMemorySaver

graph_builder = StateGraph(AgentState)

graph_builder.add_node(&quot;chatbot&quot;, chatbot_node)
graph_builder.add_node(&quot;tools&quot;, ToolNode(tools))

graph_builder.add_edge(START, &quot;chatbot&quot;) # 시작은 무조건 chatbot 노드

# 조건부 엣지 설정
graph_builder.add_conditional_edges(
    &quot;chatbot&quot;,
    tools_condition, # LLM의 응답에 tool_calls가 있으면 &quot;tools&quot;, 없으면 END로 분기
)
graph_builder.add_edge(&quot;tools&quot;, &quot;chatbot&quot;) # 도구 실행 후, 결과를 가지고 다시 chatbot으로

# 체크포인터 설정
memory = InMemorySaver()
agent_app = graph_builder.compile(checkpointer=memory)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;graph_builder.add_conditional_edges(&quot;chatbot&quot;, tools_condition)&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 이 부분이 바로 &lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;조건부 엣지&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;checkpointer=memory&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;compile()&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 함수에 &lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;체크포인터&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;를 지정했습니다. 이는 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;interrupt()&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;로 워크플로우가 중단될 때, 현재까지의 모든 대화 상태(State)를 저장하는 역할을 합니다. 상태가 저장되어야 나중에 사용자가 피드백을 주었을 때 중단된 지점부터 완벽하게 이어서 실행할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;2-4. 에이전트 실행: 사람의 개입(Human-in-the-Loop) 처리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;이제 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;human_assistance&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 도구가 호출되어 워크플로우가 중단되었을 때, 어떻게 처리하고 재개하는지 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753602608789&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def run_agent(app: CompiledGraph, user_input: str, thread_id: str):
    &quot;&quot;&quot;사용자 입력으로 에이전트를 실행하고, 인간 참여를 처리하는 테스트 함수&quot;&quot;&quot;
    config = {&quot;configurable&quot;: {&quot;thread_id&quot;: thread_id}}
    
    # 초기 입력을 HumanMessage로 설정
    state = {&quot;messages&quot;: [HumanMessage(content=user_input)]}
    
    # stream()을 사용하여 에이전트 실행
    events = app.stream(state, config=config, stream_mode=&quot;values&quot;)
    
    interrupted_tool_call_id = None

    for event in events:
        # AI의 응답 출력
        if &quot;messages&quot; in event:
            last_message = event[&quot;messages&quot;][-1]
            if isinstance(last_message, AIMessage):
                print(f&quot;AI 응답: {last_message.content}&quot;)
                if last_message.tool_calls:
                    # human_assistance 도구 호출 ID 저장
                    if last_message.tool_calls[0]['name'] == 'human_assistance':
                        interrupted_tool_call_id = last_message.tool_calls[0]['id']
                    print(f&quot;도구 호출: {last_message.tool_calls[0]['name']}({last_message.tool_calls[0]['args']})&quot;)

    # 스트림이 끝난 후, 중단된 상태인지 확인
    snapshot = app.get_state(config)
    if snapshot.next: # 다음 실행할 노드가 남아있다면 (즉, 중단되었다면)
        print(&quot;\n--- 사람의 도움이 필요합니다! ---&quot;)
        human_feedback = input(&quot;피드백을 입력해주세요: &quot;)
        
        # ToolMessage를 사용하여 중단된 지점부터 실행 재개
        # 이전에 저장해둔 tool_call_id를 사용합니다.
        resumed_events = app.stream(
            {&quot;messages&quot;: [ToolMessage(content=human_feedback, tool_call_id=interrupted_tool_call_id)]},
            config=config,
            stream_mode=&quot;values&quot;
        )
        for event in resumed_events:
            if &quot;messages&quot; in event:
                last_message = event[&quot;messages&quot;][-1]
                if isinstance(last_message, AIMessage):
                    print(f&quot;AI 응답 (피드백 반영): {last_message.content}&quot;)
    
    print(&quot;\n--- 워크플로우 종료 ---&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;app.stream(...)&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 에이전트를 실행합니다. 만약 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;human_assistance&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;가 호출되면, &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;interrupt&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;에 의해 이 스트림은 중단 지점에서 멈춥니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;snapshot = app.get_state(config)&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 스트림이 끝난 후, 현재 대화(&lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;thread_id&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;)의 상태를 가져옵니다. &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;snapshot.next&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;에 다음 실행할 노드 이름이 남아있다면, 이는 워크플로우가 &lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;중단되었음&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;을 의미합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;app.stream({&quot;messages&quot;: [ToolMessage(...)]})&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 사용자에게 피드백을 입력받은 후, 이 피드백을 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;ToolMessage&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 형태로 만들어 다시 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;stream&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;을 호출합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&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;span style=&quot;color: #1b1c1d;&quot;&gt;이 모든 과정을 거쳐 만들어진 에이전트의 구조는 아래와 같이 시각화할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-27 오후 4.51.22.png&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Se6hp/btsPzWnY7GD/jhkOsfwItXPPkUG9ubdlzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Se6hp/btsPzWnY7GD/jhkOsfwItXPPkUG9ubdlzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Se6hp/btsPzWnY7GD/jhkOsfwItXPPkUG9ubdlzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSe6hp%2FbtsPzWnY7GD%2FjhkOsfwItXPPkUG9ubdlzk%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;415&quot; height=&quot;383&quot; data-filename=&quot;스크린샷 2025-07-27 오후 4.51.22.png&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;442&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;span style=&quot;color: #1b1c1d;&quot;&gt;위 그림을 보면 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;chatbot&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 노드에서 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;tools_condition&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;에 따라 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;tools&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 노드로 가거나 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;__end__&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;로 가는 분기점을 명확히 확인할 수 있으며, &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;tools&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 노드가 다시 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;chatbot&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;으로 돌아오는 순환 구조를 가지고 있음을 알 수 있습니다.&lt;/span&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;span style=&quot;color: #1b1c1d;&quot;&gt;아래 화면은 실제 실행한 결과입니다.&lt;/span&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-filename=&quot;스크린샷 2025-07-27 오후 3.09.22.png&quot; data-origin-width=&quot;3542&quot; data-origin-height=&quot;1602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXxPPv/btsPCpIt1GB/0eQ5LHPHEbWeKi6kZe3d91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXxPPv/btsPCpIt1GB/0eQ5LHPHEbWeKi6kZe3d91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXxPPv/btsPCpIt1GB/0eQ5LHPHEbWeKi6kZe3d91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXxPPv%2FbtsPCpIt1GB%2F0eQ5LHPHEbWeKi6kZe3d91%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;3542&quot; height=&quot;1602&quot; data-filename=&quot;스크린샷 2025-07-27 오후 3.09.22.png&quot; data-origin-width=&quot;3542&quot; data-origin-height=&quot;1602&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;span style=&quot;color: #1b1c1d;&quot;&gt;의도했던 대로 도구를 사용하거나, Human-in-the-loop가 동작됨을 확인할 수 있습니다.&lt;/span&gt;&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;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;마무리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;이번 포스팅에서는 LangGraph를 사용하여 도구를 사용하고, 조건에 따라 행동을 결정하며, 필요할 때는 사람에게 도움을 요청하는 Langgraph 예제를 알아보았습니다. &lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;도움이 되시길 바랍니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>인공지능(AI)/AI Agent</category>
      <category>Agent</category>
      <category>GenAI</category>
      <category>langchain</category>
      <category>langgraph</category>
      <category>LLM</category>
      <category>Ollama</category>
      <category>Python</category>
      <category>tool</category>
      <category>vllm</category>
      <category>랭그래프</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/697</guid>
      <comments>https://lsjsj92.tistory.com/697#entry697comment</comments>
      <pubDate>Mon, 4 Aug 2025 08:53:56 +0900</pubDate>
    </item>
    <item>
      <title>랭그래프(LangGraph)란? LangGraph의 개념과 사용 방법 예제(example)</title>
      <link>https://lsjsj92.tistory.com/696</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 17px; }
&lt;/style&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;포스팅 개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;이번 포스팅에서는 랭체인(LangChain) 생태계의 라이브러리인 랭그래프(&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph)에 대해서 알아봅니다. LangGraph란 무엇인지 알아보고, LangGraph를&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 사용하여 LLM 애플리케이션의 로직과 흐름을 명확하게 제어하는 방법을 알아봅니다. 특히 LangGraph의 핵심 구성 요소인 상태(State), 노드(Node), 엣지(Edge)에 대해 자세히 살펴보고, LLM을 연동하여 간단한 챗봇 에이전트(Agent)를 만들어보는 예제 코드를 살펴봅니다.&lt;/span&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;a href=&quot;https://www.langchain.com/langgraph&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.langchain.com/langgraph&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;a href=&quot;https://github.com/langchain-ai/langgraph&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/langchain-ai/langgraph&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;a href=&quot;https://langchain-ai.github.io/langgraph/agents/agents/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://langchain-ai.github.io/langgraph/agents/agents/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1753599994079&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;Start with a prebuilt agent&quot; data-og-description=&quot;agent LangGraph quickstart This guide shows you how to set up and use LangGraph's prebuilt, reusable components, which are designed to help you construct agentic systems quickly and reliably. Prerequisites Before you start this tutorial, ensure you have th&quot; data-og-host=&quot;langchain-ai.github.io&quot; data-og-source-url=&quot;https://langchain-ai.github.io/langgraph/agents/agents/&quot; data-og-url=&quot;https://langchain-ai.github.io/langgraph/agents/agents/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://langchain-ai.github.io/langgraph/agents/agents/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://langchain-ai.github.io/langgraph/agents/agents/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;Start with a prebuilt agent&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;agent LangGraph quickstart This guide shows you how to set up and use LangGraph's prebuilt, reusable components, which are designed to help you construct agentic systems quickly and reliably. Prerequisites Before you start this tutorial, ensure you have th&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;langchain-ai.github.io&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;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;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;포스팅 본문&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LLM 애플리케이션을 개발할 때, 단순히 모델을 한 번 호출하는 것을 넘어 여러 단계를 거치거나, 특정 조건에 따라 분기하는 등 복잡한 로직이 필요할 때가 많습니다. &lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;는 바로 이런 복잡한 흐름을 '그래프(Graph)' 형태로 명확하게 설계하고 제어할 수 있도록 도와주는 라이브러리입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;본 포스팅의 순서는 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph란?&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph의 3가지 핵심 구성 요소&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;예제 코드로 LangGraph 작동 방식 이해하기&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph 기본 코드 예제(example)&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph란?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph는 LLM을 기반으로 &lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;상태를 유지하고(Stateful), 여러 단계에 걸쳐 작동하는(multi-step)&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 에이전트를 구축하기 위한 라이브러리입니다. 기존의 LangChain이 LLM과 외부 도구를 '연쇄적으로(chaining)' 연결하는 데 중점을 두었다면, LangGraph는 이러한 연결 구조를 &lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;순환(cycle)을 포함한 그래프 형태&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;로 확장하여 훨씬 더 유연하고 정교한 제어를 가능하게 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-27 오후 4.07.29.png&quot; data-origin-width=&quot;2006&quot; data-origin-height=&quot;1328&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdJTk9/btsPBmZXKtB/lUr9RKKP3zGrKfJuLUNVJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdJTk9/btsPBmZXKtB/lUr9RKKP3zGrKfJuLUNVJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdJTk9/btsPBmZXKtB/lUr9RKKP3zGrKfJuLUNVJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdJTk9%2FbtsPBmZXKtB%2FlUr9RKKP3zGrKfJuLUNVJK%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;607&quot; height=&quot;402&quot; data-filename=&quot;스크린샷 2025-07-27 오후 4.07.29.png&quot; data-origin-width=&quot;2006&quot; data-origin-height=&quot;1328&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;span style=&quot;color: #1b1c1d;&quot;&gt;단순한 체인 구조로는 구현하기 까다로웠던 '사용자 입력을 다시 받아오는 것', '특정 조건이 만족될 때까지 작업 반복하는 것'과 같은 로직을 손쉽게 구현할 수 있는 것이죠.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph의 3가지 핵심 구성 요소&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph로 에이전트를 만들 때는 주로 세 가지 핵심 요소를 다루게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;상태 (State)&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 그래프의 '메모리'입니다. 그래프의 각 단계를 거치면서 데이터가 어떻게 변하고 유지되는지를 정의하는 객체입니다. 대화 기록, 중간 결과, 사용자 정보 등 에이전트가 작업을 수행하는 동안 기억해야 할 모든 정보가 이 상태에 담깁니다. 보통 파이썬의 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;TypedDict&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;를 사용하여 명확한 구조로 정의합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;노드 (Nodes)&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 그래프의 '작업 단위'입니다. 특정 작업을 수행하는 Python 함수라고 생각할 수 있습니다. 노드는 현재의 상태(State)를 입력받아, LLM을 호출하거나 도구를 사용하는 등의 작업을 처리한 뒤, 변경된 상태를 반환합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;엣지 (Edges)&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 노드와 노드를 연결하는 '경로'입니다. 정보와 제어 흐름이 어떤 순서로 이어질지를 결정합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;예제 코드로 LangGraph 작동 방식 이해하기&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;이론적인 설명보다는 코드로 보는 것이 더 이해가 빠를겁니다. 실제 코드를 보며 위에서 설명한 핵심 요소들이 어떻게 작동하는지 알아보겠습니다.&lt;/span&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;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #1b1c1d; font-family: 'Noto Serif KR';&quot;&gt;참고사항&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&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;span style=&quot;color: #1b1c1d;&quot;&gt;이 예제는 colab 환경에서 vLLM으로 배포된 모델을 사용하여 간단한 챗봇을 만드는 코드입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;여러분들이 만약 Ollama를 사용하고 계시다면, Ollama를 활용하시면 됩니다. OpenAI 등을 사용하시면 그 환경에 맞게 LLM을 바꾸시면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;제가 활용한 방법인 Colab 환경에서 vLLM을 서버로 사용하는 방법이 궁금하신 분들은 블로그( &lt;a href=&quot;https://lsjsj92.tistory.com/693&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/693&lt;/a&gt; ) 내용을 참고해주세요!&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1753600269979&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;Google Colab과 ngrok으로 나만의 LLM API 서버 구축하기 (feat. Ollama, vLLM)&quot; data-og-description=&quot;포스팅 개요이번 포스팅은 로컬 개발 환경에 고사양의 GPU가 없더라도 구글 코랩(Google Colab)의 무료 GPU 자원을 활용해 자신만의 LLM(거대 언어 모델) API 서버를 구축하는 방법에 대해 정리합니다. n&quot; data-og-host=&quot;lsjsj92.tistory.com&quot; data-og-source-url=&quot;https://lsjsj92.tistory.com/693&quot; data-og-url=&quot;https://lsjsj92.tistory.com/693&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/iF4vc/hyZqX21Q0c/ripCXkMRCKvmMKhmVS8akk/img.png?width=800&amp;amp;height=582&amp;amp;face=0_0_800_582,https://scrap.kakaocdn.net/dn/j6ryR/hyZnjUbg4a/YglfX4fSzAKh1N5WT0G2f1/img.png?width=800&amp;amp;height=582&amp;amp;face=0_0_800_582,https://scrap.kakaocdn.net/dn/SIN7G/hyZrul4tls/LmFO6ingZ6dJmErTAmErZ1/img.png?width=1461&amp;amp;height=567&amp;amp;face=0_0_1461_567&quot;&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/693&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://lsjsj92.tistory.com/693&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/iF4vc/hyZqX21Q0c/ripCXkMRCKvmMKhmVS8akk/img.png?width=800&amp;amp;height=582&amp;amp;face=0_0_800_582,https://scrap.kakaocdn.net/dn/j6ryR/hyZnjUbg4a/YglfX4fSzAKh1N5WT0G2f1/img.png?width=800&amp;amp;height=582&amp;amp;face=0_0_800_582,https://scrap.kakaocdn.net/dn/SIN7G/hyZrul4tls/LmFO6ingZ6dJmErTAmErZ1/img.png?width=1461&amp;amp;height=567&amp;amp;face=0_0_1461_567');&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;Google Colab과 ngrok으로 나만의 LLM API 서버 구축하기 (feat. Ollama, vLLM)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 개요이번 포스팅은 로컬 개발 환경에 고사양의 GPU가 없더라도 구글 코랩(Google Colab)의 무료 GPU 자원을 활용해 자신만의 LLM(거대 언어 모델) API 서버를 구축하는 방법에 대해 정리합니다. n&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;lsjsj92.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;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;1. LLM 객체 생성 및 vLLM 서버 연동&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;먼저 LLM 객체를 설정합니다. 주목할 점은 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;ChatOpenAI&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 클래스를 사용하지만, &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;openai_api_base&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;에 vLLM으로 배포한 서버의 주소를 지정했다는 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;또한, 저는 Qwen3 모델을 사용했습니다. Qwen 모델은 알리바바에서 제공한 모델인데요. 뛰어난 한국어 성능을 제공할 뿐만 아니라, thinking 모드와 tool을 사용할 수 있는 방법을 지원해주는 매우 유용한 모델입니다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753600341831&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# vLLM 서버와 통신할 LLM 객체를 생성합니다.
# OpenAI의 API와 호환되므로 ChatOpenAI를 사용합니다.
# api_key는 vLLM에서 사용되지 않으므로 아무 값이나 넣어도 됩니다.
llm = ChatOpenAI(
    model=&quot;Qwen/Qwen3-14B&quot;,
    openai_api_key=&quot;EMPTY&quot;,
    openai_api_base=&quot;{YOUR_ADDRESS}/v1&quot;, # vLLM 서버 주소
    temperature=0.2,
    max_tokens=512,
    ...
)&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;span style=&quot;color: #1b1c1d;&quot;&gt;이렇게 하면 OpenAI 라이브러리의 편리한 인터페이스를 그대로 사용하면서, 실제 모델은 우리가 직접 배포한 로컬 LLM을 사용하게 됩니다.&lt;/span&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;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;2. 에이전트 상태(State) 정의&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;다음으로 그래프의 '메모리' 역할을 할 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;AgentState&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;를 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753600421034&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from typing import List, Annotated
from typing_extensions import TypedDict
from langchain_core.messages import AnyMessage

class AgentState(TypedDict):
    # 'messages'는 대화 기록을 저장하는 리스트입니다.
    messages: Annotated[List[AnyMessage], lambda x, y: x + y]
    turn_count: int&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;messages&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 사용자와 AI의 대화 기록을 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;list&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 형태로 계속 축적해 나갑니다. &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;Annotated&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;와 lambda 함수 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;lambda x, y: x + y&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;는 LangGraph가 새로운 메시지를 기존 리스트에 자동으로 더해주도록 하는 편리한 기능입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;turn_count&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 대화 턴 수를 기록하는 정수 값입니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;span style=&quot;color: #1b1c1d;&quot;&gt;3. 에이전트 노드(Node) 정의&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;그래프의 '작업 단위'인 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;chatbot_node&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 함수입니다. 이 함수는 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;AgentState&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;를 입력으로 받아, 그 안의 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;messages&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;를 LLM에 전달합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1753600459136&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def chatbot_node(state: AgentState):
    &quot;&quot;&quot;
    현재 상태(대화 기록)를 기반으로 LLM을 호출하여 응답을 생성하는 노드입니다.
    &quot;&quot;&quot;
    print(&quot;--- 챗봇 노드 실행 ---&quot;)
    # 현재 상태에서 메시지들을 가져옵니다.
    messages = state['messages']
    turn_count = state['turn_count']
    
    # vLLM 서버에 메시지를 보내고 응답을 받습니다.
    response = llm.invoke(messages)
    
    # 받은 응답(AIMessage)을 상태의 messages 리스트에 추가하여 반환합니다.
    return {
        &quot;messages&quot;: [response],
        &quot;turn_count&quot;: turn_count
    }&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;span style=&quot;color: #1b1c1d;&quot;&gt; 그리고 LLM으로부터 받은 응답(&lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;)을 다시 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;messages&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 키에 담아 딕셔너리 형태로 반환합니다. 또한, 카운트 값도 반환하구요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph는 이 반환값을 받아 기존 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;AgentState&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;에 자동으로 업데이트해 줍니다.&lt;/span&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;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;4. 그래프 생성 및 조립&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;이제 위에서 만든 상태와 노드를 조립하여 실제 워크플로우를 만듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753600500035&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langgraph.graph import StateGraph, END

# StateGraph에 위에서 정의한 상태(AgentState)를 연결하여 그래프 빌더를 생성합니다.
graph_builder = StateGraph(AgentState)

# 그래프에 노드를 추가합니다. &quot;chatbot&quot;이라는 이름으로 chatbot_node 함수를 등록합니다.
graph_builder.add_node(&quot;chatbot&quot;, chatbot_node)

# 그래프의 진입점(Entry Point)과 종료점(End Point)을 설정합니다.
# &quot;chatbot&quot; 노드에서 시작합니다.
graph_builder.set_entry_point(&quot;chatbot&quot;)
# &quot;chatbot&quot; 노드가 끝나면, 워크플로우를 종료(END)합니다.
graph_builder.add_edge(&quot;chatbot&quot;, END)
# 정의된 내용으로 그래프를 컴파일하여 실행 가능한 앱을 만듭니다.
agent_app = graph_builder.compile()&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;StateGraph(AgentState)&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 우리가 정의한 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;AgentState&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;를 사용하는 그래프를 만들겠다고 선언합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;graph_builder.add_node(&quot;chatbot&quot;, chatbot_node)&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;&quot;chatbot&quot;&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;이라는 이름으로 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;chatbot_node&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 함수를 그래프에 작업 단위로 추가합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;graph_builder.set_entry_point(&quot;chatbot&quot;)&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 이 그래프는 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;&quot;chatbot&quot;&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 노드에서 실행을 시작한다고 지정합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;graph_builder.add_edge(&quot;chatbot&quot;, END)&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;&quot;chatbot&quot;&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 노드의 작업이 끝나면, 더 이상 다른 노드로 가지 않고 그래프 실행을 종료(&lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;END&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;)하라고 엣지를 연결합니다. (이 예제는 노드가 하나뿐이라 간단하지만, 여러 노드를 연결할 때 이 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;add_edge&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;가 핵심 역할을 합니다.)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;agent_app = graph_builder.compile()&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 정의된 구조를 바탕으로 실행 가능한 애플리케이션을 생성합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&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;span style=&quot;color: #1b1c1d;&quot;&gt;5. 에이전트 실행 및 결과 확인&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;이제 모든 준비가 끝났습니다. 생성된 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;agent_app&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;을 직접 실행하여 vLLM 서버와 통신하는 것을 확인해 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;agent_app.invoke()&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;에 첫 사용자 메시지가 담긴 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;initial_input&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;을 전달하면, 우리가 설계한 그래프가 실행됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753600733896&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_core.messages import HumanMessage, AIMessage

# 에이전트와 상호작용을 시작합니다.
# 초기 메시지를 HumanMessage로 설정합니다.
initial_input = {
    &quot;messages&quot;: [HumanMessage(content=&quot;안녕하세요? 이수진이라고 합니다.&quot;)],
    &quot;turn_count&quot;: 0
}

# agent_app.invoke()를 사용하여 그래프를 실행합니다.
final_state = agent_app.invoke(initial_input)

# 최종 상태에 담긴 모든 메시지를 출력합니다.
print(&quot;\n--- 최종 대화 기록 ---&quot;)
for message in final_state['messages']:
    if isinstance(message, HumanMessage):
        print(f&quot;사용자: {message.content}&quot;)
    elif isinstance(message, AIMessage):
        print(f&quot;AI 응답: {message.content}&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;initial_input&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;이 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;chatbot&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 노드에 전달됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;chatbot_node&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;는 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;llm.invoke()&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;를 통해 vLLM 서버에 요청을 보내고 응답을 받습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;받은 AI 응답 메시지가 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;messages&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 리스트에 추가되어 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;final_state&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;가 반환됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-27 오후 2.53.15.png&quot; data-origin-width=&quot;3542&quot; data-origin-height=&quot;688&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWxuf8/btsPCnRoVKH/7ldbnmkAPZxer6ajKx8B20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWxuf8/btsPCnRoVKH/7ldbnmkAPZxer6ajKx8B20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWxuf8/btsPCnRoVKH/7ldbnmkAPZxer6ajKx8B20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWxuf8%2FbtsPCnRoVKH%2F7ldbnmkAPZxer6ajKx8B20%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;3542&quot; height=&quot;688&quot; data-filename=&quot;스크린샷 2025-07-27 오후 2.53.15.png&quot; data-origin-width=&quot;3542&quot; data-origin-height=&quot;688&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;span style=&quot;color: #1b1c1d;&quot;&gt;최종 출력된 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;final_state&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;를 보면, 초기 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;HumanMessage&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;와 LLM이 생성한 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;AIMessage&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;가 모두 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;messages&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 리스트에 담겨 있는 것을 확인할 수 있습니다. 저는 예제로 &quot;안녕하세요? 이수진이라고 합니다&quot;라는 메세지를 전달했는데요. 모델이 잘 응답하는 것을 확인할 수 있습니다.&lt;/span&gt;&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;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;마무리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;이번 포스팅에서는 LangGraph의 핵심 개념과 간단한 예제를 통해 복잡한 LLM 에이전트를 어떻게 제어할 수 있는지 알아보았습니다. 다음번에는 조건부 엣지(Conditional Edge)를 활용하여 여러 도구(Tool)를 사용하고, 그 결과에 따라 동적으로 판단하고 행동하는 한층 더 발전된 에이전트를 만들어 보겠습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>인공지능(AI)/AI Agent</category>
      <category>Agent</category>
      <category>aiagent</category>
      <category>langchain</category>
      <category>langgraph</category>
      <category>LLM</category>
      <category>openai</category>
      <category>RAG</category>
      <category>vllm</category>
      <category>랭그래프</category>
      <category>랭체인</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/696</guid>
      <comments>https://lsjsj92.tistory.com/696#entry696comment</comments>
      <pubDate>Sun, 27 Jul 2025 16:29:38 +0900</pubDate>
    </item>
    <item>
      <title>컨텍스트 엔지니어링(Context Engineering)이란?: A Survey of Context Engineering for Large Language Models 논문 리뷰</title>
      <link>https://lsjsj92.tistory.com/695</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 17px; }
&lt;/style&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;본 포스팅은 LLM(대규모 언어 모델)의 성능을 근본적으로 결정하는 '컨텍스트(Context)'를 체계적으로 설계하고 최적화하는 방법을 다룬 논문인 &quot;A Survey of Context Engineering for Large Language Models&quot;를 리뷰하는 포스팅입니다. 본 논문은 중국 과학원 컴퓨팅 기술 연구소(Institute of Computing Technology, Chinese Academy of Sciences)를 중심으로 칭화대, 베이징대 등 여러 유수 기관의 연구진들이 공동으로 작성했습니다. 본 논문은 RAG, 프롬프트 엔지니어링, 메모리 시스템 등 파편화되어 있던 LLM의 컨텍스트 관련 기술들을 '컨텍스트 엔지니어링(Context Engineering)'이라는 하나의 통일된 학문 분야로 정립하고, 1,400편이 넘는 연구를 분석하여 그 체계를 최초로 제시합니다. LLM의 지능을 한 단계 끌어올릴 컨텍스트 엔지니어링의 세계는 어떻게 구성되어 있을까요? 본 포스팅에서는 해당 논문에 대한 자세한 리뷰를 진행하도록 하겠습니다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/pdf/2507.13334&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/pdf/2507.13334&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.08.14.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;852&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdNmaq/btsPqVnUFru/0l8ckcfBLDgoXXL1tPt5CK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdNmaq/btsPqVnUFru/0l8ckcfBLDgoXXL1tPt5CK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdNmaq/btsPqVnUFru/0l8ckcfBLDgoXXL1tPt5CK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdNmaq%2FbtsPqVnUFru%2F0l8ckcfBLDgoXXL1tPt5CK%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;591&quot; height=&quot;373&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.08.14.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;852&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅 개요에서도 언급하였듯, 본 포스팅은 LLM의 성능을 극대화하기 위한 컨텍스트 활용법을 집대성한 서베이 논문입니다. 원 논문은 165페이지에 달하며 1,400개가 넘는 참고 문헌을 포함할 정도로 내용이 굉장히 길고 방대하기 때문에, 본 포스팅에서는 핵심적인 내용만 짚고 넘어가도록 하겠습니다. 긴 내용을 보기 힘드신 분들은, 아래 '핵심 요약' 파트와 '2-2. 핵심 수행 내용과 연구 내용'을 참고하시길 바랍니다.&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;2. 핵심 내용&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-1. 핵심 요약&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;최근 LLM의 성능이 비약적으로 발전했지만, 그 성능은 전적으로 '어떤 컨텍스트를 제공받는가'에 달려 있습니다. 기존의 '프롬프트 엔지니어링'은 이 컨텍스트를 다루는 시작점이었지만, RAG, 메모리, 도구 사용 등 복잡한 AI 시스템이 등장하면서 더 체계적인 접근법이 필요해졌습니다. 이러한 배경 속에서, 본 논문은 컨텍스트 엔지니어링(Context Engineering)을 LLM에 제공되는 정보 페이로드(information payloads)를 체계적으로 최적화하는 공식적인 학문 분야로 제안합니다. 이는 단순히 좋은 질문을 만드는 것을 넘어, 외부 지식, 메모리, 도구, 사용자 상태 등 여러 정보 소스를 동적으로 조합하여 LLM의 능력을 최대한으로 끌어내는 통합 프레임워크(?)에 가깝습니다. 본 연구의 핵심은 이 분야를 '기반 구성요소(Foundational Components)'와 '시스템 구현(System Implementations)'이라는 두 가지 큰 축으로 나누어 기술의 전체 지도를 그렸다는 점입니다.&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-filename=&quot;스크린샷 2025-07-20 오후 1.43.10.png&quot; data-origin-width=&quot;2324&quot; data-origin-height=&quot;1598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C4wSa/btsPqLFzhl1/4xncbqLSLZECGg8ya40JX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C4wSa/btsPqLFzhl1/4xncbqLSLZECGg8ya40JX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C4wSa/btsPqLFzhl1/4xncbqLSLZECGg8ya40JX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC4wSa%2FbtsPqLFzhl1%2F4xncbqLSLZECGg8ya40JX0%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;629&quot; height=&quot;433&quot; data-filename=&quot;스크린샷 2025-07-20 오후 1.43.10.png&quot; data-origin-width=&quot;2324&quot; data-origin-height=&quot;1598&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;기반 구성요소(Foundational Components)는 컨텍스트를 가져오고(검색/생성), 다듬고(처리), 보관하는(관리) 핵심 기술 블록들입니다. 시스템 구현(System Implementations)은 이 블록들을 조립하여 RAG, 메모리 시스템, 멀티-에이전트 시스템과 같은 완성된 아키텍처를 만드는 것입니다. 또한, 이 방대한 분석을 통해 연구진은 중요한 연구 격차를 발견했는데요. 현재 LLM은 고도로 설계된 복잡한 컨텍스트를 '이해'하는 데는 뛰어나지만, 그만큼 정교하고 긴 결과물을 스스로 '생성'하는 데는 한계를 보인다는 것입니다.&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;2-2. 핵심 수행 내용과 연구 내용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 연구에서 제안하는 핵심적인 내용은 바로 이 컨텍스트 엔지니어링의 전체 구조를 체계화한 분류 프레임워크(Taxonomy Framework)입니다. 이는 Figure 1에서 잘 나타나 있습니다. 연구진은 먼저 1,400편 이상의 방대한 논문을 분석하여 LLM의 컨텍스트를 다루는 기술들을 수집했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-20 오후 2.02.09.png&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;721&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/by3i2C/btsPqlm3ECU/bA6kRckDWCicqBAbOAEGO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/by3i2C/btsPqlm3ECU/bA6kRckDWCicqBAbOAEGO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/by3i2C/btsPqlm3ECU/bA6kRckDWCicqBAbOAEGO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fby3i2C%2FbtsPqlm3ECU%2FbA6kRckDWCicqBAbOAEGO1%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;499&quot; height=&quot;546&quot; data-filename=&quot;스크린샷 2025-07-20 오후 2.02.09.png&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;721&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫째, 기반 구성요소(Foundational Components): AI 시스템의 근간을 이루는 핵심 기술들입니다. &lt;br /&gt;- 컨텍스트 검색 및 생성: 필요한 정보를 어디서 어떻게 가져올 것인가? (ex. 프롬프트 작성, 외부 DB 검색) &lt;br /&gt;- 컨텍스트 처리: 가져온 정보를 어떻게 가공할 것인가? (ex. 긴 문서 요약, 구조화 데이터 변환) &lt;br /&gt;- 컨텍스트 관리: 가공된 정보를 어떻게 효율적으로 저장하고 사용할 것인가? (ex. 메모리, 압축)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;둘째, 시스템 구현(System Implementations): 위 기반 구성요소들을 건축적으로 통합하여 만든 정교한 시스템들입니다.&lt;br /&gt;- RAG: '검색/생성' 요소를 중심으로 구현된 시스템. &lt;br /&gt;- 메모리 시스템: '관리' 요소를 중심으로 구현되어 장기 기억을 가능하게 하는 시스템. &lt;br /&gt;- 도구 통합 추론 &amp;amp; 멀티-에이전트 시스템: 여러 구성요소를 복합적으로 융합하여 외부 세계와 상호작용하거나 서로 협력하는 고도화된 시스템.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 다음 파트부터 각 구성요소에 대한 상세한 내용을 리뷰해보겠습니다. 논문이 방대하기 때문에 핵심적인 내용을 위주로 리뷰하겠습니다. 만약 긴 글이 부담스러우신 독자분들은 여기까지만 보셔도 됩니다. 또한, 본 포스팅에서도 핵심 내용을 위주로 다루었기 때문에 각 기술에 대한 상세한 정보는 논문 원본을 꼭 살펴보시길 권장드립니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 논문 상세 내용 - 컨텍스트 엔지니어링(Context Engineering)&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-1. 컨텍스트 엔지니어링이란 무엇이고, 왜 필요한가?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM과 상호작용하는 방식을 이야기할 때 우리는 흔히 '프롬프트 엔지니어링'이라는 용어를 사용합니다. 하지만 논문의 저자들은 이 용어만으로는 현대 AI 시스템의 복잡성을 모두 담아내기에 더 이상 충분하지 않다고 주장합니다. 오늘날의 AI 시스템은 단순히 정적인 텍스트 한 줄을 입력받는 것을 넘어, 동적이고, 구조화되었으며, 다각적인 정보의 흐름을 활용하기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 변화에 발맞춰, 본 논문은 컨텍스트 엔지니어링(Context Engineering)이라는 새로운 패러다임을 제시합니다.&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;3-1-1. 컨텍스트 엔지니어링의 정의&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨텍스트 엔지니어링이란, LLM에 제공되는 정보 페이로드(information payloads)를 체계적으로 설계하고 최적화하는 공식적인 학문 분야입니다. 기존에는 컨텍스트 `C`를 단순히 하나의 프롬프트(C = prompt)로 보았다면, 컨텍스트 엔지니어링은 컨텍스트 `C`를 여러 정보 구성요소 \(c_1, c_2, ..., c_n\)를 동적으로 조립한 결과물(\(C = A(c₁, c₂, ..., cₙ)\))로 봅니다. 이때 조립되는 '재료(구성요소)'들은 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.09.28.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;616&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bo7qpi/btsPpvcLnw2/DdpMHlvwQoNBECeZxK3ooK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bo7qpi/btsPpvcLnw2/DdpMHlvwQoNBECeZxK3ooK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bo7qpi/btsPpvcLnw2/DdpMHlvwQoNBECeZxK3ooK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbo7qpi%2FbtsPpvcLnw2%2FDdpMHlvwQoNBECeZxK3ooK%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;698&quot; height=&quot;319&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.09.28.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;616&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지침 \(c_{instr}\):AI의 역할, 규칙 등 시스템의 기본 지침&lt;/li&gt;
&lt;li&gt;지식 \(c_{know}\): RAG 등을 통해 실시간으로 검색된 외부 최신 정보도구 \(c_tools\): AI가 사용할 수 있는 외부 API나 프로그램의 명세&lt;/li&gt;
&lt;li&gt;메모리 \(c_{mem}\): 사용자와의 과거 대화 기록이나 학습된 정보&lt;/li&gt;
&lt;li&gt;상태 \(c_{state}\): 현재 시스템이나 사용자의 동적인 상태 정보&lt;/li&gt;
&lt;li&gt;쿼리 \(c_{query}\): 사용자의 현재 질문&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.09.37.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIYRkP/btsPrI2sGvt/YAEaRDh7qNzTbiUAORhB51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIYRkP/btsPrI2sGvt/YAEaRDh7qNzTbiUAORhB51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIYRkP/btsPrI2sGvt/YAEaRDh7qNzTbiUAORhB51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIYRkP%2FbtsPrI2sGvt%2FYAEaRDh7qNzTbiUAORhB51%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;729&quot; height=&quot;223&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.09.37.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;412&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;즉, 컨텍스트 엔지니어링은 프롬프트 디자인의 기술에서 벗어나, 이러한 여러 정보 재료들을 최적으로 조합하여 LLM에게 적절한 맥락(Context)를 제공함으로써 업무를 수행할 수 있도록 하는 전환을 의미합니다.&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;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;컨텍스트 엔지니어링(Context Engineering)과 프롬프트 엔지니어링(Prompt Engineering)의 차이점은?&lt;/span&gt;&lt;/blockquote&gt;
&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;라는 질문을 계속 던졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면, 여러 커뮤니티에 이제 프폼프트 엔지니어링을 넘어 컨텍스트 엔지니어링으로 가야한다고 말을 하는 데, 둘의 차이점이 좀 명확히 와닿지 않았습니다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&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-filename=&quot;스크린샷 2025-07-19 오후 9.11.54.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bq9pW6/btsPpy1RIBG/tzk8dakS2saIu45ek1oQ8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bq9pW6/btsPpy1RIBG/tzk8dakS2saIu45ek1oQ8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bq9pW6/btsPpy1RIBG/tzk8dakS2saIu45ek1oQ8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbq9pW6%2FbtsPpy1RIBG%2Ftzk8dakS2saIu45ek1oQ8k%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;680&quot; height=&quot;208&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.11.54.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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 style=&quot;width: 20.7752%;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.9844%;&quot;&gt;&lt;b&gt;프롬프트 엔지니어링&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 41.2403%;&quot;&gt;&lt;b&gt;컨텍스트 엔지니어링&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.7752%;&quot;&gt;컨텍스트 모델&lt;/td&gt;
&lt;td style=&quot;width: 37.9844%;&quot;&gt;정적인 단일 문자열(C=prompt)&lt;/td&gt;
&lt;td style=&quot;width: 41.2403%;&quot;&gt;동적이고 구조화된 여러 구성요소의 조합(\(C = A(c₁, c₂, ..., cₙ)\))&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.7752%;&quot;&gt;주요 목표&lt;/td&gt;
&lt;td style=&quot;width: 37.9844%;&quot;&gt;LLM의 응답 품질을 높이는 최적의 프롬프트&lt;/td&gt;
&lt;td style=&quot;width: 41.2403%;&quot;&gt;LLM의 성능을 극대화하는 정보 처리 시스템 최적화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.7752%;&quot;&gt;복잡성&lt;/td&gt;
&lt;td style=&quot;width: 37.9844%;&quot;&gt;문자열 공간 탐색&lt;/td&gt;
&lt;td style=&quot;width: 41.2403%;&quot;&gt;정보 검색, 선택, 처리, 관리, 함수 등 시스템 수준의 최적화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.7752%;&quot;&gt;정보의 원천&lt;/td&gt;
&lt;td style=&quot;width: 37.9844%;&quot;&gt;프롬프트 내의 고정된 정보&lt;/td&gt;
&lt;td style=&quot;width: 41.2403%;&quot;&gt;외부 DB, 메모리, 도구 등 다양한소스에서 동적으로 정보를 가져와서 융합 및 활용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.7752%;&quot;&gt;상태 관리&lt;/td&gt;
&lt;td style=&quot;width: 37.9844%;&quot;&gt;상태가 없음(stateless)&lt;/td&gt;
&lt;td style=&quot;width: 41.2403%;&quot;&gt;메모리나 상태(state)를 명시적으로 다뤄, 상태를 가짐(stateful)&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, 제가 &quot;제주도로 3박 4일 가족여행 계획 짜줘&quot;라고 요청한다고 가정해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 36px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 19px;&quot;&gt;&lt;b&gt;프롬프트 엔지니어링&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 19px;&quot;&gt;&lt;b&gt;컨텍스트 엔지니어링&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;&quot;사용자 요청: 제주도로 3박 3일 가족여행 계획 짜줘&quot; &lt;br /&gt;&lt;br /&gt;이 프롬프트만 LLM에게 전달됩니다. &lt;br /&gt;LLM은 일반적인 정보만으로 답변 생성합니다.&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;아래와 같은 여러 정보를 동적으로 수집합니다.&lt;br /&gt;&lt;br /&gt;- c_query: 사용자 요청 수집: 제주도로 3박 4일 여행 계획 짜줘&lt;br /&gt;- c_instr: 너는 친절한 여행 전문가야.&amp;nbsp;&lt;br /&gt;- c_mem: 이 사용자는 과거에 '자연경관'을 선호했음&lt;br /&gt;- c_tool: 실시간 항공권 API 호출 및 호텔 예약 API 호출&lt;br /&gt;&lt;br /&gt;이런 정보를 활용해 하나의 구조화된 프롬프트 구성하여 LLM에게 맥락(context)를 제공하여 업무를 수행하도록 함&lt;br /&gt;&lt;br /&gt;# 시스템 지침&lt;br /&gt;너는 친절한 여행 전문가이며, 가족 친화적인 활동을 추천한다&lt;br /&gt;&lt;br /&gt;# 과거 대화 요약과 서용자 선호도&lt;br /&gt;- 이 사용자는 자연경관을 선호한다&lt;br /&gt;&lt;br /&gt;# 외부정보&lt;br /&gt;- 현재 김포-제주 왕복 최저가 항공편 oo항공, 1인 80,000원&lt;br /&gt;- 추천 숙소: oo 호텔, 패밀리룸&lt;br /&gt;- 최신 맛집 정보 : XX 식당&lt;br /&gt;&lt;br /&gt;# 사용자 현재 요청&lt;br /&gt;위 정보를 모두 고려하여, 제주도로 떠나는 3박 4일 가족여행 구성&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;blockquote data-ke-style=&quot;style1&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-2. 컨텍스트 엔지니어링이 필요한 이유&lt;/h4&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;3-2-1. 현재 LLM의 명확한 한계를 극복&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM의 기반이 되는 트랜스포머의 셀프 어텐션 메커니즘은 처리할 시퀀스 길이가 길어질수록 계산량이 제곱(\(O(n&amp;sup2;)\))으로 증가하는 문제를 안고 있습니다. 이는 긴 문서나 대화를 한 번에 처리하는 데 큰 병목이 됩니다. 그리고 LLM은 종종 사실이 아닌 내용을 그럴듯하게 지어내는 환각(hallucination) 현상을 보이거나, 입력된 컨텍스트를 제대로 따르지 않는 문제를 보입니다.&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;3-2-2. LLM의 성능을 극대화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체계적인 컨텍스트 엔지니어링은 LLM의 성능을 향상시킵니다. RAG와 같은 기술은 텍스트 탐색 정확도를 18배 향상시켰고, 잘 설계된 구조적 프롬프트는 복잡한 추론을 가능하게 합니다. CoT(Chain-of-Thought)와 같은 기법은 LLM이 중간 추론 단계를 생성하게 함으로써 복잡한 문제 해결 능력을 높여줍니다. 특히 코드 생성이나 하드웨어 설계와 같은 전문 분야에서는, 해당 도메인에 특화된 컨텍스트를 제공함으로써 범용 모델의 한계를 뛰어넘는 성과를 낼 수 있습니다.&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;3-2-3. 한정된 자원을 효율적으로 사용&lt;/h4&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;3-2-4. AI의 미래 잠재력을 실현&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨텍스트 엔지니어링은 LLM이 새로운 작업을 재학습 없이 수행하게 하는 인컨텍스트 학습(In-context Learning)을 통해 유연한 적응력을 부여합니다. CoT, ToT(Tree-of-Thought)와 같은 정교한 추론 기법들은 더 미묘하고 복잡한 언어 이해 및 생성 능력의 토대를 마련하며, 이는 결국 더 견고하고 상황을 인지하는(context-aware) AI 애플리케이션의 발전으로 이어집니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 컨텍스트 엔지니어링의 3가지 기반 구성요소 (Foundational Components)&lt;/h3&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 시스템의 컨텍스트 파이프라인을 구성하는 세 가지 핵심적인 기반 구성요소(Foundational Components)를 제시합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 가지 구성요소는 컨텍스트 검색 및 생성 (Context Retrieval and Generation) 컨텍스트 처리 (Context Processing) 컨텍스트 관리 (Context Management) 입니다. 각각의 역할은 정보를 가져오고(수집), 다듬고(전처리 등), 효율적으로 사용하는(보관, 사용) 단계에 해당합니다. 이제 하나씩 살펴보겠습니다.&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;4.1 컨텍스트 검색 및 생성 (Context Retrieval and Generation)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 단계는 LLM에게 전달할 컨텍스트의 '재료'를 어디서, 어떻게 가져올 것인지를 다룹니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.12.28.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;621&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgQrBc/btsPp9G0bw4/nrxW4dpmGBedKKRzJeE8QK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgQrBc/btsPp9G0bw4/nrxW4dpmGBedKKRzJeE8QK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgQrBc/btsPp9G0bw4/nrxW4dpmGBedKKRzJeE8QK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgQrBc%2FbtsPp9G0bw4%2FnrxW4dpmGBedKKRzJeE8QK%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;706&quot; height=&quot;325&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.12.28.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;621&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프롬프트 엔지니어링과 컨텍스트 생성 (Prompt Engineering and Context Generation): LLM의 사고를 유도하는 가장 기본적인 방법입니다. 단순히 명령을 내리는 것을 넘어, CoT(생각의 사슬), ToT(생각의 트리)와 같은 정교한 프롬프팅 기법을 통해 LLM이 복잡한 문제를 단계별로 추론하도록 이끕니다 .&lt;/li&gt;
&lt;li&gt;외부 지식 검색 (External Knowledge Retrieval): LLM이 학습하지 못한 최신 정보나 특정 도메인의 전문 지식을 외부 소스(웹, DB, 지식 그래프 등)에서 가져오는 기술입니다. RAG가 바로 이 기술의 대표적인 예시입니다.&lt;/li&gt;
&lt;li&gt;동적 컨텍스트 조립 (Dynamic Context Assembly): 위에서 얻은 여러 정보 조각들(프롬프트, 외부 지식, 사용자 정보 등)을 하나의 일관되고 최적화된 컨텍스트로 실시간으로 조합하는 과정입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.2 컨텍스트 처리 (Context Processing)&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;정보를 가져왔다면, 이제 LLM이 가장 잘 '소화'할 수 있도록 재료를 다듬는 과정이 필요합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;긴 컨텍스트 처리 (Long Context Processing): LLM의 고질적인 문제인 '긴 글 처리'의 한계를 극복하기 위한 기술입니다. Mamba와 같은 새로운 아키텍처나 FlashAttention 같은 최적화 기법을 통해 수백만 토큰에 달하는 긴 문서나 대화도 효율적으로 처리할 수 있게 합니다.&lt;/li&gt;
&lt;li&gt;문맥적 자체 개선 및 적응 (Contextual Self-Refinement and Adaptation): LLM이 스스로 자신의 답변을 평가하고 수정하게 만드는 기술입니다. 예를 들어, 'Self-Refine' 프레임워크는 LLM이 초안을 작성한 뒤, 피드백을 생성하고, 그 피드백을 바탕으로 답변을 다시 개선하는 반복적인 과정을 거칩니다.&lt;/li&gt;
&lt;li&gt;다중 모드 및 구조화된 컨텍스트 처리 (Multimodal and Structured Context): 텍스트뿐만 아니라 이미지, 오디오, 테이블, 그래프와 같은 비정형, 정형 데이터를 LLM이 이해할 수 있는 형태로 가공하고 통합하는 기술을 다룹니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.13.50.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bk2PP8/btsPqRsg0fi/KKBmRYaZUfBZonL9xfMvJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bk2PP8/btsPqRsg0fi/KKBmRYaZUfBZonL9xfMvJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bk2PP8/btsPqRsg0fi/KKBmRYaZUfBZonL9xfMvJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbk2PP8%2FbtsPqRsg0fi%2FKKBmRYaZUfBZonL9xfMvJK%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;753&quot; height=&quot;155&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.13.50.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;278&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;h4 data-ke-size=&quot;size20&quot;&gt;4.3 컨텍스트 관리 (Context Management)&lt;/h4&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;근본적인 제약사항 해결 (Fundamental Constraints): LLM은 컨텍스트 창의 길이가 제한되어 있고, 특히 긴 글의 중간에 있는 정보를 잊어버리는 'lost-in-the-middle' 현상을 겪습니다. 컨텍스트 관리는 이러한 제약을 최소화하는 것을 목표로 합니다.&lt;/li&gt;
&lt;li&gt;메모리 계층 및 저장 아키텍처 (Memory Hierarchies and Storage Architectures): 컴퓨터 운영체제(OS)의 메모리 관리 기법에서 영감을 얻은 기술입니다. 예를 들어, MemGPT는 LLM의 컨텍스트 창을 '주기억장치'로, 외부 DB를 '보조기억장치'로 사용하여 필요한 정보를 동적으로 교체(페이징)하며 거의 무한한 메모리를 사용하는 것처럼 만듭니다.&lt;/li&gt;
&lt;li&gt;컨텍스트 압축 (Context Compression): 제한된 컨텍스트 창 안에 더 많은 정보를 담기 위해, 정보의 핵심은 유지하면서 전체 텍스트 길이를 줄이는 기술입니다. 이 세 가지 기반 구성요소는 '수집 보관 및 사용'이라는 유기적인 파이프라인을 형성합니다. 이 파이프라인을 통해 생성된 고품질의 컨텍스트가 바로 다음에 설명할 RAG, 멀티-에이전트와 같은 정교한 AI 시스템을 구동 할 수 있게 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.14.01.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;557&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRQYHw/btsPriiSqGY/yPvoY76l9USS5MS9SnhH9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRQYHw/btsPriiSqGY/yPvoY76l9USS5MS9SnhH9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRQYHw/btsPriiSqGY/yPvoY76l9USS5MS9SnhH9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRQYHw%2FbtsPriiSqGY%2FyPvoY76l9USS5MS9SnhH9k%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;698&quot; height=&quot;288&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.14.01.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;557&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 시스템 구현: 4가지 지능형 AI 아키텍처 (System Implementations)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 컨텍스트 엔지니어링의 핵심 '부품'인 기반 구성요소(Foundational Components)에 대해 알아보았습니다. 그렇다면 이 부품들을 조합하여 어떤 강력한 '완성품', 즉 지능형 AI 시스템을 만들 수 있을까요? 논문에서는 기반 구성요소들을 통합하여 만든 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;5.1 검색 증강 생성 (RAG, Retrieval-Augmented Generation)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.14.11.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;451&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLiVj9/btsProwodN3/eXyZLoq1c1HkKlN3yyN0Gk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLiVj9/btsProwodN3/eXyZLoq1c1HkKlN3yyN0Gk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLiVj9/btsProwodN3/eXyZLoq1c1HkKlN3yyN0Gk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLiVj9%2FbtsProwodN3%2FeXyZLoq1c1HkKlN3yyN0Gk%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;690&quot; height=&quot;231&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.14.11.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;451&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;RAG는 이제 많은 분들께 익숙한 기술일 것입니다. LLM이 내부적으로 학습한 지식(Parametric Knowledge)의 한계를 넘어, 외부의 최신 정보 소스를 실시간으로 참조하여 답변을 생성하는 시스템입니다. 이를 통해 정보의 최신성을 유지하고 환각(Hallucination) 현상을 크게 줄일 수 있습니다. 논문에 따르면 RAG는 단순히 검색하고 생성하는 것을 넘어 다음과 같이 진화하고 있습니다.&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&gt;모듈형 RAG (Modular RAG): 검색, 생성 등의 단계를 레고 블록처럼 유연하게 재구성할 수 있는 아키텍처입니다. 이를 통해 특정 작업에 맞춰 시스템을 더 쉽게 최적화할 수 있습니다.&lt;/li&gt;
&lt;li&gt;에이전틱 RAG (Agentic RAG): AI 에이전트가 사람처럼 '언제, 무엇을 검색할지' 스스로 판단하고, 여러 단계에 걸쳐 정보를 탐색하며 동적으로 검색 전략을 수정하는 지능적인 방식입니다.&lt;/li&gt;
&lt;li&gt;그래프 강화 RAG (Graph-Enhanced RAG): 단순 텍스트 문서가 아닌, 관계가 구조화된 지식 그래프(Knowledge Graph)에서 정보를 검색합니다. 이를 통해 여러 정보 조각을 논리적으로 연결해야 하는 복잡한 질문에 더 정확하게 답변할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.2 메모리 시스템 (Memory Systems)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.15.01.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;688&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FkVie/btsPqaTqwVj/52Z0i46kzRvPgnWnZd7I31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FkVie/btsPqaTqwVj/52Z0i46kzRvPgnWnZd7I31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FkVie/btsPqaTqwVj/52Z0i46kzRvPgnWnZd7I31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFkVie%2FbtsPqaTqwVj%2F52Z0i46kzRvPgnWnZd7I31%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;635&quot; height=&quot;324&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.15.01.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;688&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;LLM은 기본적으로 '단기 기억상실증'을 앓고 있습니다. 매번의 대화를 독립적으로 처리하기 때문이죠. 메모리 시스템은 이러한 한계를 극복하고 LLM에 지속적인 기억력을 부여하는 시스템입니다. 컴퓨터의 메모리 계층 구조처럼, LLM의 컨텍스트 창을 단기 메모리로, 외부 데이터베이스를 장기 메모리로 활용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자와의 대화가 길어지면, 시스템은 중요한 정보를 장기 메모리에 저장했다가 다음 대화에서 필요할 때 다시 꺼내 단기 메모리(컨텍스트 창)에 넣어줍니다. 이를 통해 AI는 사용자의 선호도를 기억하거나 이전 대화 내용을 참조하여 훨씬 더 개인화되고 일관성 있는 소통을 할 수 있습니다.&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;5.3 도구 통합 추론 (Tool-Integrated Reasoning)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-23 오후 8.37.30.png&quot; data-origin-width=&quot;2120&quot; data-origin-height=&quot;818&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgER0Q/btsPv6iOQ0Y/p0KQmO0kCbYqW6gpy8sF21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgER0Q/btsPv6iOQ0Y/p0KQmO0kCbYqW6gpy8sF21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgER0Q/btsPv6iOQ0Y/p0KQmO0kCbYqW6gpy8sF21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgER0Q%2FbtsPv6iOQ0Y%2Fp0KQmO0kCbYqW6gpy8sF21%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;650&quot; height=&quot;251&quot; data-filename=&quot;스크린샷 2025-07-23 오후 8.37.30.png&quot; data-origin-width=&quot;2120&quot; data-origin-height=&quot;818&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;LLM은 훌륭한 언어 능력을 가졌지만, 복잡한 계산을 하거나, 최신 정보를 검색하거나, 특정 프로그램을 실행하는 능력은 없습니다. 도구 통합 추론은 LLM이 이러한 한계를 극복하기 위해 외부 도구(Tool)를 사용할 수 있도록 만드는 시스템입니다. 핵심은 'Function Calling' 메커니즘입니다. LLM은 문제 해결에 특정 도구가 필요하다고 판단하면, &quot;계산기.add(5, 8)&quot;과 같은 구조화된 명령을 생성합니다. 그러면 시스템이 이 명령을 받아 실제 계산기를 실행하고, 그 결과인 '13'을 다시 LLM에게 전달해 줍니다. LLM은 이 결과를 바탕으로 다음 추론을 이어갑니다. 이처럼 LLM은 단순한 텍스트 생성기를 넘어, 외부 도구와 상호작용하며 실제 세계의 문제를 해결하게 됩니다.&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;5.4 멀티-에이전트 시스템 (Multi-Agent Systems)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.15.26.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;684&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CipCY/btsPrQTKae5/de7j49qoGZb5irmH9c97A0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CipCY/btsPrQTKae5/de7j49qoGZb5irmH9c97A0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CipCY/btsPrQTKae5/de7j49qoGZb5irmH9c97A0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCipCY%2FbtsPrQTKae5%2Fde7j49qoGZb5irmH9c97A0%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;588&quot; height=&quot;298&quot; data-filename=&quot;스크린샷 2025-07-19 오후 9.15.26.png&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;684&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;이는 컨텍스트 엔지니어링의 정점이라 할 수 있는, 여러 명의 자율적인 AI 에이전트가 서로 소통하고 협력하여 단일 에이전트가 해결할 수 없는 복잡한 문제를 해결하는 시스템입니다. 예를 들어 '시장 분석 보고서 작성'이라는 과업이 주어지면, '자료 조사 에이전트', '데이터 분석 에이전트', '보고서 작성 에이전트'가 각자의 역할을 분담합니다. 이 시스템이 성공적으로 작동하려면 다음과 같은 핵심 요소들이 필요합니다.&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&gt;소통 프로토콜 (Communication Protocols): 에이전트들이 서로의 말을 알아들을 수 있는 표준화된 '언어'&lt;/li&gt;
&lt;li&gt;오케스트레이션 (Orchestration Mechanisms): 전체 작업 흐름을 지휘하고 각 에이전트에게 업무를 할당하는 '지휘자' 또는 '프로젝트 매니저'&lt;/li&gt;
&lt;li&gt;조정 전략 (Coordination Strategies): 에이전트 간의 충돌을 방지하고 협력을 극대화하기 위한 '팀워크 전략'&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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 컨텍스트 엔지니어링의 핵심적인 내용인 정의, 필요성, 그리고 그 구성요소와 시스템 구현 방식에 대해 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 논문은 이 외에도 각 시스템을 어떻게 평가하는지(Evaluation), 그리고 앞으로 어떤 방향으로 연구가 진행되어야 하는지(Future Directions and Open Challenges)에 대한 인사이트를 제공합니다. 논문 내용이 매우 길기 때문에, 본 포스팅은 여기서 마무리 하겠습니다.&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;p data-ke-size=&quot;size16&quot;&gt;긴 글 읽어주셔서 감사합니다.&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>AI</category>
      <category>ai agent</category>
      <category>context engineering</category>
      <category>LLM</category>
      <category>multi-agent</category>
      <category>prompt engineering</category>
      <category>논문</category>
      <category>에이전트</category>
      <category>컨텍스트엔지니어링</category>
      <category>프롬프트엔지니어링</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/695</guid>
      <comments>https://lsjsj92.tistory.com/695#entry695comment</comments>
      <pubDate>Sun, 20 Jul 2025 14:33:01 +0900</pubDate>
    </item>
    <item>
      <title>한국은행 ECOS Open API 사용 방법과 Python API 활용 예제</title>
      <link>https://lsjsj92.tistory.com/694</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 17px; }
&lt;/style&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;이번 포스팅은 한국은행에서 제공해주는 ECOS API 사용 방법과 Python 활용 방법에 대해서 정리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한국은행 경제통계시스템(ECOS)에 대해서 알아보고, 어떻게 API를 제공해주고 있는 지, 그리고 Python으로 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;제가 참고한 사이트는 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://ecos.bok.or.kr/api/#/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ecos.bok.or.kr/api/#/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1752469270655&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;한국은행 Open API 서비스&quot; data-og-description=&quot;&quot; data-og-host=&quot;ecos.bok.or.kr&quot; data-og-source-url=&quot;https://ecos.bok.or.kr/api/#/&quot; data-og-url=&quot;https://ecos.bok.or.kr/api/#/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://ecos.bok.or.kr/api/#/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ecos.bok.or.kr/api/#/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;한국은행 Open API 서비스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ecos.bok.or.kr&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;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;포스팅 본문&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;한국은행 경제통계시스템(ECOS)란?&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-14 오후 1.59.03.png&quot; data-origin-width=&quot;1463&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/egzXH6/btsPgbMAHXJ/oefl8wF48xlrAR3E9wFZvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/egzXH6/btsPgbMAHXJ/oefl8wF48xlrAR3E9wFZvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/egzXH6/btsPgbMAHXJ/oefl8wF48xlrAR3E9wFZvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FegzXH6%2FbtsPgbMAHXJ%2Foefl8wF48xlrAR3E9wFZvk%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;669&quot; height=&quot;288&quot; data-filename=&quot;스크린샷 2025-07-14 오후 1.59.03.png&quot; data-origin-width=&quot;1463&quot; data-origin-height=&quot;630&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;한국은행 경제통계시스템(ECOS)는 한국은행에서 생산하는 다양한 경제 통계 자료를 검색하고 활용할 수 있는 시스템입니다. 통화, 환율, 유동성 지표, 물가, 금리, 국제수지 등 다양한 분야의 경제 지표를 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무엇보다, 이를 API로 제공하여 편리하게 활용할 수 있구습니다. API 인증키만 발급 받아서 간단하게 사용할 수 있죠!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비록 ECOS API를 제공해주지만, 사실 생각보다 조금 불편한 점이 있습니다. 너무 많은 데이터를 제공해주다보니 지표가 너무 많아 검색하기 불편하더라구요. 그래서 그 방법을 정리해보고 Python으로 연동하는 방법을 정리하겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;한국은행 경제통계시스템 API 사용 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한국은행 ECOS API를 사용하기 위해서는 먼저 '통계표코드'를 알아야 합니다. 이 통계표코드는 한국은행 ECOS 홈페이지에서 '개발가이드' --&amp;gt; 통계코드검색 메뉴에서 확인할 수 있는데요. 아래와 같은 화면을 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCoXNi/btsPiCIcGOX/cmjD9UbFivyT4nkUvKpo4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCoXNi/btsPiCIcGOX/cmjD9UbFivyT4nkUvKpo4k/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;674&quot; data-filename=&quot;스크린샷 2025-07-14 오후 1.10.12.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCoXNi/btsPiCIcGOX/cmjD9UbFivyT4nkUvKpo4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCoXNi%2FbtsPiCIcGOX%2FcmjD9UbFivyT4nkUvKpo4k%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;804&quot; height=&quot;674&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9bFXo/btsPgu6c94q/FJA3cCaOPSzFFkfc0vxDsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9bFXo/btsPgu6c94q/FJA3cCaOPSzFFkfc0vxDsk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;674&quot; data-filename=&quot;스크린샷 2025-07-14 오후 1.10.19.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9bFXo/btsPgu6c94q/FJA3cCaOPSzFFkfc0vxDsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9bFXo%2FbtsPgu6c94q%2FFJA3cCaOPSzFFkfc0vxDsk%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;804&quot; height=&quot;674&quot;/&gt;&lt;/span&gt;&lt;/div&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;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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-14 오후 1.10.30.png&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;674&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MAcQt/btsPhudiXx9/p34bwf0BeAVCi9H7B8A2pk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MAcQt/btsPhudiXx9/p34bwf0BeAVCi9H7B8A2pk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MAcQt/btsPhudiXx9/p34bwf0BeAVCi9H7B8A2pk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMAcQt%2FbtsPhudiXx9%2Fp34bwf0BeAVCi9H7B8A2pk%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;675&quot; height=&quot;307&quot; data-filename=&quot;스크린샷 2025-07-14 오후 1.10.30.png&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;674&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;p data-ke-size=&quot;size16&quot;&gt;여기서 주요국 통화의 대원화환율 &quot;[731Y001][D]&quot;와 원/미국달러 &quot;[0000001][원]&quot; 정보를 놓쳐서는 안됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;731Y001: 이 값이 통계표코드 값이며, 각 지표의 unique 값이라고 보면 됩니다.&lt;/li&gt;
&lt;li&gt;D : 주기 정보입니다. 지표마다 A(년), S(반년), Q(분기), M(월), SM(반월), D(일)가 있습니다. 이 주기 정보에 맞춰서 나중에 날짜 검색 정보도 바뀌어야 합니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;0000001: 세부통계항목코드로서 API 호출 시 해당 값을 넣어 세부 정보를 함께 제공합니다. 세부 통계값을 넣지 않으면, 통계표코드에서 제공하는 모든 데이터를 받아오게 됩니다. 즉, 환율의 경우 제공하는 모든 나라의 값을 다 받아오게 됩니다.&lt;/li&gt;
&lt;li&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;gt; '개발 명세서' 메뉴로 들어갑니다. 이 메뉴에서는 API가 잘 동작되는 지 테스트 해볼 수 있습니다.&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-filename=&quot;스크린샷 2025-07-14 오후 1.11.11.png&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;863&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zx8Gn/btsPgg1oWIL/l8pdAkXyAgkO4Dil94j4Q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zx8Gn/btsPgg1oWIL/l8pdAkXyAgkO4Dil94j4Q1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zx8Gn/btsPgg1oWIL/l8pdAkXyAgkO4Dil94j4Q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzx8Gn%2FbtsPgg1oWIL%2Fl8pdAkXyAgkO4Dil94j4Q1%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;642&quot; height=&quot;374&quot; data-filename=&quot;스크린샷 2025-07-14 오후 1.11.11.png&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;863&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;여기서 &quot;통계 조회 조건 설정&quot; 서브 메뉴를 들어가면 위 사진이 나오는데요. 조금 더 세분화 된 설명이 여기 나와있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;통계표코드와 주기, 주기에 따른 검색시작일자, 종료일자가 나와있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, 수집하려는 데이터의 주기가 Q(분기)이면 시작 및 검색 종료일자에는 &quot;2020Q1&quot;과 같은 형태로 데이터를 전달해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수집하려는 데이터가 D(일)이라면 검색시작일자 및 종료일자에는 20200110, 20200120과 같은 형태로 데이터를 전달해야 하죠.&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;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;통계표 코드에 환율에 해당되는 코드인 &quot;731Y001&quot;을 넣고, &quot;731Y001&quot; 코드는 주기를 D만 제공하므로, 주기 값엔 D를, 그리고 날짜는 일단위이므로 20200110과 같이 '일'까지 포함된 값을 제공합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;또한, 통계항목코드1에는 0000001, 0000002와 같은 값을 넣어 달러와 엔화 값만 가져올 수 있도록 해두었습니다. 그 결과는 아래 사진과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bST4cw/btsPhIPYSiz/CDHJUs0QEFyEYS9R34KGtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bST4cw/btsPhIPYSiz/CDHJUs0QEFyEYS9R34KGtk/img.png&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;698&quot; data-filename=&quot;스크린샷 2025-07-14 오후 1.14.16.png&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bST4cw/btsPhIPYSiz/CDHJUs0QEFyEYS9R34KGtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbST4cw%2FbtsPhIPYSiz%2FCDHJUs0QEFyEYS9R34KGtk%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;1482&quot; height=&quot;698&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/otcj9/btsPgT5FBmv/Qr7yVXPLcpKiWcgFCIQk20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/otcj9/btsPgT5FBmv/Qr7yVXPLcpKiWcgFCIQk20/img.png&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;698&quot; data-filename=&quot;스크린샷 2025-07-14 오후 1.14.33.png&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/otcj9/btsPgT5FBmv/Qr7yVXPLcpKiWcgFCIQk20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fotcj9%2FbtsPgT5FBmv%2FQr7yVXPLcpKiWcgFCIQk20%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;1482&quot; height=&quot;698&quot;/&gt;&lt;/span&gt;&lt;/div&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;그리고 결과를 JSON으로도 받아볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청 유형에 xml이 아닌 json으로 넣으면 json 결과를 받을 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-14 오후 1.16.07.png&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;698&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cchmji/btsPhIPYSg2/4yR7IegwQluLnXqNlVKKi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cchmji/btsPhIPYSg2/4yR7IegwQluLnXqNlVKKi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cchmji/btsPhIPYSg2/4yR7IegwQluLnXqNlVKKi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcchmji%2FbtsPhIPYSg2%2F4yR7IegwQluLnXqNlVKKi1%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;696&quot; height=&quot;328&quot; data-filename=&quot;스크린샷 2025-07-14 오후 1.16.07.png&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;698&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;자, 그럼 이제 실제 Python 예제 코드로 넘어가보겠습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Python 예제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python 코드를 구성할 때는 위에 나와있는 url 형태로 request를 제공하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 이때 여러분들의 API KEY 값을 잘 넣어주는 게 중요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API 결과는 아래와 같은 url을 띄고 있는데요.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;https://ecos.bok.or.kr/api/StatisticSearch/sample/xml/kr/1/10/731Y001/D/20200110/20200114/0000001/?/?/?&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, sample에 여러분들의 API 키 값을 넣으면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, Python 코드는 아래와 같이 될 것입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1752470454885&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import requests

# URL 설정
url = &quot;https://ecos.bok.or.kr/api/StatisticSearch/{YOUR_KEY}/json/kr/1/10/731Y001/D/20200110/20200120/0000002/?/?/?&quot;

# GET 요청
response = requests.get(url)

# JSON 응답 확인
if response.status_code == 200:
    data = response.json()
    # print 전체 JSON
    print(data)
    
    # 필요한 데이터만 추출
    try:
        rows = data['StatisticSearch']['row']
        for item in rows:
            time = item['TIME']
            value = item['DATA_VALUE']
            print(f&quot;날짜: {time}, 데이터값: {value}&quot;)
    except KeyError:
        print(&quot;예상과 다른 JSON 구조입니다.&quot;)
else:
    print(f&quot;API 요청 실패: {response.status_code}&quot;)&lt;/code&gt;&lt;/pre&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-filename=&quot;스크린샷 2025-07-14 오후 1.17.29.png&quot; data-origin-width=&quot;2926&quot; data-origin-height=&quot;734&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yUgyU/btsPh810GhX/KYTd5R1SmhFsFAt9xWjd51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yUgyU/btsPh810GhX/KYTd5R1SmhFsFAt9xWjd51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yUgyU/btsPh810GhX/KYTd5R1SmhFsFAt9xWjd51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyUgyU%2FbtsPh810GhX%2FKYTd5R1SmhFsFAt9xWjd51%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;653&quot; height=&quot;164&quot; data-filename=&quot;스크린샷 2025-07-14 오후 1.17.29.png&quot; data-origin-width=&quot;2926&quot; data-origin-height=&quot;734&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;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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 한국은행 ECOS Open API 서비스에 대해서 알아보고 Python으로 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;&amp;nbsp;&lt;/p&gt;</description>
      <category>python</category>
      <category>ECOS</category>
      <category>ecosapi</category>
      <category>Python</category>
      <category>pythonecos</category>
      <category>python주식</category>
      <category>python환율</category>
      <category>파이썬</category>
      <category>한국은행</category>
      <category>한국은행api</category>
      <category>한국은행apipython</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/694</guid>
      <comments>https://lsjsj92.tistory.com/694#entry694comment</comments>
      <pubDate>Mon, 14 Jul 2025 14:25:45 +0900</pubDate>
    </item>
    <item>
      <title>Google Colab과 ngrok으로 나만의 LLM API 서버 구축하기 (feat. Ollama, vLLM)</title>
      <link>https://lsjsj92.tistory.com/693</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 17px; }
&lt;/style&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;포스팅 개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이번 포스팅은 로컬 개발 환경에 고사양의 GPU가 없더라도 구글 코랩(Google Colab)의 무료 GPU 자원을 활용해 자신만의 LLM(거대 언어 모델) API 서버를 구축하는 방법에 대해 정리합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ngrok이라는 터널링 도구를 활용해 Colab에서 실행되는 API 서버에 외부 접속이 가능한 공개 주소(Public URL)를 부여하고, 이를 통해 로컬 PC나 다른 환경에서 API를 자유롭게 호출하는 과정을 다룹니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;본 포스팅에서는 대표적인 LLM 서빙 프레임워크인 Ollama와 vLLM을 각각 Colab에 배포하고 API 서버로 활용하는 두 가지 실전 예제를 모두 소개합니다. 이를 통해 자신의 필요에 맞는 프레임워크를 선택하여 '나만의 LLM 서버'를 구축하고 활용하는 전반적인 과정을 이해할 수 있습니다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;본 포스팅에서 다루는 주요 내용은 다음과 같습니다.&lt;/span&gt;&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&gt;Colab과 ngrok 연동 원리 이해: 왜 이 조합을 사용하며 어떻게 동작하는지 알아봅니다.&lt;/li&gt;
&lt;li&gt;Ollama API 서버 구축: Colab에 Ollama를 설치하고 ngrok으로 외부에 노출시켜 로컬에서 API를 테스트합니다.&lt;/li&gt;
&lt;li&gt;vLLM API 서버 구축: Colab에 vLLM을 설치하고 OpenAI 호환 API 서버를 배포하여 로컬에서 활용합니다.&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;1. Colab과 ngrok 연동, 왜 함께 사용하는가?&lt;/span&gt;&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;최신 LLM(거대 언어 모델)을 로컬 환경에서 테스트하고 싶지만, GPU가 없거나 사양이 부족해 어려움을 겪는 경우가 많습니다. Llama 3나 Gemma, 요즘 나왔던 LG EXAONE, SKT A.X 4.0 이나 KT의 Midm(믿음) 같은 모델을 직접 실행해보려면 고가의 그래픽 카드가 필수적이기 때문이죠.&lt;/span&gt; &lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이때 Google Colab은 대안이 될 수 있습니다. Google 계정만 있다면 누구나 웹 브라우저를 통해 무료로 T4와 같은 강력한 GPU를 사용할 수 있기 때문입니다. &lt;/span&gt; &lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;모델을 학습시키거나 무거운 연산을 처리하는 데는 좋은 환경이죠. 저는 개인적으로 Pro로 쓰고 있는 데, 무료 계정으로도 활용이 가능합니다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333; text-align: start;&quot;&gt;Colab은 Google 클라우드 환경에서 독립된 컨테이너로 실행됩니다. &lt;/span&gt;따라서 Colab 내부에서 Ollama나 vLLM을 통해 API 서버를 실행하더라도, 외부 인터넷에 연결된 제 로컬 PC가 이 서버에 직접 접근할 방법이 없습니다.&lt;/span&gt; &lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;바로 이 문제를 해결해주는 방법이 ngrok입니다. ngrok은 Colab 내부의 특정 포트(예: 11434번)로 향하는 안전한 터널(tunnel)을 만들어 공개적으로 접속 가능한 고유 주소(URL)를 생성해줍니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;마치 외부와 단절된 Colab 내부에 나만 아는 통로를 만들어주는 것과 같습니다. 이 통로를 통해 제 로컬 PC는 ngrok이 생성해준 공개 주소로 API 요청을 보낼 수 있고, ngrok은 이 요청을 Colab 내부의 API 서버로 정확하게 전달해줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;즉, Colab의 강력한 무료 GPU(저처면 Pro면 약간의 요금을 내고 더 비싼 GPU)와 ngrok의 네트워크 연결을 결합하면, 비싼 장비 없이도 누구나 자신만의 LLM API 서버를 구축하고 제공되는 자원(resource) 안에서 마음껏 테스트할 수 있는 환경을 만들 수 있습니다.&lt;/span&gt;&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2. Ngrok 회원가입 및 Authtoken 확인&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-13 오후 3.56.40.png&quot; data-origin-width=&quot;1225&quot; data-origin-height=&quot;892&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmS8rr/btsPfHjWt5J/LxMRocVJFhsgQ3oUgAoGKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmS8rr/btsPfHjWt5J/LxMRocVJFhsgQ3oUgAoGKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmS8rr/btsPfHjWt5J/LxMRocVJFhsgQ3oUgAoGKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmS8rr%2FbtsPfHjWt5J%2FLxMRocVJFhsgQ3oUgAoGKK%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;521&quot; height=&quot;379&quot; data-filename=&quot;스크린샷 2025-07-13 오후 3.56.40.png&quot; data-origin-width=&quot;1225&quot; data-origin-height=&quot;892&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Colab과 연동하기 위해 먼저 ngrok에 가입하고 API 인증에 필요한 Authtoken을 발급받겠습니다. 과정은 매우 간단합니다.&lt;/span&gt; &lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ngrok 공식 홈페이지(&lt;a href=&quot;https://ngrok.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ngrok.com/&lt;/a&gt;)에 접속하여 price 메뉴에 들어가서, development 메뉴를 선택한 뒤 Free tier를 클릭합니다.&lt;/span&gt; &lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이때 회원가입이 요청되는데요. Google 계정을 연동하거나 이메일로 간편하게 가입을 진행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chsiFm/btsPgVBw1Vn/4NlVxJHlofo15EaqI6StsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chsiFm/btsPgVBw1Vn/4NlVxJHlofo15EaqI6StsK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;549&quot; data-origin-height=&quot;774&quot; data-filename=&quot;스크린샷 2025-07-13 오후 3.57.22.png&quot; style=&quot;width: 31.0834%; margin-right: 10px;&quot; data-widthpercent=&quot;31.45&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chsiFm/btsPgVBw1Vn/4NlVxJHlofo15EaqI6StsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchsiFm%2FbtsPgVBw1Vn%2F4NlVxJHlofo15EaqI6StsK%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;549&quot; height=&quot;774&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cocd5w/btsPfOpQ3NQ/jpv8uwwjFI3w2adbFjrXo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cocd5w/btsPfOpQ3NQ/jpv8uwwjFI3w2adbFjrXo0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;705&quot; data-filename=&quot;스크린샷 2025-07-13 오후 3.59.58.png&quot; style=&quot;width: 67.7538%;&quot; data-widthpercent=&quot;68.55&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cocd5w/btsPfOpQ3NQ/jpv8uwwjFI3w2adbFjrXo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcocd5w%2FbtsPfOpQ3NQ%2Fjpv8uwwjFI3w2adbFjrXo0%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;1090&quot; height=&quot;705&quot;/&gt;&lt;/span&gt;&lt;/div&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;로그인이 완료되면, 대시보드 왼쪽 메뉴의 Your Authtoken 탭으로 이동합니다.&lt;/span&gt; &lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;페이지에 보이는 Your Authtoken 아래의 문자열이 바로 여러분의 고유 인증 토큰입니다. 이 Authtoken은 Colab에서 실행될 ngrok 에이전트가 여러분의 계정 소유임을 증명하는 비밀 키 역할을 합니다. 이 토큰이 있어야 정상적으로 터널을 생성하고 관리할 수 있으므로, Copy 버튼을 눌러 안전한 곳에 복사해두시기 바랍니다. (토큰은 비밀번호와 같으므로 외부에 노출되지 않도록 주의해야 합니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-13 오후 4.01.26.png&quot; data-origin-width=&quot;1253&quot; data-origin-height=&quot;410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mW7Lx/btsPfgHaw3V/9cC4SwPl09l7p0hhjZvInk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mW7Lx/btsPfgHaw3V/9cC4SwPl09l7p0hhjZvInk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mW7Lx/btsPfgHaw3V/9cC4SwPl09l7p0hhjZvInk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmW7Lx%2FbtsPfgHaw3V%2F9cC4SwPl09l7p0hhjZvInk%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;682&quot; height=&quot;223&quot; data-filename=&quot;스크린샷 2025-07-13 오후 4.01.26.png&quot; data-origin-width=&quot;1253&quot; data-origin-height=&quot;410&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이제 Colab에서 LLM 서버를 실행하고 ngrok을 통해 외부와 연결할 모든 준비가 끝났습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;다음으로는 첫 번째 예제인 Ollama 서버를 구축해보겠습니다.&lt;/span&gt;&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;3. 예제 1: Colab에 Ollama 서버 구축 및 로컬 PC에서 API 호출하기&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이제 본격적으로 첫 번째 예제를 통해 Colab에 Ollama 서버를 구축하고, ngrok으로 생성된 Public URL을 이용해 로컬 PC에서 API를 호출하는 전 과정을 진행하겠습니다.&lt;/span&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;3.1. Colab 환경 설정 및 Ollama 설치&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;가장 먼저, Colab 노트북에서 필요한 패키지들을 설치하고 환경을 설정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1752391482260&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1. Ollama 설치 스크립트 실행
!curl -fsSL https://ollama.com/install.sh | sh

# 2. 원활한 GPU 연동을 위한 CUDA 드라이버 설치
# Colab 환경에 따라 필요하지 않을 수 있으나, 안정적인 구동을 위해 권장됩니다.
!echo 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections
!sudo apt-get update &amp;amp;&amp;amp; sudo apt-get install -y cuda-drivers

# 3. ngrok 연동을 위한 Python 라이브러리 설치
!pip install pyngrok&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;위 셀은 다음의 세 가지 작업을 수행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;Ollama 설치: Ollama 공식 스크립트를 실행하여 Colab 환경에 Ollama를 설치합니다.&lt;/li&gt;
&lt;li&gt;CUDA 드라이버 설치: Colab의 GPU와 Ollama 서버가 원활하게 통신할 수 있도록 NVIDIA CUDA 드라이버를 설치합니다. 이는 GPU 사용 시 발생할 수 있는 잠재적인 호환성 문제를 예방하는 데 도움이 됩니다.&lt;/li&gt;
&lt;li&gt;pyngrok 설치: Python 코드 내에서 ngrok 터널을 제어하기 위한 공식 라이브러리를 설치합니다.&lt;/li&gt;
&lt;/ol&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;3.2. 비동기 코드를 이용한 서버 및 ngrok 실행&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;설치가 완료되었다면, 이제 Ollama 서버, ngrok 터널, 그리고 모델 다운로드를 동시에 실행할 차례입니다. 이 세 가지의 실행 프로세스를 효율적으로 관리하기 위해 Python의 asyncio 라이브러리를 활용하겠습니다. asyncio를 사용하면 각 프로세스가 서로를 차단(blocking)하지 않고 동시에 실행되도록 할 수 있어, 실시간 로그 모니터링과 안정적인 프로세스 관리에 매우 유용합니다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;아래는 전체 실행 코드입니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1752391546164&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import os
import asyncio
from pyngrok import ngrok

# ngrok Authtoken을 입력합니다.
token = &quot;YOUR_NGROK_AUTHTOKEN&quot;
ngrok.set_auth_token(token)

async def run_process(cmd: list):
    &quot;&quot;&quot;
    주어진 커맨드를 비동기 서브프로세스로 실행하고,
    표준 출력/에러를 실시간으로 스트리밍합니다.
    &quot;&quot;&quot;
    print(f'&amp;gt;&amp;gt;&amp;gt; 프로세스 시작: {&quot; &quot;.join(cmd)}')
    process = await asyncio.subprocess.create_subprocess_exec(
        *cmd,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
    )

    async def pipe(stream):
        &quot;&quot;&quot;스트림의 출력을 비동기적으로 읽어 한 줄씩 디코딩하여 출력합니다.&quot;&quot;&quot;
        async for line in stream:
            print(line.decode().strip())

    # 표준 출력과 표준 에러 스트림을 동시에 처리합니다.
    await asyncio.gather(pipe(process.stdout), pipe(process.stderr))


async def main():
    &quot;&quot;&quot;
    Ollama 서버, ngrok 터널, 모델 다운로드 프로세스를 동시에 실행합니다.
    &quot;&quot;&quot;
    # 이전에 실행 중이던 ngrok 프로세스가 있다면 충돌 방지를 위해 종료합니다.
    os.system(&quot;kill -9 $(ps -aux | grep ngrok | awk '{print $2}') &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&quot;)
    
    await asyncio.gather(
        # Task 1: Ollama API 서버 실행
        # --host 0.0.0.0 플래그는 외부(ngrok)에서의 접속을 허용하기 위해 필수적입니다.
        run_process(['ollama', 'serve', '--host', '0.0.0.0']),
        
        # Task 2: ngrok을 통해 Ollama의 기본 포트인 11434에 대한 터널 생성
        run_process(['ngrok', 'http', '11434', '--log', 'stderr']),
        
        # Task 3: 사용할 LLM 모델 다운로드
        # 서버가 준비되는 즉시 클라이언트가 접속하여 다운로드를 시작합니다.
        run_process(['ollama', 'pull', 'exaone3.5:7.8b'])
    )

# 메인 비동기 함수 실행
try:
    await main()
except KeyboardInterrupt:
    print(&quot;사용자에 의해 프로세스가 중단되었습니다.&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;main 함수 내의 asyncio.gather는 세 가지 핵심 작업을 동시에 시작합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;ollama serve: Ollama API 서버를 실행합니다. 여기서 --host 0.0.0.0 플래그는 ngrok이 Colab 내부 서버에 접근할 수 있도록 하는 중요한 설정입니다.&lt;/li&gt;
&lt;li&gt;ngrok http 11434: 로컬의 11434 포트(Ollama 기본 포트)를 가리키는 공개 ngrok 터널을 생성합니다.&lt;/li&gt;
&lt;li&gt;ollama pull: API 서버에서 사용할 exaone3.5:7.8b 모델을 다운로드합니다.&lt;/li&gt;
&lt;/ol&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;3.3. 실행 결과 확인 및 Public URL 확보&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-13 오후 4.27.43.png&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;681&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bT7D7d/btsPg0ilClp/VG0uMpTmaWtIZfh3SHhook/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bT7D7d/btsPg0ilClp/VG0uMpTmaWtIZfh3SHhook/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bT7D7d/btsPg0ilClp/VG0uMpTmaWtIZfh3SHhook/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbT7D7d%2FbtsPg0ilClp%2FVG0uMpTmaWtIZfh3SHhook%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;546&quot; height=&quot;578&quot; data-filename=&quot;스크린샷 2025-07-13 오후 4.27.43.png&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;681&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;위 코드 셀을 실행하면, 세 프로세스의 로그가 실시간으로 출력되는 것을 확인할 수 있습니다. 여기서 우리가 주목해야 할 부분은 ngrok이 생성하는 url인데요. 아래와 같은 코드에서 확인할 수 있습니다. &lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1752391716875&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public_url = ngrok.connect(11434, proto=&quot;http&quot;)
NGROK_URL = public_url.public_url
print(f&quot;Ollama 서버가 실행 중이며 다음 주소에서 접속할 수 있습니다: {NGROK_URL}&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-13 오후 4.28.51.png&quot; data-origin-width=&quot;877&quot; data-origin-height=&quot;296&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CPKSK/btsPgx1WjCe/EOgKPCtsT1ZnIjA2Kk5EqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CPKSK/btsPgx1WjCe/EOgKPCtsT1ZnIjA2Kk5EqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CPKSK/btsPgx1WjCe/EOgKPCtsT1ZnIjA2Kk5EqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCPKSK%2FbtsPgx1WjCe%2FEOgKPCtsT1ZnIjA2Kk5EqK%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;638&quot; height=&quot;215&quot; data-filename=&quot;스크린샷 2025-07-13 오후 4.28.51.png&quot; data-origin-width=&quot;877&quot; data-origin-height=&quot;296&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;위&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&amp;nbsp;https://로 시작하는 이 주소가 바로 외부에서 여러분의 Colab Ollama 서버에 접속할 수 있는 Public URL입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이 주소를 복사해 둡니다. 이 URL은 매번 실행할 때마다 바뀌니 꼭 최근에 실행한 URL로 하셔야 합니다!&lt;/span&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;3.4. 로컬 PC에서 LangChain을 이용한 API 연동&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이제 마지막으로 로컬 PC의 Python 환경에서 Colab 서버에 API 요청을 보내보겠습니다. 여기서는 LLM 애플리케이션 개발에 널리 쓰이는 LangChain 프레임워크를 활용하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1752391792246&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;model = ChatOllama(model=&quot;exaone3.5:7.8b&quot;, temperature=0,
                   base_url=&quot;https://16964b620c8d.ngrok-free.app(여러분들의 주소로 바꾸세요)&quot;)

response = model.invoke(&quot;안녕하세요?&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-13 오후 4.30.55.png&quot; data-origin-width=&quot;877&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNr2Bq/btsPfOckvV0/LmqMRQJLcC25kZElApkYB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNr2Bq/btsPfOckvV0/LmqMRQJLcC25kZElApkYB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNr2Bq/btsPfOckvV0/LmqMRQJLcC25kZElApkYB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNr2Bq%2FbtsPfOckvV0%2FLmqMRQJLcC25kZElApkYB1%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;699&quot; height=&quot;196&quot; data-filename=&quot;스크린샷 2025-07-13 오후 4.30.55.png&quot; data-origin-width=&quot;877&quot; data-origin-height=&quot;246&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ChatOllama 객체를 생성할 때 base_url 파라미터에 앞서 확보한 ngrok의 Public URL을 제공해야 합니다. 위 코드를 실행했을 때 응답이 성공적으로 출력된다면, Colab의 GPU를 활용하는 여러분만의 LLM API 서버가 완벽하게 구축된 것입니다.&lt;/span&gt;&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;4. 예제 2: Colab에 vLLM 서버 구축 및 로컬 PC에서 API 호출하기&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이번에는 또 다른 강력한 LLM 서빙 프레임워크인 vLLM을 활용하는 예제를 다루겠습니다. vLLM은 PagedAttention과 같은 최신 기술을 통해 높은 처리량(high-throughput)과 효율적인 메모리 관리를 제공하는 것으로 잘 알려져 있습니다.&lt;/span&gt; &lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;vLLM의 가장 큰 장점 중 하나는 OpenAI API와 호환되는 엔드포인트를 제공한다는 점입니다. 이는 기존에 OpenAI API를 사용하던 코드에서 base_url만 vLLM 서버 주소로 변경하면 거의 수정 없이 그대로 활용할 수 있음을 의미합니다. 이러한 호환성은 개발 및 테스트 과정에서 매우 큰 유연성을 제공합니다.&lt;/span&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;4.1. Colab 환경 설정 및 vLLM 설치&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;먼저 Colab 환경에 vLLM과 pyngrok 라이브러리를 설치합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1752391922452&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# vLLM과 pyngrok 라이브러리를 설치합니다.
!pip install pyngrok vllm&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;4.2. vLLM 서버 및 ngrok 실행&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;vLLM 서버는 Ollama 예제와는 다른 접근 방식으로 실행해 보겠습니다. 여기서는 Python의 내장 라이브러리인 multiprocessing을 사용하여 vLLM 서버 프로세스를 백그라운드에서 실행시키겠습니다. 이 방식은 비동기 처리에 익숙하지 않더라도 직관적으로 백그라운드 작업을 구현할 수 있는 방법입니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1752391965488&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import os
import multiprocessing
from pyngrok import ngrok, conf

# 사용할 모델과 포트를 정의합니다.
MODEL_NAME = &quot;K-intelligence/Midm-2.0-Base-Instruct&quot;
PORT = 8000

# ngrok 설정
token = &quot;YOUR_NGROK_AUTHTOKEN&quot;
conf.get_default().auth_token = token

# 이전에 실행 중이던 프로세스나 터널이 있다면 충돌 방지를 위해 종료합니다.
!kill -9 $(lsof -t -i:{PORT}) &amp;gt; /dev/null 2&amp;gt;&amp;amp;1
ngrok.kill()

def run_vllm_server():
    &quot;&quot;&quot;
    백그라운드에서 vLLM의 OpenAI 호환 API 서버를 실행하는 함수.
    &quot;&quot;&quot;
    # vLLM 서버 실행에 필요한 인자들입니다.
    # --gpu-memory-utilization: GPU 메모리 사용률을 설정합니다. (Colab T4 환경에서는 0.9가 적절)
    # --trust-remote-code: HuggingFace의 커스텀 코드를 신뢰하고 실행합니다.
    # --max-model-len: 모델이 처리할 수 있는 최대 시퀀스 길이를 설정합니다.
    os.system(f&quot;&quot;&quot;
    python -m vllm.entrypoints.openai.api_server \
        --model {MODEL_NAME} \
        --host 0.0.0.0 \
        --port {PORT} \
        --tensor-parallel-size 1 \
        --gpu-memory-utilization 0.9 \
        --trust-remote-code \
        --max-model-len 16384 \
        &amp;gt; vllm.log 2&amp;gt;&amp;amp;1
    &quot;&quot;&quot;)

# multiprocessing을 사용하여 백그라운드에서 vLLM 서버 실행
print(&quot;백그라운드에서 vLLM 서버를 시작합니다...&quot;)
vllm_process = multiprocessing.Process(target=run_vllm_server)
vllm_process.start()

public_url = ngrok.connect(PORT, proto=&quot;http&quot;)
NGROK_URL = public_url.public_url
print(f&quot;vLLM 서버가 실행 중이며 다음 주소에서 접속할 수 있습니다: {NGROK_URL}&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;위 코드는 다음의 절차로 동작합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;프로세스 초기화: 이전에 8000번 포트를 사용하던 프로세스나 ngrok 터널이 남아있을 경우를 대비해 모두 종료시킵니다.&lt;/li&gt;
&lt;li&gt;run_vllm_server 함수 정의: os.system을 통해 터미널에서 vLLM의 OpenAI API 서버를 실행하는 명령어를 정의합니다. 다양한 옵션을 통해 GPU 사용률, 최대 토큰 길이 등을 세밀하게 제어할 수 있습니다.&lt;/li&gt;
&lt;li&gt;백그라운드 실행: multiprocessing.Process가 run_vllm_server 함수를 별도의 프로세스로 실행하여, 메인 스크립트의 흐름을 막지 않고 백그라운드에서 서버가 계속 구동되도록 합니다.&lt;/li&gt;
&lt;li&gt;ngrok 터널 생성: ngrok.connect(PORT)를 통해 Colab의 8000번 포트로 향하는 Public URL을 생성하고 출력합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #ee2323; background-color: #ffc1c8;&quot;&gt;&lt;b&gt;주의할 점!&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;vLLM은 모델이 올라가는 데 시간 소모가 있을 수 있습니다. 모델이 무거울수록 오래걸립니다.&lt;br /&gt;따라서, 아래와 같이 계속 log를 보며 API가 실행됐는 지 체크하고 동작시켜야 합니다.&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddYt4O/btsPhtR3bOO/sD6JrBmNT7507eWq51HfC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddYt4O/btsPhtR3bOO/sD6JrBmNT7507eWq51HfC1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1461&quot; data-origin-height=&quot;567&quot; data-filename=&quot;스크린샷 2025-07-12 오후 6.10.21.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddYt4O/btsPhtR3bOO/sD6JrBmNT7507eWq51HfC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FddYt4O%2FbtsPhtR3bOO%2FsD6JrBmNT7507eWq51HfC1%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;1461&quot; height=&quot;567&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y2lru/btsPfr9P8ks/KtmKS6dT21jXSYqDZIkyr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y2lru/btsPfr9P8ks/KtmKS6dT21jXSYqDZIkyr0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1461&quot; data-origin-height=&quot;567&quot; data-filename=&quot;스크린샷 2025-07-12 오후 6.10.33.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y2lru/btsPfr9P8ks/KtmKS6dT21jXSYqDZIkyr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy2lru%2FbtsPfr9P8ks%2FKtmKS6dT21jXSYqDZIkyr0%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;1461&quot; height=&quot;567&quot;/&gt;&lt;/span&gt;&lt;/div&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;4.3. 로컬 PC에서 API 연동&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;vLLM 서버의 가장 큰 매력은 OpenAI API와의 호환성입니다. 이를 활용하여 로컬 PC에서 API를 연동하는 두 가지 방법을 모두 살펴보겠습니다.&lt;/span&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;방법 A: openai 라이브러리 직접 활용&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;가장 기본적인 방법으로, openai 라이브러리를 직접 사용하여 API를 호출합니다.&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752392193269&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# openai 라이브러리를 가져옵니다.
from openai import OpenAI


client = OpenAI(
    base_url=&quot;https://0c685e4bf549.ngrok-free.app(여러분들의 주소로 바꾸세요)/v1&quot;, 
    api_key=&quot;NOT_USED&quot;
)

# vLLM 서버에 보낼 메시지를 준비합니다.
messages = [
    {&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;안녕하세요&quot;}
]

# vLLM 서버에서 사용하는 모델 이름을 지정합니다.
MODEL_NAME = &quot;K-intelligence/Midm-2.0-Base-Instruct&quot;

print(&quot;vLLM 서버에 메시지를 전송합니다!&quot;)

# Chat Completions API를 호출하여 응답을 받습니다.
try:
    response = client.chat.completions.create(
        model=MODEL_NAME,
        messages=messages,
        temperature=0.7, # 응답의 창의성을 조절합니다.
        max_tokens=100   # 최대 응답 길이를 설정합니다.
    )

    # 받은 응답에서 텍스트 부분만 추출하여 출력합니다.
    answer = response.choices[0].message.content
    print(&quot;\n[vLLM 응답]&quot;)
    print(answer)

except Exception as e:
    print(f&quot;\n오류가 발생했습니다: {e}&quot;)
    print(&quot;vLLM 서버 주소가 올바른지, 서버가 정상적으로 실행 중인지 확인해주세요.&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;vLLM이 정상적으로 실행되었으면 아래와 같이 결과가 나오는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-13 오후 4.39.38.png&quot; data-origin-width=&quot;1045&quot; data-origin-height=&quot;244&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RL3EV/btsPf0DCnwA/VLXQ1ZrjvuT7kzJBYWijF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RL3EV/btsPf0DCnwA/VLXQ1ZrjvuT7kzJBYWijF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RL3EV/btsPf0DCnwA/VLXQ1ZrjvuT7kzJBYWijF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRL3EV%2FbtsPf0DCnwA%2FVLXQ1ZrjvuT7kzJBYWijF0%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;676&quot; height=&quot;158&quot; data-filename=&quot;스크린샷 2025-07-13 오후 4.39.38.png&quot; data-origin-width=&quot;1045&quot; data-origin-height=&quot;244&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333; text-align: start;&quot;&gt;방법 B: LangChain의 ChatOpenAI를 활용&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333; text-align: start;&quot;&gt;랭체인에 있는 ChatOpenAI를 활용해서도 사용할 수 있습니다. 아래 코드와 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1752392339326&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_openai import ChatOpenAI
model = ChatOpenAI(model=&quot;K-intelligence/Midm-2.0-Base-Instruct&quot;, temperature=0,
                   base_url=&quot;https://0c685e4bf549.ngrok-free.app(여러분들의 주소)/v1&quot;,
                  api_key=&quot;NOT_USED&quot;)

response = model.invoke(&quot;안녕하세요?&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-13 오후 4.39.22.png&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;329&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWrDU2/btsPfAla5Ss/fPBrgrHI16aFUFe0bU8Go0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWrDU2/btsPfAla5Ss/fPBrgrHI16aFUFe0bU8Go0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWrDU2/btsPfAla5Ss/fPBrgrHI16aFUFe0bU8Go0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWrDU2%2FbtsPfAla5Ss%2FfPBrgrHI16aFUFe0bU8Go0%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;742&quot; height=&quot;265&quot; data-filename=&quot;스크린샷 2025-07-13 오후 4.39.22.png&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;329&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;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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 글은 ngrok을 활용해 구글 코랩(google colab)을 LLM 서버로 활용하여 API 통신이 가능하도록 만드는 과정을 소개하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, Ollama와 vLLM을 활용할 수 있는 예제(example)도 작성하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도움이 되시길 바랍니다.&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>Colab</category>
      <category>colabllm서버</category>
      <category>colabollama</category>
      <category>colabvllm</category>
      <category>langchain</category>
      <category>LLM</category>
      <category>llm서버</category>
      <category>ngrok</category>
      <category>Ollama</category>
      <category>vllm</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/693</guid>
      <comments>https://lsjsj92.tistory.com/693#entry693comment</comments>
      <pubDate>Sun, 13 Jul 2025 16:47:29 +0900</pubDate>
    </item>
    <item>
      <title>LangGraph를 활용한 Stateful 챗봇 구축: DB 연동을 통한 대화 기록 관리 및 조건부 요약 시스템 구현</title>
      <link>https://lsjsj92.tistory.com/692</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 17px; }
&lt;/style&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;포스팅 개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;이번 포스팅에서는 LangChain의 확장 라이브러리인 &lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;를 사용하여 &lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;상태 저장(Stateful) 챗봇&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;을 구축하는 방법에 대해 다룹니다. 일반적인 LLM API 호출은 이전의 대화 내용을 기억하지 못하는 &lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;무상태(Stateless)&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 특징을 가집니다. 본 포스팅에서는 이러한 한계를 극복하기 위해, PostgreSQL 데이터베이스와 연동하여 대화 기록을 영구적으로 관리하고, 대화의 길이에 따라 동적으로 요약본을 생성하여 컨텍스트(Context)를 효율적으로 관리하는 아키텍처를 LangGraph로 구현하는 전 과정을 설명합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이번 포스팅을 작성하면서 참고한 LangGraph 공식 문서는 아래와 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph Documentation:&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #0b57d0;&quot;&gt;&lt;/span&gt;&lt;a href=&quot;https://python.langchain.com/docs/langgraph/&quot;&gt;https://python.langchain.com/docs/langgraph/&lt;/a&gt;&lt;/span&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;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;포스팅 본문&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;포스팅 개요에서 언급했듯이, 이번 포스팅은 LangGraph와 데이터베이스를 연동하여 Stateful 챗봇을 구축하는 구체적인 방법을 다룹니다. 본 포스팅의 순서는 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph란?&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: LLM 워크플로우 제어를 위한 그래프 기반 라이브러리&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;Stateful 챗봇 아키텍처 설계&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: 전체 시스템 구성 요소와 상호작용&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;대화 기록 관리 구현&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;thread_id&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 기반의 메시지 지속성(Persistence) 확보&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;조건부 요약을 통한 컨텍스트 관리&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;: LangGraph의 Conditional Edges 활용&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LangGraph 워크플로우 시각화&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;실행 결과&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;랭그래프(LangGraph)란?&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-06-29 오후 7.57.51.png&quot; data-origin-width=&quot;1417&quot; data-origin-height=&quot;679&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOHy7q/btsOUU49QhC/RiPEqO03LM8TzSm4hE9utK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOHy7q/btsOUU49QhC/RiPEqO03LM8TzSm4hE9utK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOHy7q/btsOUU49QhC/RiPEqO03LM8TzSm4hE9utK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOHy7q%2FbtsOUU49QhC%2FRiPEqO03LM8TzSm4hE9utK%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;641&quot; height=&quot;307&quot; data-filename=&quot;스크린샷 2025-06-29 오후 7.57.51.png&quot; data-origin-width=&quot;1417&quot; data-origin-height=&quot;679&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;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;랭그래프(LangGraph)는 복잡하고 순환적인(Cyclic) LLM 애플리케이션을 구축하기 위해 설계된 라이브러리입니다. 기존의 렝체인(LangChain) Expression Language (LCEL)이 DAG(Directed Acyclic Graph, 방향성 비순환 그래프) 형태의 체인 구성에 최적화되어 있다면, LangGraph는 상태(State)를 중심으로 노드(Node)와 엣지(Edge)를 정의하여 보다 자유로운 형태의 그래프, 즉 워크플로우를 구현할 수 있게 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;각 노드는 LLM 호출, 함수 실행 등 특정 작업을 수행하는 단위이며, 엣지는 이 노드들 간의 전환을 정의합니다. 이를 통해 여러 에이전트(Agent)가 협력하거나, 사용자의 입력에 따라 동적으로 작업 흐름을 변경하는 등 고수준의 제어가 가능해집니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Stateful 챗봇 아키텍처 설계&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Stateful 챗봇은 상태를 유지하고 지속적으로 이 정보를 바탕으로 요청을 처리하는 구조입니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;본 포스팅에서 구현할 챗봇의 아키텍처는 다음과 같은 핵심 컴포넌트로 구성됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;Control Flow (&lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;graph.py&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;):&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; LangGraph를 사용하여 전체 대화 흐름을 제어합니다. 대화 맥락 로드, LLM 응답 생성, 메시지 저장, 요약 필요성 판단 등의 로직이 그래프로 정의됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;Persistence Layer (&lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;database.py&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;services.py&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;):&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; PostgreSQL 데이터베이스를 사용하여 대화의 상태를 영구적으로 저장합니다. &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;SQLAlchemy&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;를 통해 비동기적으로 데이터베이스와 통신하며, &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;services.py&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;는 데이터베이스 관련 로직을 추상화한 서비스 계층의 역할을 수행합니다. 본 포스팅에서 활용한 그래프 구조는 아래와 같습니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-06-29 오후 8.09.35.png&quot; data-origin-width=&quot;1072&quot; data-origin-height=&quot;862&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JzYGV/btsOV7QEbrL/Q2qhXcOzypgNCldOSvg4l0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JzYGV/btsOV7QEbrL/Q2qhXcOzypgNCldOSvg4l0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JzYGV/btsOV7QEbrL/Q2qhXcOzypgNCldOSvg4l0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJzYGV%2FbtsOV7QEbrL%2FQ2qhXcOzypgNCldOSvg4l0%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;436&quot; height=&quot;351&quot; data-filename=&quot;스크린샷 2025-06-29 오후 8.09.35.png&quot; data-origin-width=&quot;1072&quot; data-origin-height=&quot;862&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;LLM (&lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;config.py&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;):&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; Ollama를 통해 서빙되는 로컬 LLM을 추론 엔진으로 사용합니다. &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;ChatOllama&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 인터페이스를 통해 LangGraph와 연동됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;Streamlit을 통해 웹 화면으로 동작되도록 합니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이 구조에서 LangGraph는 사용자 요청이 들어왔을 때 데이터베이스 서비스와 LLM을 적절한 순서로 호출하여 응답을 생성하고 상태를 업데이트하는 역할을 담당합니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;대화 기록 관리 구현&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;Stateful 챗봇의 핵심은 각 대화를 식별하고 해당 기록을 관리하는 것입니다. 이를 위해 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;thread_id&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 개념을 도입합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;thread_id&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 기반 대화 분리:&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 모든 대화 세션은 고유한 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;thread_id&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;를 가집니다. 데이터베이스의 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;langgraph_threads&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 테이블과 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;langgraph_messages&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 테이블은 이 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;thread_id&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;를 외래 키로 사용하여 특정 대화에 속한 메시지들을 관리합니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1751195514331&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;threads_table = Table(
    &quot;langgraph_threads&quot;,
    metadata,
    Column(&quot;thread_id&quot;, String, primary_key=True),
    Column(&quot;created_at&quot;, DateTime(timezone=True), server_default=func.now(), nullable=False),
    Column(&quot;metadata&quot;, JSONB),
)

messages_table = Table(
    &quot;langgraph_messages&quot;,
    metadata,
    Column(&quot;thread_id&quot;, String, ForeignKey(&quot;langgraph_threads.thread_id&quot;), primary_key=True),
    Column(&quot;message_idx&quot;, DateTime(timezone=True), primary_key=True),
    Column(&quot;author&quot;, String, nullable=False),
    Column(&quot;content&quot;, Text, nullable=False),
)

summaries_table = Table(
    &quot;langgraph_summaries&quot;,
    metadata,
    Column(&quot;thread_id&quot;, String, ForeignKey(&quot;langgraph_threads.thread_id&quot;), primary_key=True),
    Column(&quot;summary&quot;, Text, nullable=False),
    Column(&quot;updated_at&quot;, DateTime(timezone=True), onupdate=func.now(), nullable=False),
)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;LangGraph 노드를 통한 DB 연동&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;load_context 노드: 대화 시작 시, thread_id를 기반으로 load_context 함수를 호출합니다. 이 함수는 DB에 저장된 요약본이나 이전 메시지 기록을 조회하여 현재 대화의 초기 맥락으로 로드합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;save_messages 노드: LLM이 응답을 생성한 후, save_messages 함수를 호출하여 사용자의 질문과 AI의 답변을 thread_id와 함께 DB에 저장합니다. 이로써 대화의 지속성이 보장됩니다. 특히, 이때 요약이 필요한 정보가 있으면 needs_summary를 체크해주는 구조도 가지고 있습니다. 요약을 하는 이유는 LLM이 모든 컨텍스트(context)를 기억할 수 없기에, 특정 조건이 되면 요약된 정보를 저장하고 이를 활용하도록 하기 위함입니다. 자세한 것은 다음 섹션에 추가로 설명하겠습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1751195587599&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async def load_context_node(state: ConversationState):
    thread_id = state['thread_id']
    await db_service.get_or_create_thread(thread_id)

    user_message = state['messages'][-1]
    history = await db_service.load_context(thread_id)

    return {&quot;messages&quot;: history + [user_message]}

async def save_messages_node(state: ConversationState):
    human_message = state['messages'][-2]
    ai_message = state['messages'][-1]
    now = datetime.now(timezone.utc)

    messages_to_save = [
        (&quot;human&quot;, human_message.content, now),
        (&quot;ai&quot;, ai_message.content, now.replace(microsecond=now.microsecond + 1))
    ]

    await db_service.save_messages(state['thread_id'], messages_to_save)

    total_messages, _ = await db_service.get_all_messages_for_summary(state['thread_id'])
    needs_summary = total_messages &amp;gt;= 5

    return {&quot;needs_summary&quot;: needs_summary}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;조건부 요약을 통한 컨텍스트 관리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;대화가 길어질 경우 전체 기록을 LLM의 컨텍스트에 포함시키는 것은 비효율적이며, 모델의 최대 토큰 제한을 초과할 수 있습니다. LangGraph의 조건부 엣지(Conditional Edges)를 활용하여 이 문제를 효과적으로 해결할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;조건부 분기 설정:&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;save_messages&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 노드가 실행된 후, 다음 경로를 결정하기 위해 조건부 엣지를 사용합니다.&lt;/span&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;should_summarize_edge 함수는 현재 thread_id에 해당하는 총 메시지 수를 DB에서 확인합니다. 만약 메시지 수가 미리 정의된 임계값(e.g., 5)을 초과하면 'summarize' 경로를, 그렇지 않으면 'END' 경로를 반환합니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;요약 노드 (&lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;summarize_node&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;'summarize' 경로로 분기될 경우, 이 노드가 활성화됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;get_all_messages_for_summary 함수를 호출하여 전체 대화 기록을 단일 문자열로 가져옵니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;별도의 요약용 프롬프트를 사용하여 LLM을 호출, 대화의 핵심 내용을 요약합니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #1b1c1d;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;생성된 요약문은 summaries 테이블에 저장(Upsert)되어, 다음 load_context 호출 시 활용됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이 아키텍처를 통해 챗봇은 대화 길이에 따라 동적으로 컨텍스트 관리 방식을 전환하는 지능적인 동작이 가능해집니다. 이 내용의 코드는 아래와 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751195903650&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async def summarize_node(state: ConversationState):
    if not state.get('needs_summary'):
        return {}

    _, conversation_str = await db_service.get_all_messages_for_summary(state['thread_id'])

    summary_result = await summarizer_chain.ainvoke({&quot;conversation&quot;: conversation_str})
    summary = summary_result.content

    await db_service.save_summary(state['thread_id'], summary)
    print(f&quot;\n--- [Thread: {state['thread_id']}] 대화가 요약되었습니다. ---&quot;)

    return {}

#  조건부 엣지
def should_summarize_edge(state: ConversationState) -&amp;gt; str:
    return &quot;summarize&quot; if state.get('needs_summary') else END

builder = StateGraph(ConversationState)
builder.add_node(&quot;load_context&quot;, load_context_node)
builder.add_node(&quot;chat&quot;, chat_node)
builder.add_node(&quot;save_messages&quot;, save_messages_node)
builder.add_node(&quot;summarize&quot;, summarize_node)

builder.add_edge(START, &quot;load_context&quot;)
builder.add_edge(&quot;load_context&quot;, &quot;chat&quot;)
builder.add_edge(&quot;chat&quot;, &quot;save_messages&quot;)
builder.add_conditional_edges(&quot;save_messages&quot;, should_summarize_edge, {&quot;summarize&quot;: &quot;summarize&quot;, END: END})
builder.add_edge(&quot;summarize&quot;, END)&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;LangGraph 워크플로우 시각화&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;복잡한 워크플로우는 코드로만 파악하기 어려울 수 있습니다. LangGraph는 정의된 그래프의 구조를 시각화하는 기능을 제공하여 개발 및 디버깅의 효율성을 높입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;graph.get_graph()&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 메서드를 통해 컴파일된 그래프 객체로부터 노드와 엣지 정보를 추출하고, &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;streamlit-agraph&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 라이브러리를 이용해 이를 웹 UI 상에 렌더링합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;시각화된 다이어그램을 통해 개발자는 데이터의 흐름, 노드 간의 관계, 특히 조건부 엣지에 의한 분기 지점을 명확하게 확인할 수 있어, 시스템의 동작을 직관적으로 이해하고 잠재적인 오류를 신속하게 파악할 수 있습니다.&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style8&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;실행 결과&lt;/span&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;1. 새로운 대화 시작&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;새 대화 시작하기를 통해 첫 대화를 시작할 수 있습니다. 이때, thread-id가 생성되고 해당 thread id 기반으로 대화가 저장됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-06-29 오후 8.22.01.png&quot; data-origin-width=&quot;1660&quot; data-origin-height=&quot;895&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9IeFl/btsOVf2x8pR/2xzAtXtA98RWyEUkCHn8V1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9IeFl/btsOVf2x8pR/2xzAtXtA98RWyEUkCHn8V1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9IeFl/btsOVf2x8pR/2xzAtXtA98RWyEUkCHn8V1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9IeFl%2FbtsOVf2x8pR%2F2xzAtXtA98RWyEUkCHn8V1%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;719&quot; height=&quot;388&quot; data-filename=&quot;스크린샷 2025-06-29 오후 8.22.01.png&quot; data-origin-width=&quot;1660&quot; data-origin-height=&quot;895&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-06-29 오후 8.27.38.png&quot; data-origin-width=&quot;2478&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AjhG7/btsOVIwknn1/alwTinSQ8Krnwqb0ofPg80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AjhG7/btsOVIwknn1/alwTinSQ8Krnwqb0ofPg80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AjhG7/btsOVIwknn1/alwTinSQ8Krnwqb0ofPg80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAjhG7%2FbtsOVIwknn1%2FalwTinSQ8Krnwqb0ofPg80%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;2478&quot; height=&quot;268&quot; data-filename=&quot;스크린샷 2025-06-29 오후 8.27.38.png&quot; data-origin-width=&quot;2478&quot; data-origin-height=&quot;268&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;위 첫 번째 사진은 새로운 대화를 이어간 것을 보여주고, 두 번째 사진에서는 DB에 정상적으로 thread_id에 따라 대화가 저장되는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2. 기존 대화 이어가기&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;thread_id가 있다보니, 기존 대화 이력을 가져와서 대화를 다시 이어갈 수 있습니다. 진짜 챗봇처럼 말이죠&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccs7Tm/btsOXHQQ1A5/dPXRKvAcbGHAWCKtvA2oBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccs7Tm/btsOXHQQ1A5/dPXRKvAcbGHAWCKtvA2oBK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1660&quot; data-origin-height=&quot;895&quot; data-filename=&quot;스크린샷 2025-06-29 오후 8.22.11.png&quot; style=&quot;width: 46.5975%; margin-right: 10px;&quot; data-widthpercent=&quot;47.15&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccs7Tm/btsOXHQQ1A5/dPXRKvAcbGHAWCKtvA2oBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fccs7Tm%2FbtsOXHQQ1A5%2FdPXRKvAcbGHAWCKtvA2oBK%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;1660&quot; height=&quot;895&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzDbkv/btsOXfmBTY0/XshUKBiuH1hTtcrqVz0LC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzDbkv/btsOXfmBTY0/XshUKBiuH1hTtcrqVz0LC1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1861&quot; data-origin-height=&quot;895&quot; data-filename=&quot;스크린샷 2025-06-29 오후 8.22.19.png&quot; style=&quot;width: 52.2397%;&quot; data-widthpercent=&quot;52.85&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzDbkv/btsOXfmBTY0/XshUKBiuH1hTtcrqVz0LC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzDbkv%2FbtsOXfmBTY0%2FXshUKBiuH1hTtcrqVz0LC1%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;1861&quot; height=&quot;895&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-06-29 오후 8.23.15.png&quot; data-origin-width=&quot;1207&quot; data-origin-height=&quot;349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mFARH/btsOVtzuAT1/b8JoRSq8dhrpakyumpv8ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mFARH/btsOVtzuAT1/b8JoRSq8dhrpakyumpv8ak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mFARH/btsOVtzuAT1/b8JoRSq8dhrpakyumpv8ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmFARH%2FbtsOVtzuAT1%2Fb8JoRSq8dhrpakyumpv8ak%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;677&quot; height=&quot;196&quot; data-filename=&quot;스크린샷 2025-06-29 오후 8.23.15.png&quot; data-origin-width=&quot;1207&quot; data-origin-height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-06-29 오후 8.28.21.png&quot; data-origin-width=&quot;2584&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bR6TBi/btsOWEm19Wi/hZ1SxWaZmboL0P3xT0M4ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bR6TBi/btsOWEm19Wi/hZ1SxWaZmboL0P3xT0M4ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bR6TBi/btsOWEm19Wi/hZ1SxWaZmboL0P3xT0M4ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbR6TBi%2FbtsOWEm19Wi%2FhZ1SxWaZmboL0P3xT0M4ck%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;701&quot; height=&quot;66&quot; data-filename=&quot;스크린샷 2025-06-29 오후 8.28.21.png&quot; data-origin-width=&quot;2584&quot; data-origin-height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 이전 대화의 정보가 있기 때문에 실제로 위와 같이 '제 이름이 뭐죠?'라고 다시 물어보면 기존 대화를 근거로 저의 이름을 정확히 말하는 것을 확인할 수 있습니다. 그리고 새롭게 대화를 이어가면, 같은 thread_id에 마찬가지로 DB에 데이터가 적재되어 있는 모습을 확인할 수 있습니다.&lt;/p&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-filename=&quot;스크린샷 2025-06-29 오후 8.28.11.png&quot; data-origin-width=&quot;2478&quot; data-origin-height=&quot;66&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjTikb/btsOWfgMJDp/6XxLjbr3BXBK8pdKBqIPLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjTikb/btsOWfgMJDp/6XxLjbr3BXBK8pdKBqIPLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjTikb/btsOWfgMJDp/6XxLjbr3BXBK8pdKBqIPLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjTikb%2FbtsOWfgMJDp%2F6XxLjbr3BXBK8pdKBqIPLk%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;2478&quot; height=&quot;66&quot; data-filename=&quot;스크린샷 2025-06-29 오후 8.28.11.png&quot; data-origin-width=&quot;2478&quot; data-origin-height=&quot;66&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;p data-ke-size=&quot;size16&quot;&gt;LangGraph는 그래프 구조 (노드와 엣지로 구성)를 가지고 있으므로, 아래와 같이 시각화가 가능합니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-06-29 오후 8.23.43.png&quot; data-origin-width=&quot;1207&quot; data-origin-height=&quot;837&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bU8t1K/btsOVCp2zq6/9OsEPWsn8pfKgVKYuKFuh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bU8t1K/btsOVCp2zq6/9OsEPWsn8pfKgVKYuKFuh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bU8t1K/btsOVCp2zq6/9OsEPWsn8pfKgVKYuKFuh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbU8t1K%2FbtsOVCp2zq6%2F9OsEPWsn8pfKgVKYuKFuh0%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;678&quot; height=&quot;470&quot; data-filename=&quot;스크린샷 2025-06-29 오후 8.23.43.png&quot; data-origin-width=&quot;1207&quot; data-origin-height=&quot;837&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;이러한 시각화를 통해 내 그래프가 어떤 flow로 동작되는 지 가볍게 파악할 수 있게 됩니다.&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;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;이번 포스팅에서는 LangGraph를 활용하여 무상태(Stateless) LLM 호출의 한계를 넘어, 데이터베이스 연동을 통해 대화 기록을 영구적으로 관리하는 Stateful 챗봇의 구현 방법을 알아보았습니다. &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;thread_id&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt; 기반의 메시지 관리, 그리고 &lt;/span&gt;&lt;span style=&quot;background-color: #e9eef6; color: #575b5f;&quot;&gt;Conditional Edges&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;를 이용한 동적 컨텍스트 요약은 확장성 있고 효율적인 대화형 AI 시스템을 구축하는 방법이었습니다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #1b1c1d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #1b1c1d;&quot;&gt;긴 글 읽어주셔서 감사합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>chatbot</category>
      <category>langchain</category>
      <category>langgraph</category>
      <category>LLM</category>
      <category>Ollama</category>
      <category>Python</category>
      <category>streamlit</category>
      <category>랭그래프</category>
      <category>랭체인</category>
      <category>챗봇</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/692</guid>
      <comments>https://lsjsj92.tistory.com/692#entry692comment</comments>
      <pubDate>Sun, 29 Jun 2025 20:35:31 +0900</pubDate>
    </item>
    <item>
      <title>소버린(Sovereign) AI란? - AI 주도 강국으로 가기 위한 발걸음</title>
      <link>https://lsjsj92.tistory.com/691</link>
      <description>&lt;div&gt;
&lt;style&gt;
  li { font-size: 17px; }
&lt;/style&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인공지능(AI)은 인류 역사상 가장 강력한 '게임 체인저'로 부상하며 개인의 삶, 기업의 운영 방식, 나아가 국가의 미래까지 변화시키는 대전환의 시대를 열었습니다. 이러한 거대한 변화 속에서 '소버린 AI(Sovereign AI)'는 단순히 기술적 유행어를 넘어, 한 국가의 미래 번영과 안보를 결정짓는 핵심 전략으로 주목받고 있습니다.&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(Sovereign AI)에 대해서 정리해보고 개인적인 생각도 작성해볼까 합니다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://blogs.nvidia.co.kr/blog/what-is-sovereign-ai/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://blogs.nvidia.co.kr/blog/what-is-sovereign-ai/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://clova.ai/tech-blog/ko-%EC%86%8C%EB%B2%84%EB%A6%B0-ai-ai-%EC%8B%9C%EB%8C%80-%EB%84%A4%EC%9D%B4%EB%B2%84%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%EB%8F%84%EC%A0%84%EA%B3%BC-%EA%B3%BC%EC%A0%9C&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://clova.ai/tech-blog/ko-%EC%86%8C%EB%B2%84%EB%A6%B0-ai-ai-%EC%8B%9C%EB%8C%80-%EB%84%A4%EC%9D%B4%EB%B2%84%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%EB%8F%84%EC%A0%84%EA%B3%BC-%EA%B3%BC%EC%A0%9C&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1750675662047&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(Sovereign AI)란? - NVIDIA Blog Korea&quot; data-og-description=&quot;소버린 AI는 자체 인프라, 데이터, 인력 및 비즈니스 네트워크를 사용하여 AI를 구축하는 국가의 역량을 의미합니다.&quot; data-og-host=&quot;blogs.nvidia.co.kr&quot; data-og-source-url=&quot;https://blogs.nvidia.co.kr/blog/what-is-sovereign-ai/&quot; data-og-url=&quot;https://blogs.nvidia.co.kr/blog/what-is-sovereign-ai/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/k2Gd5/hyZchguYgX/MDhpLqqHUaJxka2g0fYLa0/img.jpg?width=2048&amp;amp;height=1024&amp;amp;face=0_0_2048_1024,https://scrap.kakaocdn.net/dn/bfxyuE/hyZbzPbBKx/H4cyXjcf654mdjcmakaDx1/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540,https://scrap.kakaocdn.net/dn/bTQxmp/hyZbxRnBot/kZGjyJvo6K2gFbwlxRmqgK/img.png?width=960&amp;amp;height=510&amp;amp;face=0_0_960_510&quot;&gt;&lt;a href=&quot;https://blogs.nvidia.co.kr/blog/what-is-sovereign-ai/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blogs.nvidia.co.kr/blog/what-is-sovereign-ai/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/k2Gd5/hyZchguYgX/MDhpLqqHUaJxka2g0fYLa0/img.jpg?width=2048&amp;amp;height=1024&amp;amp;face=0_0_2048_1024,https://scrap.kakaocdn.net/dn/bfxyuE/hyZbzPbBKx/H4cyXjcf654mdjcmakaDx1/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540,https://scrap.kakaocdn.net/dn/bTQxmp/hyZbxRnBot/kZGjyJvo6K2gFbwlxRmqgK/img.png?width=960&amp;amp;height=510&amp;amp;face=0_0_960_510');&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(Sovereign AI)란? - NVIDIA Blog Korea&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;소버린 AI는 자체 인프라, 데이터, 인력 및 비즈니스 네트워크를 사용하여 AI를 구축하는 국가의 역량을 의미합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blogs.nvidia.co.kr&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;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;소버린 AI란 무엇인가요?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'소버린(Sovereign)'은 '자주적인', '주권이 있는'이라는 의미로, 자국의 정책이나 자원에 대한 독립적인 통제권을 뜻합니다. 이러한 소버린의 개념이 기술과 데이터 영역으로 확장되면서 '소버린 AI'라는 용어가 등장했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소버린 AI는 본질적으로 '데이터 주권(Data Sovereignty)'이라는 개념에서 뿌리를 찾을 수 있는데, 이는 특정 국가나 지역 내 데이터가 해당 지역의 법률과 규제를 따라야 한다는 원칙입니다.&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-filename=&quot;스크린샷 2025-06-23 오후 7.44.54.png&quot; data-origin-width=&quot;1171&quot; data-origin-height=&quot;659&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czbcgy/btsOMWPqPR3/ueLWOC7Jy2t9bRsHXveZkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czbcgy/btsOMWPqPR3/ueLWOC7Jy2t9bRsHXveZkk/img.png&quot; data-alt=&quot;가트너 하이퍼 사이클 AI 2024. 소버린AI가 명시되어 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czbcgy/btsOMWPqPR3/ueLWOC7Jy2t9bRsHXveZkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fczbcgy%2FbtsOMWPqPR3%2FueLWOC7Jy2t9bRsHXveZkk%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;625&quot; height=&quot;352&quot; data-filename=&quot;스크린샷 2025-06-23 오후 7.44.54.png&quot; data-origin-width=&quot;1171&quot; data-origin-height=&quot;659&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;가트너 하이퍼 사이클 AI 2024. 소버린AI가 명시되어 있다.&lt;/figcaption&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;소버린 AI는 이 개념을 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;AI의 전체 가치 사슬(value chain)로 확장&lt;/b&gt;&lt;/span&gt;합니다. 즉, 컴퓨팅 파워와 데이터센터 같은 '&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;인프라&lt;/b&gt;&lt;/span&gt;', 학습 데이터의 확보와 거버넌스를 포함하는 '&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;데이터&lt;/b&gt;&lt;/span&gt;', 모델의 소유권과 투명성을 의미하는 '&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;알고리즘&lt;/b&gt;&lt;/span&gt;', 숙련된 '&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;인력&lt;/b&gt;&lt;/span&gt;', 그리고 이 모든 것을 아우르는 '&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;비즈니스 네트워크&lt;/b&gt;&lt;/span&gt;'까지 포괄하는 총체적인 역량을 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔비디아(NVIDIA)의 CEO 젠슨 황(Jensen Huang)에 의해 전 세계적으로 대중화된 이 용어는 &quot;한 국가가 자국의 인프라, 데이터, 인력, 비즈니스 네트워크를 활용하여 국가적 이익, 가치, 규제에 부합하는 인공지능 시스템을 개발, 배포, 관리, 통제할 수 있는 역량&quot;으로 정의할 수 있습니다.&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의 핵심 구성 요소는 다음과 같습니다&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; GPU, 데이터센터, 소버린 클라우드 등 AI 운영에 필수적인 컴퓨팅 자원에 대한 국가적 소유권 또는 통제권 확보.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모델 소유권 및 투명성:&lt;/b&gt; 독자적인 AI 모델 개발 또는 사용 중인 모델에 대한 완전한 접근과 통제권을 통해 현지 규정과 가치에 맞게 검증 및 수정하는 능력.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인재 및 생태계:&lt;/b&gt; AI 기술 개발 및 운영이 가능한 국내 인력 양성과 자생적인 산업 생태계 구축.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;거버넌스 및 가치 정렬:&lt;/b&gt; AI 개발과 활용이 자국의 문화, 역사, 법률, 윤리적 프레임워크 및 안보 요구사항을 반영하도록 제도적 장치 마련.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;소버린 AI를 이해함에 있어 무엇이 중요할까요?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소버린 AI를 정확히 이해하기 위해서는 몇 가지 핵심적인 오해를 피해야 한다고 생각합니다. 개인적으로 저도 처음에 굉장히 헷갈렸던 부분인데요. 이를 제가 이해한 것으로 정리해봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 543px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 36.0465%; text-align: center; height: 19px;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 63.9535%; text-align: center; height: 19px;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 92px;&quot;&gt;
&lt;td style=&quot;width: 36.0465%; height: 92px;&quot;&gt;&lt;b&gt;단순한 기술적 자립을 넘어선 국가 전략 문제&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 63.9535%; height: 92px;&quot;&gt;&lt;br /&gt;소버린 AI는 단순히 기술적 독립을 추구하는 것을 넘어, 한 국가의 전략적, 운영적 역량에 관한 개념입니다. 이는 국가가 어떤 의사결정 체계를 만들고, 어떤 가치 체계를 반영한 데이터를 수집하며, 어떤 언어로 세상을 인식할 것인가에 대한 질문과 연관된다고 생각합니다.&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 204px;&quot;&gt;
&lt;td style=&quot;width: 36.0465%; height: 204px;&quot;&gt;&lt;b&gt;AI는 '툴'이 아닌 '프레임워크'이자 '운영체제'&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 63.9535%; height: 204px;&quot;&gt;&lt;br /&gt;어떤 글에서는 &quot;잘 만들어진 빅테크의 AI를 가져다 쓰자&quot;며 엑셀과 같은 생산성 툴에 비유한 것도 봤습니다. 하지만, 이는 AI를 완전히 오해한 것이라고 저는 생각합니다. AI는 정의된 기능과 예측 가능한 인터페이스를 가진 엑셀과 달리, 데이터를 다루고 진화하며 상황에 따라 최적화되어야 하는 시스템입니다. &lt;br /&gt;&lt;br /&gt;저는 AI가 언어, 사고, 판단, 추론 등 인지적 기능 전반을 추상화한 (앞으로 나아가야 할)'운영체제(Operating System)'에 가깝다고 생각합니다. 외국의 운영체제에 전적으로 의존한다면, 아무리 훌륭한 서비스를 만들어도 근본적인 제약을 벗어날 수 없으며, 진정한 디지털 주권을 확보하기 어렵다고 저는 생각합니다.&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 76px;&quot;&gt;
&lt;td style=&quot;width: 36.0465%; height: 76px;&quot;&gt;&lt;b&gt;&lt;b&gt;'피드백 루프' 통제력의 중요성&lt;/b&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 63.9535%; height: 76px;&quot;&gt;&lt;br /&gt;AI의 핵심은 모델 자체가 아니라 '피드백 루프(feedback loop)'에 있습니다. 훈련-실행-평가-재훈련 과정을 통해 AI는 지속적으로 개선되는데, 이를 통제하지 못하면 우리는 단순히 소비자일 뿐이며, 사용 과정에서 나오는 데이터마저 다시 공급자의 학습 재료로 활용됩니다. 결국 AI의 주도권은 누가 이 피드백 루프의 소유자인가의 싸움도 될 것이라고 생각합니다.&lt;br /&gt;&lt;br /&gt;마치 지금의 우리가 OpenAI 모델을 자주 사용하는 것처럼요.&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 76px;&quot;&gt;
&lt;td style=&quot;width: 36.0465%; height: 76px;&quot;&gt;&lt;b&gt;소버린 AI는 '자립'을 넘어 '주도'를 위한 것&lt;/b&gt;&lt;b&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 63.9535%; height: 76px;&quot;&gt;&lt;br /&gt;소버린 AI는 단순히 '우리가 독자적으로 만들 수 있어야 한다'는 의미를 넘어, 우리가 미래 산업과 사회 구조의 방향성을 '주도'할 수 있어야 함을 뜻합니다. &lt;br /&gt;&lt;br /&gt;예를 들어, 한국형 AI 교육 시스템이나 K-모델을 구축하려면, 모델 그 자체의 구조를 설계할 수 있는 수준의 통제권이 필요하죠. '사다 쓰는' 방식으로는 이를 확보할 수 없다고 생각합니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 76px;&quot;&gt;
&lt;td style=&quot;width: 36.0465%; height: 76px;&quot;&gt;&lt;b&gt;&lt;b&gt;가치 반영이 중요&lt;/b&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 63.9535%; height: 76px;&quot;&gt;&lt;br /&gt;해당 국가가 사용하는 AI에 자국의 가치관, 윤리, 문화적 특성이 충분히 반영되었는지, 그리고 해당 국가의 이익과 존속을 지켜낼 수 있는지를 기준으로 삼는 것이 더 합리적일 것이라고 생각합니다.&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;우리나라가 소버린 AI를 키워야 하는 이유에 대해서&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;AI는 단순한 툴이 아닌 프레임워크이자 인프라&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AI는 데이터를 다루며 끊임없이 진화하고 최적화되어야 하는 시스템입니다. 즉, AI는 단순한 상품이 아니라 살아있는 생태계이며, 단순한 '잘 만들어진 툴'로 소비하는 방식은 장기적인 주권과 전략적 자율성을 포기하는 것입니다.&lt;/li&gt;
&lt;li&gt;LLM이나 생성형 AI는 단순한 소프트웨어 패키지가 아니라 언어, 사고, 판단, 추론, 기획, 검색, 요약, 번역 등 인지적 기능 전반을 추상화한 플랫폼입니다. 이는 기업의 운영체계를 바꾸고, 국가의 행정 효율을 재정의하며, 산업의 분업 구조까지 재편할 수 있습니다.&lt;/li&gt;
&lt;li&gt;위에서도 생각을 말했듯, 저는 AI는 운영체제(Operating System)에 가깝게 발전되고 있다고 생각합니다. 외국 기업의 운영체제에 모든 것을 의존한다면, 그 위에 아무리 훌륭한 앱을 만들어도 근본적인 제약을 벗어날 수 없습니다. 마치 페이스북처럼요.&lt;/li&gt;
&lt;li&gt;무엇보다, 단순히 &quot;우리만의 LLM을 가진다&quot;라는 목표를 넘어서, 차세대 LLM이나 차세대 AI를 연구 및 개발하고 이를 실제 서비스 등에 활용할 수 있는 &quot;상용화 수준&quot;까지 가야한다고 생각합니다.&lt;/li&gt;
&lt;li&gt;그리고 '지속가능성'도 중요할 것으로 생각됩니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;디지털 주권 및 전략적 자율성 확보&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오픈AI와 같은 빅테크 모델 위에서 한국만의 AI 행정 서비스나 교육 시스템을 설계하더라도, 해당 모델의 철학, 훈련 데이터, 알고리즘 구조, 업데이트 정책에 영향을 미치지 못한다면 진정한 디지털 주권으로 보기 어렵습니다.&lt;/li&gt;
&lt;li&gt;현재의 LLM들은 대부분 영어 기반의 서구적 가치관과 그러한 세계관을 내포하고 있습니다. 한국의 행정 시스템, 교육 체계, 법률 구조, 의료 정보, 문화 코드, 역사적 맥락, 지역 언어 등은 전혀 다른 이야기이죠. 이를 반영하기 위해서는 AI 학습 구조 자체에 영향을 줄 수 있어야 한다고 생각합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;생태계와 피드백 루프의 통제력 확보&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위에서 한 번 언급한 피드백 루프의 관점입니다. 이를 통제하지 못하면 우리는 단순히 소비자일 뿐이며, 사용 과정에서 발생하는 데이터마저 공급자의 학습 재료로 활용되어 AI 주도권을 잃게 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;국가 전략 자산으로서의 AI&lt;/b&gt;&lt;/span&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;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;그 외 &lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;글로벌 협력 및 'AI 동맹' 구축이 필요하지 않을까 싶습니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;가치를 공유하는 국가들(캐나다, 프랑스, 독일, 일본 등)과 적극적으로 'AI 동맹'을 구축하여 공동 R&amp;amp;D, 데이터 공유, 글로벌 AI 거버넌스 및 표준화 논의에서 목소리를 내야 하지 않을까 싶습니다.&lt;/li&gt;
&lt;li&gt;우리나라가 강점을 가진 반도체, 제조업, 로봇, 헬스케어 등 전략 산업 분야에서 AI를 활용한 혁신을 주도하기 위해서라도 필요하지 않을까 싶습니다.&lt;/li&gt;
&lt;li&gt;또한, 국가 안보, 보안, 국방 등을 보호하기 위해서라도 필요하겠죠&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 소버린 AI(Sovereign AI)에 대해서 정리해보고 제 개인적인 생각도 정리해 보았습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소버린 AI에 대해서 조금이나마 도움이 되시길 바랍니다.&lt;/p&gt;</description>
      <category>인공지능(AI)/AI 일반</category>
      <category>ai경쟁력</category>
      <category>ai국가전략</category>
      <category>AI정책</category>
      <category>ai주권</category>
      <category>LLM</category>
      <category>sovereignai</category>
      <category>생성형ai</category>
      <category>소버린ai</category>
      <category>인공지능</category>
      <category>한국AI</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/691</guid>
      <comments>https://lsjsj92.tistory.com/691#entry691comment</comments>
      <pubDate>Mon, 23 Jun 2025 20:25:58 +0900</pubDate>
    </item>
    <item>
      <title>AI 시대, 우리는 무엇을 상상하고 어떻게 행동해야 하는가?</title>
      <link>https://lsjsj92.tistory.com/690</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;인공지능(AI) 기술의 발전은 우리 사회와 경제 전반에 걸쳐 전례 없는 변화를 가져오고 있습니다. 특히 최근에는 이 변화가 인력 구조조정이라는 구체적인 형태로 나타나며 많은 이들의 우려와 관심을 모으고 있습니다. 본 글에서는 최근 주요 기업에서 발생한 인력 구조조정 사례를 살펴보고, 이러한 변화 속에서 인공지능이 어떠한 긍정적 및 부정적 영향을 미치고 있는지 그리고 제 생각은 어떠한 지 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;지극히 개인적인 생각을 정리&lt;/b&gt;&lt;/span&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;&lt;a href=&quot;https://www.aitimes.com/news/articleView.html?idxno=171425&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://www.aitimes.com/news/articleView.html?idxno=171425&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.aitimes.com/news/articleView.html?idxno=170453&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://www.aitimes.com/news/articleView.html?idxno=170453&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mk.co.kr/news/it/11347689&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://www.mk.co.kr/news/it/11347689&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.businesstoday.in/technology/news/story/tech-layoffs-2025-ibm-lays-off-8000-employees-as-ai-replaces-hr-department-478053-2025-05-28&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://www.businesstoday.in/technology/news/story/tech-layoffs-2025-ibm-lays-off-8000-employees-as-ai-replaces-hr-department-478053-2025-05-28&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bok.or.kr/portal/bbs/P0002353/view.do?menuNo=200433&amp;amp;nttId=10089704&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.bok.or.kr/portal/bbs/P0002353/view.do?menuNo=200433&amp;amp;nttId=10089704&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1750483210395&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;Tech layoffs 2025: IBM lays off 8,000 employees as AI replaces HR department - BusinessToday&quot; data-og-description=&quot;Despite the layoffs, IBM says its workforce has actually increased, as the company has hired more people across departments like software development, marketing, and sales.&quot; data-og-host=&quot;www.businesstoday.in&quot; data-og-source-url=&quot;https://www.businesstoday.in/technology/news/story/tech-layoffs-2025-ibm-lays-off-8000-employees-as-ai-replaces-hr-department-478053-2025-05-28&quot; data-og-url=&quot;https://www.businesstoday.in/technology/news/story/tech-layoffs-2025-ibm-lays-off-8000-employees-as-ai-replaces-hr-department-478053-2025-05-28&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/808A4/hyZcjLQONm/WSBSCpTJmXYIVQcueR8Fl1/img.jpg?width=880&amp;amp;height=495&amp;amp;face=0_0_880_495,https://scrap.kakaocdn.net/dn/dL4aZ8/hyY8O023X1/TDj7O0eBeqKJ3I9mkEqODk/img.jpg?width=880&amp;amp;height=495&amp;amp;face=0_0_880_495,https://scrap.kakaocdn.net/dn/vbUE4/hyZcddNhpQ/yRx9IluUNrbSEQCzQamHG0/img.jpg?width=948&amp;amp;height=533&amp;amp;face=0_0_948_533&quot;&gt;&lt;a href=&quot;https://www.businesstoday.in/technology/news/story/tech-layoffs-2025-ibm-lays-off-8000-employees-as-ai-replaces-hr-department-478053-2025-05-28&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.businesstoday.in/technology/news/story/tech-layoffs-2025-ibm-lays-off-8000-employees-as-ai-replaces-hr-department-478053-2025-05-28&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/808A4/hyZcjLQONm/WSBSCpTJmXYIVQcueR8Fl1/img.jpg?width=880&amp;amp;height=495&amp;amp;face=0_0_880_495,https://scrap.kakaocdn.net/dn/dL4aZ8/hyY8O023X1/TDj7O0eBeqKJ3I9mkEqODk/img.jpg?width=880&amp;amp;height=495&amp;amp;face=0_0_880_495,https://scrap.kakaocdn.net/dn/vbUE4/hyZcddNhpQ/yRx9IluUNrbSEQCzQamHG0/img.jpg?width=948&amp;amp;height=533&amp;amp;face=0_0_948_533');&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;Tech layoffs 2025: IBM lays off 8,000 employees as AI replaces HR department - BusinessToday&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Despite the layoffs, IBM says its workforce has actually increased, as the company has hired more people across departments like software development, marketing, and sales.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.businesstoday.in&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;figure id=&quot;og_1750482670530&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;1만명 자르고 2년 뒤 7천명 해고3개월 만에 또 수천명 감원한다는 이 회사 - 매일경제&quot; data-og-description=&quot;MS, 또 대규모 구조조정 AI發 일자리 충격 현실화 내달 초 수천명 감원 예고 인건비 절감해 AI 투자&quot; data-og-host=&quot;www.mk.co.kr&quot; data-og-source-url=&quot;https://www.mk.co.kr/news/it/11347689&quot; data-og-url=&quot;https://www.mk.co.kr/news/it/11347689&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/6EAiO/hyZcfbBJMf/kbwN8MSBTAHDuMImh2LFB1/img.png?width=1200&amp;amp;height=798&amp;amp;face=0_0_1200_798,https://scrap.kakaocdn.net/dn/bqbGt3/hyZbtA15j1/KK3MSQwXZGaCZnY29nbuI1/img.png?width=1200&amp;amp;height=798&amp;amp;face=0_0_1200_798,https://scrap.kakaocdn.net/dn/bsmt7c/hyZbtVmtyw/FboBCfqW78wcjnsBAamtg1/img.png?width=700&amp;amp;height=466&amp;amp;face=0_0_700_466&quot;&gt;&lt;a href=&quot;https://www.mk.co.kr/news/it/11347689&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.mk.co.kr/news/it/11347689&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/6EAiO/hyZcfbBJMf/kbwN8MSBTAHDuMImh2LFB1/img.png?width=1200&amp;amp;height=798&amp;amp;face=0_0_1200_798,https://scrap.kakaocdn.net/dn/bqbGt3/hyZbtA15j1/KK3MSQwXZGaCZnY29nbuI1/img.png?width=1200&amp;amp;height=798&amp;amp;face=0_0_1200_798,https://scrap.kakaocdn.net/dn/bsmt7c/hyZbtVmtyw/FboBCfqW78wcjnsBAamtg1/img.png?width=700&amp;amp;height=466&amp;amp;face=0_0_700_466');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1만명 자르고 2년 뒤 7천명 해고3개월 만에 또 수천명 감원한다는 이 회사 - 매일경제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MS, 또 대규모 구조조정 AI發 일자리 충격 현실화 내달 초 수천명 감원 예고 인건비 절감해 AI 투자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;www.mk.co.kr&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;거대한 전환의 서막: AI가 촉발한 글로벌 인력 구조조정&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;마이크로소프트(Mircrosoft)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 인력 구조조정의 대표적인 사례로는 마이크로소프트(MS)의 행보를 들 수 있습니다. MS는 인공지능 개발에 막대한 투자를 이어가는 동시에 수천 명 규모의 인력 감축을 계획하고 있다고 알려졌습니다. 이미 MS는 지난 5월에도 6천에서 7천 명 규모의 구조조정을 단행했으며, 이는 2023년의 1만 명 감축 이후 최대 규모였습니다. 이러한 구조조정은 주로 제품 및 엔지니어링 직책에서 이루어졌습니다. MS의 경영진은 인공지능 관련 서버 및 데이터 센터에 수백억 달러를 투자하면서 다른 분야의 지출을 줄이겠다고 밝힌 바 있습니다. 또한 MS의 구조조정은 중간 관리자 계층을 압축시키는 형태로 진행되었는데, 이는 인공지능 에이전트의 도입으로 인해 상위 보고를 받고 하위 전달하는 전통적인 중간 관리자의 역할이 줄어들기 때문입니다.&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-filename=&quot;스크린샷 2025-06-21 오후 2.12.48.png&quot; data-origin-width=&quot;813&quot; data-origin-height=&quot;682&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buYhks/btsOLvcOhg4/2B3FkLtifTRyEAKpvk2am0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buYhks/btsOLvcOhg4/2B3FkLtifTRyEAKpvk2am0/img.png&quot; data-alt=&quot;출처: https://www.mk.co.kr/news/it/11347689&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buYhks/btsOLvcOhg4/2B3FkLtifTRyEAKpvk2am0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuYhks%2FbtsOLvcOhg4%2F2B3FkLtifTRyEAKpvk2am0%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;585&quot; height=&quot;491&quot; data-filename=&quot;스크린샷 2025-06-21 오후 2.12.48.png&quot; data-origin-width=&quot;813&quot; data-origin-height=&quot;682&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: https://www.mk.co.kr/news/it/11347689&lt;/figcaption&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;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;아마존(Amazon)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마존 또한 이러한 변화의 흐름에 동참하고 있습니다. 아마존의 앤디 재시 CEO는 인공지능의 광범위한 도입으로 인해 향후 몇 년간 전체 본사 인력이 감소할 것이라고 예측했습니다. 그는 현재 사람들이 맡고 있는 몇몇 업무에서는 인력이 줄어들고 새로운 유형의 업무에서는 인력이 늘어날 것이라고 언급하며, 인공지능으로 인한 효율성 향상이 사무직 인력 감축으로 이어질 것이라고 경고했습니다. 아마존은 이미 올해 인공지능 데이터 센터에 1천억 달러 이상을 투자할 계획을 발표하며 인공지능 중심 전략을 강조하고 있습니다.&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;span style=&quot;background-color: #ffc9af;&quot;&gt;쇼피파이와 IBM&lt;/span&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;IBM도 또한, 최근 HR 인력에 대한 구조조정을 시행했죠.&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;span style=&quot;background-color: #ffc9af;&quot;&gt;대한민국은 어떨까요?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한국 또한 이러한 흐름에서 예외는 아닙니다. 한국은행의 보고서에 따르면 국내 일자리 중 절반 이상인 51%가 인공지능 도입에 큰 영향을 받을 것으로 분석되었습니다. 특히 통신 관련 판매직, 법률 및 감사 사무 종사자, 고객 상담 및 기타 사무원, 통계 사무원, 비서 및 사무 보조원 등의 대체 가능성이 상대적으로 큰 것으로 나타났습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 국내 채용 시장에서는 초급 IT 인력의 수요가 감소하여, IT 개발직 신입 채용 공고가 2023년 대비 43% 크게 줄었습니다. 한국은 노동 인구 감소라는 특수한 상황에 직면해 있어, 인공지능이 부족한 인력을 대체하는 환경이 조성되고 있기도 하는 것 같습니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-06-21 오후 2.20.56.png&quot; data-origin-width=&quot;3090&quot; data-origin-height=&quot;1616&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vsXVp/btsOMmMZh61/1jtvqsEdPhgTcnUB1RiYNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vsXVp/btsOMmMZh61/1jtvqsEdPhgTcnUB1RiYNK/img.png&quot; data-alt=&quot;출처: https://www.bok.or.kr/portal/bbs/P0002353/view.do?menuNo=200433&amp;amp;amp;nttId=10089704&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vsXVp/btsOMmMZh61/1jtvqsEdPhgTcnUB1RiYNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvsXVp%2FbtsOMmMZh61%2F1jtvqsEdPhgTcnUB1RiYNK%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;646&quot; height=&quot;338&quot; data-filename=&quot;스크린샷 2025-06-21 오후 2.20.56.png&quot; data-origin-width=&quot;3090&quot; data-origin-height=&quot;1616&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: https://www.bok.or.kr/portal/bbs/P0002353/view.do?menuNo=200433&amp;amp;nttId=10089704&lt;/figcaption&gt;
&lt;/figure&gt;
&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;style7&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;AI의 두 얼굴: 위기인가, 기회인가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 개인적으로 인공지능은 누가 어떻게 쓰느냐에 따라 그 잠재력은 어마어마하게 차이가 날 것이라고 생각합니다. 예를 들어, 같은 '식칼'이라고 하더라도, 셰프가 쓰느냐, 저와 같은 사람이 쓰느냐에 따라서 요리의 퀄리티가 달라지니까요. 나중에는 이러한 불균등이 점차 커져서, 어떤 또 다른 사회적 이슈가 나올 수도 있지 않을까?라는 생각도 드는 요즘입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 인공지능 기술에 대한 접근성이나 활용 능력이 부족한 사람들은 '가난'을 경험하게 될 수 있지 않을까?라는 생각도 듭니다. 당장 지금만하더라도 유용한 AI 서비스들이 전부 구독제라서 아무래도 현실적으로 모든 유용한 서비스를 사용할 수 없으니까요(ㅠㅠㅜ).&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)은 분업화된 기존의 조직 구조를 통합형으로 전환시키며, 개인에게 더 넓은 권한과 책임을 부여합니다. 이는 리더십의 '조율' 기능이 축소되고, 개인이 주도적으로 문제를 정의하고 해결하는 '개인 기여자(Individual Contributor, IC)' 시대를 여는 전환점이 될 것이라고 생각합니다.&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;p data-ke-size=&quot;size16&quot;&gt;제가 그냥 개인적으로 생각하는 AI시대의 위협과 우려(Risk)와 AI 시대의 기회와 전망(Opportunities)는 아래 표와 같습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 209px;&quot; border=&quot;1&quot; data-sheets-baot=&quot;1&quot; data-sheets-root=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;text-align: center; width: 11.0465%; height: 19px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;구분&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; width: 44.6511%; height: 19px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;AI 시대의 위협과 우려 (Risks)&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; width: 44.1861%; height: 19px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;AI 시대의 기회와 전망 (Opportunities)&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 38px;&quot;&gt;
&lt;td style=&quot;width: 11.0465%; height: 38px;&quot;&gt;&lt;b&gt;개인과 격차&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.6511%; height: 38px;&quot;&gt;AI 활용 능력에 따라 개인 간 성과 격차가 극대화될 수 있습니다.&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 44.1861%; height: 38px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;개인이 더 넓은 권한과 책임을 갖고 주도적으로 문제를 해결하는 시대가 열릴 수 있습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 38px;&quot;&gt;
&lt;td style=&quot;width: 11.0465%; height: 38px;&quot;&gt;&lt;b&gt;사회와 경제&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.6511%; height: 38px;&quot;&gt;유료 구독 모델 등 기술 접근성의 차이가 경제적 불평등과 새로운 소외 계층을 낳을 수 있습니다.&lt;/td&gt;
&lt;td style=&quot;width: 44.1861%; height: 38px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;논문 정리, 데이터 분석, 과학 연구, 경제 등 전 분야에서 상상 이상의 효율성을 가져옵니다.&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 38px;&quot;&gt;
&lt;td style=&quot;width: 11.0465%; height: 38px;&quot;&gt;&lt;b&gt;기업과 시장&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.6511%; height: 38px;&quot;&gt;소수 기업에 기술 권력이 집중되어 경제적 종속이 심화될 위험이 있습니다.&lt;/td&gt;
&lt;td style=&quot;width: 44.1861%; height: 38px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;전통적인 분업 구조가 해체되고, 소수의 인원이 다기능을 수행하는 통합형 팀으로 전환됩니다.&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 38px;&quot;&gt;
&lt;td style=&quot;width: 11.0465%; height: 38px;&quot;&gt;&lt;b&gt;핵심 역량&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.6511%; height: 38px;&quot;&gt;AI가 대체 가능한 업무를 수행하는 능력은 더 이상 경쟁력이 되기 어렵습니다.&lt;/td&gt;
&lt;td style=&quot;width: 44.1861%; height: 38px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;AI를 동료처럼 활용해 소통하고 시너지를 내는 협업 능력이 핵심 역량이 됩니다.&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 38px;&quot;&gt;
&lt;td style=&quot;width: 11.0465%; height: 38px;&quot;&gt;&lt;b&gt;미래 준비&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.6511%; height: 38px;&quot;&gt;기술 발전 속도를 제도가 따라가지 못해 회복 불가능한 사회적 갈등이 발생할 수 있습니다.&lt;/td&gt;
&lt;td style=&quot;width: 44.1861%; height: 38px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;비판적 사고, 훌륭한 질문, 공감 능력 등 인간만이 가진 역량의 가치가 더욱 높아집니다.&lt;/div&gt;
&lt;/div&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;인공지능을 통해 생산성이 높아진 조직은 이제 앞으로 더 큰 목표와 꿈을 향해 나아가야 하지 않을까 생각합니다. 단순 자동화를 넘어 구성원이 더 높은 가치의 일을 할 수 있는 발판이 되어야 하지 않을까 싶습니다. 그렇기에 빠른 속도로 빠르게 실행하여 시장을 관찰하고 어떤 가치(value)를 제공할 수 있는지 고민하고, 다시 시도하는 그 일련의 사이클이 나와야 하지 않을까 싶습니다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;AI 시대 생존 전략, 무엇을, 어떻게 준비해야 할까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 AI시대에서 우리는 어떻게 살아가야 할까요? 다른건 다 제쳐두고, 당장 제 개인적인 상황으로만 봐도 아래와 같은 것들을 고민해야 하고 이미 고민하고 있습니다. (어쩌면, 제 스스로에게 하고 싶은 말이기도 합니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-sheets-baot=&quot;1&quot; data-sheets-root=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;핵심 태도&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;주요 내용 및 실천 방안&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&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;div&gt;
&lt;div&gt;완벽함보다 빠른 실험과 실행이 중요하며, 조직 전체의 'AI 리터러시' 함양이 필수적이 될 것입니다.&lt;/div&gt;
&lt;/div&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;div&gt;
&lt;div&gt;전통적 분업 구조가 아닌 '개인 기여자(IC)'로서 스스로 일의 목적과 가치를 디자인할 수 있어야 합니다.&lt;/div&gt;
&lt;/div&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;div&gt;
&lt;div&gt;AI를 동료로 여기고 자연스럽게 소통하면서도, 결과물을 비판적으로 사고하고 발전시키는 능력을 길러야 합니다.&lt;/div&gt;
&lt;/div&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;div&gt;
&lt;div&gt;공감 능력, 경험에 기반한 순발력, 그리고 풍부한 교양을 바탕으로 '질문'을 던지는 능력이 중요해집니다.&lt;/div&gt;
&lt;/div&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;table style=&quot;border-collapse: collapse; width: 100%; height: 95px;&quot; border=&quot;1&quot; data-sheets-baot=&quot;1&quot; data-sheets-root=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px; width: 15%;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;영역&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px; width: 84.8837%;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;구체적인 변화&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px; width: 15%;&quot;&gt;&lt;b&gt;일자리와 직무&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px; width: 84.8837%;&quot;&gt;
&lt;div&gt;
&lt;div&gt;특정 사무직, 중간 관리직, 초급 개발자 등의 일자리가 감소하고 직무 재편이 있지 않을까 싶습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px; width: 15%;&quot;&gt;&lt;b&gt;개인과 조직&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px; width: 84.8837%;&quot;&gt;
&lt;div&gt;
&lt;div&gt;보고서 작성, 데이터 분석 등 업무 효율이 비약적으로 향상되어 개인의 생산성이 5배 이상 증가할 것이라 생각합니다.&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px; width: 15%;&quot;&gt;&lt;b&gt;사회와 경제&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px; width: 84.8837%;&quot;&gt;
&lt;div&gt;
&lt;div&gt;AI 기술 접근성에 따른 불평등이 심화되고, 거대 기업의 독점이 강화될 수 있어 사회적 논의가 필요할 것이라 생각합니다.&lt;br /&gt;&lt;br /&gt;특히 우리나라의 AI 기술 발전 등의 투자 등의 논의가 잘 이루어져야 할 것입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px; width: 15%;&quot;&gt;&lt;b&gt;인지와 감성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px; width: 84.8837%;&quot;&gt;
&lt;div&gt;
&lt;div&gt;AI에 과의존할 경우 인지 능력이 저하될 수 있으며, 반대로 공감, 창의성 등 인간 고유 역량의 가치가 재조명되지 않을까?싶습니다.&amp;nbsp;&lt;/div&gt;
&lt;/div&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;특히, 저는 데이터 사이언티스트(Data Scientist)로서, 개발도 하면서 PM도 수행하는 사람으로서 과거와 다르게 제가 수행하는 일의 방식이 크게 바뀌었다는 것을 느끼고, 실제로 행동하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과거에는 5~6명에서 같이 하던 일을 이제 혼자서 단기간에 수행하고 있으니까요. 기획도하고 전략도 짜고, 코드도 짜고, 보고서 내용도 만들고, 연구도하고, 그 외의 다양한 조사도 수행하고 있습니다. 그리고 이런 프로젝트 성 업무와 아젠다가 3~4개가 있습니다. 이걸 혼자서 하고 있습니다. 불과 2년 전까지만해도 상상하기도 힘들었던 것인데, 이게 이제 가능하게 된 것은 든든한 AI들이 있기 때문입니다. 이는 단순히 수십 퍼센트의 효율화가 아니라, 정말 500% 이상의 효율화, 퍼포먼스 향상을 경험하고 있다고 생각됩니다.&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의 잠재력을 단순한 효율성 개선 도구로 한정해서는 안 된다는 점을 시사한다고 생각합니다. 진정한 변화는 기술 활용 넘어에 있으니까요. 우리의 '상상력'을 어디까지 확장할 것인가, 우리가 진정으로 해결해야 할 문제는 무엇이고, 어떤 가치를 제공할 것인가를 더 깊게 고민해야 하지 않을까 싶습니다.&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이러한 시대에 우리가 AI라는 큰 생태계, 산업에 뒤쳐지지 않고 주도적으로 리드해 나가는 우리와 우리나라가 되었으면 하는 개인적인 바람입니다.&lt;/p&gt;</description>
      <category>일상</category>
      <category>AI리터러시</category>
      <category>AI산업</category>
      <category>AI시대</category>
      <category>AI혁명</category>
      <category>it트랜드</category>
      <category>디지털전환</category>
      <category>산업혁명</category>
      <category>생성형ai</category>
      <category>인공지능</category>
      <category>일하는방식의변화</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/690</guid>
      <comments>https://lsjsj92.tistory.com/690#entry690comment</comments>
      <pubDate>Sat, 21 Jun 2025 15:03:46 +0900</pubDate>
    </item>
    <item>
      <title>google colab에서 Ollama 사용하기 - 코랩(colab) ollama LLM API 사용법</title>
      <link>https://lsjsj92.tistory.com/689</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 구글 코랩(google colab)에서 Ollama를 사용하는 방법에 대해서 정리합니다. 아무래도 요즘은 LLM을 활용해 RAG와 같은 다양한 애플리케이션 개발을 많이 수행하게 되는데요. 이때, 로컬에 LLM을 올려두어 사용하기도 하죠. 이때 많이 사용되는 것이 Ollama인데요. 이러한 Ollama를 colab에서도 사용할 수 있고, 최근에 개인적으로 해야할 상황이 있었습니다. 따라서, 이번 글은 코랩에서 ollama을 실행해서 LLM을 사용하는 방법에 대해서 정리해볼까 합니다.&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;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글 코랩은 무료로 GPU도 사용할 수 있고, 구글 드라이브 등에 데이터를 올려둔 상태로 파이썬(Python) 개발 등을 수행할 수 있는 매우 유용한 서비스인데요. 문제는 HuggingFace등에서 받은 오픈소스 LLM 등을 사용하기가 조금은 불편하다는 것입니다. 물론, 허깅페이스의 각 모델에 나와있는 예제 코드를 기반으로 사용해도 되긴합니다. 예를 들어, 아래 코드와 같이 말이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1748673429594&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import torch
from transformers import AutoTokenizer, AutoModelForCausalLM

model_id = 'Bllossom/llama-3.2-Korean-Bllossom-3B'

tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    torch_dtype=torch.bfloat16,
    device_map=&quot;auto&quot;,
)
instruction = &quot;철수가 20개의 연필을 가지고 있었는데 영희가 절반을 가져가고 민수가 남은 5개를 가져갔으면 철수에게 남은 연필의 갯수는 몇개인가요?&quot;

messages = [
    {&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: f&quot;{instruction}&quot;}
    ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://huggingface.co/Bllossom/llama-3.2-Korean-Bllossom-3B&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://huggingface.co/Bllossom/llama-3.2-Korean-Bllossom-3B&lt;/a&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;transformer 라이브러리의 AutoTokenizer, AutoModelForCausalLM 등을 사용해서 코랩 환경에서 실행할 수도 있습니다. 하지만, 아무래도 향후 확장성을 고려해서 Ollama와 같은 서비스를 이용해 LLM 모델을 띄어두고, API 형태로 호출하는 것이 더 유용하겠죠?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히도, colab에서도 Ollama를 활용해 LLM과 API 통신을 수행할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. colab-xterm 설치 및 터미널 실행&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저, colab-xterm을 설치해줍니다. 이 라이브러리를 설치하면 colab 환경에서 터미널(terminal)을 사용할 수 있는데요. 다음과 같은 명령어로 쉽게 설치할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1748673721822&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;!pip install colab-xterm&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.13.17.png&quot; data-origin-width=&quot;2144&quot; data-origin-height=&quot;448&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxv3Dy/btsOmszL6TQ/gZajhTLlCfOrBk4tMDBzwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxv3Dy/btsOmszL6TQ/gZajhTLlCfOrBk4tMDBzwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxv3Dy/btsOmszL6TQ/gZajhTLlCfOrBk4tMDBzwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbxv3Dy%2FbtsOmszL6TQ%2FgZajhTLlCfOrBk4tMDBzwk%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;2144&quot; height=&quot;448&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.13.17.png&quot; data-origin-width=&quot;2144&quot; data-origin-height=&quot;448&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;위 명령어를 실행하면 정상적으로 설치가 되면서 successfully installed colab-xterm이 나오게 될 것입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 colab에서 터미널을 사용할 수 있는 준비가 되었는데요. 바로 실행해봅시다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1748673787325&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;%load_ext colabxterm
%xterm&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.14.26.png&quot; data-origin-width=&quot;2898&quot; data-origin-height=&quot;1138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9nyux/btsOmtlamqH/RECNOiAv1nSHODKZw4GZNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9nyux/btsOmtlamqH/RECNOiAv1nSHODKZw4GZNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9nyux/btsOmtlamqH/RECNOiAv1nSHODKZw4GZNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9nyux%2FbtsOmtlamqH%2FRECNOiAv1nSHODKZw4GZNK%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;735&quot; height=&quot;289&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.14.26.png&quot; data-origin-width=&quot;2898&quot; data-origin-height=&quot;1138&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;먼저, colabxterm을 load하고 %xterm 명령어로 실행하면 코랩 환경을 기준으로 terminal을 실행할 수 있게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 기본적인 리눅스 명령어 등을 수행할 수 있는데요. 예를 들어, ll 명령어를 입력하면 아래와 같이 현재 디렉토리 경로의 리스트 결과가 나오게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.14.38.png&quot; data-origin-width=&quot;2898&quot; data-origin-height=&quot;1138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnwFbF/btsOlZSdvsD/dIPzJAmZvHWa2lKJ5dMP21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnwFbF/btsOlZSdvsD/dIPzJAmZvHWa2lKJ5dMP21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnwFbF/btsOlZSdvsD/dIPzJAmZvHWa2lKJ5dMP21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnwFbF%2FbtsOlZSdvsD%2FdIPzJAmZvHWa2lKJ5dMP21%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;720&quot; height=&quot;283&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.14.38.png&quot; data-origin-width=&quot;2898&quot; data-origin-height=&quot;1138&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Colab에 Ollama 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 상태에서 ollama를 설치합니다. 즉, colab의 터미널 환경을 활용해서 colab 환경에 ollama를 설치하는 것이죠. 다음과 같은 명령어를 입력합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1748673896195&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;curl https://ollama.ai/install.sh | sh&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.15.01.png&quot; data-origin-width=&quot;2572&quot; data-origin-height=&quot;948&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRxRvi/btsOmO3JPvq/S3jTkwRB5hQZFiwaRJPvhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRxRvi/btsOmO3JPvq/S3jTkwRB5hQZFiwaRJPvhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRxRvi/btsOmO3JPvq/S3jTkwRB5hQZFiwaRJPvhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRxRvi%2FbtsOmO3JPvq%2FS3jTkwRB5hQZFiwaRJPvhK%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;689&quot; height=&quot;254&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.15.01.png&quot; data-origin-width=&quot;2572&quot; data-origin-height=&quot;948&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&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;ollama.ai의 install.sh을 curl 명령어로 설치하는 과정입니다. 한 1~2분 정도면 설치가 완료됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치가 다 되면, 이제 ollama를 백그라운드에서도 동작되도록 명령어를 입력하면 되는데요.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서부터는 xterm을 이용하셔도 되고, 아니면 colab 셀에 &quot;! 명령어&quot;구로조 실행하셔도 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #f89009;&quot;&gt;&lt;b&gt;여기서부터 colab의 xterm이 잘 수행이 안될 때가 있는데요.&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;위에까지는 잘 수행이 되는데, ollama를 실행시키는 것부터는 잘 안될 때가 있습니다.&lt;br /&gt;이럴 때는 구글 코랩에서 !nohup 명령어로 ollama를 실행시키는 것을 추천드립니다.&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1748674058855&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ollama serve &amp;amp;

또는 colab 터미널에서

!nohup ollama serve &amp;gt; ollama.log &amp;amp;&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;위와 같은 명령어를 실행하면 아래와 같이 ollama list 명령어를 입력했을 때 정상적으로 나오는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(colab 코드 셀에서 !ollama list 를 입력하셔도 같은 결과를 볼 수 있습니다. xterm이 잘 안되시는 분들은 colab 셀에서 실행해주세요.(오른쪽 사진))&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mSMbl/btsOl7WWhqz/vuO0KSApXetvFGmZTPgdgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mSMbl/btsOl7WWhqz/vuO0KSApXetvFGmZTPgdgk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2572&quot; data-origin-height=&quot;396&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.16.50.png&quot; style=&quot;width: 61.5984%; margin-right: 10px;&quot; data-widthpercent=&quot;62.32&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mSMbl/btsOl7WWhqz/vuO0KSApXetvFGmZTPgdgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmSMbl%2FbtsOl7WWhqz%2FvuO0KSApXetvFGmZTPgdgk%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;2572&quot; height=&quot;396&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kU29k/btsOlvD6dbN/zrw1PniYkIkfyKqgJMk2Ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kU29k/btsOlvD6dbN/zrw1PniYkIkfyKqgJMk2Ck/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;136&quot; data-filename=&quot;스크린샷 2025-05-31 오후 3.52.03.png&quot; style=&quot;width: 37.2388%;&quot; data-widthpercent=&quot;37.68&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kU29k/btsOlvD6dbN/zrw1PniYkIkfyKqgJMk2Ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkU29k%2FbtsOlvD6dbN%2Fzrw1PniYkIkfyKqgJMk2Ck%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;534&quot; height=&quot;136&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 원하는 LLM 모델 다운받기(feat. 허깅페이스(HuggingFace))&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 아마 ollama list를 하면 아무것도 보이지 않을 겁니다. 왜냐하면, ollama에서 실행시킬 llm 모델을 셋팅하지 않았기 때문인데요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.27.17.png&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;226&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wxCPW/btsOlgtA8xE/cbx6hECdCErALGwKVQ5HI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wxCPW/btsOlgtA8xE/cbx6hECdCErALGwKVQ5HI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wxCPW/btsOlgtA8xE/cbx6hECdCErALGwKVQ5HI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwxCPW%2FbtsOlgtA8xE%2Fcbx6hECdCErALGwKVQ5HI1%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;572&quot; height=&quot;123&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.27.17.png&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;226&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;이제 여러분들이 원하는 LLM 모델을 다운로드 받아서 활용하면 됩니다. 저는 허깅페이스(HuggingFace)에 올라와있는 모델 중 llama-3.2-Korean-Bllossom-3B-f16.gguf 모델을 사용하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 모델은 wget과 같은 명령어로 쉽게 받을 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1748674532409&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;!wget https://huggingface.co/bartowski/llama-3.2-Korean-Bllossom-3B-GGUF/resolve/main/llama-3.2-Korean-Bllossom-3B-f16.gguf -O /content/llama-3.2-Korean-Bllossom-3B-f16.gguf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAV1Qq/btsOmKG23L2/e5wJ6vuf1JRIt3aMlCTqvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAV1Qq/btsOmKG23L2/e5wJ6vuf1JRIt3aMlCTqvk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2332&quot; data-origin-height=&quot;648&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.37.58.png&quot; data-widthpercent=&quot;68.5&quot; style=&quot;width: 67.7032%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAV1Qq/btsOmKG23L2/e5wJ6vuf1JRIt3aMlCTqvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAV1Qq%2FbtsOmKG23L2%2Fe5wJ6vuf1JRIt3aMlCTqvk%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;2332&quot; height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FnSwI/btsOk8Qb8wY/FAhilW3rQmMA5UFdQjGYt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FnSwI/btsOk8Qb8wY/FAhilW3rQmMA5UFdQjGYt0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;284&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.24.29.png&quot; style=&quot;width: 31.134%;&quot; data-widthpercent=&quot;31.5&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FnSwI/btsOk8Qb8wY/FAhilW3rQmMA5UFdQjGYt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFnSwI%2FbtsOk8Qb8wY%2FFAhilW3rQmMA5UFdQjGYt0%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;470&quot; height=&quot;284&quot;/&gt;&lt;/span&gt;&lt;/div&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;이후, 여러분들이 받으신 모델에 맞는 Modelfile을 만드셔서 모델을 준비하시면 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(만약, Ollama 설치나 모델 준비 등이 궁금하시다면 &lt;a href=&quot;https://lsjsj92.tistory.com/666&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/666&lt;/a&gt; 글과 &lt;a href=&quot;https://lsjsj92.tistory.com/685&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/685&lt;/a&gt; 글을 참고해주세요.)&lt;/p&gt;
&lt;figure id=&quot;og_1748674668717&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;Ollama 사용법 - 개인 로컬 환경에서 LLM 모델 실행 및 배포하기&quot; data-og-description=&quot;포스팅 개요이번 포스팅은 대규모 언어 모델(Large Language Model, LLM)을 개인 로컬 환경에서 실행하고 배포하기 위한 Ollama 사용법을 정리하는 포스팅입니다. Ollama를 사용하면 유명한 모델들인 LLaMA&quot; data-og-host=&quot;lsjsj92.tistory.com&quot; data-og-source-url=&quot;https://lsjsj92.tistory.com/666&quot; data-og-url=&quot;https://lsjsj92.tistory.com/666&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bWpaYr/hyY1gbjJmH/kFW92eXhQBYVHEPaa5YXX0/img.png?width=800&amp;amp;height=284&amp;amp;face=0_0_800_284,https://scrap.kakaocdn.net/dn/c2uNo5/hyY1huxg1V/NSEYikMpCKkgbka7KHLJKk/img.png?width=800&amp;amp;height=284&amp;amp;face=0_0_800_284,https://scrap.kakaocdn.net/dn/qz8DM/hyY1h89qfm/m5sJIm3PKZR6pUQbbquq2K/img.png?width=1906&amp;amp;height=1382&amp;amp;face=0_0_1906_1382&quot;&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/666&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://lsjsj92.tistory.com/666&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bWpaYr/hyY1gbjJmH/kFW92eXhQBYVHEPaa5YXX0/img.png?width=800&amp;amp;height=284&amp;amp;face=0_0_800_284,https://scrap.kakaocdn.net/dn/c2uNo5/hyY1huxg1V/NSEYikMpCKkgbka7KHLJKk/img.png?width=800&amp;amp;height=284&amp;amp;face=0_0_800_284,https://scrap.kakaocdn.net/dn/qz8DM/hyY1h89qfm/m5sJIm3PKZR6pUQbbquq2K/img.png?width=1906&amp;amp;height=1382&amp;amp;face=0_0_1906_1382');&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;Ollama 사용법 - 개인 로컬 환경에서 LLM 모델 실행 및 배포하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 개요이번 포스팅은 대규모 언어 모델(Large Language Model, LLM)을 개인 로컬 환경에서 실행하고 배포하기 위한 Ollama 사용법을 정리하는 포스팅입니다. Ollama를 사용하면 유명한 모델들인 LLaMA&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;lsjsj92.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;p data-ke-size=&quot;size16&quot;&gt;Modelfile이 준비되었으면 ollama create -f를 통해 LLM 모델을 Ollama에 셋팅해줍시다.&lt;/p&gt;
&lt;pre id=&quot;code_1748674724099&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;!ollama create llama3.2-bllossom-3b-kr -f /content/Modelfile&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.47.27.png&quot; data-origin-width=&quot;2174&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O4AQF/btsOlatGLl3/r1uCsMts6OsvAn1wPBCW01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O4AQF/btsOlatGLl3/r1uCsMts6OsvAn1wPBCW01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O4AQF/btsOlatGLl3/r1uCsMts6OsvAn1wPBCW01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO4AQF%2FbtsOlatGLl3%2Fr1uCsMts6OsvAn1wPBCW01%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;705&quot; height=&quot;132&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.47.27.png&quot; data-origin-width=&quot;2174&quot; data-origin-height=&quot;408&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;이제 !ollama list를 통해 확인하면 Modelfile로 등록한 LLM 모델이 정상적으로 셋팅된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. Ollama API로 LLM과 통신 수행&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자! 이제 코랩(colab)에 Ollama 설치도 완료했고, 허깅페이스에서 모델도 받아 Ollama에 셋팅도 완료하였습니다.&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;먼저, colab 셀에서 아래와 같은 명령어로도 Ollama의 실행 결과를 간단하게 확인해볼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1748674911592&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;!ollama run llama3.2-bllossom-3b-kr:latest &quot;안녕하세요?&quot; 2&amp;gt; ollama.log&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.56.43.png&quot; data-origin-width=&quot;2174&quot; data-origin-height=&quot;200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnXvTf/btsOmwCdcQd/cOrnqh9KcED2YMPt0xpdq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnXvTf/btsOmwCdcQd/cOrnqh9KcED2YMPt0xpdq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnXvTf/btsOmwCdcQd/cOrnqh9KcED2YMPt0xpdq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnXvTf%2FbtsOmwCdcQd%2FcOrnqh9KcED2YMPt0xpdq1%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;740&quot; height=&quot;68&quot; data-filename=&quot;스크린샷 2025-05-29 오후 9.56.43.png&quot; data-origin-width=&quot;2174&quot; data-origin-height=&quot;200&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;그리고, Python requests를 이용해 colab LLM과 API 통신할 수도 있습니다. 아래는 Ollama와 통신하는 파이썬 예제 코드입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1748674993294&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import requests
import json

url = 'http://localhost:11434/api/generate'

prompt_text = &quot;You are an AI assistant!\nUser: 안녕하세요\nAssistant:&quot;

payload = {
    &quot;model&quot;: &quot;llama3.2-bllossom-3b-kr&quot;,
    &quot;temperature&quot;: 0.6,
    &quot;stream&quot;: False,
    &quot;prompt&quot;: prompt_text
}

response = requests.post(url, json=payload)
message_str = response.content.decode('utf-8')
message_dict = json.loads(message_str)
print(message_dict['response'])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-29 오후 10.11.48.png&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;862&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/doL4aV/btsOlevPnz1/e9migIpmSsIGHK4v6a3Huk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doL4aV/btsOlevPnz1/e9migIpmSsIGHK4v6a3Huk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doL4aV/btsOlevPnz1/e9migIpmSsIGHK4v6a3Huk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdoL4aV%2FbtsOlevPnz1%2Fe9migIpmSsIGHK4v6a3Huk%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;672&quot; height=&quot;389&quot; data-filename=&quot;스크린샷 2025-05-29 오후 10.11.48.png&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;862&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;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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 구글 코랩(google colab)에서 Ollama를 설치하고, LLM을 셋팅하여 API 통신을 통해 Ollama 환경의 LLM을 사용하고 실행하는 방법에 대해 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도움이 되시길 바랍니다.&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>Colab</category>
      <category>GenAI</category>
      <category>huggingface</category>
      <category>largelanguagemodels</category>
      <category>LLM</category>
      <category>NLP</category>
      <category>Ollama</category>
      <category>Python</category>
      <category>구글코랩</category>
      <category>코랩</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/689</guid>
      <comments>https://lsjsj92.tistory.com/689#entry689comment</comments>
      <pubDate>Wed, 4 Jun 2025 10:05:15 +0900</pubDate>
    </item>
    <item>
      <title>DART API - 전자공시 API 사용법과 Python 연동 및 분석 예시</title>
      <link>https://lsjsj92.tistory.com/688</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전자공시시스템(DART, Data Analysis, Retrieval and Transfer System)은 상장법인 등이 공시서류를 인터넷으로 제출하고, 투자자는 이를 활용해 다양한 기업의 정보를 확인할 수 있도록 지원해주는 시스템입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 주식과 같은 재테크를 활발하게 하면서 기업에 대한 다양한 정보를 쉽게 접근해서 분석하고자 하는 니즈가 꽤 있는데요. 기업 분석을 위해서 전자공시 DART에서 제공해주는 API(DART API)를 사용하면 쉽게 기업에 대한 다양한 정보를 활용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 전자공시 DART의 API를 신청하고 파이썬(Python)을 통해 데이터를 가져올 수 있는 예제를 정리해보겠습니다.&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;- DART: &lt;a href=&quot;https://dart.fss.or.kr/main.do&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dart.fss.or.kr/main.do&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- OPEN DART: &lt;a href=&quot;https://opendart.fss.or.kr/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://opendart.fss.or.kr/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1747468988552&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;전자공시 OPENDART 시스템&quot; data-og-description=&quot;25년도 1분기 XBRL 주석 미제출 및 정정 예정 법인 안내 25년도 1분기보고서에 XBRL 주석을 포함하여 공시하여야 하나 '25.5.15. 제출 마감일 기준 XBRL 주석을 제출하지 않은 법인이 있어 다음과 같이 &quot; data-og-host=&quot;opendart.fss.or.kr&quot; data-og-source-url=&quot;https://opendart.fss.or.kr/&quot; data-og-url=&quot;https://opendart.fss.or.kr/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://opendart.fss.or.kr/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://opendart.fss.or.kr/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;전자공시 OPENDART 시스템&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;25년도 1분기 XBRL 주석 미제출 및 정정 예정 법인 안내 25년도 1분기보고서에 XBRL 주석을 포함하여 공시하여야 하나 '25.5.15. 제출 마감일 기준 XBRL 주석을 제출하지 않은 법인이 있어 다음과 같이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;opendart.fss.or.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-17 오후 5.02.35.png&quot; data-origin-width=&quot;1516&quot; data-origin-height=&quot;875&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cremiP/btsN2besPMj/Ma4Ax6Eu9kGkpAMkZWUndk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cremiP/btsN2besPMj/Ma4Ax6Eu9kGkpAMkZWUndk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cremiP/btsN2besPMj/Ma4Ax6Eu9kGkpAMkZWUndk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcremiP%2FbtsN2besPMj%2FMa4Ax6Eu9kGkpAMkZWUndk%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;698&quot; height=&quot;403&quot; data-filename=&quot;스크린샷 2025-05-17 오후 5.02.35.png&quot; data-origin-width=&quot;1516&quot; data-origin-height=&quot;875&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OPEN DART는 전자공시 시스템(DART)에 공시되고 있는 공시보고서 원문 등을 오픈 API를 통해 활용할 수 있는 API 서비스입니다. 활용을 원하는 (개인 기관 등) 사람들이 이용할 수 있습니다. OPEN DART API의 특징은 다음과 같습니다.&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;- DART 공시원문을 활용할 수 있습니다. DART에 공시되는 공시보고서의 원문을 XML 형식으로 다운로드 받아 원하는 자료를 자유롭게 추출하여 사용할 수 있습니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;OPEN DART 이용하기 - 회원가입 및 API Key 발급 받기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OPEN DART API 서비스를 사용하려면 가장 먼저, API Key를 받아야 하는데요. 처음엔 회원가입을 해야하는 줄 알았는 데, 인증키 신청으로도 되더라구요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-17 오후 5.08.20.png&quot; data-origin-width=&quot;1516&quot; data-origin-height=&quot;812&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6pYo2/btsN1rCl0n8/Ij0Gb9j0TvepPBQIAho6E0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6pYo2/btsN1rCl0n8/Ij0Gb9j0TvepPBQIAho6E0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6pYo2/btsN1rCl0n8/Ij0Gb9j0TvepPBQIAho6E0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6pYo2%2FbtsN1rCl0n8%2FIj0Gb9j0TvepPBQIAho6E0%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;741&quot; height=&quot;397&quot; data-filename=&quot;스크린샷 2025-05-17 오후 5.08.20.png&quot; data-origin-width=&quot;1516&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;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-filename=&quot;스크린샷 2025-05-17 오후 5.15.44.png&quot; data-origin-width=&quot;1147&quot; data-origin-height=&quot;737&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBJBR7/btsN0AmyeyX/KF0T297Mp2SceJ1OJPWvgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBJBR7/btsN0AmyeyX/KF0T297Mp2SceJ1OJPWvgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBJBR7/btsN0AmyeyX/KF0T297Mp2SceJ1OJPWvgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBJBR7%2FbtsN0AmyeyX%2FKF0T297Mp2SceJ1OJPWvgK%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;715&quot; height=&quot;459&quot; data-filename=&quot;스크린샷 2025-05-17 오후 5.15.44.png&quot; data-origin-width=&quot;1147&quot; data-origin-height=&quot;737&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;p data-ke-size=&quot;size16&quot;&gt;저는 개인용으로 신청했고, 사용 용도도 개인적 데이터 분석으로 사용해서 제출했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 간단히 신청을 하게 되면, 아래와 같이 API Key를 받을 수 있게 됩니다.&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-filename=&quot;스크린샷 2025-05-17 오후 5.18.08.png&quot; data-origin-width=&quot;1183&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CHUGh/btsN1htewIn/KeOlG74AM5DfQCL8Ku5Ln0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CHUGh/btsN1htewIn/KeOlG74AM5DfQCL8Ku5Ln0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CHUGh/btsN1htewIn/KeOlG74AM5DfQCL8Ku5Ln0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCHUGh%2FbtsN1htewIn%2FKeOlG74AM5DfQCL8Ku5Ln0%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;680&quot; height=&quot;216&quot; data-filename=&quot;스크린샷 2025-05-17 오후 5.18.08.png&quot; data-origin-width=&quot;1183&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;전자공시 DART 데이터 API로 활용하기&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bA9gHg/btsN2stvCc4/kr6BifuqGThr6pudnCvZn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bA9gHg/btsN2stvCc4/kr6BifuqGThr6pudnCvZn1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1396&quot; data-origin-height=&quot;631&quot; data-filename=&quot;스크린샷 2025-05-17 오후 5.20.31.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bA9gHg/btsN2stvCc4/kr6BifuqGThr6pudnCvZn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbA9gHg%2FbtsN2stvCc4%2Fkr6BifuqGThr6pudnCvZn1%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;1396&quot; height=&quot;631&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mDBXu/btsN01KZwUk/c4iutTqc1mHEuuLM8WKPtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mDBXu/btsN01KZwUk/c4iutTqc1mHEuuLM8WKPtk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1396&quot; data-origin-height=&quot;631&quot; data-filename=&quot;스크린샷 2025-05-17 오후 5.20.37.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mDBXu/btsN01KZwUk/c4iutTqc1mHEuuLM8WKPtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmDBXu%2FbtsN01KZwUk%2Fc4iutTqc1mHEuuLM8WKPtk%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;1396&quot; height=&quot;631&quot;/&gt;&lt;/span&gt;&lt;/div&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;DART에서 제공해주는 전자공시 데이터는 상당히 많이 있습니다. 기업에서 제출하는 재무정보를 포함한 다양한 정보를 확인할 수 있는데요. 예를 들어, 왼쪽 사진과 같이 정기보고서 주요 정보를 보면 증자(감자) 현황, 배당에 관한 사항, 최대주주 현황, 최대주주 변동 현황, 소액주주 현황, 임원 현황 등의 정보를 확인할 수도 있습니다.&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;여기서, 정기보고서 재무정보 중 단일회사 주요계정 API를 확인해보겠습니다.&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-filename=&quot;스크린샷 2025-05-17 오후 5.20.46.png&quot; data-origin-width=&quot;1396&quot; data-origin-height=&quot;772&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eahrKP/btsN1yVv6yc/NAkV6GkHwMZNS5fwRDl980/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eahrKP/btsN1yVv6yc/NAkV6GkHwMZNS5fwRDl980/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eahrKP/btsN1yVv6yc/NAkV6GkHwMZNS5fwRDl980/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeahrKP%2FbtsN1yVv6yc%2FNAkV6GkHwMZNS5fwRDl980%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;779&quot; height=&quot;431&quot; data-filename=&quot;스크린샷 2025-05-17 오후 5.20.46.png&quot; data-origin-width=&quot;1396&quot; data-origin-height=&quot;772&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 API에 들어오게 되면, 메서드 GET으로 요청 URL이 어떻게 되고, 요청 인자(Request parameter)가 무엇이 있는 지 설명해주고 있습니다. 이 DART API의 경우 고유번호로 조회할 수 있는데요. 고유번호는 개바가이드 &amp;gt; 공시정보 &amp;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-filename=&quot;스크린샷 2025-05-17 오후 5.20.57.png&quot; data-origin-width=&quot;1133&quot; data-origin-height=&quot;772&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnjvkA/btsN12B5fYr/7TG1tqxOckDxqlgJNbUhL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnjvkA/btsN12B5fYr/7TG1tqxOckDxqlgJNbUhL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnjvkA/btsN12B5fYr/7TG1tqxOckDxqlgJNbUhL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnjvkA%2FbtsN12B5fYr%2F7TG1tqxOckDxqlgJNbUhL0%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;693&quot; height=&quot;472&quot; data-filename=&quot;스크린샷 2025-05-17 오후 5.20.57.png&quot; data-origin-width=&quot;1133&quot; data-origin-height=&quot;772&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;또한, 그 아래에 응답 결과(Response parameter)에 대한 설명도 있습니다. 즉, API Request를 보냈을 때 어떤 응답을 받을 수 있는지 설명해주고 있는데요. 예를 들어, 에러 번호라던가, 사업 연도, 재무제표인지 연결재무제표인지의 구분 값, 손익계산서인지 재무상태표인지에 대한 구분 값 등 다양한 정보를 받을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 이 DART API를 잘 활용한다면 기업의 자산 총계나, 부채총계, 자본에 대한 정보, 매출액 정보, 영업이익 정보 등을 데이터로 확인할 수 있게 되는 것입니다.&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;이렇게 DART API에 대한 설명을 OPEN DART에서 꽤나 친절하게 데이터에 대한 설명과 가이드를 해주고 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;파이썬(Python)을 활용해 API 요청하고 데이터 받아오기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 그러면 어떻게 저 API와 통신할 수 있을까요? 파이썬(Python)을 활용해서 간단하게 API 호출하고 결과를 받아와서 시각화 할 수 있는 방법을 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1747470531300&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def fetch_financial_statements(crtfc_key, corp_code, bsns_year, reprt_code):
    url = &quot;https://opendart.fss.or.kr/api/fnlttSinglAcnt.xml&quot;
    params = {
        'crtfc_key': crtfc_key,
        'corp_code': corp_code,
        'bsns_year': bsns_year,
        'reprt_code': reprt_code,
    }

    response = requests.get(url, params=params)
    if response.status_code != 200:
        raise Exception(f&quot;[HTTP 오류] 상태 코드: {response.status_code}&quot;)

    root = ET.fromstring(response.content)

    status = root.findtext(&quot;status&quot;)
    message = root.findtext(&quot;message&quot;)
    if status != '000':
        error_desc = ERROR_MESSAGES.get(status, '알 수 없는 오류입니다.')
        # 조회 데이터 없음은 경고만 출력
        if status == '013':
            print(f&quot;[정보] {bsns_year}년 {REPORT_CODES[reprt_code]}: 조회된 데이터 없음.&quot;)
            return []
        raise Exception(f&quot;[API 오류] 상태 코드: {status} - {error_desc}\n&amp;rarr; DART 응답 메시지: {message}&quot;)

    results = []
    for item in root.findall(&quot;list&quot;):
        data = {
            'bsns_year': bsns_year,
            'report_type': REPORT_CODES[reprt_code],
            'rcept_no': item.findtext('rcept_no'),
            'account_nm': item.findtext('account_nm'),
            'fs_div': item.findtext('fs_div'),
            'sj_div': item.findtext('sj_div'),
            'thstrm_nm': item.findtext('thstrm_nm'),
            'thstrm_dt': item.findtext('thstrm_dt'),
            'thstrm_amount': item.findtext('thstrm_amount'),
            'frmtrm_nm': item.findtext('frmtrm_nm'),
            'frmtrm_dt': item.findtext('frmtrm_dt'),
            'frmtrm_amount': item.findtext('frmtrm_amount'),
            'currency': item.findtext('currency'),
        }
        results.append(data)

    return results

def fetch_all_reports_last_n_years(crtfc_key, corp_code):
    current_year = datetime.now().year
    years = [str(current_year - 1), str(current_year)]
    all_data = []

    for year in years:
        for code in REPORT_CODES.keys():
            print(f&quot;수집 중: {year}년 {REPORT_CODES[code]}&quot;)
            try:
                result = fetch_financial_statements(crtfc_key, corp_code, year, code)
                all_data.extend(result)
            except Exception as e:
                print(f&quot;[오류] {year}년 {REPORT_CODES[code]} - {e}&quot;)

    df = pd.DataFrame(all_data)
    return df&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;/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;p data-ke-size=&quot;size16&quot;&gt;2. DART API에 요청을 보내 재무제표 데이터를 받아옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 여러 연도, 여러 종류의 보고서를 반복적으로 수집합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 데이터를 정리해서 Python의 데이터프레임(pandas dataframe)으로 만들어서 제공합니다.&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;예를 들어서, 삼성전자의 2023년 사업보고서 데이터를 보고 싶다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- corp_code = '00126380', bsns_year='2023', reprt_code = '11011'과 같이 설정할 수 있습니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-17 오후 5.30.37.png&quot; data-origin-width=&quot;839&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckEjvP/btsN1nGHjNr/CebXLLhnVIYNi7QUtqAob0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckEjvP/btsN1nGHjNr/CebXLLhnVIYNi7QUtqAob0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckEjvP/btsN1nGHjNr/CebXLLhnVIYNi7QUtqAob0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckEjvP%2FbtsN1nGHjNr%2FCebXLLhnVIYNi7QUtqAob0%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;713&quot; height=&quot;338&quot; data-filename=&quot;스크린샷 2025-05-17 오후 5.30.37.png&quot; data-origin-width=&quot;839&quot; data-origin-height=&quot;398&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;Open DART 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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-17 오후 5.37.00.png&quot; data-origin-width=&quot;1401&quot; data-origin-height=&quot;437&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WtWsv/btsN2sG0Ywv/jngMKBekc97Gaz72RExN80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WtWsv/btsN2sG0Ywv/jngMKBekc97Gaz72RExN80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WtWsv/btsN2sG0Ywv/jngMKBekc97Gaz72RExN80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWtWsv%2FbtsN2sG0Ywv%2FjngMKBekc97Gaz72RExN80%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;1401&quot; height=&quot;437&quot; data-filename=&quot;스크린샷 2025-05-17 오후 5.37.00.png&quot; data-origin-width=&quot;1401&quot; data-origin-height=&quot;437&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;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 기업의 자산, 부채, 자본 추이를 알고 싶다거나, 영업이익률, 순이익률을 알고 싶다면 아래와 같이 분석을 할 수도 있겠죠.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bT8O2m/btsN1qwE6Ol/T9hMoEHZbeLCvc82z64vGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bT8O2m/btsN1qwE6Ol/T9hMoEHZbeLCvc82z64vGk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;997&quot; data-origin-height=&quot;620&quot; data-filename=&quot;스크린샷 2025-05-17 오후 5.29.10.png&quot; style=&quot;width: 51.9455%; margin-right: 10px;&quot; data-widthpercent=&quot;52.56&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bT8O2m/btsN1qwE6Ol/T9hMoEHZbeLCvc82z64vGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbT8O2m%2FbtsN1qwE6Ol%2FT9hMoEHZbeLCvc82z64vGk%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;997&quot; height=&quot;620&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JGLtj/btsN1tmAhNr/EsUAEUu2Z9EqS2qAnrgUD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JGLtj/btsN1tmAhNr/EsUAEUu2Z9EqS2qAnrgUD0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;620&quot; data-filename=&quot;스크린샷 2025-05-17 오후 5.29.19.png&quot; style=&quot;width: 46.8917%;&quot; data-widthpercent=&quot;47.44&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JGLtj/btsN1tmAhNr/EsUAEUu2Z9EqS2qAnrgUD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJGLtj%2FbtsN1tmAhNr%2FEsUAEUu2Z9EqS2qAnrgUD0%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;900&quot; height=&quot;620&quot;/&gt;&lt;/span&gt;&lt;/div&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;이렇게 전자공시 서비스인 DART의 OPEN DART API를 이용하면 다양한 기업 정보를 가져올 수 있고, 원하는 방식대로 데이터를 추출 및 분석할 수 있습니다.&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;도움이 되셨기를 바랍니다.&lt;/p&gt;</description>
      <category>python</category>
      <category>dart</category>
      <category>dart api</category>
      <category>dartapi</category>
      <category>opendart</category>
      <category>Python</category>
      <category>python 데이터분석</category>
      <category>전자공시시스템</category>
      <category>파이썬</category>
      <category>파이썬 기업분석</category>
      <category>파이썬 주식투자</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/688</guid>
      <comments>https://lsjsj92.tistory.com/688#entry688comment</comments>
      <pubDate>Wed, 28 May 2025 09:41:42 +0900</pubDate>
    </item>
    <item>
      <title>Kipris plus API 활용하는 방법 - 특허 API 사용법과 Python 연동 예시</title>
      <link>https://lsjsj92.tistory.com/687</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kipris plus를 사용하면 특허 분석에 필요한 각종 데이터를 제공 받을 수 있는데요. 특허청에서 제공해주는 서비스인만큼 필요한 특허 데이터를 비교적 자유롭게 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 이번 포스팅은 Kipris plus API를 활용해 특허 데이터를 사용할 수 있는 방법에 대해서 알아보겠습니다. 그리고 파이썬(Python)을 활용해 특허 API를 연동하여 데이터를 가져올 수 있는 방법도 알아보겠습니다.&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;kipris plus 사이트는 아래와 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://plus.kipris.or.kr/portal/main.do&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://plus.kipris.or.kr/portal/main.do&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1747463366055&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;KIPRIS Plus&quot; data-og-description=&quot;&amp;ldquo; 특허정보 활용의 새로운 패러다임 &amp;rdquo; 특허청이 개방중인 산업재산권 정보를 Bulk Data, OPEN API 방식으로 제공하여, 이용자가 새로운 가치를 창출하도록 지원하는 서비스 133 Bulk Data 75 API(REST) --&amp;gt; &quot; data-og-host=&quot;plus.kipris.or.kr&quot; data-og-source-url=&quot;https://plus.kipris.or.kr/portal/main.do&quot; data-og-url=&quot;https://plus.kipris.or.kr/portal/main.do&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bVfm94/hyYU9pD5Vk/yz7JFk6xjKLxWfXD4uEUU0/img.png?width=657&amp;amp;height=657&amp;amp;face=0_0_657_657,https://scrap.kakaocdn.net/dn/byRmSD/hyYVcNtjCR/XV9CjNYYFcAuQA09pQE7iK/img.png?width=641&amp;amp;height=394&amp;amp;face=0_0_641_394,https://scrap.kakaocdn.net/dn/KSyCN/hyYVgPRpVn/RLZpD2dxvCxe6f5p7t0aYk/img.png?width=358&amp;amp;height=353&amp;amp;face=0_0_358_353&quot;&gt;&lt;a href=&quot;https://plus.kipris.or.kr/portal/main.do&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://plus.kipris.or.kr/portal/main.do&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bVfm94/hyYU9pD5Vk/yz7JFk6xjKLxWfXD4uEUU0/img.png?width=657&amp;amp;height=657&amp;amp;face=0_0_657_657,https://scrap.kakaocdn.net/dn/byRmSD/hyYVcNtjCR/XV9CjNYYFcAuQA09pQE7iK/img.png?width=641&amp;amp;height=394&amp;amp;face=0_0_641_394,https://scrap.kakaocdn.net/dn/KSyCN/hyYVgPRpVn/RLZpD2dxvCxe6f5p7t0aYk/img.png?width=358&amp;amp;height=353&amp;amp;face=0_0_358_353');&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;KIPRIS Plus&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo; 특허정보 활용의 새로운 패러다임 &amp;rdquo; 특허청이 개방중인 산업재산권 정보를 Bulk Data, OPEN API 방식으로 제공하여, 이용자가 새로운 가치를 창출하도록 지원하는 서비스 133 Bulk Data 75 API(REST) --&amp;gt;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;plus.kipris.or.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-17 오후 3.29.17.png&quot; data-origin-width=&quot;1474&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmhe8X/btsN0PRiDE5/RLhYyCHHRBLaTdyBh0AbOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmhe8X/btsN0PRiDE5/RLhYyCHHRBLaTdyBh0AbOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmhe8X/btsN0PRiDE5/RLhYyCHHRBLaTdyBh0AbOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcmhe8X%2FbtsN0PRiDE5%2FRLhYyCHHRBLaTdyBh0AbOK%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;667&quot; height=&quot;376&quot; data-filename=&quot;스크린샷 2025-05-17 오후 3.29.17.png&quot; data-origin-width=&quot;1474&quot; data-origin-height=&quot;832&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kipris plus는 특허청이 개방중인 사업재산권 정보를 Bulk Data, Open API 방식으로 제공하여 이용자가 새로운 가치를 창출하도록 지원하는 서비스입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 벌크 데이터(Bulk data)라는 것은 특허 정보를 온라인 다운로드 서비스를 통하여 자체 DB로 대용량 일괄 제공하는 방식이며, Open API 방식은 특허청 DB와 네트워크 통신을 통하여 필요한 정보를 요청하고 응답 받아 자체 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;특허정보 활용 서비스 kipris plus의 API 비용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 특허정보를 제공하는 kipris plus의 비용 체계를 확인해보겠습니다. 특허 API인 kipris plus는 무조건 무료로 데이터를 전부 제공하는 것은 아니구요. 개인 사용자와 같이 가볍게 사용하는 사용자는 월 1000건까지 무료로 사용할 수 있습니다. 그러나, 대용량 통신을 원하시거나, 기업이 사용할 경우엔 그에 맞는 비용을 제공해야 합니다.&amp;nbsp;&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-filename=&quot;스크린샷 2025-05-17 오후 3.33.11.png&quot; data-origin-width=&quot;1474&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bx6l64/btsN1QImpos/Mv4sXhZxIU70q4nMkWVDRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bx6l64/btsN1QImpos/Mv4sXhZxIU70q4nMkWVDRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bx6l64/btsN1QImpos/Mv4sXhZxIU70q4nMkWVDRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbx6l64%2FbtsN1QImpos%2FMv4sXhZxIU70q4nMkWVDRk%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;716&quot; height=&quot;404&quot; data-filename=&quot;스크린샷 2025-05-17 오후 3.33.11.png&quot; data-origin-width=&quot;1474&quot; data-origin-height=&quot;832&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;Kipris plus 특허 DB API에 대한 비용을 자세히 알고 싶으시면 &lt;a href=&quot;https://plus.kipris.or.kr/portal/use/paymentMmg.do?menuNo=200026&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://plus.kipris.or.kr/portal/use/paymentMmg.do?menuNo=200026&lt;/a&gt;를 참고하셔서 확인하시면 되겠습니다.&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;style8&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;kipris plus API 사용하기 - 회원가입 및 API 키 발급&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본격적으로 kipris plus API를 사용하는 방법에 대해서 알아보겠습니다. Kipris plus 특허 데이터를 사용하려면 API key를 발급 받아야 하는데요. 이를 위해서는 회원가입이 필요합니다.&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-filename=&quot;스크린샷 2025-05-12 오후 8.40.10.png&quot; data-origin-width=&quot;3098&quot; data-origin-height=&quot;2124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xa56I/btsN10xp40I/aFjg41nTyFniGoB29bcD81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xa56I/btsN10xp40I/aFjg41nTyFniGoB29bcD81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xa56I/btsN10xp40I/aFjg41nTyFniGoB29bcD81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxa56I%2FbtsN10xp40I%2FaFjg41nTyFniGoB29bcD81%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;722&quot; height=&quot;495&quot; data-filename=&quot;스크린샷 2025-05-12 오후 8.40.10.png&quot; data-origin-width=&quot;3098&quot; data-origin-height=&quot;2124&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;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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-12 오후 8.41.12.png&quot; data-origin-width=&quot;3098&quot; data-origin-height=&quot;2124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvVdLj/btsN1pLfwtQ/j4et05amkfU4w251fxZGjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvVdLj/btsN1pLfwtQ/j4et05amkfU4w251fxZGjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvVdLj/btsN1pLfwtQ/j4et05amkfU4w251fxZGjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvVdLj%2FbtsN1pLfwtQ%2Fj4et05amkfU4w251fxZGjk%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;757&quot; height=&quot;519&quot; data-filename=&quot;스크린샷 2025-05-12 오후 8.41.12.png&quot; data-origin-width=&quot;3098&quot; data-origin-height=&quot;2124&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;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;본 포스팅에서는 일반적으로 활용될 수 있는 특허 데이터인 &quot;특허 실용 공개 및 등록 정보 서비스&quot;를 활용하도록 하겠습니다.&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-filename=&quot;스크린샷 2025-05-12 오후 8.41.24.png&quot; data-origin-width=&quot;3098&quot; data-origin-height=&quot;736&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccZl52/btsN2RT3I8A/rGlZ2RXkzKgYOK8goZCHXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccZl52/btsN2RT3I8A/rGlZ2RXkzKgYOK8goZCHXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccZl52/btsN2RT3I8A/rGlZ2RXkzKgYOK8goZCHXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccZl52%2FbtsN2RT3I8A%2FrGlZ2RXkzKgYOK8goZCHXk%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;3098&quot; height=&quot;736&quot; data-filename=&quot;스크린샷 2025-05-12 오후 8.41.24.png&quot; data-origin-width=&quot;3098&quot; data-origin-height=&quot;736&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;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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0gHif/btsN0837oaj/FweBIlkv8sIONFLjAlSfi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0gHif/btsN0837oaj/FweBIlkv8sIONFLjAlSfi1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3098&quot; data-origin-height=&quot;1690&quot; data-filename=&quot;스크린샷 2025-05-12 오후 8.41.41.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0gHif/btsN0837oaj/FweBIlkv8sIONFLjAlSfi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0gHif%2FbtsN0837oaj%2FFweBIlkv8sIONFLjAlSfi1%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;3098&quot; height=&quot;1690&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCUq8X/btsN1crQ8Lv/m6bFHMwaUl0cafinUs7Zyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCUq8X/btsN1crQ8Lv/m6bFHMwaUl0cafinUs7Zyk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3098&quot; data-origin-height=&quot;1690&quot; data-filename=&quot;스크린샷 2025-05-12 오후 8.41.52.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCUq8X/btsN1crQ8Lv/m6bFHMwaUl0cafinUs7Zyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCUq8X%2FbtsN1crQ8Lv%2Fm6bFHMwaUl0cafinUs7Zyk%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;3098&quot; height=&quot;1690&quot;/&gt;&lt;/span&gt;&lt;/div&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;여기서 전체 선택을 하고, 서비스 신청하기를 누르면 특허 API 서비스 신청이 완료됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자! 이제 kipris plus에서 특허 데이터를 사용하기 위한 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;다만, 그 전에 나의 API Key가 무엇인지 확인해야합니다. kipris 특허 API 서비스를 사용하기 위해서, 인증키가 필요한데요. 그게 API Key라고 보시면 됩니다.&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-filename=&quot;스크린샷 2025-05-12 오후 8.41.59.png&quot; data-origin-width=&quot;3098&quot; data-origin-height=&quot;1690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vRYqY/btsN1NE6lRi/KdYxVAgmuTNEHqKkOE2dG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vRYqY/btsN1NE6lRi/KdYxVAgmuTNEHqKkOE2dG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vRYqY/btsN1NE6lRi/KdYxVAgmuTNEHqKkOE2dG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvRYqY%2FbtsN1NE6lRi%2FKdYxVAgmuTNEHqKkOE2dG0%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;3098&quot; height=&quot;1690&quot; data-filename=&quot;스크린샷 2025-05-12 오후 8.41.59.png&quot; data-origin-width=&quot;3098&quot; data-origin-height=&quot;1690&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;API Key 관리 메뉴에서 나의 API Key를 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 정보는 꼭 외부로 유출되지 않도록 조심해서 사용해주시고, 위 키를 이용해 이제 특허 API를 호출해서 실제 결과를 받아보겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Kipris 특허 API 사용하기 - 웹에서 간단하게 사용해보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kipris plus 사이트에서는 API를 사용해볼 수 있는 환경을 잘 제공해주고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 정말 마음에 들었던 것은, 각 서비스에서 제공해주는 다양한 기능별로, API url과 입력 값(request parameter) 그리고 response로 돌아오는 출력값(response parameter)들이 잘 명시되어 있다는 점입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bliWNM/btsN2MkUPyi/Uj2eAM2KzAKdpzDUXKNVz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bliWNM/btsN2MkUPyi/Uj2eAM2KzAKdpzDUXKNVz1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1182&quot; data-origin-height=&quot;828&quot; data-filename=&quot;스크린샷 2025-05-10 오후 6.04.19.png&quot; style=&quot;width: 52.3916%; margin-right: 10px;&quot; data-widthpercent=&quot;53.01&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bliWNM/btsN2MkUPyi/Uj2eAM2KzAKdpzDUXKNVz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbliWNM%2FbtsN2MkUPyi%2FUj2eAM2KzAKdpzDUXKNVz1%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;1182&quot; height=&quot;828&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dl8212/btsN1MzsAR8/mY7goTINy3e5CQH004wAc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dl8212/btsN1MzsAR8/mY7goTINy3e5CQH004wAc0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1182&quot; data-origin-height=&quot;934&quot; data-filename=&quot;스크린샷 2025-05-10 오후 6.04.38.png&quot; style=&quot;width: 46.4456%;&quot; data-widthpercent=&quot;46.99&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dl8212/btsN1MzsAR8/mY7goTINy3e5CQH004wAc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdl8212%2FbtsN1MzsAR8%2FmY7goTINy3e5CQH004wAc0%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;1182&quot; height=&quot;934&quot;/&gt;&lt;/span&gt;&lt;/div&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;위 사진은 제가 신청한 특허 서비스인 &quot;특허 실용 공개 및 등록 정보 서비스&quot;에 있는 일반 검색, 항목별 검색의 세부 서비스 내용에 대한 설명입니다. 일반 검색의 경우 폐기 예정이라고 명시되어 있는 것으로 보아, 곧 서비스가 종료될 것으로 보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항목별 검색을 확인하면 전체 검색이나, 발명의 명칭 등으로 검색을 할 수 있도록 제공해주며 각각의 요청 주소(Request URL)도 명시해주고 있습니다. 그리고 화면 하단으로 내리면 어떤 응답(Response)가 넘어오는 지도 잘 보여주고 있습니다.&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;무엇보다, Kipris plus API는 API 샘플을 제공해줍니다. 예를 들어, 아래와 같은 샘플을 제공해주죠.&lt;/p&gt;
&lt;pre id=&quot;code_1747465559667&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;http://plus.kipris.or.kr/kipo-api/kipi/patUtiModInfoSearchSevice/getAdvancedSearch?astrtCont=발명&amp;amp;inventionTitle=센서&amp;amp;ServiceKey=write your service key&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;여기서 ServiceKey에다가 아까 회원가입 후 받았던 각자의 API Key를 넣으시면 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 web url에 그대로 넣어도 결과를 볼 수 있는데요. 크롬이나 엣지 등에 넣어서 실행하면 아래와 같은 결과를 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-17 오후 4.00.58.png&quot; data-origin-width=&quot;1474&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pkTWS/btsN0zVp09w/p2D5WRwVvdOvBVMJA7rgTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pkTWS/btsN0zVp09w/p2D5WRwVvdOvBVMJA7rgTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pkTWS/btsN0zVp09w/p2D5WRwVvdOvBVMJA7rgTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpkTWS%2FbtsN0zVp09w%2Fp2D5WRwVvdOvBVMJA7rgTk%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;1474&quot; height=&quot;832&quot; data-filename=&quot;스크린샷 2025-05-17 오후 4.00.58.png&quot; data-origin-width=&quot;1474&quot; data-origin-height=&quot;832&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;이렇게 결과가 나오면 정상적으로 특허 API 서비스를 이용할 수 있는 상태가 되는 것입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Python을 활용해 Kipris 특허 API 사용하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹에서도 데이터를 받을 수 있지만, 매번 저렇게 데이터를 호출하고 받는 것은 불편한 일입니다. 이때, 파이썬(Python)과 같은 프로그래밍 언어를 활용하면 쉽게 API와 통신할 수 있죠.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 파이썬을 활용한 kipris plus 특허 API 통신 예제입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1747466473773&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ADVANCED_SEARCH_URL = &quot;https://plus.kipris.or.kr/kipo-api/kipi/patUtiModInfoSearchSevice/getAdvancedSearch&quot;

MAX_ROWS_PER_PAGE = 10
DEFAULT_TOTAL_TARGET = 10

def advanced_search_bulk(
    word_query: str,
    service_key: str,
    total_target: int = DEFAULT_TOTAL_TARGET,
    rows_per_page: int = MAX_ROWS_PER_PAGE
) -&amp;gt; List[Dict]:
    &quot;&quot;&quot;
    KIPRIS AdvancedSearch API를 반복 호출해 다건 조회

    Args:
        word_query (str): 검색어 
        service_key (str): 인증 키
        total_target (int): 가져올 총 개수
        rows_per_page (int): 페이지당 건수 (최대 500)

    Returns:
        List[Dict]: 특허 항목 전체 리스트
    &quot;&quot;&quot;
    results = []
    total_pages = (total_target + rows_per_page - 1) // rows_per_page

    for page in range(1, total_pages + 1):
        # 직접 URL 문자열로 구성 (params 사용하지 않음)
        url = (
            f&quot;{ADVANCED_SEARCH_URL}&quot;
            f&quot;?word={word_query}&quot;
            f&quot;&amp;amp;numOfRows={rows_per_page}&quot;
            f&quot;&amp;amp;pageNo={page}&quot;
            f&quot;&amp;amp;ServiceKey={service_key}&quot;
        )

        response = requests.get(url)
        response.raise_for_status()

        root = ET.fromstring(response.content)
        items = root.findall(&quot;.//item&quot;)

        for item in items:
            results.append({
                &quot;applicationNumber&quot;: item.findtext(&quot;applicationNumber&quot;, default=&quot;&quot;),
                &quot;inventionTitle&quot;: item.findtext(&quot;inventionTitle&quot;, default=&quot;&quot;),
                &quot;astrtCont&quot;: item.findtext(&quot;astrtCont&quot;, default=&quot;&quot;).strip(),
                &quot;applicantName&quot;: item.findtext(&quot;applicantName&quot;, default=&quot;&quot;),
                &quot;registerStatus&quot;: item.findtext(&quot;registerStatus&quot;, default=&quot;&quot;),
                &quot;drawing&quot;: item.findtext(&quot;drawing&quot;, default=&quot;&quot;),
                &quot;bigDrawing&quot;: item.findtext(&quot;bigDrawing&quot;, default=&quot;&quot;),
                &quot;applicationDate&quot;: item.findtext(&quot;applicationDate&quot;, default=&quot;&quot;),
                &quot;openDate&quot;: item.findtext(&quot;openDate&quot;, default=&quot;&quot;),
            })

        if len(items) &amp;lt; rows_per_page:
            break

    return results[:total_target]&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;kipris plus의 전체 검색 API를 활용했습니다. 입력 단어를 제공 받으면, url에 따라 request parameter들이 구성되고 그 파라미터에 따라 API request를 보내게 됩니다. 그리고 만약, 정상적으로 값이 받아와졌다면 xml 형태로 받아와지기 때문에 파이썬의 xml 파싱 라이브러리를 활용해서 값을 가져오도록 합니다.&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-filename=&quot;스크린샷 2025-05-17 오후 4.21.27.png&quot; data-origin-width=&quot;1353&quot; data-origin-height=&quot;561&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWxaBd/btsN1hGIbwM/iGDcwVDb50div06ZrfvEu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWxaBd/btsN1hGIbwM/iGDcwVDb50div06ZrfvEu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWxaBd/btsN1hGIbwM/iGDcwVDb50div06ZrfvEu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWxaBd%2FbtsN1hGIbwM%2FiGDcwVDb50div06ZrfvEu1%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;1353&quot; height=&quot;561&quot; data-filename=&quot;스크린샷 2025-05-17 오후 4.21.27.png&quot; data-origin-width=&quot;1353&quot; data-origin-height=&quot;561&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;예를 들어서, 추천 시스템이라는 단어를 제공하였을 때 추천 시스템과 관련된 여러 특허 정보가 정상적으로 검색되어서 API response가 된 것을 확인할 수 있습니다.&lt;/p&gt;</description>
      <category>python</category>
      <category>KIPRIS</category>
      <category>kiprisplus</category>
      <category>kiprisplusapi</category>
      <category>Python</category>
      <category>키프리스플러스</category>
      <category>특허api</category>
      <category>특허데이터</category>
      <category>특허분석</category>
      <category>파이썬</category>
      <category>파이썬특허분석</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/687</guid>
      <comments>https://lsjsj92.tistory.com/687#entry687comment</comments>
      <pubDate>Mon, 19 May 2025 08:27:56 +0900</pubDate>
    </item>
    <item>
      <title>블로그 Q&amp;amp;A 챗봇(Chatbot) RAG 만들어보기 - LangChain + Ollama + FastAPI + Streamlit + PGVector</title>
      <link>https://lsjsj92.tistory.com/686</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 저의 티스토리 블로그 글을 활용한 AI Q&amp;amp;A 챗봇(Chatbot) RAG를 만들어본 포스팅입니다. PostgreSQL의 PGVector를 사용해서 벡터 데이터베이스(vector database)로 사용했고, Python의 랭체인(langchain)과 ollama, FastAPI, Streamlit을 활용해서 데이터를 저장, LLM 통신, 챗봇 Q&amp;amp;A 화면을 구성했습니다.&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;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;p data-ke-size=&quot;size16&quot;&gt;2. 티스토리 블로그 크롤링 및 postgresql 데이터베이스에 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 데이터 청킹(Chunking) 및 벡터(Vector) 추출 후 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. FastAPI를 이용한 Ollama LLM 통신&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. Streamlit을 활용하여 Q&amp;amp;A Chatbot 구현&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;이 사이드 프로젝트(?)를 진행한 이유&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실, 티스토리에도 검색 기능이 충분히 있습니다. 하지만, 제가 필요한 검색이 잘 안되거나, 다시 읽거나 해야하는 경우가 많더라구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 제 블로그 Q&amp;amp;A 자체가 제 스스로 필요하다는 생각이 들어서, 하루 시간을 사용해 만들어보았습니다.&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;h2 data-ke-size=&quot;size26&quot;&gt;1. 데이터베이스 테이블 구성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저, 데이터베이스를 준비해야 합니다. 데이터베이스를 준비하는 이유는, 제 티스토리 블로그 글을 크롤링 한 다음 저장할 때도 필요하며, 허깅페이스(HuggingFace) 모델을 이용해 텍스트 벡터를 추출한 후 벡터 값을 저장할 때도 필요하기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 관계형 데이터베이스(RDB)로도 사용할 수 있으면서도 동시에 벡터 데이터베이스(Vector database)로도 사용할 수 있는 PostgreSQL을 사용했습니다. 혹시 PostgreSQL에 대한 설치 방법과 개념이 익숙하지 않다면 제가 일전에 작성한 글을 참조해주세요.&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;- PostgreSQL 설치 :&amp;nbsp; &lt;a href=&quot;https://lsjsj92.tistory.com/675&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/675&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1746264768319&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;PostgreSQL PGVector 설치 및 사용하기(Feat. 벡터 데이터베이스(Vector Database) 구축)&quot; data-og-description=&quot;포스팅 개요이번 포스팅은 검색 증강 생성(Retrieval Augmented Generation, RAG)에서 많이 활용되는 벡터 데이터베이스 중 PostgreSQL의 PGVector에 대해서 작성하는 포스팅입니다. 이번 포스팅은 그 중, PostgreS&quot; data-og-host=&quot;lsjsj92.tistory.com&quot; data-og-source-url=&quot;https://lsjsj92.tistory.com/675&quot; data-og-url=&quot;https://lsjsj92.tistory.com/675&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bDwN0J/hyYPsbdK8X/jMxl2gowldluoOc6Dnsjo1/img.png?width=800&amp;amp;height=293&amp;amp;face=0_0_800_293,https://scrap.kakaocdn.net/dn/d2Txrw/hyYL2ZyAPo/l8Q795quKGxkKKiiUmBOJ1/img.png?width=800&amp;amp;height=293&amp;amp;face=0_0_800_293,https://scrap.kakaocdn.net/dn/SFRNm/hyYMWROkhc/c1mp0ssxArax3dLqAHDGUK/img.png?width=1856&amp;amp;height=1344&amp;amp;face=0_0_1856_1344&quot;&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/675&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://lsjsj92.tistory.com/675&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bDwN0J/hyYPsbdK8X/jMxl2gowldluoOc6Dnsjo1/img.png?width=800&amp;amp;height=293&amp;amp;face=0_0_800_293,https://scrap.kakaocdn.net/dn/d2Txrw/hyYL2ZyAPo/l8Q795quKGxkKKiiUmBOJ1/img.png?width=800&amp;amp;height=293&amp;amp;face=0_0_800_293,https://scrap.kakaocdn.net/dn/SFRNm/hyYMWROkhc/c1mp0ssxArax3dLqAHDGUK/img.png?width=1856&amp;amp;height=1344&amp;amp;face=0_0_1856_1344');&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;PostgreSQL PGVector 설치 및 사용하기(Feat. 벡터 데이터베이스(Vector Database) 구축)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 개요이번 포스팅은 검색 증강 생성(Retrieval Augmented Generation, RAG)에서 많이 활용되는 벡터 데이터베이스 중 PostgreSQL의 PGVector에 대해서 작성하는 포스팅입니다. 이번 포스팅은 그 중, PostgreS&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;lsjsj92.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;p data-ke-size=&quot;size16&quot;&gt;- PostgreSQL PGVector 사용하기: &lt;a href=&quot;https://lsjsj92.tistory.com/677&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/677&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1746264792445&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;PGVector와 Python FastAPI를 연동하여 벡터 데이터 저장 및 유사도 기반 조회하기&quot; data-og-description=&quot;포스팅 개요이번 포스팅은 PostgreSQL의 PGVector extension을 활용해 벡터 데이터베이스로 사용하여 파이썬(Python)의 FastAPI를 연동해 데이터를 저장하고 조회하는 방법에 대해 정리하는 포스팅입니다. &quot; data-og-host=&quot;lsjsj92.tistory.com&quot; data-og-source-url=&quot;https://lsjsj92.tistory.com/677&quot; data-og-url=&quot;https://lsjsj92.tistory.com/677&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ltzWO/hyYMVL8qzs/3oeVX4DepTQ7NQ6lOrABg1/img.png?width=800&amp;amp;height=501&amp;amp;face=0_0_800_501,https://scrap.kakaocdn.net/dn/bbkJLV/hyYL8rWxkt/8WKeyn8tvyVy1wkAbn0JI0/img.png?width=800&amp;amp;height=501&amp;amp;face=0_0_800_501,https://scrap.kakaocdn.net/dn/lqBIA/hyYMhWHFgy/Q8529V3QmuKiRYgCIZ8Ck1/img.png?width=2572&amp;amp;height=1670&amp;amp;face=0_0_2572_1670&quot;&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/677&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://lsjsj92.tistory.com/677&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ltzWO/hyYMVL8qzs/3oeVX4DepTQ7NQ6lOrABg1/img.png?width=800&amp;amp;height=501&amp;amp;face=0_0_800_501,https://scrap.kakaocdn.net/dn/bbkJLV/hyYL8rWxkt/8WKeyn8tvyVy1wkAbn0JI0/img.png?width=800&amp;amp;height=501&amp;amp;face=0_0_800_501,https://scrap.kakaocdn.net/dn/lqBIA/hyYMhWHFgy/Q8529V3QmuKiRYgCIZ8Ck1/img.png?width=2572&amp;amp;height=1670&amp;amp;face=0_0_2572_1670');&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;PGVector와 Python FastAPI를 연동하여 벡터 데이터 저장 및 유사도 기반 조회하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 개요이번 포스팅은 PostgreSQL의 PGVector extension을 활용해 벡터 데이터베이스로 사용하여 파이썬(Python)의 FastAPI를 연동해 데이터를 저장하고 조회하는 방법에 대해 정리하는 포스팅입니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;lsjsj92.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;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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-03 오후 3.33.24.png&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;1430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQNaef/btsNJkEmapq/gckRKMkZuHnvSHiq5KjYH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQNaef/btsNJkEmapq/gckRKMkZuHnvSHiq5KjYH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQNaef/btsNJkEmapq/gckRKMkZuHnvSHiq5KjYH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQNaef%2FbtsNJkEmapq%2FgckRKMkZuHnvSHiq5KjYH1%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;535&quot; height=&quot;503&quot; data-filename=&quot;스크린샷 2025-05-03 오후 3.33.24.png&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;1430&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;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;- blog_posts 테이블&lt;/b&gt;: 제 블로그의 원본 글에 대한 데이터입니다. 즉, 제 티스토리 블로그 글을 크롤링할 때 제목, 발행일자, 콘텐츠 내용, 블로그 url, 태그, 카테고리 정보 등을 가지고 오는데요. 그 중 제목, 발행일, 콘텐츠 내용, 블로그 url 정보를 저장합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- post_tags 테이블&lt;/b&gt;: blog_posts에 해당하는 블로그 글의 태그 정보입니다. 저는 블로그 글에 태그를 달아두는 습관이 있어, #으로 시작하는 태그 정보들을 넣어두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- tags 테이블&lt;/b&gt;: 전체 태그 정보를 담아두고 있습니다. 이미 기존에 사용된 태그 값이 있다면 그 태그를 사용할 수 있도록 관계를 구성했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- processing_status 테이블&lt;/b&gt;: 블로그 포스팅 글이 청킹(Chunking)과정이나 벡터 임베딩(vector embedding) 과정을 수행했는지 체크하는 테이블입니다. 만약, 블로그 포스트 글이 있는데 청킹을 수행하지 않았다면 그 체크 값을 활용해 chunking 및 vector embedding 과정을 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- post_categories 테이블&lt;/b&gt;: tags와 비슷하게 카테고리 정보를 담아두는 테이블입니다. 블로그에 해당되는 카테고리를 저장합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- categories 테이블&lt;/b&gt;: 전체 카테고리 정보를 담고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- content_chunks 테이블&lt;/b&gt;: blog_posts에서 content를 기준으로 chunking을 수행하고 그 결과를 저장한 테이블입니다. 이때, embedding_id와도 연계되어서 해당 임베딩이 어떤 chunking 결과인지 알 수 있도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- embeddings 테이블&lt;/b&gt;: chunking을 수행한 텍스트의 vector embedding 값입니다. 저는 huggingface의 embedding 모델을 사용했습니다.&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;저는 기본적으로 파이썬(Python) 코드 안에서 테이블을 생성할 수 있도록 아래 코드와 같이 미리 구성해두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1746265783424&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class ContentChunk(Base):
    __tablename__ = 'content_chunks'
    
    chunk_id = Column(Integer, primary_key=True)
    post_id = Column(Integer, ForeignKey('blog_posts.post_id', ondelete='CASCADE'), nullable=False)
    chunk_index = Column(Integer, nullable=False)
    chunk_text = Column(Text, nullable=False)
    chunk_hash = Column(String(64), unique=True)
    chunk_metadata = Column(JSON, nullable=True)  # metadata -&amp;gt; chunk_metadata로 변경
    embedding_id = Column(String(36), nullable=True)
    
    # 관계 정의
    post = relationship(&quot;BlogPost&quot;, back_populates=&quot;chunks&quot;)
    embedding = relationship(&quot;Embedding&quot;, back_populates=&quot;chunk&quot;, uselist=False, cascade=&quot;all, delete-orphan&quot;)
    
    def __repr__(self):
        return f&quot;&amp;lt;ContentChunk(chunk_id={self.chunk_id}, post_id={self.post_id}, index={self.chunk_index})&amp;gt;&quot;

class Embedding(Base):
    __tablename__ = 'embeddings'
    
    embedding_id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    chunk_id = Column(Integer, ForeignKey('content_chunks.chunk_id', ondelete='CASCADE'), unique=True)

    embedding = Column(Vector(1024), nullable=False)

    model_name = Column(String(255), nullable=False)
    created_at = Column(DateTime, nullable=False, server_default='now()')
    
    chunk = relationship(&quot;ContentChunk&quot;, back_populates=&quot;embedding&quot;)
    
    def __repr__(self):
        return f&quot;&amp;lt;Embedding(embedding_id='{self.embedding_id}', chunk_id={self.chunk_id})&amp;gt;&quot;
        

async def init_db():
    &quot;&quot;&quot;데이터베이스 초기화&quot;&quot;&quot;
    async with async_engine.begin() as conn:
        # pgvector 확장 활성화
        try:
            await conn.execute(text(&quot;CREATE EXTENSION IF NOT EXISTS vector&quot;))
            logger.info(&quot;pgvector 확장이 활성화되었습니다.&quot;)
        except Exception as e:
            logger.warning(f&quot;pgvector 확장 활성화 중 오류 발생: {e}&quot;)
        
        # 테이블 생성
        await conn.run_sync(Base.metadata.create_all)&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;/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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 티스토리 블로그 크롤링 및 PostgreSQL 데이터베이스 저장&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블을 구성했으니, 데이터를 넣어야겠죠? 블로그 Q&amp;amp;A 챗봇을 만들기 위해서는 당연히 기본적으로 블로그 글 내용이 필요할겁니다. 저는 제 티스토리 블로그(지금 이 블로그입니다.) 글을 기준으로 크롤링을 진행했습니다.&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;클로링은 Python의 beautifulsoup4을 사용했으며, 아래와 같이 파이썬 코드를 구성하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1746265969158&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;url = f&quot;https://lsjsj92.tistory.com/{post_number}&quot;
# 이미 크롤링된 URL인지 확인
if check_exists_func:
    if await check_exists_func(url):
        print(f&quot;포스트 {post_number} (URL: {url})는 이미 크롤링되었습니다. 건너뜁니다.&quot;)
        return None

try:
    res = requests.get(url)
    if res.status_code == 404:
        return None  # 게시글이 존재하지 않음
    soup = BeautifulSoup(res.text, 'html.parser')

    # 카테고리 추출
    category_element = soup.select_one('.area_title .tit_category a')
    category = category_element.text if category_element else &quot;카테고리 없음&quot;

    # 제목 추출
    title_element = soup.select_one('.area_title h3.tit_post')
    title = title_element.text if title_element else &quot;제목 없음&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;이렇게 구성된 크롤링 코드를 python main.py와 같이 실행시키면 아래 사진과 같이 크롤링이 진행됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/efmoiT/btsNKs2ascj/6gLZxuYn305n0oq2x4KgEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/efmoiT/btsNKs2ascj/6gLZxuYn305n0oq2x4KgEk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2648&quot; data-origin-height=&quot;602&quot; data-filename=&quot;스크린샷 2025-05-03 오후 3.31.39.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/efmoiT/btsNKs2ascj/6gLZxuYn305n0oq2x4KgEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FefmoiT%2FbtsNKs2ascj%2F6gLZxuYn305n0oq2x4KgEk%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;2648&quot; height=&quot;602&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vPmIE/btsNJwLlciE/D2I0ZLjo2kmsBqYVJYdLh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vPmIE/btsNJwLlciE/D2I0ZLjo2kmsBqYVJYdLh0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2648&quot; data-origin-height=&quot;602&quot; data-filename=&quot;스크린샷 2025-05-03 오후 3.31.46.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vPmIE/btsNJwLlciE/D2I0ZLjo2kmsBqYVJYdLh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvPmIE%2FbtsNJwLlciE%2FD2I0ZLjo2kmsBqYVJYdLh0%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;2648&quot; height=&quot;602&quot;/&gt;&lt;/span&gt;&lt;/div&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;제가 지정한 url 범위에서 데이터를 하나씩 수집하고 그것이 완료되는 과정을 볼 수 있습니다.&amp;nbsp;&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-filename=&quot;스크린샷 2025-05-03 오후 3.31.55.png&quot; data-origin-width=&quot;2648&quot; data-origin-height=&quot;602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ch2xye/btsNK2B72gK/CgnmKcv5TvmTQzzTKs7Imk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ch2xye/btsNK2B72gK/CgnmKcv5TvmTQzzTKs7Imk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ch2xye/btsNK2B72gK/CgnmKcv5TvmTQzzTKs7Imk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fch2xye%2FbtsNK2B72gK%2FCgnmKcv5TvmTQzzTKs7Imk%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;2648&quot; height=&quot;602&quot; data-filename=&quot;스크린샷 2025-05-03 오후 3.31.55.png&quot; data-origin-width=&quot;2648&quot; data-origin-height=&quot;602&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-03 오후 3.37.53.png&quot; data-origin-width=&quot;3198&quot; data-origin-height=&quot;518&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dkV7Nx/btsNLcxMnc9/M0qczNlr02pUGhGvzBSLY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dkV7Nx/btsNLcxMnc9/M0qczNlr02pUGhGvzBSLY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dkV7Nx/btsNLcxMnc9/M0qczNlr02pUGhGvzBSLY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdkV7Nx%2FbtsNLcxMnc9%2FM0qczNlr02pUGhGvzBSLY0%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;3198&quot; height=&quot;518&quot; data-filename=&quot;스크린샷 2025-05-03 오후 3.37.53.png&quot; data-origin-width=&quot;3198&quot; data-origin-height=&quot;518&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;모든 크롤링 과정이 종료되었으면 위와 같이 마지막에 크롤링 완료가 나오게 해놨습니다. 그리고 실제 DB를 확인해보면 정상적으로 데이터가 저장이 되었음을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 새로 추가된 포스트가 몇 개인지, 기존에 수집한 포스팅은 몇 개인지 등도 체크하도록 해두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 데이터가 수집되었으면 이제 Q&amp;amp;A 챗봇을 만들 준비가 50%는 끝났다고 볼 수 있습니다!&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;3. 데이터 청킹(Chunking) 및 벡터(vector) 추출 후 저장&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 데이터 청킹(Chunking)하는 부분과 이 청킹된 데이터를 벡터로 추출해 PostgreSQL PGVector를 사용해서 저장하는 과정입니다.&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;3-1. 데이터 청킹 과정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;텍스트 chunking 과정은 다른 말로 텍스트 분할(text split) 과정이라고도 표현합니다. 저는 이 Text split 과정은 langchain을 이용해 진행했습니다. Langchain에서 제공해주는 텍스트 청킹은 다양한 방법이 있는데요. 저는 그 중 RecursiveCharacterTextSplitter( &lt;a href=&quot;https://python.langchain.com/docs/how_to/recursive_text_splitter/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://python.langchain.com/docs/how_to/recursive_text_splitter/&lt;/a&gt; )를 사용했습니다. 사용한 Python langchain 코드는 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1746266782594&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain.text_splitter import RecursiveCharacterTextSplitter
from config.settings import CHUNK_SIZE, CHUNK_OVERLAP


async def chunk_blog_post(post: BlogPost) -&amp;gt; List[int]:
    &quot;&quot;&quot;
    블로그 포스트를 청킹하고 데이터베이스에 저장합니다.
    RecursiveCharacterTextSplitter를 사용하여 자연스러운 분할점에서 텍스트를 청킹합니다.
    &quot;&quot;&quot;
    # 이미 청킹되었는지 확인
    if await is_post_chunked(post.post_id):
        print(f&quot;Post {post.post_id} has already been chunked.&quot;)
        return []
    
    # 텍스트 청킹
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=CHUNK_SIZE,
        chunk_overlap=CHUNK_OVERLAP,
        length_function=len,
        separators=[&quot;\n\n&quot;, &quot;\n&quot;, &quot;.&quot;, &quot; &quot;, &quot;&quot;]
    )
    
    # 청킹할 내용 준비
    content = post.content
    if not content:
        return []
    
    # 메타데이터 준비
    metadata = {
        &quot;title&quot;: post.title,
        &quot;url&quot;: post.url,
        &quot;publication_date&quot;: post.publication_date.isoformat() if post.publication_date else None,
    }
    
    # 청킹 수행 - RecursiveCharacterTextSplitter가 내부적으로 재귀적 분할을 처리
    chunks = text_splitter.create_documents([content], [metadata])
    chunk_ids = []
    
    # 청크 저장
    for i, chunk in enumerate(chunks):
        chunk_text = chunk.page_content
        
        # 청크 해시 생성
        chunk_hash = generate_chunk_hash(chunk_text)
        
        # 청크 저장
        chunk_id = await save_chunk(
            post_id=post.post_id,
            chunk_text=chunk_text,
            chunk_index=i,
            chunk_hash=chunk_hash,
            metadata=chunk.metadata
        )
        
        chunk_ids.append(chunk_id)&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;RecursiveCharacterTextAplitter를 사용해 텍스트 청킹을 진행하며, Chunk_size와 overlap을 기준으로 크기와 중복되는 영역을 설정하였습니다. 그리고 이렇게 분리된 텍스트는 chunking content_chunking에 저장되도록 구성해놨습니다.&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;3-2. 텍스트 임베딩 벡터 추출 및 벡터데이터베이스 저장 과정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 chunking된 텍스트를 기준으로 이제 텍스트 임베딩 벡터(Text embedding vector)를 추출하고 이를 embeddings 테이블에 저장합니다. 저는 embedding vector로 허깅페이스(huggingface)에 올려와있는 오픈된 모델을 사용했는데요. 그 중 nlpai-lab/KURE-v1 모델( &lt;a href=&quot;https://huggingface.co/nlpai-lab/KURE-v1&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://huggingface.co/nlpai-lab/KURE-v1&lt;/a&gt; ) 을 사용했습니다. 해당 모델은 KoE5 모델보다 긴 시퀀스 길이를 가지고 있으며, 차원수는 1024, 성능도 괜찮다고 알려진 모델입니다.&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;해당 모델을 사용하려면 sentence_transformer를 이용하면 됩니다. 아래는 제가 사용한 예제 코드입니다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1746269158544&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;EMBEDDING_MODEL_NAME = &quot;nlpai-lab/KURE-v1&quot;

# 모델 로드
model = None

def load_embedding_model():
    &quot;&quot;&quot;임베딩 모델을 로드합니다.&quot;&quot;&quot;
    global model
    if model is None:
        model = SentenceTransformer(EMBEDDING_MODEL_NAME)

def create_embedding(text: str) -&amp;gt; List[float]:
    &quot;&quot;&quot;텍스트에 대한 임베딩 벡터를 생성합니다.&quot;&quot;&quot;
    # 모델이 로드되지 않았다면 로드
    if model is None:
        load_embedding_model()
    
    # SentenceTransformer를 사용한 임베딩 생성
    embedding_vector = model.encode(text).tolist()
    
    return embedding_vector

async def embed_chunk(chunk: ContentChunk) -&amp;gt; Optional[str]:
    &quot;&quot;&quot;청크에 대한 임베딩을 생성하고 저장합니다.&quot;&quot;&quot;
    # 이미 임베딩이 있으면 건너뛰기
    if chunk.embedding_id:
        return chunk.embedding_id
    
    # 임베딩 생성
    embedding_vector = create_embedding(chunk.chunk_text)
    if embedding_vector is None:
        return None
    
    # 임베딩 저장
    embedding_id = await save_embedding(
        chunk_id=chunk.chunk_id,
        embedding_vector=embedding_vector,
        model_name=EMBEDDING_MODEL_NAME
    )
    
    return embedding_id&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;미리 임베딩 모델 이름 KURE-v1을 설정해두고, sentence_transformer를 이용해 모델을 load합니다. 이 load된 model을 활용해서 model.encode(text)를 통해 텍스트에서 임베딩 벡터를 추출할 수 있는데요. chunking된 텍스트를 가지고 온 후 임베딩 모델을 활용해 벡터를 추출한 뒤, 추출된 정보를 embeddings&amp;nbsp; 테이블에 저장하는 프로세스로 진행됩니다. 이때 chunk_id도 같이 저장하여 어떤 chunk에 해당되는 임베딩 벡터 정보인지 확인할 수 있도록 foreign key 값으로 설정해주었습니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-03 오후 3.39.16.png&quot; data-origin-width=&quot;3346&quot; data-origin-height=&quot;518&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beyw84/btsNJsIYcY4/zfRkK6kiCq5mW29AM7V9Z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beyw84/btsNJsIYcY4/zfRkK6kiCq5mW29AM7V9Z1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beyw84/btsNJsIYcY4/zfRkK6kiCq5mW29AM7V9Z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbeyw84%2FbtsNJsIYcY4%2FzfRkK6kiCq5mW29AM7V9Z1%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;3346&quot; height=&quot;518&quot; data-filename=&quot;스크린샷 2025-05-03 오후 3.39.16.png&quot; data-origin-width=&quot;3346&quot; data-origin-height=&quot;518&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2025-05-03 오후 3.39.24.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2KjaZ/btsNJuGMOPZ/cXO34iFjG0F1WzoAHbEcEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2KjaZ/btsNJuGMOPZ/cXO34iFjG0F1WzoAHbEcEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2KjaZ/btsNJuGMOPZ/cXO34iFjG0F1WzoAHbEcEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2KjaZ%2FbtsNJuGMOPZ%2FcXO34iFjG0F1WzoAHbEcEk%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;3000&quot; height=&quot;286&quot; data-filename=&quot;edited_스크린샷 2025-05-03 오후 3.39.24.png&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;286&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;로그를 확인한 결과 completed embedding이 나오면서 모든 chunk가 수행이 완료된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccFkDT/btsNJYmYuSJ/ztkJtaPiEEZNTE24hZq0KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccFkDT/btsNJYmYuSJ/ztkJtaPiEEZNTE24hZq0KK/img.png&quot; data-origin-width=&quot;3254&quot; data-origin-height=&quot;1532&quot; data-is-animation=&quot;false&quot; data-filename=&quot;스크린샷 2025-05-03 오후 3.41.57.png&quot; style=&quot;width: 50.945%; margin-right: 10px;&quot; data-widthpercent=&quot;51.54&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccFkDT/btsNJYmYuSJ/ztkJtaPiEEZNTE24hZq0KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccFkDT%2FbtsNJYmYuSJ%2FztkJtaPiEEZNTE24hZq0KK%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;3254&quot; height=&quot;1532&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0jPlP/btsNJEh1U3b/YpFGvS2kL6w3JOkTbVbtb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0jPlP/btsNJEh1U3b/YpFGvS2kL6w3JOkTbVbtb1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;614&quot; data-filename=&quot;스크린샷 2025-05-03 오후 3.42.09.png&quot; style=&quot;width: 47.8922%;&quot; data-widthpercent=&quot;48.46&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0jPlP/btsNJEh1U3b/YpFGvS2kL6w3JOkTbVbtb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0jPlP%2FbtsNJEh1U3b%2FYpFGvS2kL6w3JOkTbVbtb1%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;1226&quot; height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;/div&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;또한, 실제 DB를 확인해보면 왼쪽 사진과 같이 블로그 데이터가 chunking되어 저장된 것을 확인할 수 있습니다. 그리고 오른쪽 사진은 chunking을 수행했는지 유무를 체크하는 DB인데요. 정상적으로 데이터가 체크가 된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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. FastAPI를 이용한 Ollama LLM 통신&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Q&amp;amp;A 챗봇 RAG 구축이 80% 완료되었습니다. 앞선 과정을 정리하자면, 티스토리에서 블로그 글을 크롤링한 후 저장하였고, 그 저장된 데이터를 본문을 기준으로 chunking(text split)을 진행하였으며, chunking된 text를 huggingface embedding model을 활용해 text embedding vector를 추출한 뒤 저장하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 RAG의 역할을 수행하는 LLM을 붙이면 되는데요. 저는 Ollama를 활용해서 간단히 local LLM 환경으로 동작시켰습니다.&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;저는 LLM 모델로 llama3.2-bllossom-3b 모델( &lt;a href=&quot;https://huggingface.co/Bllossom/llama-3.2-Korean-Bllossom-3B&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://huggingface.co/Bllossom/llama-3.2-Korean-Bllossom-3B&lt;/a&gt; )을 사용하였습니다. 또한, 요청을 하는 클라이언트가 바로 Ollama와 통신하는 것이 아니라, 중간에 FastAPI 서버를 두어, FastAPI가 Ollama와 통신하도록 구성했습니다. 제가 구성한 Python FastAPI 코드는 아래 예시와 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1746271245172&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;router = APIRouter()

@router.post(&quot;/query&quot;, response_model=QueryResponse)
async def query_blog(
    request: QueryRequest, 
    session: AsyncSession = Depends(get_db_session)
):
    &quot;&quot;&quot;블로그 내용에 대한 질문에 답변합니다.&quot;&quot;&quot;
    try:
        # 유사한 청크 검색
        search_results = await search_similar_chunks(
            query=request.query,
            session=session, 
            top_k=request.top_k, 
            threshold=request.threshold
        )
        
        # 검색 결과 포맷팅
        formatted_context = await format_search_results(search_results)
        
        # 관련 정보 유무 확인
        has_relevant_info = formatted_context is not None
        
        # LLM으로 응답 생성
        response, success = await generate_response(
            query=request.query,
            context=formatted_context
        )
        
        return QueryResponse(
            response=response,
            has_relevant_info=has_relevant_info if success else False,
            search_results=search_results if (has_relevant_info and success) else None
        )
        
    except Exception as e:
        # logger.error(f&quot;쿼리 처리 중 예상치 못한 오류 발생: {str(e)}&quot;)
        # 최종 폴백 응답
        return QueryResponse(
            response=&quot;죄송합니다. 요청을 처리하는 중에 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.&quot;,
            has_relevant_info=False,
            search_results=None
        )&lt;/code&gt;&lt;/pre&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-filename=&quot;스크린샷 2025-05-03 오후 3.49.59.png&quot; data-origin-width=&quot;1530&quot; data-origin-height=&quot;467&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/be8B5B/btsNJomssSz/xKzyU3dcHAkQto6kwQtme0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/be8B5B/btsNJomssSz/xKzyU3dcHAkQto6kwQtme0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/be8B5B/btsNJomssSz/xKzyU3dcHAkQto6kwQtme0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbe8B5B%2FbtsNJomssSz%2FxKzyU3dcHAkQto6kwQtme0%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;1530&quot; height=&quot;467&quot; data-filename=&quot;스크린샷 2025-05-03 오후 3.49.59.png&quot; data-origin-width=&quot;1530&quot; data-origin-height=&quot;467&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;이 FastAPI 코드는 사용자의 질문(query, request)이 들어오면&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. 가장 먼저, 질문을 벡터로 변환한 뒤 가장 유사한 chunk를 찾습니다. 이때, top k개수 만큼 찾으며, threshold 이상의 유사도를 가진 chunk를 찾습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 결과를 LLM이 읽을 수 있게 format을 변경합니다. format_search_result라는 함수에서 진행하며, 이 함수에서는 단순히 LLM이 읽을 수 있도록 markdown 형식으로 변환하는 구조를 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. generate_response 함수를 통해 Ollama와 통신할 수 있도록 합니다. 이때, 2번 과정에서 만든 정보를 함께 Ollama에게 제공하여 Ollama에 올라가서 서빙되는 LLM이 응답을 생성할 수 있도록 합니다.&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;5. Streamlit을 활용하여 Q&amp;amp;A Chatbot 구현&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 이제 LLM 연동까지 끝냈으니 Q&amp;amp;A Chatbot 화면만 구현하면 되겠죠? 챗봇 화면은 그렇게 어렵지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 사용자의 질문을 받을 수 있는 챗봇 형태의 UI를 python streamlit 등을 활용해 구성하면 되고, FastAPI server에 정보를 request한 후 response 받은 정보를 화면에 뿌려주기만하면 됩니다.&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-filename=&quot;스크린샷 2025-05-03 오후 4.14.45.png&quot; data-origin-width=&quot;1275&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rrYb9/btsNLSlkjpL/ugS14iuqRX1LOkyslUrs10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rrYb9/btsNLSlkjpL/ugS14iuqRX1LOkyslUrs10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rrYb9/btsNLSlkjpL/ugS14iuqRX1LOkyslUrs10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrrYb9%2FbtsNLSlkjpL%2FugS14iuqRX1LOkyslUrs10%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;666&quot; height=&quot;312&quot; data-filename=&quot;스크린샷 2025-05-03 오후 4.14.45.png&quot; data-origin-width=&quot;1275&quot; data-origin-height=&quot;598&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;위 사진은 제가 구성한 Chatbot 형식의 UI를 가진 Python streamlit 화면입니다. 질문을 입력하도록 되어있고, 이러한 Q&amp;amp;A가 계속 반본적으로 이어질 수 있도록 수행합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, 사용자가 어떤 질의사항이 있다고 하면 질문을 입력하는 text input 란에 입력하면 되는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 제가 일전에 제 블로그에 업로드한 프롬프트 엔지니어링 기법을 검색하기 위해서 '프롬프트 기법 중 ReAct 프롬프팅이나 one-shot, few-shot prompt에 대해서 소개한 자료가 있을까?'를 검색해서 물어보았습니다.&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;이제 저 질문을 FastAPI 서버에서 받고 아래와 같은 프로세스로 응답을 처리합니다.&lt;/p&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;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;'프롬프트 기법 중 ReAct 프롬프팅이나 one-shot, few-shot prompt에 대해서 소개한 자료가 있을까?' 질문이 request로 들어옵니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;2. request로 들어온 텍스트를 embedding vector 모델( 임베딩을 수행했던 모델과 동일한 모델 )을 활용해 벡터로 변환합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;3. PostgreSQL의 PGVector를 활용해 저장된 embeddings 테이블에서 코사인 유사도로 유사도 검색을 수행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;4. 유사도가 높은 chunk_id에 따라 post_id까지 join하여 원본 블로그 글을 가져옵니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;5. 해당 글의 정보를 LLM에게 넘겨주어, 응답을 생성하게 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;6. reference 자료와 llm의 결과를 client에게 넘겨줍니다.(response)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;7. 클라이언트는 해당 값을 받아 화면에 출력합니다.&lt;/span&gt;&lt;/p&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-03 오후 4.27.15.png&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;882&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5rcNA/btsNKx3ukco/b08bAnfeSpBpuDSECL2cz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5rcNA/btsNKx3ukco/b08bAnfeSpBpuDSECL2cz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5rcNA/btsNKx3ukco/b08bAnfeSpBpuDSECL2cz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5rcNA%2FbtsNKx3ukco%2Fb08bAnfeSpBpuDSECL2cz1%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;650&quot; height=&quot;422&quot; data-filename=&quot;스크린샷 2025-05-03 오후 4.27.15.png&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;882&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;위 사진은 제가 질문한 질의에 따라 LLM이 생성해준 결과가 streamlit 화면에 출력되는 사진입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 이전에 작성한 프롬프트 기법 글이 있고, 거기에 ReAct와 one-shot, few-shot과 관련된 글이 있기에 그 글들을 조합해 LLM이 응답을 생성해준 것입니다.&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-filename=&quot;스크린샷 2025-05-03 오후 6.46.30.png&quot; data-origin-width=&quot;1439&quot; data-origin-height=&quot;691&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7U0MB/btsNK3gKw1v/1jtrUBynglWh5Oue9XjsGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7U0MB/btsNK3gKw1v/1jtrUBynglWh5Oue9XjsGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7U0MB/btsNK3gKw1v/1jtrUBynglWh5Oue9XjsGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7U0MB%2FbtsNK3gKw1v%2F1jtrUBynglWh5Oue9XjsGK%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;698&quot; height=&quot;335&quot; data-filename=&quot;스크린샷 2025-05-03 오후 6.46.30.png&quot; data-origin-width=&quot;1439&quot; data-origin-height=&quot;691&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;또한 저는 위 사진처럼 각 chunk마다 참조한 원 본 글(레퍼런스 글, reference)가 나오도록 했습니다. 즉, 검색된 chunk text가 어디 블로그에 있는 것이고, 그 chunk가 무슨 내용인지 참조 정보로 보여주는 것이죠.&amp;nbsp;&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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은&amp;nbsp;Python을 활용해 내 블로그 Q&amp;amp;A 챗봇 RAG를 간단하게 만들어보았습니다. 벡터 데이터베이스로는 PostgreSQL PGVector를 사용했고 Python의 FastAPI, Langchain을 활용하였으며, LLM은 Ollama를 사용했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 블로그이지만 제 스스로 블로그 Q&amp;amp;A 챗봇이 필요해서 만들어보았는데요. 나름 쏠쏠하게 잘 쓰고 있습니다 ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러분들도 블로그를 하고 계시다면 한 번 만들어보시는 것은 어떠실까요?&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>chatbot</category>
      <category>fastapi</category>
      <category>langchain</category>
      <category>LLM</category>
      <category>Ollama</category>
      <category>pgvector</category>
      <category>PostgreSQL</category>
      <category>RAG</category>
      <category>streamlit</category>
      <category>챗봇</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/686</guid>
      <comments>https://lsjsj92.tistory.com/686#entry686comment</comments>
      <pubDate>Mon, 5 May 2025 09:38:04 +0900</pubDate>
    </item>
    <item>
      <title>Ollama LLM 스트리밍(streaming) 응답 받는 방법 - Ollama 실시간 응답 받기(Feat. Streamlit)</title>
      <link>https://lsjsj92.tistory.com/685</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 Local 환경에서 LLM을 실행시킬 때 많이 활용하는 Ollama를 스트리밍(streaming) 형태로 LLM의 응답(response)를 받는 방법에 대해서 정리한 포스팅입니다. Ollama에게 직접 request 할 때와, Python requests를 이용한 방법 그리고 PoC(Proof-of-Concept)으로 많이 활용하는 Python streamlit으로 웹 페이지를 만들었을 때 활용하는 방법을 기준으로 설명합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ollama란 무엇인지는 본 포스팅에서 소개하지 않습니다. LLM을 로컬 환경에서 실행하고 서버 형태로도 배포 가능한 Ollama에 대해서 궁금하신 분들은 제 이전 포스팅이나, 다른 글들을 참고하시길 바랍니다.&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;- Ollama란?: &lt;a href=&quot;https://lsjsj92.tistory.com/666&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/666&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1745582942401&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;Ollama 사용법 - 개인 로컬 환경에서 LLM 모델 실행 및 배포하기&quot; data-og-description=&quot;포스팅 개요이번 포스팅은 대규모 언어 모델(Large Language Model, LLM)을 개인 로컬 환경에서 실행하고 배포하기 위한 Ollama 사용법을 정리하는 포스팅입니다. Ollama를 사용하면 유명한 모델들인 LLaMA&quot; data-og-host=&quot;lsjsj92.tistory.com&quot; data-og-source-url=&quot;https://lsjsj92.tistory.com/666&quot; data-og-url=&quot;https://lsjsj92.tistory.com/666&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bfIo8Y/hyYH7FZrsZ/xaSkfakaHrTCJGcUBknuc1/img.png?width=800&amp;amp;height=284&amp;amp;face=0_0_800_284,https://scrap.kakaocdn.net/dn/ZXTlD/hyYH7lHakZ/kuxLLnzSlqVKUk9AaEBvR0/img.png?width=800&amp;amp;height=284&amp;amp;face=0_0_800_284,https://scrap.kakaocdn.net/dn/s8sxS/hyYIfD4cqe/gSlfzcQ4ezpwmBKrt94Ri1/img.png?width=1906&amp;amp;height=1382&amp;amp;face=0_0_1906_1382&quot;&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/666&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://lsjsj92.tistory.com/666&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bfIo8Y/hyYH7FZrsZ/xaSkfakaHrTCJGcUBknuc1/img.png?width=800&amp;amp;height=284&amp;amp;face=0_0_800_284,https://scrap.kakaocdn.net/dn/ZXTlD/hyYH7lHakZ/kuxLLnzSlqVKUk9AaEBvR0/img.png?width=800&amp;amp;height=284&amp;amp;face=0_0_800_284,https://scrap.kakaocdn.net/dn/s8sxS/hyYIfD4cqe/gSlfzcQ4ezpwmBKrt94Ri1/img.png?width=1906&amp;amp;height=1382&amp;amp;face=0_0_1906_1382');&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;Ollama 사용법 - 개인 로컬 환경에서 LLM 모델 실행 및 배포하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 개요이번 포스팅은 대규모 언어 모델(Large Language Model, LLM)을 개인 로컬 환경에서 실행하고 배포하기 위한 Ollama 사용법을 정리하는 포스팅입니다. Ollama를 사용하면 유명한 모델들인 LLaMA&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;lsjsj92.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-23 오후 8.49.45.png&quot; data-origin-width=&quot;914&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dAGQGF/btsNBCXCbDT/PvJ8k8qeiVOKyZQYeq56t0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dAGQGF/btsNBCXCbDT/PvJ8k8qeiVOKyZQYeq56t0/img.png&quot; data-alt=&quot;Ollama + Streamlit 스트리밍 출력 결과 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dAGQGF/btsNBCXCbDT/PvJ8k8qeiVOKyZQYeq56t0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdAGQGF%2FbtsNBCXCbDT%2FPvJ8k8qeiVOKyZQYeq56t0%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;718&quot; height=&quot;542&quot; data-filename=&quot;스크린샷 2025-04-23 오후 8.49.45.png&quot; data-origin-width=&quot;914&quot; data-origin-height=&quot;690&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Ollama + Streamlit 스트리밍 출력 결과 예시&lt;/figcaption&gt;
&lt;/figure&gt;
&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;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 포스팅 개요에서도 말씀드렸듯, Ollama와 통신하여 LLM의 결과를 받아올 때 실시간 성으로 스트리밍(streaming) 형식으로 LLM의 응답을 받아오는 방법에 대해서 정리합니다. 총 아래와 같은 4개의 방법을 정리해보겠습니다.&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. Ollama와 Curl 명령어로 직접 통신할 때 스트리밍으로 받는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Python requests를 활용해서 Ollama API 호출할 때 스트리밍으로 받는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Python FastAPI를 활용해 Ollama와 API로 통신할 때 스트리밍으로 받는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Python Streamlit 화면에서 Ollama의 스트리밍 통신을 출력하는 방법&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-filename=&quot;스크린샷 2025-04-23 오후 8.43.27.png&quot; data-origin-width=&quot;1524&quot; data-origin-height=&quot;226&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clv0tD/btsNBKnLfsP/QKfe2YmwXwxkUJxKToAack/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clv0tD/btsNBKnLfsP/QKfe2YmwXwxkUJxKToAack/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clv0tD/btsNBKnLfsP/QKfe2YmwXwxkUJxKToAack/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fclv0tD%2FbtsNBKnLfsP%2FQKfe2YmwXwxkUJxKToAack%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;1524&quot; height=&quot;226&quot; data-filename=&quot;스크린샷 2025-04-23 오후 8.43.27.png&quot; data-origin-width=&quot;1524&quot; data-origin-height=&quot;226&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;하나씩 알아보겠습니다. 참고로 제가 Ollama에서 사용한 LLM 모델은 llama3.2-bllossom-3b-kr 모델입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Ollama와 Curl 명령어로 직접 통신할 때 스트리밍으로 받는 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ollama는 REST API를 통해 모델과 통신할 수 있는 엔드포인트(endpoint)를 제공합니다. API를 통해 LLM 모델에 쿼리(사용자 요청)을 보내고 응답을 받을 수 있는데, 이 과정에서 스트리밍 방식을 활용하면 실시간으로 응답을 확인할 수 있습니다.&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;가장 기본적인 방법은 curl의 -N 옵션을 사용해 스트리밍 요청을 보내는 것입니다. -N 옵션은 버퍼링을 비활성화하여 응답이 생성될 때마다 즉시 출력되도록 합니다. 아래는 ollama API에 streaming request를 보내는 curl&amp;nbsp; 명령어 예시(example)입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1745585300504&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;curl -N http://localhost:11434/api/generate \
  -H &quot;Content-Type: application/json&quot; \
  -d '{
    &quot;model&quot;: &quot;llama3.2-bllossom-3b-kr:latest&quot;,
    &quot;prompt&quot;: &quot;안녕하세요! 인공지능에 대해 간단히 설명해주세요.&quot;,
    &quot;stream&quot;: true
  }'&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;curl기본.gif&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUeafR/btsNBCXDkGx/bljURr9iZfpiFFe0N4FxW1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUeafR/btsNBCXDkGx/bljURr9iZfpiFFe0N4FxW1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUeafR/btsNBCXDkGx/bljURr9iZfpiFFe0N4FxW1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cUeafR/btsNBCXDkGx/bljURr9iZfpiFFe0N4FxW1/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;1080&quot; height=&quot;540&quot; data-filename=&quot;curl기본.gif&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 curl 명령어는 stream:true 파라미터로 ollama에게 응답을 스트리밍 형태로 반환하도록 요청합니다. 실제 수행 결과는 위 gif 사진과 같이 ollama에서 API를 제공하고 있는 LLM 모델 결과가 출력되는 것을 확인할 수 있을 것입니다. 그러나, 이 방식으로 받은 출력은 위 예시를 보시면 아시겠지만 굉장히 가독성이 떨어집니다. 왜냐하면 JSON 형태로 반환되기 때문인데요. 이는 각 토큰(token)이 생성될 때마다 별도의 JSON 객체로 반환되기 때문입니다. 실제로 보면 모델 정보, 생성 시간, 응답 텍스트, 완료 여부 등 다양한 메타데이터가 포함되어 있어 사람이 읽기는 가독성이 떨어지죠.&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;동일하게 curl 명령어로 수행할 때 아래와 같이 수정할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1745585821780&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;curl -sN http://localhost:11434/api/generate \
  -H &quot;Content-Type: application/json&quot; \
  -d '{
    &quot;model&quot;: &quot;llama3.2-bllossom-3b-kr:latest&quot;,
    &quot;prompt&quot;: &quot;안녕하세요! 인공지능에 대해 간단히 설명해주세요.&quot;,
    &quot;stream&quot;: true
  }' | while IFS= read -r line; do
    response=$(echo &quot;$line&quot; | grep -o '&quot;response&quot;:&quot;[^&quot;]*&quot;' | sed 's/&quot;response&quot;:&quot;//;s/&quot;$//')
    printf &quot;%s&quot; &quot;$response&quot;
done&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 명령어는 다음과 같이 설명할 수 있는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. -s 옵션은 curl의 진행 정보를 숨겨 출력을 깔끔하게 보여줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. -N 옵션은 앞서 설명한 것처럼 버퍼링을 비활성화 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 파이프(pipe, | )이후의 while 루프는 각 줄을 순차적으로 처리하도록 해줍니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. while IFS= read -r line 의 의미는 입력을 한 줄씩 읽는다는 의미입니다. IFS=는 입력 필드 구분자를 비활성화하여 공백을 포함한 전체 줄을 보존하도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. grep -o '&quot;response&quot;:&quot;[^&quot;]*&quot;'는 JSON에서 응답 테스트만 추출하도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. sed 's/&quot;response&quot;:&quot;//;s/&quot;$//'는 추출된 문자열에서 따옴표와 필드 이름을 제거합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;curl-응용.gif&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zY78C/btsNz4nGP1a/iBkuu8UMclp5E2RO23xJJ1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zY78C/btsNz4nGP1a/iBkuu8UMclp5E2RO23xJJ1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zY78C/btsNz4nGP1a/iBkuu8UMclp5E2RO23xJJ1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/zY78C/btsNz4nGP1a/iBkuu8UMclp5E2RO23xJJ1/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;1080&quot; height=&quot;540&quot; data-filename=&quot;curl-응용.gif&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 curl 명령어 수행 결과는 위 사진과 같습니다. 첫 번째 curl 명령어와 다르게 JSON 표현이 없어지고 깔끔하게 텍스트만 출력되는 것을 확인할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;2. Python requests를 활용해서 Ollama API 호출할 때 스트리밍으로 받는 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 살펴본 curl&amp;nbsp; 명령어를 이용한 방식은 터미널에서 빠르게 테스트하기에 유용하지만, 더 복잡한 애플리케이션을 개발하거나 Python 환경에서 작업할 때는 Python의 requests 라이브러리를 활용하는 것이 더 편리합니다. Python을 통해 Ollama API를 호출하고 응답을 처리하는 방법에 대해 알아보겠습니다.&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;다음 Python 코드는 requests 라이브러리를 이용하여 Ollama API와 통신하는 예제 코드입니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1745632535750&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import requests
import json
import sys

def stream_ollama_response(prompt, model=&quot;llama3.2-bllossom-3b-kr:latest&quot;, api_url=&quot;http://localhost:11434/api/generate&quot;):
    &quot;&quot;&quot;
    Stream responses from an Ollama model
    
    Args:
        prompt (str): The input text to send to the model
        model (str): The Ollama model to use
        api_url (str): The Ollama API URL
    &quot;&quot;&quot;
    # Prepare the request payload
    payload = {
        &quot;model&quot;: model,
        &quot;prompt&quot;: prompt,
        &quot;stream&quot;: True  # Enable streaming
    }
    
    print(&quot;\nStreaming response from model:&quot;, model)
    print(&quot;-&quot; * 50)
    
    # Make the request with streaming enabled
    with requests.post(api_url, json=payload, stream=True) as response:
        if response.status_code != 200:
            print(f&quot;Error: Received status code {response.status_code}&quot;)
            print(response.text)
            return
        
        # Process the streaming response
        full_response = &quot;&quot;
        for line in response.iter_lines():
            if line:
                # Decode the JSON line
                try:
                    json_data = json.loads(line.decode('utf-8'))
                    
                    # Extract and print the response chunk
                    if 'response' in json_data:
                        chunk = json_data['response']
                        sys.stdout.write(chunk)
                        sys.stdout.flush()
                        full_response += chunk
                    
                    # Check if this is the final response
                    if json_data.get('done', False):
                        break
                        
                except json.JSONDecodeError as e:
                    print(f&quot;Error decoding JSON: {e}&quot;)
                    print(f&quot;Received data: {line.decode('utf-8')}&quot;)
        
        print(&quot;\n&quot; + &quot;-&quot; * 50)
        return full_response

def main():
    # Constants
    OLLAMA_MODEL = &quot;llama3.2-bllossom-3b-kr:latest&quot;
    OLLAMA_API_URL = &quot;http://localhost:11434/api/generate&quot;
    
    # Get user input or use a default prompt
    if len(sys.argv) &amp;gt; 1:
        user_prompt = &quot; &quot;.join(sys.argv[1:])
    else:
        user_prompt = input(&quot;Enter your prompt (or press Enter for a default Korean prompt): &quot;)
        if not user_prompt:
            user_prompt = &quot;안녕하세요! 인공지능에 대해 간략하게 설명해주세요.&quot;
    
    # Stream the response
    stream_ollama_response(user_prompt, OLLAMA_MODEL, OLLAMA_API_URL)

if __name__ == &quot;__main__&quot;:
    main()&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;이 코드에서는 POST 요청을 보내면서 Ollama API와 통신하는데요. 이때 stream=True 파라미터를 설정하여 응답이 오는 대로 실시간 스트리밍 처리를 할 수 있게 합니다. 또한, 돌아오는 데이터가 JSON 형식으로 돌아오다보니, JSON 형식으로 처리를 하게 되는데요. json_data['response']에 실제 응답이 들어있으므로, 실제 텍스트 응답을 추출하니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 sys.stdout.write(chunk)와 sys.stdout.flush()를 통해 응답을 즉시 콘솔에 출력하도록 코드를 구성하였습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 Python 코드를 실행하면 아래와 같이 결과가 나오게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ollama-directpy실행.gif&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBdgl9/btsNAJXB1kA/LpkxP4l19mTSEQGxDlXdk0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBdgl9/btsNAJXB1kA/LpkxP4l19mTSEQGxDlXdk0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBdgl9/btsNAJXB1kA/LpkxP4l19mTSEQGxDlXdk0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cBdgl9/btsNAJXB1kA/LpkxP4l19mTSEQGxDlXdk0/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;1080&quot; height=&quot;309&quot; data-filename=&quot;ollama-directpy실행.gif&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;309&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;스트리밍 형식으로 응답이 나오는 것을 확인할 수 있습니다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3. Python FastAPI를 활용해 Ollama와 API로 통신할 때 스트리밍으로 받는 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지는 Ollama API와 직접 통신하는 방법을 알아보았습니다. 그러나, 실제 서비스를 구축할 때는 중간 API 서버를 두어 클라이언트와 Ollama 사이의 통신을 관리하는 형태로도 구축할 수 있는데요. 이번에는 Python의 FastAPI 프레임워크를 사용하여 중간에 API 서버를 구축하고 이를 통해 Ollama와 스트리밍 방식으로 통신하는 방법을 알아보겠습니다. 아래는 FastAPI를 활용한 스트리밍 API 서버 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1745635420461&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
import httpx
import json

app = FastAPI()

OLLAMA_API_URL = &quot;http://localhost:11434/api/generate&quot;
OLLAMA_MODEL = &quot;llama3.2-bllossom-3b-kr:latest&quot;  # 예시 모델명

class PromptRequest(BaseModel):
    prompt: str
    model: str = None  # 선택적 모델 지정 가능

@app.post(&quot;/generate-stream&quot;)
async def generate_stream(request: PromptRequest):
    # 요청에서 모델을 지정했으면 해당 모델 사용, 아니면 기본 모델 사용
    model = request.model if request.model else OLLAMA_MODEL
    
    payload = {
        &quot;model&quot;: model,
        &quot;prompt&quot;: request.prompt,
        &quot;stream&quot;: True
    }

    async def event_stream():
        try:
            async with httpx.AsyncClient(timeout=None) as client:
                async with client.stream(&quot;POST&quot;, OLLAMA_API_URL, json=payload) as response:
                    if response.status_code != 200:
                        error_content = await response.aread()
                        yield f&quot;오류 발생: {error_content.decode('utf-8')}&quot;
                        return
                    
                    async for line in response.aiter_lines():
                        if line.strip():  # 빈 줄 제거
                            try:
                                data = json.loads(line)
                                content = data.get(&quot;response&quot;, &quot;&quot;)
                                if content:
                                    yield content
                                    
                                # 응답 완료 여부 확인
                                if data.get(&quot;done&quot;, False):
                                    break
                                    
                            except json.JSONDecodeError:
                                continue
        except Exception as e:
            yield f&quot;스트리밍 처리 중 오류 발생: {str(e)}&quot;

    return StreamingResponse(event_stream(), media_type=&quot;text/plain&quot;)

# 상태 확인 엔드포인트 추가
@app.get(&quot;/health&quot;)
async def health_check():
    return {&quot;status&quot;: &quot;ok&quot;, &quot;model&quot;: OLLAMA_MODEL}&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item dable&quot; style=&quot;height: 250px;&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;300x250&lt;/div&gt;
    &lt;div id=&quot;dablewidget_Pl1aE8lE&quot; data-widget_id=&quot;Pl1aE8lE&quot;&gt;
      &lt;script&gt;(function(d,a,b,l,e,_) {
    if(d[b]&amp;&amp;d[b].q)return;d[b]=function(){(d[b].q=d[b].q||[]).push(arguments)};e=a.createElement(l);
    e.async=1;e.charset='utf-8';e.src='//static.dable.io/dist/plugin.min.js';
    _=a.getElementsByTagName(l)[0];_.parentNode.insertBefore(e,_);
    })(window,document,'dable','script');
dable('setService', 'lsjsj92.tistory.com');
dable('sendLogOnce');
dable('renderWidget', 'dablewidget_Pl1aE8lE', {ignore_items: true});&lt;/script&gt;
    &lt;/div&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;이 FastAPI 코드는 클라이언트의 요청을 받아 Ollama API로 전달하고 Ollama의 응답을 스트리밍 방식으로 클라이언트에게 전달하는 중개 역할을 수행합니다. 위 코드의 핵심을 정리하자면&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;- API 엔드포인트 생성: /generate-stream 엔드포인트를 통해 사용자의 프롬프트를 받습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- StreamingResponse를 사용하여 클라이언트에게 스트리밍 방식으로 응답을 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- httpx 라이브러리의 비동기 HTTP 클라이언트를 사용하여 Olllama API와 비동기 통신을 구현합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 핵심 적인 부분은 event_stream 함수로, 이 함수가 Ollama API의 응답을 실시간으로 처리하여 클라이언트에게 스트리밍합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- async for line in response.aiter_lines()를 통해 Ollama의 응답을 한 줄씩 비동기로 읽어오고 필요한 데이터만 추출하여 클라이언트에게 전달합니다.&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;위 FastAPI 서버를 실행하면 아래와 같이 정상적으로 실행이 될탠데요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tjV0B/btsNAWvxPsx/WOmMl5pgf22RuQv8KpJgiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tjV0B/btsNAWvxPsx/WOmMl5pgf22RuQv8KpJgiK/img.png&quot; data-origin-width=&quot;1258&quot; data-origin-height=&quot;448&quot; data-filename=&quot;스크린샷 2025-04-23 오후 8.43.29.png&quot; data-is-animation=&quot;false&quot; width=&quot;750&quot; height=&quot;267&quot; style=&quot;width: 45.7593%; margin-right: 10px;&quot; data-widthpercent=&quot;46.3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tjV0B/btsNAWvxPsx/WOmMl5pgf22RuQv8KpJgiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtjV0B%2FbtsNAWvxPsx%2FWOmMl5pgf22RuQv8KpJgiK%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;1258&quot; height=&quot;448&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dj4O2E/btsNAjdL3sY/49OKknOhQT3QIgoRwofZi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dj4O2E/btsNAjdL3sY/49OKknOhQT3QIgoRwofZi0/img.png&quot; data-origin-width=&quot;1140&quot; data-origin-height=&quot;350&quot; data-filename=&quot;스크린샷 2025-04-23 오후 8.43.39.png&quot; data-is-animation=&quot;false&quot; style=&quot;width: 53.0779%;&quot; data-widthpercent=&quot;53.7&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dj4O2E/btsNAjdL3sY/49OKknOhQT3QIgoRwofZi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdj4O2E%2FbtsNAjdL3sY%2F49OKknOhQT3QIgoRwofZi0%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;1140&quot; height=&quot;350&quot;/&gt;&lt;/span&gt;&lt;/div&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;저는 uvicorn app:app --port 8004 --reload와 같이 실행하여 8004번 포트에서 실행이 되도록 하였습니다. 만약, 호스트(host)까지 지정하고 싶다면 uvicorn app:app --host 0.0.0.0 --port 8004 --reload와 같이 실행하시면 됩니다.&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;이제, 저 API를 호출하여 실제 결과가 잘 나오는지 확인해보겠습니다. FastAPI 서버에 요청을 보내는 방법은 크게 두 가지가 있습니다.&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;&lt;b&gt;1. Curl 명령어 활용&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1745635926003&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;curl -N -X POST http://localhost:8004/generate-stream \
     -H &quot;Content-Type: application/json&quot; \
     -d '{&quot;prompt&quot;: &quot;안녕하세요?&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;이 명령어는 앞서 살펴본 것처럼 -N 옵션을 사용하여 버퍼링을 비활성화하고, 스트리밍 응답을 실시간으로 출력합니다. 이미 FastAPI 내부에서 깔끔하게 출력하도록 설정하였기 떄문에 위 curl 명령어로도 깔끔한 결과가 나옵니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ollama-curl실행.gif&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sI97K/btsNBIwKG78/TmCwxZGxmO416Gzf317bs1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sI97K/btsNBIwKG78/TmCwxZGxmO416Gzf317bs1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sI97K/btsNBIwKG78/TmCwxZGxmO416Gzf317bs1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/sI97K/btsNBIwKG78/TmCwxZGxmO416Gzf317bs1/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;1080&quot; height=&quot;309&quot; data-filename=&quot;ollama-curl실행.gif&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;309&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;curl 명령어를 실행하면 위와 같은 사진으로 결과가 나오는 것을 확인할 수 있습니다.&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;&lt;b&gt;2. Python 코드 활용&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1745636005948&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import asyncio
import httpx

async def main():
    url = &quot;http://localhost:8004/generate-stream&quot;
    payload = {
        &quot;prompt&quot;: &quot;안녕하세요? 제 이름은 이수진이라고 합니다.&quot;
    }

    async with httpx.AsyncClient(timeout=None) as client:
        async with client.stream(&quot;POST&quot;, url, json=payload) as response:
            # 청크 단위로 데이터를 처리 (바이트 단위)
            async for chunk in response.aiter_bytes():
                if chunk:
                    # 바이트를 문자열로 디코딩
                    text = chunk.decode('utf-8')
                    print(text, end=&quot;&quot;, flush=True)

asyncio.run(main())&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;이 Python 코드는 httpx 라이브러리를 사용하여 FastAPI 서버에 POST 요청을 보내고, 스트리밍 응답을 실시간으로 처리합니다. 이때, response.aiter_bytes를 통해 응답을 바이트 단위로 읽어오고, 이를 문자열로 변환하여 출력합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ollama-reqpy실행.gif&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8YyUO/btsNBy1YyTk/wcMtF8mFTxhuutWS05zAgK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8YyUO/btsNBy1YyTk/wcMtF8mFTxhuutWS05zAgK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8YyUO/btsNBy1YyTk/wcMtF8mFTxhuutWS05zAgK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/c8YyUO/btsNBy1YyTk/wcMtF8mFTxhuutWS05zAgK/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;1080&quot; height=&quot;309&quot; data-filename=&quot;ollama-reqpy실행.gif&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;309&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 실행하면 위 사진과 같은 결과가 나옵니다. 정상적으로 Ollama의 결과가 FastAPI를 거쳐 스트리밍 형식으로 잘 나오는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;4. Python Streamlit 화면에서 Ollama의 스트리밍 통신을 출력하는 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 CLI 환경과 API 서버를 통해 Ollama와 통신하는 방법을 알아봤습니다. 이제 Python을 활용한 개발 과정에서 PoC 등으로&amp;nbsp; 많이 활용하는 Streamlit을 활용해 Ollama의 스트리밍 통신을 할 수 있는 방법을 알아보겠습니다. Streamlit 라이브러리는 데이터 애플리케이션 등을 빠르게 개발하고 볼 수 있게 해주는 강력한 라이브러리인데요. 아마 많은 분들이 사용하고 계실거라 생각합니다. 이 Streamlit에서 Ollama에서 serving 중인 LLM과의 스트리밍 통신을 하여 웹 화면에 출력하는 과정을 보겠습니다. 아래는 그 Stsreamlit 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1745652480928&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import streamlit as st
import httpx
import asyncio
from typing import Iterator, Callable

# 페이지 설정
st.set_page_config(
    page_title=&quot;Ollama 스트리밍 채팅&quot;,
    layout=&quot;wide&quot;
)

# 앱 제목
st.title(&quot;Ollama 스트리밍 채팅 예제&quot;)

# API 설정
API_URL = &quot;http://localhost:8004/generate-stream&quot;  # FastAPI 서버 주소

# 세션 상태 초기화
if &quot;messages&quot; not in st.session_state:
    st.session_state.messages = []
if &quot;current_response&quot; not in st.session_state:
    st.session_state.current_response = &quot;&quot;
    
# 함수: 스트리밍 응답 생성
async def generate_streaming_response(prompt: str) -&amp;gt; Iterator[str]:
    &quot;&quot;&quot;Ollama API를 통해 스트리밍 응답을 비동기적으로 생성합니다.&quot;&quot;&quot;
    payload = {&quot;prompt&quot;: prompt}
    
    # 응답 초기화
    st.session_state.current_response = &quot;&quot;
    
    async with httpx.AsyncClient(timeout=None) as client:
        async with client.stream(&quot;POST&quot;, API_URL, json=payload) as response:
            async for chunk in response.aiter_bytes():
                if chunk:
                    text = chunk.decode('utf-8')
                    st.session_state.current_response += text
                    # 현재까지의 전체 응답 반환
                    yield st.session_state.current_response

# 함수: 비동기 결과를 Streamlit에서 처리
def stream_response(prompt: str, callback: Callable[[str], None]):
    &quot;&quot;&quot;비동기 스트리밍 응답을 Streamlit UI에 표시합니다.&quot;&quot;&quot;
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    
    # 응답 초기화
    st.session_state.current_response = &quot;&quot;
    
    async def process_response():
        async for response_text in generate_streaming_response(prompt):
            # 콜백 함수를 호출하여 UI 업데이트
            callback(response_text)
            # 작은 딜레이로 UI 업데이트 시간 확보
            await asyncio.sleep(0.00)
    
    # 비동기 처리 실행
    loop.run_until_complete(process_response())
    
    # 최종 응답 반환 (세션 상태에서 가져옴)
    return st.session_state.current_response

# 채팅 기록 표시
for message in st.session_state.messages:
    with st.chat_message(message[&quot;role&quot;]):
        st.markdown(message[&quot;content&quot;])

# 사용자 입력
user_input = st.chat_input(&quot;메시지를 입력하세요!&quot;)

if user_input:
    # 사용자 메시지 표시 및 저장
    with st.chat_message(&quot;user&quot;):
        st.markdown(user_input)
    st.session_state.messages.append({&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: user_input})
    
    # 응답 컨테이너 생성
    with st.chat_message(&quot;assistant&quot;):
        response_container = st.empty()
        
        # 스트리밍 응답 처리 및 UI 업데이트 함수
        def update_response(text):
            response_container.markdown(text)
        
        # 응답 생성 및 스트리밍
        final_response = stream_response(user_input, update_response)
        
        # 채팅 이력에 응답 저장
        if final_response and final_response.strip():
            st.session_state.messages.append({&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: final_response})
        
# 사이드바 정보
with st.sidebar:
    st.subheader(&quot;모델 정보&quot;)
    st.write(&quot;현재 모델: llama3.2-bllossom-3b-kr:latest&quot;)
    st.write(&quot;API 엔드포인트: &quot; + API_URL)&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;위 Streamlit 코드를 실행하면 하나의 간단하게 Ollama와 API 통신을 수행할 수 있는 웹 페이지를 실행시킬 수 있습니다. 이때, 저는 앞에서 실행시킨 FastAPI를 활용해서 Ollama와 통신하도록 했습니다. generate_streaming_response 함수는 비동기 방식으로 FastAPI 서버에 요청을 보내고 스트리밍 응답을 처리합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, stream_response 함수는 비동기 응답을 streamlit ui에 표시하기 위한 로직을 담고 있습니다. 위 streamlit을 실행시키면 아래와 같은 결과를 받을 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ollama 스트리밍 gif.gif&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dSWKYV/btsNz5fNhp1/MtAjUdiNrA9W0XmX831r1K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dSWKYV/btsNz5fNhp1/MtAjUdiNrA9W0XmX831r1K/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dSWKYV/btsNz5fNhp1/MtAjUdiNrA9W0XmX831r1K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/dSWKYV/btsNz5fNhp1/MtAjUdiNrA9W0XmX831r1K/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;1080&quot; height=&quot;608&quot; data-filename=&quot;ollama 스트리밍 gif.gif&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;608&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;원하는 메세지를 입력하면 Ollama와 API 통신을 하고, 그 결과를 스트리밍 형식으로 출력하는 것을 확인할 수 있습니다.&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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 LLM을 배포하고 serving하는 Ollama와 API 통신을 할 때 스트리밍(streaming) 형태로 데이터를 받아오는 방법에 대해서 알아봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도움이 되시길 바랍니다.&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>fastapi</category>
      <category>GenAI</category>
      <category>huggingface</category>
      <category>LLM</category>
      <category>NLP</category>
      <category>Ollama</category>
      <category>Python</category>
      <category>streaming</category>
      <category>스트리밍</category>
      <category>자연어처리</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/685</guid>
      <comments>https://lsjsj92.tistory.com/685#entry685comment</comments>
      <pubDate>Mon, 28 Apr 2025 09:49:39 +0900</pubDate>
    </item>
    <item>
      <title>프롬프트 엔지니어링이란? 효과적인 LLM 사용을 위한 프롬프트 작성 방법과 기법들</title>
      <link>https://lsjsj92.tistory.com/684</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 프롬프트 엔지니어링(Prompt Engineering)이라는 용어가 많이 언급되고 있습니다. 대규모 언어 모델(Large Language Models, LLM)을 효과적으로 활용하기 위해서는 프롬프트 설계가 중요한데요. 본 포스팅에서는 구글의 프롬프트 엔지니어링 백서(Prompt Engineering white paper)를 기반으로 프롬프트 엔지니어링이란 무엇인지, 프롬프트 엔지니어링의 개념들과 다양한 기법들, 그리고 최적의 결과를 얻기 위한 방법과 팁들을 정리해보겠습니다.&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;제가 참고한 Google의 Prompt Engineering 자료의 출처는 아래와 같으며, 추가로 참고한 자료의 리스트는 아래와 같습니다.&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;span style=&quot;color: #000000;&quot;&gt;&lt;a href=&quot;https://arxiv.org/pdf/2210.03629&quot;&gt;https://arxiv.org/pdf/2210.03629&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://arxiv.org/pdf/2203.11171&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/pdf/2203.11171&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;span style=&quot;color: #000000;&quot;&gt;&lt;a href=&quot;https://arxiv.org/pdf/2305.10601&quot;&gt;https://arxiv.org/pdf/2305.10601&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://arxiv.org/pdf/2201.11903&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/pdf/2201.11903&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://www.kaggle.com/whitepaper-prompt-engineering&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.kaggle.com/whitepaper-prompt-engineering&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1744887893417&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;Prompt Engineering&quot; data-og-description=&quot; &quot; data-og-host=&quot;www.kaggle.com&quot; data-og-source-url=&quot;https://www.kaggle.com/whitepaper-prompt-engineering&quot; data-og-url=&quot;https://www.kaggle.com/whitepaper-prompt-engineering&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cAtohQ/hyYFDLg3j5/aWNIXIxi8UnxImZSyPwBb0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/zOfPe/hyYH49j7wu/qVov5kYj5VPmvJpRQoVFwk/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://www.kaggle.com/whitepaper-prompt-engineering&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.kaggle.com/whitepaper-prompt-engineering&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cAtohQ/hyYFDLg3j5/aWNIXIxi8UnxImZSyPwBb0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/zOfPe/hyYH49j7wu/qVov5kYj5VPmvJpRQoVFwk/img.png?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;Prompt Engineering&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.kaggle.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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 본문&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.05.23.png&quot; data-origin-width=&quot;1682&quot; data-origin-height=&quot;1912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/laxrt/btsNo7x9Qtd/xdElZ4GHygOOUKrbXRqho0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/laxrt/btsNo7x9Qtd/xdElZ4GHygOOUKrbXRqho0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/laxrt/btsNo7x9Qtd/xdElZ4GHygOOUKrbXRqho0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flaxrt%2FbtsNo7x9Qtd%2FxdElZ4GHygOOUKrbXRqho0%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;548&quot; height=&quot;623&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.05.23.png&quot; data-origin-width=&quot;1682&quot; data-origin-height=&quot;1912&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;1. 프롬프트 엔지니어링이란 무엇인가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프롬프트 엔지니어링(Prompt Engineering)이라는 것은 이제 아마 많이들 익숙한 용어일 것입니다. 그럼에도, 프롬프트 엔지니어링에 대한 설명을 하는 자료이니 한 번 집고 넘어가겠습니다. 프롬프트 엔지니어링이란 LLM에 효과적인 입력을 설계하여 원하는 출력을 얻는 과정입니다. 언어 모델은 기본적으로 텍스트를 입력받아 다음에 올 토큰(단어 등)을 예측하는 방식으로 작동하는데요. 토큰 예측은 모델이 학습 중에 본 텍스트 간의 관계에 기반합니다.&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;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;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;p data-ke-size=&quot;size16&quot;&gt;이러한 프롬프트 설계는 작성을 위해 흔히 데이터 과학자(Data Scientist)나 머신러닝(Machine Learning) 전문가가 아니어도 됩니다. 누구나 프롬프트를 작성할 수 있는 것이죠. 그렇지만, 효과적인 프롬프트를 설계하는 것은 노력을 요구합니다.&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. LLM 출력 구성 설정하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 본격적으로 프롬프트 엔지니어링에 대해서 알아볼 것인데요. 그 전에, LLM의 출력 구성을 설정하는 방법에 대해서 본 whitepaper에서는 이야기합니다.&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;2.1 출력 길이 제어&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력 길이는 모델이 생성하는 토큰 수로 제어할 수 있습니다. 더 많은 토큰을 생성하면 더 많은 컴퓨팅 자원과 에너지가 소비되는데요. 그렇게 되면 응답 시간이 길어지고, OpenAI나 Claude, Gemini와 같은 모델을 사용할 경우 비용도 증가하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히, ReAct와 같은 기법을 사용할 때는 출력 길이 제한이 중요하다고 말합니다.&amp;nbsp;&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;2.2 샘플링 제어&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM은 실제로 단일 토큰을 예측하기보다, 각 토큰에 대한 확률을 예측합니다. 이러한 토큰 확률은 온도(Temperature)와 Top-K 그리고 Top-p을 통해 제어가 될 수 있습니다.&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;온도(Temperature)의 경우 토큰 선택의 '무작위(diverse or unexpected)'성 정도를 제어하는데요. 낮은 온도(0에 가까운)를 설정하면 예측 가능한(deterministic) 응답이 되며, 높은 값이면 예상치 못한(다양한) 값으로 설정되게 됩니다.&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;Top-K는 모델의 예측 분포에서 상위 K개의 가능성 높은 토큰만 선택하는 것이며, Top-K가 높을수록 출력이 더 창의적이고 다양해지는 것입니다. Top-P는 누적 확률이 특정 값(P)을 초과하지 않은 상위 토큰을 선택하는 것입니다.&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;style8&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 다양한 프롬프트(Prompt) 기법들&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 제로샷(Zero-shot) prompting&lt;/h3&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-filename=&quot;스크린샷 2025-04-17 오후 8.54.13.png&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;354&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GMoOc/btsNpaBHtZH/LO6RHF6xE7N7yzf53CCf01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GMoOc/btsNpaBHtZH/LO6RHF6xE7N7yzf53CCf01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GMoOc/btsNpaBHtZH/LO6RHF6xE7N7yzf53CCf01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGMoOc%2FbtsNpaBHtZH%2FLO6RHF6xE7N7yzf53CCf01%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;709&quot; height=&quot;313&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.54.13.png&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;354&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;영화 리뷰를 긍정적, 중립적 또는 부정적으로 분류하라는 프롬프트인데요. 지시어 다음에 바로 리뷰를 제공해주고 감정(Sentiment)를 표기하는 방식으로 매우 간단하게 동작되는 프롬프트 입니다.&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;3.2 원샷(one-host)과 few-shot prompting&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;one-shot 프롬프팅은 단일 예시를 제공하여 모델이 이를 참고하도록 합니다. 이와 유사하게 few-shot prompt는 예시를 여러게 제공하여 모델이 패턴을 더 정확하게 참조할 수 있도록 유도합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 E-book에서 예시로 든 one-shot, few-shot prompt는 아래와 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.54.29.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;341&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Rnj5C/btsNpyPzgkg/rBESA7JhKy4LuKwDyJriYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Rnj5C/btsNpyPzgkg/rBESA7JhKy4LuKwDyJriYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Rnj5C/btsNpyPzgkg/rBESA7JhKy4LuKwDyJriYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRnj5C%2FbtsNpyPzgkg%2FrBESA7JhKy4LuKwDyJriYk%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;528&quot; height=&quot;341&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.54.29.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;341&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;고객의 주문을 JSON 형태로 파싱하라는 메세지인데요. EXAMPLE처럼 예시를 제공하여 LLM이 예시를 보고 사용자가 원하는 task를 수행하도록 합니다. 본 책에서는 few-shot의 경우 보통 3~5개 정도 사용하는 것이 좋다고 이야기하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3 시스템, 역할(role), 맥락(context) prompting&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;시스템 프롬프팅(System prompting)&lt;/b&gt;&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;system prompt는 모델의 전반적인 전반적인 맥락과 목적을 설정하는 방법입니다. 모델이 수행해야 할 일종의 '큰 그림'을 정의하는 것이죠. 예를 들어, 언어 번역을 한다던가, 리뷰 분류를 수행한다 던가 등이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 책에서 제시한 system prompting 예시입니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.54.42.png&quot; data-origin-width=&quot;1180&quot; data-origin-height=&quot;341&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pAtxP/btsNl6TEk8J/LyOa9mq7VsjqeHY2xd74Rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pAtxP/btsNl6TEk8J/LyOa9mq7VsjqeHY2xd74Rk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pAtxP/btsNl6TEk8J/LyOa9mq7VsjqeHY2xd74Rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpAtxP%2FbtsNl6TEk8J%2FLyOa9mq7VsjqeHY2xd74Rk%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;1180&quot; height=&quot;341&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.54.42.png&quot; data-origin-width=&quot;1180&quot; data-origin-height=&quot;341&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;역할 프롬프팅(Role prompting)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;role prompting은 LLM 모델에게 일종의 역할을 부여하는 것인데요. 어떻게 보면 system prompting과 비슷해 보일 수 도 있습니다. 제가 이해한 system promting과 role prompting의 차이점은 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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 style=&quot;width: 12.093%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;분류&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.9303%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;시스템 프롬프팅(system prompting)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 46.9767%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;역할&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt; 프롬프팅(role prompting)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.093%; text-align: center;&quot;&gt;목적&lt;/td&gt;
&lt;td style=&quot;width: 40.9303%;&quot;&gt;모델의 전반적인 맥락과 작업 목적을 설정&lt;/td&gt;
&lt;td style=&quot;width: 46.9767%;&quot;&gt;모델에게 특정 역할이나 정체성을 부여&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.093%; text-align: center;&quot;&gt;범위&lt;/td&gt;
&lt;td style=&quot;width: 40.9303%;&quot;&gt;큰 그림을 정의하고 모델이 수행해야 할 기본 기능을 결정하도록 합니다.&lt;/td&gt;
&lt;td style=&quot;width: 46.9767%;&quot;&gt;특정 인물이나 직업의 관점에서 응답을 수행하도록 합니다. 시스템 프롬프팅보다는 조금 좁은 범위라고 볼 수 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.093%; text-align: center;&quot;&gt;집중하는 것&lt;/td&gt;
&lt;td style=&quot;width: 40.9303%;&quot;&gt;모델의 근본적인 능력과 작업 목적에 집중합니다.&lt;/td&gt;
&lt;td style=&quot;width: 46.9767%;&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;아래는 role prompting의 예시입니다. 예시를 보면, LLM에게 '여행 가이드'라는 역할을 부여하도록 합니다. 그리고 여행 가이드의 입장에서 여행지를 추천해달라는 것을 유도하죠.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.55.13.png&quot; data-origin-width=&quot;1357&quot; data-origin-height=&quot;223&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bS8IVc/btsNpsCag0I/XtE0veWXrAsG4HkLBjpt41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bS8IVc/btsNpsCag0I/XtE0veWXrAsG4HkLBjpt41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bS8IVc/btsNpsCag0I/XtE0veWXrAsG4HkLBjpt41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbS8IVc%2FbtsNpsCag0I%2FXtE0veWXrAsG4HkLBjpt41%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;1357&quot; height=&quot;223&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.55.13.png&quot; data-origin-width=&quot;1357&quot; data-origin-height=&quot;223&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.55.24.png&quot; data-origin-width=&quot;1369&quot; data-origin-height=&quot;271&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbyuLX/btsNpSNwY2S/KG8SRpjkBMCSB8x53ASL2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbyuLX/btsNpSNwY2S/KG8SRpjkBMCSB8x53ASL2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbyuLX/btsNpSNwY2S/KG8SRpjkBMCSB8x53ASL2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbyuLX%2FbtsNpSNwY2S%2FKG8SRpjkBMCSB8x53ASL2K%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;1369&quot; height=&quot;271&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.55.24.png&quot; data-origin-width=&quot;1369&quot; data-origin-height=&quot;271&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;맥락 프롬프팅(Context prompting)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 맥락(context) prompting 입니다. 이것은 현재 대화나 작업과 관련된 구체적인 세부 정보나 배경 정보 즉, 맥락(context) 정보를 제공하여 LLM이 task를 수행하도록 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.54.57.png&quot; data-origin-width=&quot;1325&quot; data-origin-height=&quot;298&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k5FjH/btsNp1pS3Nb/ksTuKeRy10wU3rpGuiK1QK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k5FjH/btsNp1pS3Nb/ksTuKeRy10wU3rpGuiK1QK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k5FjH/btsNp1pS3Nb/ksTuKeRy10wU3rpGuiK1QK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk5FjH%2FbtsNp1pS3Nb%2FksTuKeRy10wU3rpGuiK1QK%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;1325&quot; height=&quot;298&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.54.57.png&quot; data-origin-width=&quot;1325&quot; data-origin-height=&quot;298&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;3.4 Chain-of-Thought(CoT)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사고 연쇄(Chain of Thought, CoT)는 아마 많이 들어보셨을 법한 프롬프트 방법입니다. CoT prompt는 중간 추론 단계(reasoning step)을 생성하여 LLM의 추론 능력을 향상시키는 방법입니다. 이는 모델이 더 정확한 답변을 생성할 수 있도록 도와주죠. 이러한 CoT는 적은 노력으로도 충분히 높은 효과를 얻을 수 있다는 장점이 있으며, 모델의 응답과 reasoning 단계를 이해할 수 있는 해석 가능성도 제공해주는 장점도 있습니다. 단점도 존재합니다. CoT를 수행하면 더 많은 출력 토큰을 생성하기에 비용이 많이 발생할 수 있고 시간이 더 많이 소모 될 수 있습니다.&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;아래는 원본 Chain of Thought 논문에서 소개된 일반적인 프롬프트(Standard Prompting)과 Chain-of-Thought Prompting 방법의 비교 자료입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.55.40.png&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EYx7F/btsNpPQLZMg/ur7761D16qqkI1UK8SZkSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EYx7F/btsNpPQLZMg/ur7761D16qqkI1UK8SZkSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EYx7F/btsNpPQLZMg/ur7761D16qqkI1UK8SZkSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEYx7F%2FbtsNpPQLZMg%2Fur7761D16qqkI1UK8SZkSK%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;708&quot; height=&quot;340&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.55.40.png&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;340&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;결과를 보면 일반적인 프롬프트는 수식 계산이 틀렸지만, CoT를 활용한 프롬프트에서는 reasoning 단계를 포함시키기에 LLM이 올바른 대답을 제공할 수 있음을 확인할 수 있습니다.&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;본 prompt engineering whitepaper에서는 아래와 같이 CoT의 예시를 제공합니다. 마찬가리조 CoT를 사용하지 않았을 때 올바르지 않은 정답이 나오는 것을 보여주는데요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.55.50.png&quot; data-origin-width=&quot;947&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmZd6B/btsNpFt6gZf/QFoZXq9Krq3eFXApiMMO70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmZd6B/btsNpFt6gZf/QFoZXq9Krq3eFXApiMMO70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmZd6B/btsNpFt6gZf/QFoZXq9Krq3eFXApiMMO70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmZd6B%2FbtsNpFt6gZf%2FQFoZXq9Krq3eFXApiMMO70%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;947&quot; height=&quot;225&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.55.50.png&quot; data-origin-width=&quot;947&quot; data-origin-height=&quot;225&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;이를 CoT 프롬프트로 변경하면 올바른 정답을 제공하는 것을 확인할 수 있습니다. 아래 사진은 Chain of Thought를 사용하는 데 zero-shot 형태로 CoT를 사용하는 것을 보여줍니다. Zero shot으로 사용할 경우 'think step by step'의 단계별로 생각해보라는 지시 형태로 task 수행을 유도합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.56.05.png&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o7n5g/btsNpQPGW66/z0QsWUVyKPurLrwhan1ru1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o7n5g/btsNpQPGW66/z0QsWUVyKPurLrwhan1ru1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o7n5g/btsNpQPGW66/z0QsWUVyKPurLrwhan1ru1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo7n5g%2FbtsNpQPGW66%2Fz0QsWUVyKPurLrwhan1ru1%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;1366&quot; height=&quot;340&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.56.05.png&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;340&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;반면, CoT에 Few-shot을 적용한 것도 있습니다. 아래는 one-shot CoT의 예시입니다. Answer를 생성할 때 reasoning 단계의 예시를 하나 제공함으로써 똑같이 LLM이 추론을 수행하여 정답을 생성하도록 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.56.15.png&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;295&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cssKRh/btsNpEBYmBV/dc6KKnjohaJK45J4AiTpS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cssKRh/btsNpEBYmBV/dc6KKnjohaJK45J4AiTpS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cssKRh/btsNpEBYmBV/dc6KKnjohaJK45J4AiTpS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcssKRh%2FbtsNpEBYmBV%2Fdc6KKnjohaJK45J4AiTpS1%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;1366&quot; height=&quot;295&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.56.15.png&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;295&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;3.5 자기 일관성(Self-consistency)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대규모 언어 모델(Large Language Model, LLM)은 다양한 NLP 작업에서 성공을 보여주었는데요. 추론 능력(reasoning ability)는 모델 크기를 키우는 것만으로 극복할 수 없는 한계로 간주되었습니다. 자기 일관성이라고 불리우는 self-consistency 프롬프트 방법은 이 문제를 해결하기 위한 방법인데요. self-consistency는 샘플링과 다수결 투표를 결합해서 다양한 추론 경로(reasoning path)를 생성하고 가장 일관된 답변을 선택하는 방법입니다.&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;아래는 self-consistency의 예시인데요. 이메일 분류 시스템에서 이메일을 중요하다(Important) 또는 중요하지 않다(Not important)로 분류하는 경우입니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.56.29.png&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;369&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWMkUI/btsNqheWVLe/6ZEKddGG749xvnh9tK6MO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWMkUI/btsNqheWVLe/6ZEKddGG749xvnh9tK6MO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWMkUI/btsNqheWVLe/6ZEKddGG749xvnh9tK6MO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWMkUI%2FbtsNqheWVLe%2F6ZEKddGG749xvnh9tK6MO1%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;510&quot; height=&quot;369&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.56.29.png&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;369&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d7TQWa/btsNoZMALkO/BQRU3LDKNy7Ob0BqpQQe3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d7TQWa/btsNoZMALkO/BQRU3LDKNy7Ob0BqpQQe3K/img.png&quot; data-origin-width=&quot;1057&quot; data-origin-height=&quot;338&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.56.37.png&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.7516%; margin-right: 10px;&quot; data-widthpercent=&quot;53.37&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d7TQWa/btsNoZMALkO/BQRU3LDKNy7Ob0BqpQQe3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7TQWa%2FbtsNoZMALkO%2FBQRU3LDKNy7Ob0BqpQQe3K%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;1057&quot; height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dd9mRa/btsNpRVmeM6/CkRX6Xy6URaKYiLlpPlUmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dd9mRa/btsNpRVmeM6/CkRX6Xy6URaKYiLlpPlUmK/img.png&quot; data-origin-width=&quot;989&quot; data-origin-height=&quot;362&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.56.52.png&quot; data-is-animation=&quot;false&quot; style=&quot;width: 46.0856%;&quot; data-widthpercent=&quot;46.63&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dd9mRa/btsNpRVmeM6/CkRX6Xy6URaKYiLlpPlUmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdd9mRa%2FbtsNpRVmeM6%2FCkRX6Xy6URaKYiLlpPlUmK%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;989&quot; height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/div&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;총 세 번의 reasoning process를 수행하고 그 과정에서 나온 결과 중 가장 일관성 있는(다수결) 결과를 선택하는 것입니다.&amp;nbsp;&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;h3 data-ke-size=&quot;size23&quot;&gt;3.6 생각 트리(Tree of Thoughts, ToT)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각 트리(Tree of Thought, ToT)는 CoT의 개념을 좀 더 확장해 일반화한 개념입니다. LLM이 단일 선형 CoT(single linear Chain of Thought)가 아닌, 여러 다른 reasoning path를 동시에 탐색할 수 있게 하는 방법입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 사진은 Tree of Thought의 원본 논문에서 설명하는 ToT 자료인데요. CoT와 ToT의 차이점에 대해서도 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.57.05.png&quot; data-origin-width=&quot;1336&quot; data-origin-height=&quot;345&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FgEPX/btsNpsozWbt/UcbyIhkqVrIra1zDTezwC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FgEPX/btsNpsozWbt/UcbyIhkqVrIra1zDTezwC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FgEPX/btsNpsozWbt/UcbyIhkqVrIra1zDTezwC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFgEPX%2FbtsNpsozWbt%2FUcbyIhkqVrIra1zDTezwC1%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;1336&quot; height=&quot;345&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.57.05.png&quot; data-origin-width=&quot;1336&quot; data-origin-height=&quot;345&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;3.7 ReAct(Reason &amp;amp; Act)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Reason &amp;amp; Act의 약자인 ReAct는 LLM이 자연어적인 추론과 외부 도구(검색, code interpreter)를 결합하여 복잡한 작업을 해결할 수 있게 하는 패러다임이라고 본 백서에서는 소개하고 있습니다. 이는 LLM이 특정 작업을 수행하거나 정보를 검색하기 위해 외부 API와 상호 작용하는 등의 행동을 취할 수 있게 하는 에이전트 모델링을 위한 단계라고도 볼 수 있죠. 요즘 AI Agent, Agentic AI 등 에이전트와 관련된 이야기가 많이 나오고 있는데요. 이때 ReAct prompt 방법이 많이 사용되고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 ReAct 논문에서 소개하는 ReAct의 방법인데요. Thought하고 Act하는 과정을 통해 추론과 행동을 수행하는 일종의 루프(loop)로 결합되 동작됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.57.17.png&quot; data-origin-width=&quot;851&quot; data-origin-height=&quot;371&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cU9S6j/btsNo9Jyr2D/wO31BbKEQlqg8t1F2fnnUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cU9S6j/btsNo9Jyr2D/wO31BbKEQlqg8t1F2fnnUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cU9S6j/btsNo9Jyr2D/wO31BbKEQlqg8t1F2fnnUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcU9S6j%2FbtsNo9Jyr2D%2FwO31BbKEQlqg8t1F2fnnUK%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;851&quot; height=&quot;371&quot; data-filename=&quot;스크린샷 2025-04-17 오후 8.57.17.png&quot; data-origin-width=&quot;851&quot; data-origin-height=&quot;371&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;ReAct 프롬프닝은 아래와 같이 작동된다고 정리할 수 있습니다.&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. LLM이 문제에 대해 추론하고 행동 계획을 생성합니다.&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. LLM은 관찰 결과르 사용하여 reasoning을 업데이트하고 새로운 act 계획을 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. LLM이 문제에 대한 해결책에 도달할 때까지 계속 수행합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 코드 프롬프팅(Code prompting)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1 코드 작성을 위한 프롬프트(Prompt for writing code)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gemni, Cladue의 Haiku, Sonnet, ChatGPT와 같은 LLM은 다양한 프로그래밍 언어로 코드 작성(일명 코딩)을 도울 수 있습니다. 저도 개발을 할 때 도움을 많이 받고 있는 부분인데요. 본 프롬프트 엔지니어링 백서에서도 이를 활용하면 코드 작성 프로세스를 가속화할 수 있다고 말하고 있습니다.&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-17 오후 9.25.40.png&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;662&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biLrdj/btsNpya4W8I/Cv3U4ewYVcwWQ1XfLbK5t0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biLrdj/btsNpya4W8I/Cv3U4ewYVcwWQ1XfLbK5t0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biLrdj/btsNpya4W8I/Cv3U4ewYVcwWQ1XfLbK5t0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiLrdj%2FbtsNpya4W8I%2FCv3U4ewYVcwWQ1XfLbK5t0%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;528&quot; height=&quot;509&quot; data-filename=&quot;스크린샷 2025-04-17 오후 9.25.40.png&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;662&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;폴더의 모든 내용을 가져와서 모든 파일의 이름 앞에 draft라는 이름을 붙여 파일 이름을 저장하는 Bash 코드 스니펫을 작성해달라는 간단한 프롬프트 하나면 파일의 이름을 변경할 수 있는 간단한 코드를 빠른 시간에 받을 수 있습니다.&amp;nbsp;&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;4.2 코드 설명을 위한 프롬프트(Prompt for explaining code)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발을 할 때 많이 겪는 상황인데요. 오픈소스(Open source)에 올라와져 있는 코드 등을 해석하고 이해할 상황이 많이 있습니다. 이 과정이 즐겁기도하고 뿌듯한 과정이지만 아무래도 시간이 드는데요. LLM은 이런 코드 설명에 대해서도 기가막히게 해줍니다. 본 prompt engineering whitepaper에서는 아래와 같은 예시를 들어주고 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-17 오후 9.25.53.png&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ci2fTb/btsNpZZZ9Hn/ONlLMj3GF5BUbjPXIxk6x0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ci2fTb/btsNpZZZ9Hn/ONlLMj3GF5BUbjPXIxk6x0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ci2fTb/btsNpZZZ9Hn/ONlLMj3GF5BUbjPXIxk6x0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fci2fTb%2FbtsNpZZZ9Hn%2FONlLMj3GF5BUbjPXIxk6x0%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;535&quot; height=&quot;561&quot; data-filename=&quot;스크린샷 2025-04-17 오후 9.25.53.png&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;720&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;코드를 복사해서 이 코드에 대해서 설명을 해달라는 간단한 프롬프트로도 LLM은 깔끔하면서도 명확하게 코드에 대한 설명을 제공해줍니다. . 개인적으로 저는 헷갈리는 코드와 라이브러리, 코드의 흐름 등을 파악할 때 LLM 서비스를 적극 활용하고 있습니다.&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;4.3 코드 번역을 위한 프롬프트(Prompt for translating code)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 또 코딩 작업에서 많이 활용하는 것이 코드 번역(translate code)인데요. 코드 번역이라는 것은 예를 들어, Bash 코드를 Python 코드로 바꾼다던가 Python 코드를 R로 바꾼다던가 하는 작업입니다. 아래는 그 예시인데요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-17 오후 9.26.01.png&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL0L86/btsNpyPBmMe/XoZ4xs51fm4rZ2NXZuD9U0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL0L86/btsNpyPBmMe/XoZ4xs51fm4rZ2NXZuD9U0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL0L86/btsNpyPBmMe/XoZ4xs51fm4rZ2NXZuD9U0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL0L86%2FbtsNpyPBmMe%2FXoZ4xs51fm4rZ2NXZuD9U0%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;596&quot; height=&quot;625&quot; data-filename=&quot;스크린샷 2025-04-17 오후 9.26.01.png&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시에서는 Bash 코드를 Python 코드로 변환해달라는 프롬프트를 수행했습니다. 그리고 LLM은 그 역할을 충실하게 수행합니다.&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;5. 프롬프트 엔지니어링 모범 사례(Best Practices)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 마무리 단계입니다. 본 백서의 마지막 장에서는 Best Practice를 간단하게 소개하고 있습니다. Best Practice는 아래와 같은 것을 강조하고 있습니다.&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;: one-shot / few-shot 형태로 예제를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 단순하게 디자인하기&lt;/b&gt;: 프롬프트는 사용자와 모델 모두에게 간결하고 명확하며 이해하기 쉬워야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 출력에 대해 구체적으로 지정하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 제약(constraints)보다 지시(Instruction) 사용하기&lt;/b&gt;: 긍정적인 지시에 집중하는 것이 제약에 의존하는 것보다 효과적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 최대 토큰 길이 제어하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. 프롬프트에서 변수(variables) 사용하기&lt;/b&gt;: 프롬프트를 재사용하고 동적으로 만들기 위해 입력에 따라 변경할 수 있는 변수를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7. 입력 형태(input format)과 작성 스타일(writing styles)를 실험하기&lt;/b&gt;: 다른 모델, 모델 구성, 프롬프트 형식, 단어 선택 등에 따라 다른 결과를 얻을 수 있으므로 프롬프트 속성을 실험하는 것이 중요하다.&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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅에서는 프롬프트 엔지니어링의 개념부터 다양한 기법, 모범 사례까지 Google의 'Prompt Engineering' 백서(White paper)를 기반으로 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;효과적인 프롬프트 설계는 LLM의 힘을 최대한 활용하는 핵심 요소입니다. 각 프롬프트 기법은 특정 상황에서 더 효과적일 수도 있고, 때에 따라서 반복적인 과정을 지속하면서 프롬프트를 개선해 나갈 수도 있습니다. 그렇기에 계속 실험해보면서 지속적으로 개선해 나가는 자세가 필요할 것입니다.&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;긴 글 읽어주셔서 감사합니다.&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;p data-ke-size=&quot;size16&quot;&gt;- linkedin: &lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.linkedin.com/in/lsjsj92/&lt;/a&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;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>chainofthought</category>
      <category>COT</category>
      <category>fewshot</category>
      <category>Google</category>
      <category>LLM</category>
      <category>llm prompt</category>
      <category>promptengineering</category>
      <category>생성형ai</category>
      <category>프롬프트관리</category>
      <category>프롬프트엔지니어링</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/684</guid>
      <comments>https://lsjsj92.tistory.com/684#entry684comment</comments>
      <pubDate>Sat, 19 Apr 2025 08:57:37 +0900</pubDate>
    </item>
    <item>
      <title>글 쓰는 개발자 모임(글또) 10기를 마무리하며(Feat. 4기부터 진행한 글또)</title>
      <link>https://lsjsj92.tistory.com/683</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글은 글 쓰는 개발자 모임을 마무리하며 작성하는 회고글입니다. 10기에 대한 회고 글이라기 보다 4기부터 시작한 글또 전체에 대한 회고인데요. 글 쓰는 개발자 모임 글또가 10기를 끝으로 마무리 되기 때문입니다. 지난 활동들을 통해 어떤 생각을 했었는지, 무엇이 좋았고, 무엇이 아쉬웠는지 머릿속에 있는 생각들을 정리해보고자 합니다.&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; background-color: #ffffff; color: #5c5c5c; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://www.facebook.com/groups/geultto/&quot;&gt;www.facebook.com/groups/geultto/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 4기 다짐글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://lsjsj92.tistory.com/576&quot;&gt;lsjsj92.tistory.com/576&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 4기 회고글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://lsjsj92.tistory.com/595&quot;&gt;lsjsj92.tistory.com/595&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 5기 다짐글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/603&quot;&gt;https://lsjsj92.tistory.com/603&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 5기 회고글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/614&quot;&gt;https://lsjsj92.tistory.com/614&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 6기 다짐글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/619&quot;&gt;https://lsjsj92.tistory.com/619&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 6기 회고글 : 21년 회고글과 함께 작성 (&lt;a href=&quot;https://lsjsj92.tistory.com/630&quot;&gt;https://lsjsj92.tistory.com/630&lt;/a&gt;)&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 7기 다짐글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/635&quot;&gt;https://lsjsj92.tistory.com/635&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 7기 회고글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/646&quot;&gt;https://lsjsj92.tistory.com/646&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;글또 8기 다짐글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/654&quot;&gt;https://lsjsj92.tistory.com/654&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;글또 8기 회고글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/658&quot;&gt;https://lsjsj92.tistory.com/658&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;글또 10기 다짐글: &lt;a href=&quot;https://lsjsj92.tistory.com/672&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/672&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;style6&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;/h2&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-filename=&quot;edited_스크린샷 2025-03-24 오전 7.11.18.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;881&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b41QQD/btsMS2Ykxru/MKUxkf7OlEaA4bkCKaIDKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b41QQD/btsMS2Ykxru/MKUxkf7OlEaA4bkCKaIDKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b41QQD/btsMS2Ykxru/MKUxkf7OlEaA4bkCKaIDKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb41QQD%2FbtsMS2Ykxru%2FMKUxkf7OlEaA4bkCKaIDKK%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;962&quot; height=&quot;881&quot; data-filename=&quot;edited_스크린샷 2025-03-24 오전 7.11.18.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;881&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;가장 첫 번째로 드는 회고 주제는 바로 '나는 왜 글또를 시작하게 되었을까?'이다. 이 생각을 따라가기 위해서는 첫 4기 다짐글을 보면된다. 4기 다짐글에서 나는 이렇게 작성했었다.&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;&quot;&quot;&quot;&lt;/b&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;&lt;b&gt;&quot;&quot;&quot;&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;그리고 조금 더 발전된 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;&quot;&quot;&quot;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;&quot;&quot;&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;그렇다. 나는 성장하고 싶었고, 내 취미를 키우고 싶었으며, 피드백을 받아보고 싶었다. 그러면서, 다른 삶을 느껴보고 싶었다. 그렇게 글또를 시작하게 되었다.&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;그리고 신기한 것은 위에 다짐했었던 리스트는 현재 글또 10기를 진행하는 시간까지 관통하는 주제들이었다. 4, 5, 6, 7, 8, 10기까지 모든 기수에서 위의 생각은 변하지 않았다는 것이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6기수(4기~8기, 10기) 동안 진행하면서, 첫 다짐을 달성했는가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 4, 5, 6, 7, 8, 10기까지 모든 기수에서 위의 생각은 변하지 않았다고 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 다행일까? 아니면 &quot;너는 6기수 라는 시간동안 배운 게 없는가?&quot;라는 질문을 던져야 할 것인가?&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;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;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;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;/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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6기수(4기~8기, 10기) 동안 진행하면서, 나는 어떤 삶의 변화가 있었는가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6기수라는 시간은 짧지 않다. 1기수당 6개월이라는 시간이니, 순수하게 기수에서 활동한 시간으로만 총 36개월 정도가 걸린 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 시간은 더 흘렀다. 중간중간 기수가 끝나고 다음 기수가 시작할 때마다 1~3달의 텀이 있었고 9기는 참여하지 못했으니까.&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;나의 첫 글또 시작글은 2020.02.27의 다짐글이다. 그리고 현재 이 글을 쓰고 있는 시간은 2025년 3월 23일이다. (아마 글 공개하는 시간은 더 이후일 것이다). 이렇게만 봐도 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;&quot;&quot;&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 첫 글을 썼던 당시의 회사에서 이직을 하였다. 당시 사회 생활 1년차 초년생이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 어느덧 책임연구원이라는 직급을 가지고 있고 리더의 포지션으로 역할을 수행하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 결혼을 했다 ( 이때 9기를 참여하지 못했다 )&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;- 관심사가 추천 시스템에서 LLM, RAG로 변화되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;&quot;&quot;&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;/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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I8TZt/btsMTa9PC59/s1ptSsMsGvmc11xzgEcJBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I8TZt/btsMTa9PC59/s1ptSsMsGvmc11xzgEcJBk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1901&quot; data-origin-height=&quot;1018&quot; data-filename=&quot;스크린샷 2025-03-24 오후 12.19.24.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I8TZt/btsMTa9PC59/s1ptSsMsGvmc11xzgEcJBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI8TZt%2FbtsMTa9PC59%2Fs1ptSsMsGvmc11xzgEcJBk%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;1901&quot; height=&quot;1018&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EaMQt/btsMVrWmfrJ/TRdzvYjfRkwJAiDAKxhH2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EaMQt/btsMVrWmfrJ/TRdzvYjfRkwJAiDAKxhH2K/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1901&quot; data-origin-height=&quot;1018&quot; data-filename=&quot;스크린샷 2025-03-24 오후 12.20.23.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EaMQt/btsMVrWmfrJ/TRdzvYjfRkwJAiDAKxhH2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEaMQt%2FbtsMVrWmfrJ%2FTRdzvYjfRkwJAiDAKxhH2K%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;1901&quot; height=&quot;1018&quot;/&gt;&lt;/span&gt;&lt;/div&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;&amp;nbsp;&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시원섭섭한 글또 마지막 기수 - LLM과&amp;nbsp; RAG 글에 대한 도전&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;10기를 시작할 때 다짐했던 것을 보면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;&quot;&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 주기적인 글 작성, LLM 및 RAG글에 대한 작성&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;amp; 기상 &amp;amp; 운동 커뮤니티 참여&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;b&gt;&quot;&quot;&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 있었다. 이 중 주기적인 글 작성과 LLM, 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;평범하게 활동하는 것을 벗어나야지 라고 생각했던 주제가 바로 이 2개의 주제 LLM과 RAG였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존까지는 주로 추천 시스템이나, 머신러닝 파이프라인, Airflow, FastAPI 등의 글을 작성했는데, LLM 및 RAG 기반으로 글을 쓴다는 것은 또 다른 도전이었기 때문이다.&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;사실, 이 글들이 인기가 있을까?라는 테스트도 해봤다. 단순히 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;한편으론 허탈하기도 했다. 왜냐하면, 최근에 올린 LLM 보안 관련된 글(Anthropic claude에서 작성한 universql jailbreak 논문, &lt;a href=&quot;https://lsjsj92.tistory.com/681&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/681&lt;/a&gt;)은 논문을 읽는대도 힘들었고, 리뷰하는 것은 더욱 힘들었기 때문이다. 블로그 글 자체도 길어졌기에 핵심 요약 등도 따로 뺄 정도로 신경을 썼는데, 결과가 좋지 못해서 아쉽긴하다 ㅠ 글이 어려운 것인지, 길어서 그런 것인지, 아니면 대중적인 주제가 아니어서인지는 모르겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에, 굉장히 쉬운 글들인 프롬프트 관리 제작기(&lt;a href=&quot;https://lsjsj92.tistory.com/679&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/679&lt;/a&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;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;style8&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;시원섭섭한 글또 마지막 기수 - 커뮤니티 활동&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;10기의 목표 중 하나는 커뮤니티 참여도 있었다. 감사나, 일기, 운동 등의 커뮤니티 참여를 적극적으로 하고 싶었고 그 중 몇 개는 계속 참여도 하고 있었다.&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;감사와 같은 것이나, 일기도 비슷한 맥락이었다. 특히 일기의 경우 시간대가 안 맞아서 인증 글 남기는 게 애매한 경우가 많아 그냥 하지 않았다. 출퇴근 시간이 길다보니, 집에와서 씻고 바로 뻗기 일수였다 ㅠ 그리고 어차피 평소에 잘 쓰는 것들이니 굳이 라는 생각도 들기도 했고. 그 시간에 체력 더 아껴서, 머릿속 생각을 하나 더 줄이면서 책 한 줄 더 보고, 논문 하나 더 읽고, 블로그 한 글자라도, 글 하나라도 더 쓰자!라고 생각했다.&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;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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-03-24 오후 12.10.42.png&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;75&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbubtq/btsMUQbdiEc/XZIe6WpKU77Gl4jGpfyJ51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbubtq/btsMUQbdiEc/XZIe6WpKU77Gl4jGpfyJ51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbubtq/btsMUQbdiEc/XZIe6WpKU77Gl4jGpfyJ51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbbubtq%2FbtsMUQbdiEc%2FXZIe6WpKU77Gl4jGpfyJ51%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;681&quot; height=&quot;75&quot; data-filename=&quot;스크린샷 2025-03-24 오후 12.10.42.png&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;75&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;아직도 이 문구는 내 마음과 머릿속에 박아두고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비록 글또는 이제 끝이지만, 여기서 만난 인연과 커뮤니티의 추억은 내 평생의 기억속에 남지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떻게보면 대학교 졸업 이후, 내 20 후반과 30대 초반까지 함께한 커뮤니티이기에 더욱 기억에 남을 것이다.&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~2개는 유지하고 싶은데 ㅠ)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그동안 글또 하셨던 분들, 인연이 닿으셨던 분들 모두 고생 많으셨고 감사했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;혹시라도 저에게 연락을 주시고 싶으시다면,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- Linkedin:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot;&gt;https://www.linkedin.com/in/lsjsj92/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 블로그 댓글 또는 방명록&lt;/p&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;으로 연락 남겨주시길 바랍니다.&lt;/p&gt;</description>
      <category>일상</category>
      <category>글또</category>
      <category>글쓰는개발자</category>
      <category>기록</category>
      <category>기록이기억을지배한다</category>
      <category>기술블로그</category>
      <category>블로그</category>
      <category>일상</category>
      <category>커뮤니티</category>
      <category>커피챗</category>
      <category>회고</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/683</guid>
      <comments>https://lsjsj92.tistory.com/683#entry683comment</comments>
      <pubDate>Tue, 1 Apr 2025 09:28:41 +0900</pubDate>
    </item>
    <item>
      <title>AI Agent란? Agent와 RAG와의 차이점은 무엇인가?(AI Agent의 방법론과 써야하는 이유에 대해서)</title>
      <link>https://lsjsj92.tistory.com/682</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 에이전트(Agent)라는 용어가 많이 들리고 있습니다. AI Agent 형태의 서비스와 개발 방법론 등이 많이 나오고 있는데요. 본 포스팅은 이러한 인공지능 에이전트(AI Agent)에 대해서 정리하는 문서입니다. 이때, Galileo에서 제공해준 Mastering AI Agents 라는 자료를 기반으로 AI Agent란 무엇이며, 검색 증강 생성(Retrieval Augmented Generation, RAG)와 AI Agent의 차이점은 무엇인지, AI Agent에는 어떠한 종류와 방법론이 있는지, 어떨 때 AI Agent를 써야하는지, AI Agent르 지원해주는 라이브러리는 무엇이 있는지 등을 정리하겠습니다.&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;본 포스팅에서 참고한 Mastering AI Agent 자료는 아래와 같습니다.&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&gt;Mastering AI Agents: &lt;a href=&quot;https://www.galileo.ai/ebook-mastering-agents&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.galileo.ai/ebook-mastering-agents&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1742004310029&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;Mastering Agents - Galileo AI&quot; data-og-description=&quot;A comprehensive guide for evaluating AI agents&quot; data-og-host=&quot;www.galileo.ai&quot; data-og-source-url=&quot;https://www.galileo.ai/ebook-mastering-agents&quot; data-og-url=&quot;https://www.galileo.ai/ebook-mastering-agents&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bKbcvE/hyYqLjirp8/pWQeKpcgEv9mAjUwqL16e1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/stqDh/hyYqTVS0lG/6LLsN7olkUB4Ue1XKP0yAk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bwII1K/hyYqLcv6M2/MNtHxwyJkdkFsHnp3keRb0/img.png?width=795&amp;amp;height=795&amp;amp;face=0_0_795_795&quot;&gt;&lt;a href=&quot;https://www.galileo.ai/ebook-mastering-agents&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.galileo.ai/ebook-mastering-agents&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bKbcvE/hyYqLjirp8/pWQeKpcgEv9mAjUwqL16e1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/stqDh/hyYqTVS0lG/6LLsN7olkUB4Ue1XKP0yAk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bwII1K/hyYqLcv6M2/MNtHxwyJkdkFsHnp3keRb0/img.png?width=795&amp;amp;height=795&amp;amp;face=0_0_795_795');&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;Mastering Agents - Galileo AI&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A comprehensive guide for evaluating AI agents&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.galileo.ai&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-03-15 오전 11.02.52.png&quot; data-origin-width=&quot;1259&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHf9Z9/btsMNcLNYlX/5jdO1LnJyGLRtjStlRdj3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHf9Z9/btsMNcLNYlX/5jdO1LnJyGLRtjStlRdj3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHf9Z9/btsMNcLNYlX/5jdO1LnJyGLRtjStlRdj3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHf9Z9%2FbtsMNcLNYlX%2F5jdO1LnJyGLRtjStlRdj3K%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;1259&quot; height=&quot;580&quot; data-filename=&quot;스크린샷 2025-03-15 오전 11.02.52.png&quot; data-origin-width=&quot;1259&quot; data-origin-height=&quot;580&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;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;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅에서는 AI Agent에 대해서 아래와 같은 순서로 AI Agent에 대해서 소개해볼까 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;AI Agent란 무엇인가? AI Agent를 왜 사용하는가?&lt;/li&gt;
&lt;li&gt;검색 증강 생성(Retrieval Augmented Generation, RAG)와 AI Agent의 차이점은 무엇인가?&lt;/li&gt;
&lt;li&gt;AI Agent에는 어떠한 종류와 방법론이 있는가?&lt;/li&gt;
&lt;li&gt;언제 AI Agent를 써야하는가? 그리고 어떨 때 필요 없는가?&lt;/li&gt;
&lt;li&gt;AI Agent를 지원해주는 라이브러리는 무엇이 있는가?&lt;/li&gt;
&lt;/ol&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;h3 data-ke-size=&quot;size23&quot;&gt;1. AI Agent란 무엇인가? AI Agent를 왜 사용하는가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mastering AI Agent에서는 AI Agent에 대해서 &quot;AI 에이전트는 대규모 언어 모델(LLM)을 활용하는 소프트웨어 애플리케이션(software application)&quot;이라고 설명합니다. 즉, AI Agent가 단순한 프로그램이 아니라, LLM을 활용하여 동작함을 의미하는데요. 사용자의 질문에 대한 답변부터 시작하여 다양한 백엔드 서비스 처리까지 특정 작업을 자발적(Autonomous, 스스로)으로 수행하는 software application이라고 볼 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 AI 에이전트는 복잡한 의사 걸졍(Complex decision making)이나, 자율성(Autonomy), 적응성(Adaptability)이 요구되는 작업에서 매우 유용하다고 합니다. 단순한 환경보다는 변화가 많은 환경(Dynamic environment)에서 유용하고 효과적이라는 것인데요. 업무 흐름이 여러 단계로 구성되거나(workflow involves multiple steps) 자동화의 이점을 받을 수 있는 상호작용(interaction)이 포함된 환경(상호작용이 많아 자동화가 필요한 영역)에서 효과적이라는 것입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어서, 본 원서에서는 세일즈포스(Salesforce)에 따르면 영업 담당자는 업무 시간의 71%를 비영업 업무에 사용한다고 말합니다. 행정 업무나 데이터 수동 입력(manually entering data)과 같은 작업이죠. 만약, AI 에이전트가 이러한 비영업 업무를 대신 처리할 수 있다면 고객과 소통하고, 관계를 구축하는데 시간을 더 사용하게 될 것이고 궁극적으로 더 많은 판매를 성사시키는 데 기여할 수 있을 것이라고 말합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 다른 예시를 하나 더 들어주는데요. 만약 우리가 온라인 리테일 비즈니스를 운영하고 있고 매일 수백 건의 고객 문의를 받는다고 했을 때( 주문 사태나, 제품 정보나, 배송 정보 등) AI Agent는 고객이 '내 주문은 언제 배송되는가?'에 대한 질문에 대해서 주문 관리 시스템에 접근하여 주문 정보를 찾고, 검색된 정보를 기반으로 AI Agent는 고객에게 자동으로 업데이트 정보를 제공하면서 이메일을 보내는 등 후속 업무까지 수행할 수 있는 것이죠.&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-filename=&quot;스크린샷 2025-03-15 오후 12.39.11.png&quot; data-origin-width=&quot;1081&quot; data-origin-height=&quot;831&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHdyDJ/btsML9CrSJZ/DhkfS9iAkAtHXp1ckqB8N1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHdyDJ/btsML9CrSJZ/DhkfS9iAkAtHXp1ckqB8N1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHdyDJ/btsML9CrSJZ/DhkfS9iAkAtHXp1ckqB8N1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHdyDJ%2FbtsML9CrSJZ%2FDhkfS9iAkAtHXp1ckqB8N1%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;688&quot; height=&quot;529&quot; data-filename=&quot;스크린샷 2025-03-15 오후 12.39.11.png&quot; data-origin-width=&quot;1081&quot; data-origin-height=&quot;831&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;2. 검색 증강 생성(Retrieval Augmented Generation, RAG)와 AI Agent의 차이점은 무엇인가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면, RAG와 AI Agent의 차이점은 무엇일까요? 언뜻보면 비슷한 두 개념이지만, RAG와 AI Agent는 차이점이 분명히 존재합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Masgering AI Agent에서는 다음과 같이 RAG와 AI Agent의 차이점을 언급하고 있습니다.&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;&quot; RAG 시스템은 LLM을 도와서 주어진 문맥을 기반으로 정확한 답변을 제공하도록 노력합니다. 그러나, AI Agent는 그 답변을 받아서 실제로 무언가를 수행합니다. 결정을 내리고(decision making), 작업을 실행하며(execute task), 목표 달성을 위해 여러 단계를 조율하기도 합니다.&quot;&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;즉, RAG를 활용한다면 LLM은 보험 정책과 같은 세부적인 대한 질문에 답변을 할 수 있는 것이죠. 하지만, AI Agent를 사용하다면 보험 창구를 end-to-end로 처리할 수 있다는 것입니다. 스스로 문서를 분석하고, 정책 준수를 확인하며, 지급액을 계산하기도 하는 것이죠. 그리고 필요할 경우에는 다른 AI Agent와 협력하기도 할 것입니다. 그러면서 AI Agent는 사전에 정의된 규칙 없이 context를 이해하는 능력과, context에 따라 결정을 조정하며, 다양한 상호작용에서 학습하는 능력을 얻게 된 것이 지금의 AI Agent라고 말할 수 있겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 수행되는 AI Agent는 단순히 규칙(rule)로 동작되는 단순한 봇(bot)이 아닌 것이죠. 스스로 결정을 내릴 수 있는 시스템이라는 것입니다.&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;다음 표는 RAG와 AI Agent에 대해서 차이점을 정리한 내용입니다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 131px;&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: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.031%; height: 19px;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 42.2868%; height: 19px;&quot;&gt;&lt;b&gt;RAG(Retrieval-Augmented Generation)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.6821%; height: 19px;&quot;&gt;&lt;b&gt;AI Agent&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.031%; height: 17px;&quot;&gt;정의&lt;/td&gt;
&lt;td style=&quot;width: 42.2868%; height: 17px;&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;외부 DataBase와 같은 source data에서 정보를 검색(Retrieve)하여 LLM의 응답을 강화하는 방식&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.6821%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;LLM을 활용하여 의사 결정을 내리고, 작업을 실행하며, multi-step 프로세스를 조율하는 시스템&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 38px;&quot;&gt;
&lt;td style=&quot;width: 14.031%; height: 38px;&quot;&gt;역할&lt;/td&gt;
&lt;td style=&quot;width: 42.2868%; height: 38px;&quot;&gt;&lt;br /&gt;- 사용자 입력이 들어오면 적절한 문서를 검색하고 이를 기반으로 정확한 답변을 생성&lt;br /&gt;- 최신 정보 반영, 문서 검색 및 요약&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.6821%; height: 38px;&quot;&gt;- 검색된 정보를 활용해 실제 행동을 수행하고, 여러 작업을 연계하여 실행&lt;br /&gt;- 자동화된 작업 수행, 의사 결정 지원&lt;br /&gt;- 상호작용 기반 문제 해결&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.031%; height: 19px;&quot;&gt;작동 방식&lt;/td&gt;
&lt;td style=&quot;width: 42.2868%; height: 19px;&quot;&gt;&lt;br /&gt;1. 사용자의 질문을 분석&lt;br /&gt;2. Database 등에서 관련 문서를 검색(검색하는 과정에서 re-ranking이나 다양한 retrieve 방법이 활용)&lt;br /&gt;3. 검색된 정보를 기반으로 LLM이 답변 생성&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.6821%; height: 19px;&quot;&gt;1. 입력 분석 및 정보 수집&lt;br /&gt;2. 의사 결정 및 계획 수립&lt;br /&gt;3. 실행 가능한 액션 수행(또는 사용자와 상호작용)&lt;br /&gt;4. 결과 조율 및 응답&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.031%; height: 19px;&quot;&gt;주요 사례&lt;/td&gt;
&lt;td style=&quot;width: 42.2868%; height: 19px;&quot;&gt;&lt;br /&gt;- 법률 문서, 정책 문서 등에서 정확한 답변 제공&lt;br /&gt;- 기술 문서 검색 및 응답&lt;br /&gt;- 내부 DB 기반의 고객 서비스&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.6821%; height: 19px;&quot;&gt;- 챗봇과 대화 후 실제 예약 진행&lt;br /&gt;- AI 자동화 워크플로우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.031%; height: 19px;&quot;&gt;장점 및 한계점&lt;/td&gt;
&lt;td style=&quot;width: 42.2868%; height: 19px;&quot;&gt;&lt;br /&gt;- 최산 정보 반영 가능&lt;br /&gt;- 문맥적 일관성 강화&lt;br /&gt;- 검색된 문서 품질에 성능이 좌우됨&lt;br /&gt;- 검색과 생성이 따로 최적화&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.6821%; height: 19px;&quot;&gt;- 다양한 환경에서 활용 가능하고, 지속적 학습 및 적응 가능&lt;br /&gt;- 반복적 작업을 자동화&lt;br /&gt;- 복잡한 의사결정에 있어 오류 발생 가능 (시스템 복잡도)&lt;br /&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;h3 data-ke-size=&quot;size23&quot;&gt;3. AI Agent에는 어떠한 종류와 방법론이 있는가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI Agent라고 해서 다 똑같은 Agent가 아닙니다. 마치, RAG에도 Naive RAG와, Advanced RAG, Modular RAG 등 다양한 기법이 있고 검색에서도 Pre-retrieval, Post-retrieval, Re-ranking 등 다양한 검색 방법이 있는 것처럼 말이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mastering AI Agent에서는 에이전트와 주요 특징을 아래와 같이 제공하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 138px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px; text-align: center;&quot;&gt;&lt;b&gt;Agent 이름&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px; text-align: center;&quot;&gt;&lt;b&gt;Agent의 주요 특징&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px; text-align: center;&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;Fixed Automation Agent&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Intelligence가 없으며, 행동을 예측하지만, 범위가 한정적&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;RPA, basic scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;LLM-Enhanced: Smarter, but not Einstein&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;컨텍스트 기반으로 동작되고, rule에 제약되어 있으며, state 관리는 없는 방법&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;Email filger, content moderation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;ReAct: Reasoning Meets Action&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Multi-step workflows, 동적 계획(dynamic planing) 가능, basic problem-solving&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;Travel planners, project planning tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;ReAct + RAG: Grounded Intelligence&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;외부 지식(Exteral knowledge)에 접근, 할루시네이션(hallucination)이 적음, real-time data가 가능&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;Legal research tools, medical assistants, technical support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;Tool-Enhanced: The Multi-Taskers&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;여러 개의 툴(multi-tool)을 활용하고, dynamic execution, 수준있는 자동화(high automation)&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;Code generation tools, data analysis bot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;Self-Reflecting: The Philosophers&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;메타 인지(Meta-cognition, 설명 가능성(explainability), self-improvement&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;QA Agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;Memory-Enhanced: The Personalized Powerhouses&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Long-term memory, 개인화(Personalization), 적응형 학습(Adaptive learning)&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;AI personalized assistants&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 자료에서 소개하는 각 Agent 특징마다 workflow는 아래 그림과 같습니다. (노란색으로 칠해진 것은 제가 읽을 때 칠해놨던 것입니다. 양해 부탁드립니다.)&lt;/p&gt;
&lt;table style=&quot;color: #333333; text-align: start; border-collapse: collapse; width: 100%; height: 138px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 19.186%; height: 19px;&quot;&gt;&lt;b&gt;Agent 이름&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 30.814%; height: 19px;&quot;&gt;&lt;b&gt;사진&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 19.186%; height: 17px;&quot;&gt;&amp;nbsp; Fixed Automation Agent&lt;/td&gt;
&lt;td style=&quot;width: 30.814%; height: 17px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-03-15 오후 2.43.08.png&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/betR7c/btsMNdqtCr7/gQUXLM0RtUKgHvbpaUBGjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/betR7c/btsMNdqtCr7/gQUXLM0RtUKgHvbpaUBGjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/betR7c/btsMNdqtCr7/gQUXLM0RtUKgHvbpaUBGjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbetR7c%2FbtsMNdqtCr7%2FgQUXLM0RtUKgHvbpaUBGjK%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;916&quot; height=&quot;310&quot; data-filename=&quot;스크린샷 2025-03-15 오후 2.43.08.png&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;310&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 19.186%; height: 17px;&quot;&gt;&amp;nbsp; LLM-Enhanced: Smarter, but not Einstein&lt;/td&gt;
&lt;td style=&quot;width: 30.814%; height: 17px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-03-15 오후 2.43.13.png&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pKQ2z/btsMLyv7Utt/jiLZNG2oITqLYz0wFz77DK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pKQ2z/btsMLyv7Utt/jiLZNG2oITqLYz0wFz77DK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pKQ2z/btsMLyv7Utt/jiLZNG2oITqLYz0wFz77DK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpKQ2z%2FbtsMLyv7Utt%2FjiLZNG2oITqLYz0wFz77DK%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;916&quot; height=&quot;310&quot; data-filename=&quot;스크린샷 2025-03-15 오후 2.43.13.png&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;310&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 19.186%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;ReAct: Reasoning Meets Action&lt;/td&gt;
&lt;td style=&quot;width: 30.814%; height: 17px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-03-15 오후 2.43.21.png&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;341&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cRdcVJ/btsMLxcSjMJ/THgWglWHkxKz7WdqKKVvHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRdcVJ/btsMLxcSjMJ/THgWglWHkxKz7WdqKKVvHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRdcVJ/btsMLxcSjMJ/THgWglWHkxKz7WdqKKVvHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRdcVJ%2FbtsMLxcSjMJ%2FTHgWglWHkxKz7WdqKKVvHK%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;916&quot; height=&quot;341&quot; data-filename=&quot;스크린샷 2025-03-15 오후 2.43.21.png&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;341&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 19.186%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;ReAct + RAG: Grounded Intelligence&lt;/td&gt;
&lt;td style=&quot;width: 30.814%; height: 17px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-03-15 오후 2.42.41.png&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0ZiTd/btsMMc6RX3h/k4kABh52yQPb6EUJSgkqt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0ZiTd/btsMMc6RX3h/k4kABh52yQPb6EUJSgkqt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0ZiTd/btsMMc6RX3h/k4kABh52yQPb6EUJSgkqt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0ZiTd%2FbtsMMc6RX3h%2Fk4kABh52yQPb6EUJSgkqt0%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;916&quot; height=&quot;348&quot; data-filename=&quot;스크린샷 2025-03-15 오후 2.42.41.png&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;348&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 19.186%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Tool-Enhanced: The Multi-Taskers&lt;/td&gt;
&lt;td style=&quot;width: 30.814%; height: 17px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-03-15 오후 2.43.30.png&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;369&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bc773K/btsMKOff8CA/kCKkTOXsY6KfIjPXHIPDh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bc773K/btsMKOff8CA/kCKkTOXsY6KfIjPXHIPDh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bc773K/btsMKOff8CA/kCKkTOXsY6KfIjPXHIPDh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbc773K%2FbtsMKOff8CA%2FkCKkTOXsY6KfIjPXHIPDh1%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;916&quot; height=&quot;369&quot; data-filename=&quot;스크린샷 2025-03-15 오후 2.43.30.png&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;369&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 19.186%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Self-Reflecting: The Philosophers&lt;/td&gt;
&lt;td style=&quot;width: 30.814%; height: 17px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-03-15 오후 2.43.37.png&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d3HdWZ/btsMNcd1G7W/WaECebi53aoWy3xzCrizT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d3HdWZ/btsMNcd1G7W/WaECebi53aoWy3xzCrizT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d3HdWZ/btsMNcd1G7W/WaECebi53aoWy3xzCrizT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd3HdWZ%2FbtsMNcd1G7W%2FWaECebi53aoWy3xzCrizT0%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;916&quot; height=&quot;416&quot; data-filename=&quot;스크린샷 2025-03-15 오후 2.43.37.png&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;416&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 19.186%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Memory-Enhanced: The Personalized Powerhouses&lt;/td&gt;
&lt;td style=&quot;width: 30.814%; height: 17px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-03-15 오후 2.43.48.png&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;372&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dcmEh7/btsMNhzzGqf/njSEmGbUpjGY9qKasbzHE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dcmEh7/btsMNhzzGqf/njSEmGbUpjGY9qKasbzHE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dcmEh7/btsMNhzzGqf/njSEmGbUpjGY9qKasbzHE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdcmEh7%2FbtsMNhzzGqf%2FnjSEmGbUpjGY9qKasbzHE1%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;916&quot; height=&quot;372&quot; data-filename=&quot;스크린샷 2025-03-15 오후 2.43.48.png&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;372&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&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;4. 언제 AI Agent를 써야하는가? 그리고 어떨 때 필요 없는가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다고 무조건 Agent가 좋은 것은 아닙니다. 본 자료에서도 마찬가지로 언제 Agent를 써야하는지, 쓸 필요가 없는지 구분을 해놨는데요. 각 설명은 다음과 같습니다.&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;4-1. Agent가 필요할 때&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 복잡한 의사 결정이나, 자율성, 그리고 적응형이 필요한 작업일 때, 혹은 이러한 업무가 필요할 때 에이전트가 필요하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- AI 에이전트는 업무 흐름이 동적(Dynamic)인 환경에서 특히 뛰어남. 여러 단계의 프로세스나, interaction이 포함된 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 고객 지원으로 요청 사항을 다루거나, 실시간(real-time)으로 도움을 제공하는 것 등에서 활용될 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터를 분석하고 조사를 수행하는 것에서도 사용될 수 있음. 데이터 수집이나, 처리(processing), 분석과 같은 업무를 수행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 교육(Education)에서도 활용. 개인화된 학습 경험을 제공할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item dable&quot; style=&quot;height: 250px;&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;300x250&lt;/div&gt;
    &lt;div id=&quot;dablewidget_Pl1aE8lE&quot; data-widget_id=&quot;Pl1aE8lE&quot;&gt;
      &lt;script&gt;(function(d,a,b,l,e,_) {
    if(d[b]&amp;&amp;d[b].q)return;d[b]=function(){(d[b].q=d[b].q||[]).push(arguments)};e=a.createElement(l);
    e.async=1;e.charset='utf-8';e.src='//static.dable.io/dist/plugin.min.js';
    _=a.getElementsByTagName(l)[0];_.parentNode.insertBefore(e,_);
    })(window,document,'dable','script');
dable('setService', 'lsjsj92.tistory.com');
dable('sendLogOnce');
dable('renderWidget', 'dablewidget_Pl1aE8lE', {ignore_items: true});&lt;/script&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4-2. Agent가 필요하지 않을 때&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 Agent가 필요하지 않을 경우는 아래와 같다고 설명하고 있습니다.&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;- 단순한 작업이거나, 자주 발생하지 않은(occur infrequently), 최소한의 자동화만 필요한 경우에는 기존 소프트웨어로도 충분히 처리할 수 있으므로 AI Agent의 복잡성을 도입할 필요가 없음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 전문 지식이 필요한 경우 즉, 특정 도메인에 대한 깊은 지식이나 전문성을 요구하는 경우(복잡한 법률 분석, 정밀한 의료 진단 등)에는 풍부한 전문가가 처리하는 것이 바람직함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 인간적인 요소가 중요한 경우 즉, 심리 치료, 상담, 창작 등과 같은 경우에는 AI Agent보다 사람이 하는게 좋다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 비용 및 규제 이슈가 있을 경우에는 AI 에이전트는 시간, 자원, 전문성이 필요하기에 제한성이 있을 수 있음&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;4-3. AI Agent를 고려하기 위한 10개의 질문&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 AI Agent를 고려하기 위해서 아래 10개의 질문을 활용해 질문에 대한 답을 유도해보면서 Agent가 필요한 지 검토하는데 참고하도록 자료를 제공해주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 174px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 36.3953%; height: 19px;&quot;&gt;&lt;b&gt;질문&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 63.6047%; height: 19px;&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 36.3953%; height: 19px;&quot;&gt;&amp;nbsp;1. 작업의 복잡도&lt;/td&gt;
&lt;td style=&quot;width: 63.6047%; height: 19px;&quot;&gt;&lt;br /&gt;&amp;nbsp;작업이 단순하고 반복적인가? 아니면 복잡한 의사 결정이 포함되어 있는가?&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 36.3953%; height: 17px;&quot;&gt;&amp;nbsp;2. 작업의 발생 빈도&lt;/td&gt;
&lt;td style=&quot;width: 63.6047%; height: 17px;&quot;&gt;&lt;br /&gt;&amp;nbsp;해당 작업이 자주 발생해기에, 자동화가 시간 및 자원 절약에 도움이 되는가? 투자 대비 효과는 어떠한가?&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 36.3953%; height: 17px;&quot;&gt;&amp;nbsp;3. 데이터 처리 또는 요청량이 얼마나 되는가?&lt;/td&gt;
&lt;td style=&quot;width: 63.6047%; height: 17px;&quot;&gt;&lt;br /&gt;&amp;nbsp;AI 에이전트가 대량의 데이터를 처리해야 하는가? 속도와 효율성이 중요한가?&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 36.3953%; height: 17px;&quot;&gt;&amp;nbsp;4. 작업이 변화에 적응(Adaptability)해야 하는가?&lt;/td&gt;
&lt;td style=&quot;width: 63.6047%; height: 17px;&quot;&gt;&lt;br /&gt;&amp;nbsp;작업을 수행하는 조건이 지속적으로 변하며, 이를 유연하게 대응해야 하는가? 자주 변화하고 즉각적인 적응이 필요하다면, AI 에이전트가 강력한 도구가 될 수 있음&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 36.3953%; height: 17px;&quot;&gt;&amp;nbsp;5. 시간이 지남에 따라 학습과 진화(evolving)를 통해 얻는 이점이 있는가?&lt;/td&gt;
&lt;td style=&quot;width: 63.6047%; height: 17px;&quot;&gt;&lt;br /&gt;&amp;nbsp; AI 시스템이 상호작용을 통해 학습하고 시간이 지남에 따라 더 나은 결과를 제공할 수 있는가?&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 36.3953%; height: 17px;&quot;&gt;&amp;nbsp;6. 정확성이 중요한가?&lt;/td&gt;
&lt;td style=&quot;width: 63.6047%; height: 17px;&quot;&gt;&lt;br /&gt;&amp;nbsp; 의료, 금융 등 높은 정확성이 요구되는 환경에서 AI를 신뢰할 수 있는가? 높은 정확성이 유지될 수 있는가?&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 36.3953%; height: 17px;&quot;&gt;&amp;nbsp;7. 인간의 전문성이나 감성 지능이 중요한가?&lt;/td&gt;
&lt;td style=&quot;width: 63.6047%; height: 17px;&quot;&gt;&lt;br /&gt;&amp;nbsp; 깊은 도메인 지식, 인간의 직관, 감성, 공감 등이 요구되는가?&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 36.3953%; height: 17px;&quot;&gt;&amp;nbsp;8. 개인정보 및 보안 고려 사항&lt;/td&gt;
&lt;td style=&quot;width: 63.6047%; height: 17px;&quot;&gt;&lt;br /&gt;&amp;nbsp; 민감한 정보를 다루며, 강력한 보안이 요구되는가?&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 36.3953%; height: 17px;&quot;&gt;&amp;nbsp;9. 규제 및 법적 요구 사항&lt;/td&gt;
&lt;td style=&quot;width: 63.6047%; height: 17px;&quot;&gt;&lt;br /&gt;&amp;nbsp; AI 사용이 특정 산업 규제나 법적 제한을 받는가?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 36.3953%;&quot;&gt;&amp;nbsp;10. 비용 대비 효과 분석&lt;/td&gt;
&lt;td style=&quot;width: 63.6047%;&quot;&gt;&lt;br /&gt;&amp;nbsp; AI Agent 도입으로 시간 절약, 효율성 증가, 성과 향상이 비용을 초과하는가?&lt;br /&gt;&lt;br /&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;h3 data-ke-size=&quot;size23&quot;&gt;5. AI Agent를 지원해주는 라이브러리는 무엇이 있는가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 자료에서는 AI Agent를 지원해주는 라이브러리에 대해서 소개도 진행해줍니다. 이때, 라이브러리는 LangGraph와 Autogen 그리고 CrewAI에 대해서 소개하며 이 셋을 비교해서 설명합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-03-15 오후 3.31.41.png&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwlW33/btsMLZNyhEX/unMK24Moow69krceMZCPqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwlW33/btsMLZNyhEX/unMK24Moow69krceMZCPqk/img.png&quot; data-alt=&quot;Mastering of Agent에서 소개하는 라이브러리(Langchain vs Autogen vs CrewAI) 비교 표&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwlW33/btsMLZNyhEX/unMK24Moow69krceMZCPqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwlW33%2FbtsMLZNyhEX%2FunMK24Moow69krceMZCPqk%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;916&quot; height=&quot;432&quot; data-filename=&quot;스크린샷 2025-03-15 오후 3.31.41.png&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Mastering of Agent에서 소개하는 라이브러리(Langchain vs Autogen vs CrewAI) 비교 표&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;5-1. LangGraph(&lt;a href=&quot;https://github.com/langchain-ai/langgraph&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/langchain-ai/langgraph&lt;/a&gt;)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LangGraph는 익히 알고 있는 LangChain 계열의 라이브러리입니다. DAG(Directed Acyclic Graph) 기반의 workflow로 동작되며 상태(stageful) 관리 기능, Multi-actor 기반의 애플리케이션 지원, LangChain과의 통합 등을 지원하는 특징을 가지고 있습니다. workflow 기반의 graph 형태로 설계하기에 다양한 복잡한 task에 활용할 수 있습니다. 즉, 데이터 처리 파이프라인을 그래프 형태로 표현하여 워크플로우를 구성합니다. 이때, 각 노드는 특정 task 또는 Function을 의미합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;5-2. Autogen(&lt;a href=&quot;https://github.com/microsoft/autogen&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/microsoft/autogen&lt;/a&gt;)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Microsoft에서 만든 대화형 기반의 에이전트입니다. 대화형(Conversational) 기반의 에이전트이므로 대화형 인터페이스를 활용할 수 있다는 특징이 있습니다. AI Agent가 마치 대화형 방식으로 상호작용하며, 사용자의 요청사항을 처리합니다. 그 외로 코드 실행과 function calling을 지원하며 모듈화된 커스타미이징 기능을 지원합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;5-3. CrewAI(&lt;a href=&quot;https://github.com/crewAIInc/crewAI&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/crewAIInc/crewAI&lt;/a&gt;)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CrewAI에서 만든 Role-based AI입니다. 즉, 역할 기반의 멀티 에이전트를 구축할 수 있습니다. AI 에이전트에게 특정 역할을 부여하여 자율적인 일종의 팀워크를 형성합니다. 이를 통해, 각 AI 에이전트는 특정 목표를 수행하며, 에이전트간 협업을 통해 작업을 진행합니다.&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;또한, 본 자료에서는 아래와 같은 질문을 통해 LangGraph와 Autogen, CrewAI를 비교했습니다.&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. 사용 편의성은 어떠한가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 지원하는 Tool이나 Functionalities는 무엇이 있는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Context를 얼마나 잘 유지하는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 잘 구조화(Well-Organized) 되어있고 해석이 용이(Easy to Interpret)한가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 공식 문서(Documentation)가 잘 작성되어 있는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. Multi-Agent를 지원하는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. 캐싱 기능(Caching)이 있는가?&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;등 13개의 질문을 기반으로 비교 분석을 진행합니다. 상세한 내용은 지면상 생략하겠으니, 꼭 참고해서 봐보시길 바랍니다. 예를 들어, 아래 그림과 같이 비교 분석을 수행하였습니다.&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-filename=&quot;스크린샷 2025-03-15 오후 4.36.05.png&quot; data-origin-width=&quot;1078&quot; data-origin-height=&quot;775&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C0LzE/btsMLwLUJ8u/EdeuBOlOWcKc1x4hPSSsRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C0LzE/btsMLwLUJ8u/EdeuBOlOWcKc1x4hPSSsRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C0LzE/btsMLwLUJ8u/EdeuBOlOWcKc1x4hPSSsRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC0LzE%2FbtsMLwLUJ8u%2FEdeuBOlOWcKc1x4hPSSsRk%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;756&quot; height=&quot;544&quot; data-filename=&quot;스크린샷 2025-03-15 오후 4.36.05.png&quot; data-origin-width=&quot;1078&quot; data-origin-height=&quot;775&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 Galileo에서 제공해준 Mastering AI Agents 라는 자료를 기반으로 AI Agent란 무엇이며, RAG와 AI Agent의 차이점은 무엇인지, AI Agent에는 어떠한 종류와 방법론이 있는지를 정리한 포스팅입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI Agent에 대해서 공부하시는 분들께 도움이 되시길 바랍니다.&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;br /&gt;혹시라도 저에게 연락을 주시고 싶으시다면,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- Linkedin:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot;&gt;https://www.linkedin.com/in/lsjsj92/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 블로그 댓글 또는 방명록&lt;/p&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;으로 연락 남겨주시길 바랍니다.&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>Agent</category>
      <category>aiagent</category>
      <category>autogen</category>
      <category>ChatGPT</category>
      <category>crewai</category>
      <category>langgraph</category>
      <category>LLM</category>
      <category>RAG</category>
      <category>에이전트</category>
      <category>에이전트란</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/682</guid>
      <comments>https://lsjsj92.tistory.com/682#entry682comment</comments>
      <pubDate>Mon, 17 Mar 2025 09:12:42 +0900</pubDate>
    </item>
    <item>
      <title>LLM의 보안을 우회할 수 있을까? Anthropic의 Universal Jailbreak(탈옥) 실험 연구(Constitutional Classifiers: Defending against Universal Jailbreaks)</title>
      <link>https://lsjsj92.tistory.com/681</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 ChatGPT와 같은 LLM 모델들에 대한 보안 문제, 구체적으로 탈옥(Jailbreak) 문제를 다룬 논문인 Constitutional Classifiers: Defending against Universal Jailbreaks across Thousands of Hours of Red Teaming 논문을 리뷰하는 포스팅입니다. 본 논문은 클로드(Claude) 계열의 모델(Claude Sonnect, Haiku 등)을 만든 회사인 앤트로픽(Anthropic)의 Safeguards Research Team에서 작성한 논문입니다. 본 논문은 LLM의 취약점 중 하나인 Jailbreak 공격에 대해서 어떻게 대응하고 방어할 지 연구하였으며 Red Team을 활용해 3,000시간 이상의 테스트(공격)에서 효과적으로 차단하는 성과를 거두었습니다.&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;&lt;a href=&quot;https://arxiv.org/pdf/2501.18837&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/pdf/2501.18837&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-03-04 오후 7.35.14.png&quot; data-origin-width=&quot;987&quot; data-origin-height=&quot;579&quot;&gt;&lt;a href=&quot;https://arxiv.org/pdf/2501.18837&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NUYLF/btsMAGOEDxX/31SGDcKIEYoTMZVYgjhfWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNUYLF%2FbtsMAGOEDxX%2F31SGDcKIEYoTMZVYgjhfWK%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;987&quot; height=&quot;579&quot; data-filename=&quot;스크린샷 2025-03-04 오후 7.35.14.png&quot; data-origin-width=&quot;987&quot; data-origin-height=&quot;579&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;
&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅 개요에서도 언급하였듯, 본 포스팅은 LLM에서 이슈가 발생할 수 있는 보안 문제를 해결하도록 연구한 논문입니다. 원 논문은 내용이 굉장히 길고 방대하기 때문에 본 포스팅에서는 핵심적인 것만 집고 넘어가도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;긴 내용을 보기 힘드신 분들은, 아래 '요약' 파트와 '1. 핵심 수행 내용과 연구 내용'을 참고하시길 바랍니다.&lt;/span&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;핵심 요약&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 대규모 언어 모델(Large Language Model, LLM)이 다양한 분야에서 활용되면서, AI 모델의 보안 취약점과 그에 따른 위험성도 점점 더 중요하게 다뤄지고 있습니다. 특히, AI 모델을 악용하는 방법 중 하나로 Universal Jailbreak(한국말로 하면, 보편적 탈옥..?)가 있는데요. 이는 특정한 프롬프트 기법을 사용해서 AI 모델의 보안 필터를 체계적으로 우회하고, 불법적인 활동을 수행할 수 있도록 정보를 제공하는 공격 방법입니다. 예를 들어서, 불법 물질의 대량 제조와 같은 복잡한 과정을 안내하도록 LLM의 응답을 유도하는 방식이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 보안 위협을 방어하기 위해, 앤트로픽(Anthropic)은 Constituional Classifiers라는 보호 방법을 본 논문에서 제안하였습니다. 이는 허용된 콘텐츠와 제한된 콘텐츠를 정의하는 자연어 규칙(Constituion, 헌법)을 기반으로 LLM을 활용해 Synthetic data(합성 데이터)를 생성하고 이를 학습시켜 만들어진 보안 필터라고 볼 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 연구에서는 Universal Jailbreak가 AI 보안을 얼마나 효과적으로 우회할 수 있는지를 평가했는데요. 3,000시간이 넘는 시간동안 Red teaming을 수행하면서 연구를 통해 구축한 보안 필터가 얼마나 효과적으로 차단할 수 있는지를 평가했습니다. 연구 결과, Constituional Classifiers가 적용된 모델은 대부분의 Query에 대해 보안이 적용되지 않은 모델(Unsafe guarded model, Helpful-only model)과 유사한 수준의 정보를 제공하는 Universal Jailbreak를 허용하지 않았습니다. 즉, 어떤 Red team도 보안을 일관되게 우회할 수 있는 Universal Jailbreak을 발견하는 업무를 수행하는데 실패했습니다. 간단히 말하면, 모든 보안에 이슈가 되는 것들을 차단할 수 있었다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 classifier는 실제 프로덕션 트래픽(production-traffic)에서 거부(refusal)가 0.38% 증가했습니다 즉, 보안이 강화되었음에도 모델의 유용성에 미치는 영향력은 미미한 것이죠. 또한, 모델의 추론 속도(inference overhead)는 23.7% 증가했습니다. 이는 보안 필터가 적용된만큼 계산량이 증가했음을 의미하지만, 여전히 실질적인 배포 가능성을 유지(practical deployment viability)하는 것을 보여준다고 저자들은 말합니다.&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;1. 핵심 수행 내용과 연구 내용&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-03-04 오후 8.15.53.png&quot; data-origin-width=&quot;1104&quot; data-origin-height=&quot;789&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHEKeD/btsMB4AKF9T/DHEmM1xwNKGOSEgNErkpJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHEKeD/btsMB4AKF9T/DHEmM1xwNKGOSEgNErkpJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHEKeD/btsMB4AKF9T/DHEmM1xwNKGOSEgNErkpJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHEKeD%2FbtsMB4AKF9T%2FDHEmM1xwNKGOSEgNErkpJ0%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;752&quot; height=&quot;537&quot; data-filename=&quot;스크린샷 2025-03-04 오후 8.15.53.png&quot; data-origin-width=&quot;1104&quot; data-origin-height=&quot;789&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;잠깐! 본 논문에서 나오는 핵심 수행 내용에 따른, 기술 용어를 먼저 정리하고 진행해봅시다. &lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 618px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 20px;&quot;&gt;&lt;b&gt;기술 용어&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 71.3953%; height: 20px;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 80px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 80px;&quot;&gt;Universal Jailbreak&lt;/td&gt;
&lt;td style=&quot;width: 71.3953%; height: 80px;&quot;&gt;우리나라 말로 하면 보편적 탈옥이라는 용어입니다. Universal Jailbreak는 특정 프롬프트나 기법에 의존하지 않고도 대부분의 질의에서 높은 확률로 모델의 보안 장치를 무력화 할 수 있는 방법을 의미합니다. 즉, LLM의 보안 필터를 우회해서 금지된 정보를 제공하도록 유도하는 방법이죠. 이러한 Universal Jailbreak를 허용한다는 것은 보안에 치명적인 문제가 발생할 수 있다는 것을 의미합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 34px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 34px;&quot;&gt;Without Safeguard model&lt;/td&gt;
&lt;td style=&quot;width: 71.3953%; height: 102px;&quot; rowspan=&quot;3&quot;&gt;세 개 다 비슷한 용어로 사용되는데요. 보안 장치가 없는 모델이라고 이해하시면 됩니다. 즉, 방어 기법이 적용되지 않은 모델인 것이죠. 사용자의 질문에 대해 최대한 도움이 되는 정보를 제공하는 모델이며, 본 연구에서는 이를 기준으로 삼아 보안이 적용된 AI 모델이 얼마나 금지된 정보를 효과적으로 차단하는지 비교합니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;만약, 실험에서 Helpful-only model과 유사한 점수를 받았다는 것은, 유사한 수준의 정보를 제공해주었다는 것이고 이는 Jailbreak가 성공했다는 것을 의미하는 것이죠.&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 34px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 34px;&quot;&gt;Unrestrict model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 34px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 34px;&quot;&gt;Helpful-only model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 60px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 60px;&quot;&gt;Linear Value Head&lt;/td&gt;
&lt;td style=&quot;width: 71.3953%; height: 60px;&quot;&gt;모델이 특정 문장의 유해성 점수(Harmfulness score)를 예측하는 신경망 구조입니다. 다음 문장을 예측하는 LLM과 다르게 문장의 위험성을 판별하죠. 이때, T=10이라는 것은, T=10 토큰 길이의 문장을 가지고 위험성을 예측하는 것입니다. 10개만 보고도 즉시 차단할 수 있는 그런 구조인 것입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 120px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 120px;&quot;&gt;Rubric 점수&lt;/td&gt;
&lt;td style=&quot;width: 71.3953%; height: 120px;&quot;&gt;학습자의 과제 수행을 평가하기 위한 기준을 정한 표. 즉, 평가를 위한 기준 집합(채점 기준)이라고 보시면 됩니다. Jailbreak된 모델의 응답이 이 Rubric과 얼마나 유사한지를 평가 기준으로 삼습니다. 예를 들어서, Rubric 점수가 33%라면 일부 정보를 포함하지만, Jailbreak 성공률이 낮다. 60% 이상이면 가능성이 있다 등으로 평가합니다.&amp;nbsp;&lt;br /&gt;이때, 비교를 하는 것은 Helpful-only model과 거의 비슷한 수준의 정보를 제공하면 Jailbreak가 성공되었다고 간주하는 것입니다.&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 100px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 100px;&quot;&gt;Constitution 기반의 데이터 학습&lt;/td&gt;
&lt;td style=&quot;width: 71.3953%; height: 100px;&quot;&gt;이 데이터는 필터링 룰이 아니라, LLM이 이해할 수 있도록 정의된 규칙 집합입니다.&amp;nbsp;&lt;br /&gt;예를 들어서, &quot;1. 대량 oooo 제조법을 제공하지 않는다&quot;와 같은 형태로 규칙 집합이 정의된 것이죠. 이를 바탕으로 합성 데이터(Synthetic data)를 생성하고 LLM을 이용해 다양한 질문과 응답을 생성하게 됩니다. 이 생성된 내용을 헌법(Constitution)에 따라 분류해 금지된 내용과 허용된 내용을 구분해서&amp;nbsp; Classifier를 학습시키는 것입니다.&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 118px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 118px;&quot;&gt;Constitutional classifier&lt;/td&gt;
&lt;td style=&quot;width: 71.3953%; height: 118px;&quot;&gt;이 방법이 논문에서 저자들이 제안한 분류기입니다. 적용된 모델이 방어 체계가 적용된 모델이라고 볼 수 있습니다. 2개의 Classifier가 있습니다.&lt;br /&gt;&lt;br /&gt;- Input Classifier: 사용자가 LLM에게 보낼 질문을 사전에 감지해서, LLM에 가기 전에 미리 차단&lt;br /&gt;- Output Classifier: LLM이 생성한 응답을 실시간으로 모니터링하면서, 위험한 정보가 있으면 출력을 차단&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;본 연구에서 제안하는 핵심 수행 연구는 Figure 1과 같습니다. 이를 위해서 Constituional Classifier 기반의 보안 필터를 설계를 했는데요. 각 과정에 대해서 단계별로 설명을 하자면 아래와 같습니다.&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; Constitution 기반의 데이터를 활용해서 합성 데이터(Synthetic Data)를 만들어두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 이를 활용해 Input classifier와 Output classifier 모델을 훈련하여 만들어두었습니다. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Input Classifier는 Claude 3.5 Sonnet을 활용해서 Fine-tuning을 진행했으며, Next Token Prediction 방법으로 모델 훈련을 진행했다고 하며, 사용자의 입력이 위험을 포함하는지 여부를 훈련한 것이죠. Output Classifier는 LLM의 응답이 유해한지 실시간으로 감지할 수 있도록 훈련되었다고 합니다. 마찬가지로 Claude 3.5 Sonnect을 활용해 Fine-tuning을 진행했으며 이때 Linear Value Head 방식과 Cumulative-maximum 방식의 장점을 결합하여 학습했다고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;3.&amp;nbsp;&lt;/span&gt;사용자의 입력 Query가 들어오게 되면 먼저 Constitutional Input Classifier가 사용자 입력 데이터에서 먼저 사전 필터링을 수행합니다. Jailbreak 공격 가능성이 있는 것을 사전에 차단하는 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Constitutional 만약 유해한 정보가 없다면 작업을 수행하게 되며, LLM이 응답을 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. LLM이 어떤 결과를 출력하게 될 때, 이 출력하는 과정에서 Constitutional Output Classifier가 실시간으로 LLM이 생성한 응답이 금지된 정보를 포함하는지를 분석하게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 이상이 없다면 응답을 제공한다.&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;앤트로픽(Anthropic)이 제안한 Constituional Classifiers는 이와 같은 과정을 제안하는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;이제 다음 파트부터 상세한 내용을 리뷰해보겠습니다. 논문이 방대하기 때문에 핵심적인 내용을 위주로 리뷰하겠습니다. 만약, 긴 글이 부담스러우신 독자 분들은 여기까지만 보셔도 됩니다. 또한, 본 포스팅에서도 핵심적인 내용을 위주로 리뷰하였기 때문에 상세한 내용은 논문을 꼭 살펴보시길 권장드립니다.&lt;/span&gt;&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;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Problem Formulation: Robust and Pratically Viable Defenses Against Universal Jailbreaks&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2장에서는 Universal Jailbreak에 대한 문제 정의(Problem Formulation)와 이를 방어하기 위한 보안 시스템이 충족해야 할 핵심 요구 사항(Desideratum)을 설명하고 있습니다.&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;요구 사항(Desideratum)-1(Robustness to universal jailbreaks).&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 모델이 발전하면서, 과학적으로 정교한 지식을 제공할 수 있는 능력이 강화되었습니다. 이는 다양한 분야에서 긍정적인 영향을 미칠 수 있지만, 동시에 악의적인 사용 가능성(dual-use risk)도 존재하게 됩니다. 특히, 과거에 Anthropic과 OpenAI 연구에서는 LLM과 같은 AI 모델이 비전문가(non-expert)에게도 위험한 CBRN(Chemical, Biological, Radiological, Nuclear) 정보를 제공할 가능성이 있다는 점을 우려했었다고 합니다. 그렇기에 Universal Jailbreak를 방어하는 것은 AI가 실제 환경에서 악용되지 않도록 하는 핵심 과제인 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Universal Jailbreak에 대한 설명은 본 파트에서 나오지만, 제 포스팅에서는 위의 기술 용어 설명에서 설명하였으니, 간단히 설명하고 넘어가겠습니다. Universal Jailbreak라는 것은 특정 프롬프트 기법을 통해서 대부분의 보안 필터를 우회할 수 있는 방법을 말합니다. 이런 공격이 성공하면 AI 모델이 사실상 Unrestricted(보안 필터가 없는) 상태가 되어 버리는 것입니다. 이러한 Universal Jailbreak이 비전문가에게 위험한 이유는 비전문가도 복잡한 과학적, 기술적 과정을 수행할 수 있게 도와줄 수 있다는 점인데요. 논문에서는 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) 비전문가도 신뢰할 수 있는 정확한 정보를 쉽게 얻을 수 있다는 점입니다. 비전문가는 일반적으로 과학적 정보를 전문가보다 검증할 능력이 부족하기에, AI가 제공하는 정보가 사실인지 여부를 판단하지 못하고 그대로 실행할 가능성이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 하나의 공격 기법이 대부분의 질문을 처리할 수 있습니다. Universal Jailbreak은 단순히 특정 문장 하나가 아니라, 다양한 방식으로 보안 필터를 지속적으로 우회할 수 있습니다. 즉, 한두개의 질문에만 답하는 것이 아니라, 위협 행위를 실행하기 위해 다양한 질문에 대해 연속적이고 일관된 도움을 줄 수 있다는 것입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) LLM은 일반적인 지식보다, 매우 구체적이고 정확한 정보를 제공합니다.&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;따라서, universal jailbreaks를 방지하면, CBRN 위험이 실질적으로 커지기 전에, 이에 대한 위험성을 크게 줄일 수 있다고 저자들은 말합니다. 왜냐하면 LLM이 탈옥되면 비전문가도 전문가 수준의 정보를 쉽게 얻을 수 있고 이것은 위험성이 커지기 때문이죠. 비전문가가 전문가처럼 행동할 수 있게 되고 AI의 도움으로 원래 할 수 없었던 과학적, 기술적 절차를 수행할 가능성이 있게 되는 것입니다. 또한, 한두 개의 정보를 제공하는것이 아니라, 전체 과정에서 지속적으로 가이드를 해준다면 더 위험해지게 되겠죠. 그리고 일반적인 지식보다 구체적인 지식을 제공한다면 비전문가가 실제로 기술적 절차를 수해아는데 필요한 수준의 지침을 제공할 수 있게 됩니다. 그렇기에 Universal Jailbreak을 방지하는 게 중요한 것입니다.&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;요구 사항(Desideratum)-2(Practical deployment viability).&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI의 보안장치(Safeguard)가 실제 서비스에 적용될 때 현실적으로 실행 가능해야 한다는 것입니다. 아무리 강력해도 실제 운영 환경에서 너무 많은 자원(resource)를 소모하거나, 성능을 저하시킨다면 의미가 없겠죠. 이에, (a) 합리적인 연산 비용(Inference overhead)과 지연 시간(Latency)을 유지하며 운영 환경에서 비용 효율적이어야 한다는 것을 언급합니다. 또한, (b) 첫 번째 토큰 응답 속도(time to first token)와 스트리밍 기능(streaming capabilities)을 유지하여 사용자 경험을 보장해야 한다는 것 그리고 (c) False positive 를 최소화해서 정당한 사용자의 불편을 방지해야 한다는 것을 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(False Positive는 실제로는 안전한 data를 잘못된 판단으로 '위험'이라고 판단해 차단하는 것이며 즉, 위험하지 않은 요청을 잘못 차단하는 경우를 의미합니다.)&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;요구 사항(Desideratum)-3(flexibility).&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변화하는 환경에 맞춰 적응할 수 있어야합니다. Safeguard는 변화하는 위험 영역에 적응할 수 있을만큼 유연(Flexbility)해야 합니다. 새로운 기술과 위협이 계속 등장하기 때문에 AI의 보안 장치도 지속적으로 발전할 수 있어야 한다는 것이죠. 공격자들이 점점 더 정교한 기법을 개발할수록, 시스템은 새로운 공격 패턴에 대한 방어 기능을 포함할 수 있어야 합니다.&amp;nbsp;&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;3. Constitutional Classifiers&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 universal jailbreaks에 실용적인 방어 시스템을 개발하기 위해서 constitution-guided한 합성 데이터(synthetic data)로 classifier를 훈련합니다. 이러한 classifier를 활용해서 safeguard를 훈련해 jailbreak를 탐지하고 차단하는 것이죠.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item dable&quot; style=&quot;height: 250px;&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;300x250&lt;/div&gt;
    &lt;div id=&quot;dablewidget_Pl1aE8lE&quot; data-widget_id=&quot;Pl1aE8lE&quot;&gt;
      &lt;script&gt;(function(d,a,b,l,e,_) {
    if(d[b]&amp;&amp;d[b].q)return;d[b]=function(){(d[b].q=d[b].q||[]).push(arguments)};e=a.createElement(l);
    e.async=1;e.charset='utf-8';e.src='//static.dable.io/dist/plugin.min.js';
    _=a.getElementsByTagName(l)[0];_.parentNode.insertBefore(e,_);
    })(window,document,'dable','script');
dable('setService', 'lsjsj92.tistory.com');
dable('sendLogOnce');
dable('renderWidget', 'dablewidget_Pl1aE8lE', {ignore_items: true});&lt;/script&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 헌법(Constitution) 접근 방식은 해로운 콘텐츠와 허용 가능한 콘텐츠의 범위를 유연하게(flexibility) 정의할 수 있도록 하고, 새로운 위협이 등장할 때마다 safeguard를 업데이트 할 수 있을 뿐만 아니라, 대량의 훈련 데이터를 생성하는데에도 도움이 된다고 저자들은 말합니다. robustness를 유지하면서도 false positive를 최소화 하기 위해, data-augmentation 기법을 활용해서 정상적인 입력, 출력 데이터를 대량으로 사용한다고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1 Specifying a constituion&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들의 접근법은 헌법(constitution, 자연어로 정의된 규칙의 집합)을 사용하여 허용된 콘텐츠와 제한된 콘텐츠의 범주를 정의합니다. 이는 테이블 1과 같은데요.&amp;nbsp;&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-filename=&quot;스크린샷 2025-03-09 오후 4.33.32.png&quot; data-origin-width=&quot;2704&quot; data-origin-height=&quot;778&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biSmob/btsMFs9EwAe/zjNEmujmO7PAWJ0SfNNDpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biSmob/btsMFs9EwAe/zjNEmujmO7PAWJ0SfNNDpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biSmob/btsMFs9EwAe/zjNEmujmO7PAWJ0SfNNDpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiSmob%2FbtsMFs9EwAe%2FzjNEmujmO7PAWJ0SfNNDpk%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;2704&quot; height=&quot;778&quot; data-filename=&quot;스크린샷 2025-03-09 오후 4.33.32.png&quot; data-origin-width=&quot;2704&quot; data-origin-height=&quot;778&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;이렇게 허용된 헌법(constitution)과 아닌 것을 구분해놓는 것입니다. 또한, over-refusal(LLM이 정상적인 질문까지도 거부하는 현상)을 방지하기 위해 허용된 콘텐츠의 범주를 명확히 정의한다고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이렇게 constitution이 자연어로 작성되었기 때문에, 새로운 위협 모델이나 방법이 등장할 때마다 콘텐츠 범주를 업데이트하여 이를 조정하고 개선할 수 있다고 저자들은 말합니다. 마지막으로 이렇게 생성된 라벨링된 데이터는 다양한 보안 시스템을 훈련하는데 사용할 수 있다고도 말하면서 해로운 콘텐츠와 해롭지 않은 것을 명확히 구분함으로써 더 정교한 훈련 데이터를 생성할 수 있다고, 이를 통해 classifier가 적절한 기준을 학습하는데 도움이 된다고 저자들은 말합니다.&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;3.2 Generating synthetic data&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 classifier를 만드는데, 이는 fine-tuned LLM입니다. 이를 통해서 시스템의 취약점을 체계적으로 해결할 수 있고 LLM을 분류 작업에 특화시킴으로써 연산 비용(computational overhead)를 줄일 수 있다고 저자들은 말합니다. 따라서, 이를 위해 synthetic data를 생성하게 되는데요. 여기서는 2가지 stage가 있습니다.&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;Stage-1&lt;/b&gt;: Constitution-based synthetic-data generation 스테이지로, helpful-only 모델을 사용하여 constitution 마테고리 전반에 걸친 질문을 생성하도록 합니다. 그 다음, helpful-only 모델을 사용해 생성된 질문에 대해 해로운 답변(출력)과 무해한 출력(harmless)을 각각 생성하도록 합니다. 그 이후, 프롬프트 기반 언어 모델(prompted language model)을 사용해서 생성된 입력 및 울력에서 의도하지 않은 거부(inadvertent refusals)를 제거합니다. 즉, 불필요하게 질문을 거부하는 경우를 방지하기 위해 필터링을 수행하는 것입니다.&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;Stage-2&lt;/b&gt;: Data augmentation 스테이지로, 합성 데이터의 다양성과 적용 범위를 확장하기 위해 이 스테이지를 적용했다고 합니다. 다양한 변형(transformation)은 의미를 유지하면서 입력과 출력의 다양성을 확장하며, 여러 언어(multiple linguistic)에 대한 확장도 있습니다. 여기에서는 번역, LLM 기반의 의역(paraphrasing), 시스템 프롬프트 variation, 다양한 jailbreaking 기법 등이 있다고 합니다.&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;3.3 Automated red teaming&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 자동화된 레드팀에 대해서 소개하는데요. Red Teaming은 보안 시스템의 취약점을 찾기 위해 공격 시뮬레이션 등을 수행하는 팀입니다. 저자들이 말하는 Automated Read Teaming은 AI 모델을 활용해 자동으로 공격을 생성하는 것인데요. helpful-only 모델에 알려진 탈옥 기법을 설명하고, 새로운 공격을 생성하도록 요청하는 것입니다. 이미 차단된 질문을 기반으로 보안 시스템을 우회할 수 있는 새로운 패턴을 만들어내는 것입니다. 이때 Multi-turn 방식이나, Long-context 공격까지 생성해서 우회할 수 있는 질문을 더욱 정교하게 만들어둡니다.&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;3.4 Training classifiers&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 저자들이 제안하는 classifier에 대해서 상세하게 설명이 나옵니다. Input Classifier와 Output classifier로 나뉘어진 방법에 대해서 각각 설명하는데요.&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;Input Classifier&lt;/b&gt;: 입력 분류 작업은 다음 토큰 예측 문제(Next token prediction problem)으로 설정하고 이를 수행하도록 Language 모델을 미세 조정(Fine-tuning) 학습시킵니다. 입력 질문을 해당 작업을 수행하는 템플릿(Template) 형태로 감싸서 처리하도록 합니다. 또한, 데이터는 constitution을 활용한 synthetic data를 활용해서 훈련을 진행하고 암호화된 질문이나 모호한 표현을 사용한 공격도 탐지하고 차단하도록 훈련을 진행했다고 합니다. 또한, 위에서 한 번 언급한것과 같이 False Positive 비율을 줄이기 위해서 무해한 질문 데이터도 포함시켰다고 합니다.&amp;nbsp;&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-filename=&quot;스크린샷 2025-03-09 오후 4.24.09.png&quot; data-origin-width=&quot;2634&quot; data-origin-height=&quot;772&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D9Knk/btsMEbhgebY/fl9kNdCo6OOODN11m2r3ek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D9Knk/btsMEbhgebY/fl9kNdCo6OOODN11m2r3ek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D9Knk/btsMEbhgebY/fl9kNdCo6OOODN11m2r3ek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD9Knk%2FbtsMEbhgebY%2Ffl9kNdCo6OOODN11m2r3ek%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;2634&quot; height=&quot;772&quot; data-filename=&quot;스크린샷 2025-03-09 오후 4.24.09.png&quot; data-origin-width=&quot;2634&quot; data-origin-height=&quot;772&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;b&gt;Output Classifier&lt;/b&gt;: 출력 스트리밍 기능을 유지하면서 보안 문제를 차단하는 방법을 제안합니다. 즉, 실시간으로 문장을 출력하면서도 위험한 내용이 탐지되면 즉시 차단하는 것이죠. 저자들은 이 방법은 latency가 중요한 application에서 특히 중요하다고 말합니다. 이를 달성하기 위해서 Linear Value Head를 갖춘 Language model을 fine-tuninig하여 길이 T인 전체 토큰 시퀀스의 유해성을 \(\tilde{T} \leq T\)인 prefix 시퀀스를 기반으로 예측하도록 수행합니다(Figure 2를 참고). 즉, 문장을 생성하면서 앞부분만 보고 전체 문장이 유해할 가능성이 있는지 판단하는 것이죠. 만약, classifier가 특정 토큰에 대해 예측한 점수가 threshold를 초과하면, 출력을 차단하고 스트리밍을 중단시키게 됩니다. 저자들은 이 방법을 사용하면 샘플링 및 토큰 단위 예측 동안 중간 활성화(intermediate activation)를 캐시할 수 있으며, 스트리밍 분류(Streaming classification)에 효과적인 접근법이 된다고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구체적으로 모델이 \( p(y = 1 | t_1:T' ) \) 를 학습하도록 훈련하는데, 이는 전체 문장의 유해성을 접두 시퀀스(prefix) \( t_1:T' \)를 기반으로 예측하도록 합니다(\( T' \leq T \)). 이것의 의미는 전체 문장을 보고 예측하는 것이 아니라, 앞부분 \( T' \)까지만 보고 위험성을 판단하고, 유해해질 가능성이 있다면 미리 차단할 수 있도록 학습하는 것입니다. 이를 위해 논문에서는 아래와 같은 loss 함수를 최적화하다고 합니다.&amp;nbsp;&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-filename=&quot;스크린샷 2025-03-09 오후 4.24.47.png&quot; data-origin-width=&quot;2216&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL8YjD/btsMD4PTMOi/uXbddqHHfeErCrYa80QMl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL8YjD/btsMD4PTMOi/uXbddqHHfeErCrYa80QMl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL8YjD/btsMD4PTMOi/uXbddqHHfeErCrYa80QMl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL8YjD%2FbtsMD4PTMOi%2FuXbddqHHfeErCrYa80QMl1%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;2216&quot; height=&quot;242&quot; data-filename=&quot;스크린샷 2025-03-09 오후 4.24.47.png&quot; data-origin-width=&quot;2216&quot; data-origin-height=&quot;242&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;첫 번째 항인 \( L_{NTP} (t_1:T ) \)은 Next token prediction loss로서, 다음 단어의 예측에 대한 손실입니다. LLM이 문장의 자연스러운 흐름을 유지하면서 텍스트를 예측하도록 하기 위함입니다. 두 번째 항인 \( \sum_{T' = 1}^{T} L_{\text{BCE}} (y, p(y = 1 | t_1:T') \)은 binar cross entropy loss로서 유해성을 예측하는 과정을 수행하게 됩니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-03-09 오후 4.25.12.png&quot; data-origin-width=&quot;2704&quot; data-origin-height=&quot;1330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oO9f2/btsMGfWeDxY/nZ4mKNgKzr4hlny8kFJzfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oO9f2/btsMGfWeDxY/nZ4mKNgKzr4hlny8kFJzfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oO9f2/btsMGfWeDxY/nZ4mKNgKzr4hlny8kFJzfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoO9f2%2FbtsMGfWeDxY%2FnZ4mKNgKzr4hlny8kFJzfK%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;750&quot; height=&quot;369&quot; data-filename=&quot;스크린샷 2025-03-09 오후 4.25.12.png&quot; data-origin-width=&quot;2704&quot; data-origin-height=&quot;1330&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;첫 번째로는 각 토큰별 확률을 사용해 전체 문장이 유해한지를 판별하는 것이고, 두 번째는 누적 최대값(cumulatvie-maximum)을 사용해 문장이 유해한지 예측하는 것입니다. 논문에서는 두 방법을 적절히 혼합해서 최적화하였으며, 학습 과정에서 선형 보간(linear interpolation)하도록 합니다. 초기에는 1번 방법을 사용하다가 점차 2번 방법으로 적용하는 것이죠.&amp;nbsp;&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;4. Constitutional classifiers defend against universal jailbreaks across thousands of hours of human red teaming&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 장에서부터는 저자들이 제안한 Constitutional classifier가 얼마나 실제 공격에서도 잘 동작하는지 평가한 결과를 설명합니다.&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;4.1 Methods&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 방법론입니다. 여기서는 Red team을 구성하는 것, jailbreak가 성공했다는 것을 평가하는 것, Read teaming task 등의 설명이 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jailbreak가 성공했다는 것은 LLM 기반 루브릭 평가 시스템(rubric-grading pipleline)을 구현해 사용했다고 합니다. 이를 위해서 먼저, 보안 필터가 없는 helpful-only 모델을 사용해 금지된 질문에 대한 AI 응답을 사용해 기준 데이터를 만들었고, jailbreak된 응답을 평가하기 위해 LLM을 사용한 평가 시스템(LLM Grader)으로 루브릭과 비교하여 위험한 정보가 포함된 정도를 점수화했다고 합니다. 그런 다음 이 점수를 helpful-only 모델의 평균 점수와 비교해 Jailbreak 효과를 평가했다고 합니다. Figure 3는 그 과정을 보여주는 예시입니다.&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-filename=&quot;스크린샷 2025-03-09 오후 4.24.30.png&quot; data-origin-width=&quot;2634&quot; data-origin-height=&quot;1666&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o99z1/btsMFEB5pRV/KaDSAzulhKRyJhniQ0j4i1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o99z1/btsMFEB5pRV/KaDSAzulhKRyJhniQ0j4i1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o99z1/btsMFEB5pRV/KaDSAzulhKRyJhniQ0j4i1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo99z1%2FbtsMFEB5pRV%2FKaDSAzulhKRyJhniQ0j4i1%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;632&quot; height=&quot;400&quot; data-filename=&quot;스크린샷 2025-03-09 오후 4.24.30.png&quot; data-origin-width=&quot;2634&quot; data-origin-height=&quot;1666&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외에, Read teaming에게 상금을 지불했고, 이들의 투입한 총 시간(Estimating red-teaming effort), 얼마나 투입했고, 어떻게 모집했는지에 대한 이야기도 있지만 지면상 내용을 생략합니다. 자세한 내용은 논문을 참고해주세요.&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;4.2 Results&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 4.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;&lt;b&gt;[1] 레드팀은 다양한 공격 전략을 채택하였음&lt;/b&gt;: 참가자들은 다양한 기법을 활용해서 Jailbreak를 시도했으며, role-playing, multi-turn등이 그 예시입니다. 그리고 텍스트-이미지 변환과 같은 방법도 시도했다고 하네요.&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;[2] 레드팀 테스트에서 완전한 성공을 거둔 사례는 없음&lt;/b&gt;: 113개의 Jailbreak 보고서 중, helpful-only 모델이 제공한 정보의 절반 이상을 포함하면서(이렇게 수행한 이유는 4.1과 같이 helpful-only 모델을 이용해 먼저 답을 구성하고 이와 비교하는 것이기 때문), 10개 질문 모두에 성공적으로 답변한 사례는 없었다고 합니다. 그래도 9개 정도는 50% 기준에서 6개 이상의 질문에 실질적인 답변을 제공했지만, helpful-only 모델과 응답의 세부 사항이 완전히 일치하는 엄격한 기준을 적용했을 때, 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] 가장 성공적인 레드팀 참가자도, 제한적인 결과만 얻었음&lt;/b&gt;: 모든 보고서를 종합적으로 분석했을 때, 가장 성공적인 레드팀 조차도 제한적인 결과를 얻었다고 합니다. 특히, 더 엄격한 기준(Helpful-only모델 수준의 세부 정보를 포함하는 답변을 요구)을 적용했을 때, 가장 성공적인 레드팀 참가자조차도 10개 질문 중 6개에만 답변할 수 있었다고 하네요. 이러한 결과를 저자들이 제안한 방법이 Universal jailbreak에 대해 강력한 보안성을 가지고 있다는 것을 입증한다고 저자들은 말합니다.&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;[4] 어떤 질문들은 다른 질문들보다 jailbreak하기 어려움&lt;/b&gt;: 가장 쉬운 것은 30개 이상의 보고서에서 탈옥이 성공되었고, 어려운 것은 4개의 보고서에서만 jailbreak가 성공하였다고 합니다. 즉, 질문 내용에 따라 보안 시스템이 더 강하게 작용할 수도 있는 것이죠. 이러한 결과는 보안 테스트에서 질문을 어떻게 구성하느냐가 중요해지는 것입니다. 따라서, 저자들은 의미 있는 평가를 위해 실제 위협 모델과 밀접하게 연관된 질문을 선택할 것을 권장한다고 합니다.&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;[5] 레드팀 참가자들은 루브릭 평가 방식을 악용하려고 했음&lt;/b&gt;: 레드팀 참가자들은 방어 체계를 우회하기 보다, 루브릭 평가 방식을 악용하려고 했다고 합니다. 즉, 보안 시스템 자체를 뚫는다기보다 평가 시스템의 허점을 이용하기도 한 것이죠. 그리고 여기서 Jailbreak가 성공한 주요한 두 가지 성공 전략이 확인되었다고 하는데요. 무해한 표현으로 바꾸는 방식(benign paraphrasing)과 length exploitation이라고 합니다. 여기서 무해한 표현으로 바꾸는 것이란, 유해한 질문인데 겉보기에는 무해해 보이도록 하는 것이라고 합니다. 또한, 길이를 활용하는 것은 LLM이 긴 출력을 생성하도록 해서 유해한 내용이라기보단 전체적인 양(volumn)으로 높은 점수를 얻는 방식입니다. 그럼에도 universal jailbreak는 대부분 효과적이지 못했다고 하죠.&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;[6] real-world 활용 가능성&lt;/b&gt;: 복잡한 과정을 N개의 연속적인 단계로 단순화하여 분석하였다고 합니다. 그리고 제안한 방법이 여러 단계의 과정을 필요로 하는 작업에서 악용의 가능성을 감소시킬 수 있음을 보았다고 저자들은 말합니다.&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;[7] 한계&lt;/b&gt;: universal jailbreak의 가능성을 입증했으나, 강력한 보안성을 우선시한 결과 refusal rate가 너무 높았다고 합니다. 또한, 여전히 일부 취약점이 발견되었기도 하였구요. 그리고 저자들은 red-team 참가자들이 실제 모든 공격자를 대표할 수 없다는 것도 한계라고 지적하면서 jailbreak 기법이 발전함에 따라, 새로운 전략이 등장할 수 있을 것이라고 언급하였습니다.&amp;nbsp;&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;5. Constitutional classifiers are flexible and practically viable defenses&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 논문의 5장에서 constitutional classifier는 유연성(flexible)과 배포 가능성(deployment viability)이 있다고 이를 입증하는 과정을 수행합니다. 결과적으로 저자들은 강한 보안성(strong robustness)를 제공하면서도 연산 비용(inference overhead)과 과도한 거부(over-refusals)를 제한한다고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;5-1.  Methodology&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논문에서는 Constituional classifier의 flexible과 deployment viability를 실험하기 위해서 (1) Enhanced classifier methodology, (2)  Jailbreak-attempts dataset, (3)  Grading model responses,&amp;nbsp;(4) Over-refusal datasets,&amp;nbsp;(5) Setting classification threshold, (6) Estimating inference costs을 수행합니다. harmless한 질문을 정의하는 constitution을 확장하거나, data augumentation을 수행하고 이때 Claude 3.5 Haiku를 사용해 연산 비용을 줄이는 등 시도를 한 내용이 나와있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅에서는 5-2절에 집중하기 위해 5-1은 넘어가겠습니다. 궁금하신 분들은 논문을 참고해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;5-2. Result&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논문의 5.2절에서는 실험 결과를 제공합니다. 저자들은 가장 널리 사용되는 배포 시나리오는 harmlessness training을 적용한 unguarded instance인 Claude 3.5 Sonnet 모델이라고 말합니다. 또한, Claude 3.5 sonnet을 기반으로 세 가지 프롬프트 분류기 변형(variants of prompted classifier)도 실험에 포함시켰다고 하며, 세 가지는 (1) Zero-shot prompting, (2) Chain of Thought, (3) 32-shot prompting 입니다.&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] Constitutional classifiers substantially enhance robustness while preserving model utility&lt;/b&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-filename=&quot;스크린샷 2025-03-12 오후 9.06.15.png&quot; data-origin-width=&quot;2378&quot; data-origin-height=&quot;1914&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dPEfEF/btsMIECPnNe/xmC28HkDxFQKxqiuYnC710/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dPEfEF/btsMIECPnNe/xmC28HkDxFQKxqiuYnC710/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dPEfEF/btsMIECPnNe/xmC28HkDxFQKxqiuYnC710/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdPEfEF%2FbtsMIECPnNe%2FxmC28HkDxFQKxqiuYnC710%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;669&quot; height=&quot;538&quot; data-filename=&quot;스크린샷 2025-03-12 오후 9.06.15.png&quot; data-origin-width=&quot;2378&quot; data-origin-height=&quot;1914&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;소제목에도 나와있지만, 이 실험의 결과는 모델의 유용성을 유지하면서도 보안성(강건성, robustness)를 크게 향상시킨다고 합니다. Claude 3.5 Sonnet에 constitutional input and output classifier를 추가하면 jailbreak 방어 성능이 크게 향상된다고 저자들은 말합니다. Figure 6의 (A)를 보면 Constitutional classifier가 적용된 Claude 3.5 Haiku가 가장 낮은 공격 성공률(보안성이 가장 좋게 됨)을 보여줌을 확인할 수 있습니다. 또한, singile transformation으로 10개의 query에 모두 답할 수 있는 사례가 없었으며 저자들은 이르 ㄹ두고 universal jailbreak도 방어할 수 있음을 시사한다고 말합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Figure 6의 (B)를 보면 소폭의 False positive rate만을 관찰한 것을 확인할 수 있으며 Figure 6의 (C)를 보면 연산 비용도 적정 수준에서 유지되었다고 저자들은 말합니다.&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;[2] Classifier robustness scales with model size, data quantity, and data augmentation&lt;/b&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-filename=&quot;스크린샷 2025-03-12 오후 9.06.26.png&quot; data-origin-width=&quot;2378&quot; data-origin-height=&quot;1564&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cH9ZJl/btsMH67BzjP/DNPSJkN1ZsiKJQrxS6mUWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cH9ZJl/btsMH67BzjP/DNPSJkN1ZsiKJQrxS6mUWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cH9ZJl/btsMH67BzjP/DNPSJkN1ZsiKJQrxS6mUWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcH9ZJl%2FbtsMH67BzjP%2FDNPSJkN1ZsiKJQrxS6mUWk%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;666&quot; height=&quot;438&quot; data-filename=&quot;스크린샷 2025-03-12 오후 9.06.26.png&quot; data-origin-width=&quot;2378&quot; data-origin-height=&quot;1564&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;저자들은 하이퍼파라미터와 training data의 크기를 고정한 뒤, 모델 크기만 다르게 설정해서 classifier를 훈련했다고 합니다. 실험을 통해 저자들은 모델 크기가 증가할수록 보안성이 지속적으로 향상됨을 발견했다고 하며 특히, Figure 7의 (A)와 같이 더 큰 모델일수록 input classification에서 generalization gap(일반화 오류)가 줄어드는 경향이 보였다고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Claude 3.5 Haiku 기반 classifier를 subset of training data(훈련 데이터의 일부)를 사용하여 fine-tuning한 결과, training dataset이 커질수록 robustness가 향상됨을 보였다고 하며 그 결과가 Figure 7의 (B)라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 data augmentation 기법이 classifier에 미치는 영향을 분석한 결과 Figure 7의 (C)와 같이 transformation을 도입할수록 robustness가 전반적으로 향상되었다고 합니다.&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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 Claude 계열의 모델을 만든 Anthropic의 Safeguards Research Team에서 작성한 논문으로, ChatGPT와 같은 LLM 모델들이 겪을 수 있는 Jailbreak 문제를 다룬 논문입니다. 특히, Universal jailbreak를 방어하기 위해 classifier를 도입했고 Constitutional classifier를 도입했고 이러한 Constitution을 기반으로 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;LLM을 활용해 Synthetic data(합성 데이터)를 활용해 학습된 보안 필터라고 볼 수 있습니다.&amp;nbsp;&lt;/span&gt; 다양한 실험 결과 LLM의 보안성을 강화할 수 있었다는 것을 보여주었구요.&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;긴 글 읽어주셔서 감사합니다.&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;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- Linkedin:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot;&gt;https://www.linkedin.com/in/lsjsj92/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 블로그 댓글 또는 방명록&lt;/p&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;으로 연락 남겨주시면 됩니다!&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>Anthropic</category>
      <category>ChatGPT</category>
      <category>Claude</category>
      <category>GenAI</category>
      <category>JailBreak</category>
      <category>LLM</category>
      <category>llm safeguard</category>
      <category>robustness</category>
      <category>universal jailbreak</category>
      <category>보안</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/681</guid>
      <comments>https://lsjsj92.tistory.com/681#entry681comment</comments>
      <pubDate>Wed, 12 Mar 2025 21:32:46 +0900</pubDate>
    </item>
    <item>
      <title>Agent4Edu: AI 기반 맞춤형 교육(Feat. AI Agent와 LLM이 만드는 개인화 학습 시뮬레이터)</title>
      <link>https://lsjsj92.tistory.com/680</link>
      <description>&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;본 포스팅은 Agent4Edu라는 논문을 리뷰하는 포스팅입니다. 최근 AI 기술의 발전은 단순한 질의응답을 넘어, 보다 능동적이고 지속적인 상호작용(interaction)이 가능한 AI 에이전트(Agent)로 진화하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성형 AI(Generative AI)가 등장하면서, ChatGPT와 같은 대형 언어 모델(Large Language Model, LLM)이 다양한 영역에서 활동하고 있는데요. 이제는 단순한 텍스트 생성을 넘어서 AI가 사용자의 행동을 분석하고, 학습 패턴을 이해하며, 능동적으로 문제를 해결하도록 설계된 AI Agent 기반 시스템이 주목 받고 있습니다.&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;Agent4Edu는 이러한 AI 에이전트를 교육(Education) 도메인에 적용하여, 학습자를 지원하는 방법을 제안합니다. LLM을 기반으로 학습자의 사고 과정과 학습 패턴을 분석하고, 이를 바탕으로 맞춤형 학습 경험, 개인화 된(Personalized) 맞춤형 교육 경험을 제공하는 AI 에이전트(Agent) 시스템을 설계하는 방법을 제안합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 논문의 공개된 arxiv 링크는 아래와 같으며 본 포스팅은 아래 링크의 논문을 참고해서 작성한 리뷰 포스팅입니다.&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&gt;&lt;a href=&quot;https://arxiv.org/pdf/2501.10332&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/pdf/2501.10332&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-02-15 오전 11.14.16.png&quot; data-origin-width=&quot;1215&quot; data-origin-height=&quot;413&quot;&gt;&lt;a href=&quot;https://arxiv.org/pdf/2501.10332&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8zPoF/btsMiGaUJRX/x7xSJkoLDWcAMh6Klvk9ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8zPoF%2FbtsMiGaUJRX%2Fx7xSJkoLDWcAMh6Klvk9ak%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;1215&quot; height=&quot;413&quot; data-filename=&quot;스크린샷 2025-02-15 오전 11.14.16.png&quot; data-origin-width=&quot;1215&quot; data-origin-height=&quot;413&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;
&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;&lt;b&gt;포스팅 본문&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅 개요에서도 언급하였듯, 이제 AI는 사용자와 능동적으로 상호작용할 수 있는 AI Agent로 확장되고 있습니다. 본 포스팅은 그 중 교육(Education) 영역에서 개인화된 학습 경험, 맞춤형 학습을 제공하는 Agent4Edu 논문을 리뷰하는 포스팅입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 논문에 작성되어진 순서를 따라갑니다. 먼저, Abstract부터 시작하여 Introduction, Agent4Edu 소개, 마지막 Experiment(실험)까지 살펴보도록 하겠습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[1]. Abstract&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논문의 저자들은 abstract에서 개인 맞춤형 학습은 지능형 교육 시스템(intelligent educational system)내에서 학습자(learner)의 실습 실효성(practice efficiency)를 높이는 것을 목표로 하는데, 기존 오프라인 metric과 온라인 성과 간의 차이는 이러한 진척을 방해한다고 말합니다. 이에 저자들은 새로운 개인 맞춤형 학습 시뮬레이터(personalized learning simulator) Agnet4Edu를 소개합니다. Agent4Edu는 학습자 프로필(learner profile), 메모리 모듈(memory module) 및 개인 학습 알고리즘에 맞춘 액션 모듈(action module)을 장착한 대규모 언어 모델(Large Language Model, LLM) 기반 생성 에이전트(generative agent)를 특징으로 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, 학습자 프로필은 실제 응답 데이터를 사용해 초기화되고 연습 스타일과 인지 요소(cognitive factors)를 캡처한다고 합니다. 메모리 모듈은 심리학 이론에서 영감을 받아 practice fact와 고수준 요약(high-level summary)을 기록하고 반성(reflection)을 함께 통합합니다. 마지막으로 액션 모듈은 문제에 대한 이해, 반응 생성(response generation), 분석 등 다양한 행동을 지원한다고 이야기 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모듈들에 대해서는 논문을 리뷰하며 보다 자세히 설명하도록 하겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[2]. Introduction&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 오늘날 교육 플랫폼에서는 학습자들이 직접 연습 문제를 선택하고 풀이하는 실습(Practice) 활동이 핵심적인 학습 방식으로 자리 잡고 있다고 말합니다. 그 대표적인 예로 코세라(Coursera), 칸 아카데미(Khan Academy), 리트코드(LeetCode)와 같은 플랫폼이 있죠. 그러나, 학습자들 개개인은 학습 속도, 선호하는 문제 유형, 문제 해결 방식 등이 다르기에 개인 맞춤형 학습인 개익화 학습(Personalized Learning)이 중요한 이슈로 떠오르고 있다고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 개인화 학습 시스템이 효과적으로 동작되려면, AI 모델이 실제 학습자들의 실습 데이터를 분석하고 학습할 수 있어야 하는데, 아무래도 현장 실제 교육 환경과 연구 환경에서는 차이(gap)이 존재하기 마련입니다. 예를 들어, 온라인에서 실시간으로 변화하는 학습자의 행동을 반영하지 못하는 데이터라던가 등이죠. 이로 인해, 오프라인 모델의 평가 지표와 실제 온라인 학습 성과 간의 불일치(discrepancy)가 발생하며 연구된 모델을 실제 현장에서 쓰기 어려운 측면이 있죠.&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;&lt;u&gt;1) 단순화된 시뮬레이션(Simplified Simulations)&lt;/u&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;u&gt;2) 실제 응답 데이터에 대한 의존성(Dependency on Real Response Data)&lt;/u&gt;: 이상적인 시뮬레이터는 실제 데이터가 부족하더라도 학습자의 응답을 시뮬레이션 할 수 있어야 하는데, 현재 방법들은 그렇지 못합니다. 현재 방법들은 시뮬레이션 전략을 위해 고품질의 실제 데이터를 필요로 하기에, 기존 실제 데이터 셋과 유사한 응답 패턴 데이터만 생성할 수 있고 제로샷(zero-shot)과 같은 어려운 시나리오에 일반화 하는 데 어려움을 겪습니다.&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;이러한 문제를 해결하기 위해 최근 LLM의 발전이 주목을 받고 있습니다. 이전 연구인 Smallville 프로젝트에서는 AI가 가상의 마을을 구성해 어떻게 상호작용하는지 실험이 진행되었었는데요. 이러한 실험들은 AI가 단순히 패턴 매칭을 넘어, 사고하고 행동을 모방할 수 있는 가능성을 보여준 것이죠. 또한, in-context learning 능력을 가진 LLM은 실제 데이터에 대한 의존도를 최소화하면서 zero-shot과 같은 시뮬레이션을 수행할 수 있습니다.&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-filename=&quot;스크린샷 2025-02-15 오전 11.14.26.png&quot; data-origin-width=&quot;1409&quot; data-origin-height=&quot;677&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sa6KP/btsMi3Kvf3W/kHYbPk49Wmeeg8Qg1fTO71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sa6KP/btsMi3Kvf3W/kHYbPk49Wmeeg8Qg1fTO71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sa6KP/btsMi3Kvf3W/kHYbPk49Wmeeg8Qg1fTO71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsa6KP%2FbtsMi3Kvf3W%2FkHYbPk49Wmeeg8Qg1fTO71%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;708&quot; height=&quot;340&quot; data-filename=&quot;스크린샷 2025-02-15 오전 11.14.26.png&quot; data-origin-width=&quot;1409&quot; data-origin-height=&quot;677&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;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&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;이러한 배경을 바탕으로 논문의 저자들은 Agent4Edu라는 개인화 학습 시뮬레이터(Personalized learning simulator)를 소개합니다. 이는 Figure 1과 같습니다. 이 방법은 지능형 교육 시스템(Intelligent educational system)을 위한 것으로 1) LLM 기반 생성형 에이전트(LLM-powered Generative Agent)와 개인 맞춤형 학습 환경(Personalized Learning Framework)의 두 가지 핵심 요소를 포함하고 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, Agent4Edu는 세 가지의 주요 모듈로 구성되어 있는데요. 이 모듈은 교육을 위해 특별히 설계되었다고 합니다.&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. Learner Profile Module: 학습자의 practice style, 인지 요인(cognitive factor)를 저장해 학습자의 학습 상태에 맞춰 조정됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Memory Module: 심리 이론과 human learning mechanism에 영감을 받은 모듈이며, 과거의 practice experiences를 기록하고 reflection을 통해 학습 상태를 요약합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Action Module: 개인화된 학습 알고리즘이 추천하는 연습 문제를 선택, 이해, 분석, 해결할 수 있도록 합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[3]. LLM-Powered Agent(LLM 기반의 에이전트)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 논문에서 3장부터 본격적인 Agent4Edu 내용을 소개합니다. 논문에서 소개한 Agent4Edu를 살펴보기 전에, 논문에서는 다양한 수식을 활용하는데요. 이를 먼저 정리하고 진행하려고 합니다. 본 논문에서는 아래와 같이 수식을 정의하고 있습니다.&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;- \(|U|\)는 학습자 (learners)를 의미하고 \(|E|\)는 문제(exercises)를 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 학습자 \(u \in U\)는 시간 순서대로 정렬된 응답 데이터 \(l_u = {(e_1, c_{e_1}, y_{u,e_1}), (e_2, c_{e_2}, y_{u,e_2}), ..., (e_n, c_{e_n}, y_{u,e_n})}\)이 있으며 \(e_i \in E\)는 \(i\) 번째 step에서의 학습자 \(u\)의 exercise이고 \(y_{u, e_i}\)는 \(u\) 학습자가 \(e_i\)에 응답한 데이터로 정답이면 1, 오답이면 0으로 표시됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 저자들은 \(c_e\)를 \(&amp;lt;Key, Value&amp;gt;\) 형태로 제공한다고 하며, 이는 Figure 1에 나와있는 것과 같다고 말합니다.&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;위에서 논문의 abstract와 introduction에서도 소개하였듯, 논문에서 제시한 Agent4Edu는 LLM을 기본 아키텍처(Foundational architecture)로 사용하고 있으며 profile, memory module, action module의 3개의 모듈을 활용해 개인 맞춤형 학습 시나리오에 맞추었습니다. 이제, 논문에서 제안한 각 모듈에 대해서 자세히 소개하겠습니다.&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;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;[3-1]. Learner Profile Module(학습자 프로포필 모듈)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모듈은 학습자의 전반적인 특성을 반영하며 학습자의 연습 패턴(Practice pattern)과 인지적 요소(Cognitive factor)를 분석해 초기 프로필을 생성합니다. 이때, 연습 스타일은 논문에서 명시적(explicit) 요소라고 칭하고 있으며, 인지적 요소는 암시적(Implicit) 요소라고 칭하고 있습니다. 그럼 각 요소는 어떤 특징을 가지고 있을까요?&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-1-1]. Practice style&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Practice style 요소는 학습 활동(learning activity), 성공률(success rate), 연습 다양성(pratice diversity), 선호도(perference)와 같은 각 학습자 \(u\)의 사용 가능한 기록 \(l_u\)에서 명시적으로 도출된 통계적 특징(statistical feature)입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, 활동성은 학습 열정을 나타낼 수 있고 이는 연습 행동을 시뮬레이션하는 데 단서를 제공할 수 있습니다. 예를 들어, 학습에 대한 열의가 높은 학습자는 일반적으로 더 나은 성과를 거두는 것이죠. 본 논문에서는 수학적으로 학습자 \(u\)의 활동 수준을 \(P_{act}^u = \frac{|l_u|}{|E|}\)로 나타내었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학습 다양성은 학습자가 연습하는 지식 범위(Knowledge coverage)를 반영하며&amp;nbsp;\(P_{div}^u = \frac{|K_u|}{|K|}\)로 나타내었습니다. 이때, \(|K_u|\)는 학습자 \(u\)가 연습하는 지식 개념(Knowledge Concepts)의 수를 나타내며, 더 높은 다양성은 학습자에게 더 큰 호기심을 나타낸다고 볼 수 있습니다.&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item dable&quot; style=&quot;height: 250px;&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;300x250&lt;/div&gt;
    &lt;div id=&quot;dablewidget_Pl1aE8lE&quot; data-widget_id=&quot;Pl1aE8lE&quot;&gt;
      &lt;script&gt;(function(d,a,b,l,e,_) {
    if(d[b]&amp;&amp;d[b].q)return;d[b]=function(){(d[b].q=d[b].q||[]).push(arguments)};e=a.createElement(l);
    e.async=1;e.charset='utf-8';e.src='//static.dable.io/dist/plugin.min.js';
    _=a.getElementsByTagName(l)[0];_.parentNode.insertBefore(e,_);
    })(window,document,'dable','script');
dable('setService', 'lsjsj92.tistory.com');
dable('sendLogOnce');
dable('renderWidget', 'dablewidget_Pl1aE8lE', {ignore_items: true});&lt;/script&gt;
    &lt;/div&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;[3-1-2]. Cognitive Factor&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인지적 요인은 심리학에서 연구된 implicit feature로 학습자의 practice performance에 중요한 역할을 미치는 요소입니다. 저자들은 Agent4Edu를 위해 문제 해결 능력(problem solving ability)과 지식 숙련도(knowledge proficiency)를 선택했다고 합니다. 문제 해결 능력은 학습 과정에서 안정적이라고 가정되며, 지식 숙련은 일반적으로 학습 진행에 따라 향상됩니다. 따라서, 프로필 모듈에서는 메모리 모듈에서 지식 숙련을 고려해 능력 계수 \(P\)만 구성한다고 합니다. 또한, 암묵적 능력을 얻기 위해서 IRT 모델을 에이전트 도구를 지정해 학습자 반응 기록을 바탕으로 응답 데이터에서 학습자 \(u\)의 능력 요소를 추론할 수 있도록 하였습니다.&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;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;[3-2]. Memory Module(기억 모듈)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기억 모듈(memory module)은 논문 3.2절의 내용에서 상당한 양을 차지하는 부분인데요. 메모리 모듈은 LLM 기반 에이전트가 학습자 \(u\)의 과거 practice 경험을 단계 별로 관찰하고 요약할 수 있도록 합니다. 이 모듈은 Factual Memory, Short-term memory, Long-term memory에 대한 내용이 담겨있고 그만큼 설명하는 양과 요소들이 많습니다. 이에, 하나씩 주된 요소별로 정리를 진행해보도록 하겠습니다.&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;b&gt;[3-2-1]. Factual Memory(사실 기억)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시뮬레이션에서 Factual Memory는 실제 학습자의 과거 응답 기록으로 정의가 된다고 논문에서는 말하고 있습니다. 에이전트가 \(i\) 단계에서 \(u\)의 새로운 응답 기록을 얻으면, \(l_{u, i} = (e_i, c_{e_i}, y_{u, e_i})\) 응답 기록이 Factual Memory로 전송되어 처리됩니다. 여기서는 인간의 학습 매커니즘을 반영해 에이전트가 유사한 질문이나 지식을 반복적으로 수행하면 기억력이 강화됩니다. 따라서, 사용자 선호도 시뮬레이션에 성공적으로 사용된 방법을 적용하는데요. 각 레코드 \(l_{u, i}\)에 대해 additional counter(초기에는 1로 설정됨)을 도입해 강화된 횟수를 추적하게 됩니다. 이를 공식으로 표현하면 각 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;\(Agent_u\)에 대해 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;\(n\)개의 Factual Memory가 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;\(M_u = {l_{u,1}, l_{u,2}...l_{u,n}}\)이라고 가정하면 새로운 응답 기록 \(l_{u, n+1}\)을 수신할 수 있는 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 현재 메모리 \(M_u\)에서 \(l_{u, n+1}\)과 기존 Factual memory \(l_{u,i}\) 사이의 유사성을 계산하고 유사성이 있을 경우 두 기록은 유사하다고 간주됩니다. 그리고 \(l_{u,i}\)의 카운터를 1만큼 증가시키며, 이는 \(l_{u, n+1}\)에 의해 기억이 강화되었음을 의미한다고 저자들은 말합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 Factual memory에서는 새로운 응답 기록을 처리하고 저장한 후에 이제 short-term memory와 long-term memory를 업데이트하도록 trigger한다고 합니다.&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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;[3-2-2].&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; Short-term Memory(단기 기억)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에이전트의 가장 최근 관찰된 \(s\) 기록의 디테일한 정보를 유지하도록 합니다. \(Agent_u\)의 현재 Factual Memory가 \(M_u = {l_{u,1}, l_{u,2}...l_{u,n}}\)이라고 하면, 단기 기억 저장 장치는 \(M_{u,short} = {l_{u,n-s+1},...l_{u,n}}\)으로 정의됩니다.&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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;[3-2-3].&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Long-term Memory(장기 기억)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장기 기억은 반복적인 연습과 자기 성찰(self-reflection)에서 영감을 받아 인간의 장기 기억으로 강화된 기억을 통해 형성되는 과정을 뜻합니다. 이 기억은 넓은 수용 영역(wide receptive field)을 가지고 있어 오래 전에 관찰된 정보를 유지하는 등의 인사이트를 생성할 수 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 장기 기억에서 아래와 같은 3가지 정보를 사용해서 장기 기억을 설계하였습니다.&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;u&gt;1) Reinforced Facts&lt;/u&gt;: 장기 기억을 업데이트 할 때마다 에이전트는 먼저 현재의 Factual memory \(M_u\)를 통과합니다. 레코드 \(l_{u,i}\)의 카운트 \(f_{u,i}\)가 미리 설정된 임계값 F를 초과하면 메모리가 F번 강화되었음을 나타내고, 이는 장기 메모리로 변환됩니다.&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;u&gt;2) Learning Process Summary&lt;/u&gt;: Agent에 내장된 LLM을 활용하여 Memory Reflection을 통해 단기 및 장기 기억에서 Agent의 학습 상태를 요약합니다. 요약은 Practice process에 대한 언어적 설명(Linguistic description)과 에이전트 자체의 new insight로 구성됩니다. 저자들은 이를 통해 상당한 공간을 절약하고 운영 효율성을 향상시킬 수 있다고 말합니다.&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;u&gt;3) Knowledge Proficiency&lt;/u&gt;: 학습자 반응 데이터를 기반으로 최적화된 DNeuralCDM을 도구로 활용해 각 연습 단계 후 특정 지식 개념(Knowledge concepts)에 대한 학습자의 동적 숙련도(dynamic proficiency)를 얻을 수 있다고 합니다. 지식 숙련도는 교육에 인간의 반응을 크게 반영하는 일종의 동적 인지 요소라고 저자들은 말합니다.&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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;[3-2-4].&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Forgotten(망각)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람은 기억을 잊기 마련이죠. 저자들은 인간의 기억 붕괴가 빠르게 시작되다가 시간이 지남에 따라 점차 느려진다는 인간 망각 곡선 이론(human forgetting curve theory)에 따라 장기 기억의 각각 Factual memory가 잊혀질 수 있다고 말합니다. 장기 기억 \(M_u\)의 각 factual 기록에 대해 \(g(l_{u,i}\)가 미리 정해진 입계값을 초과하고 그 강화 빈도가 Factual memory에서 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;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;[3-2-5].&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Memory Operation(메모리 조작 연산)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 저자들은 AI Agent가 개인화된 학습 환경과 상호 작용할 수 있도록 세 가지 메모리 작업을 소개하는데요. 이는 아래와 같습니다.&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;u&gt;1) Memory Retrieval&lt;/u&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;u&gt;2) Memory Writing&lt;/u&gt;: raw한 관찰(observation)은 먼저 factual memory에 팩트로 기록되게 됩니다. 그런 다음, 최근 사실을 단기 기억에 저장하고 강화된 사실을 장기 기억에 기록하게 됩니다.&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;u&gt;3) Memory Reflection&lt;/u&gt;: 장기 기억내에서 이루어지는 연산인데요. 먼저, 요약 반영(summary reflection)이 있습니다. 이는 단기 기억과 장기 기억을 기반으로 한 아이디어를 요약하기 위해 수행됩니다. 그 다음은 수정 반영(Corrective Reflection)이 있습니다. 에이전트의 행동이 실제 학습자와 일치하지 않을 때 수정 반영이 수정되며, 더 자세한 내용은 Action module에서 설명하겠습니다.&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;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;[3-3]. Action Module(행동 모듈)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Agent4Edu의 Action moodule은 학습자 프로필과 메모리 모듈을 장착하고 학습자가 문제를 푸는 과정에서 수행하는 다양한 인지적 행동을 시뮬레이션하는 역할을 수행합니다. 여기서는 크게 3가지 주요 액션 카테고리가 있습니다.&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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;[3-3-1].&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Cognitive-driven Actions(인지 기반 행동 결정)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Agent4Edu는 기존의 학습 모델들과 달리, 학습자의 인지적 요소(Cognitive Factor)를 기반으로 학습자의 행동을 결정할 수 있습니다. 시뮬레이션에서 개인화된 학습 알고리즘은 에이전트에게 하나의 excercise를 권장하게 되는데요. 이때 에이전트는 excercise가 학습자의 현재 인지적 요소에 적합한지 따라 수행 여부를 결정하게 됩니다. 만약, exercise 문제가 평가된 능력이나 지식 숙련도(knowledge proficiency)보다 어렵다면 에이전트는 이 문제를 거절할 수도 있습니다.&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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;[3-3-2].&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Reading &amp;amp; Understanding Exercises(문제 이해)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 에이전트는 학습자처럼 주어진 문제를 읽고, 문제를 테스트하는 지식 개념(knowledge concpet)을 식별해야합니다. 이를 통해, AI가 단순히 정답을 예측하는 것이 아니라, 문제의 맥락을 파악하고 어떤 개념이 적용되는지 이해하는 과정을 수행하는 것인데요. 에이전트가 문제의 개념을 식별하고, 올바르게 매칭할 경우 이는 인간 학습자(Human learner)가 문제를 이해하는 과정과 유사한 방식으로 동작한다는 것을 의미합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, Agent가 잘못된 개념을 식별하거나 하면 수정 반성(corrective reflection)이 트리거되어 Agent가 올바른 지식 개념으로 안내하기 위해 올바르게 수정할 수 있도록 유도하게 됩니다.&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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;[3-3-3].&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Analyzing &amp;amp; Solving Exercises(문제 해결 및 분석)&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;AI 에이전트가 문제를 해결하는 방법을 모방하는 과정입니다. 이전 시뮬레이션 방법들이 정답과 정확성 측면에서 학습자의 반응을 직접 예측하는 것과 다르게 논문에서 제안한 방법은 학습자의 답변 과정을 모방하므로 신뢰성(credibility)과 해석 가능성(interpretability)을 모두 향상시킬 수 있다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, 저자들은 복잡한 답변 과정을 효과적으로 시뮬레이션 하기 위해 CoT(Chain-of-Thought) 방법을 활용했다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기에는 에이전트가 프로필과 메모리를 결합해 연습 문제에 대한 초기 해결 아이디어를 공식화하는데요. 그 다음 문제에 대한 최종 답변을 작성하게 되고 이게 정답인지 아닌지 예측합니다. 만약, 일치하지 않으면 수정 반영(corrective reflection)이 트리거 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 여기서는 AI가 정답을 맞히는 것만 중요하는 게 보는 것이 아닌, 어떤 방식으로 풀었는지, 학습자의 사고 과정과 유사하게 문제 해결을 수행하였는지를 보는 것입니다.&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;style1&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; background-color: #f6e199;&quot;&gt;[이쯤에서 잠깐!]. 그래서 도대체 어떻게 사용자와 상호작용 되는 것일까?&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&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;이 부분이 저는 논문을 보면서 정말 많이 헷갈렸습니다. 개인화 학습을 도와주고 교육을 도와주는 AI Agent이라는 것은 알겠는데, 그래서 이 수많은 기능들이 서로 어떻게 유기적으로 연결되어 동작이 되는 것일까? 라는 궁금증이 생겼습니다. 그래서 개인적으로 정리를 해봤는데요. 아래는 제가 이해한 하나의 예시입니다. 저자가 이해한 것으로 작성된 것이니, 혹 틀렸다면 피드백 부탁드립니다!&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;[전체 동작 흐름]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Leaner Profile Module에서 학습자의 특성(연습 스타일, 성공률, 인지적 요소 등)을 분석해 프로필로 구성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Memory Module에서 학습자의 과거 학습 데이터를 기반으로 기억을 불러오고 업데이트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Action Module에서 학습자가 문제를 풀지 여부를 결정하고, 문제 해결 과정을 수행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 학습자의 응답을 평가해 새로운 학습 데이터를 구성하고 Memory Module을 업데이트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 학습자가 수행한 학습 데이터가 Learner Profile Module에도 영항을 주어 업데이트 됨&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;[예시]&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;1. Learner Profile Module에서 학습자(이수진)을 분석&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Agent4Edu는 학습자 이수진의 기존 학습 데이터르 기반으로 초기 프로필을 생성함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 연습 스타일(Practice Style): 연습 횟수가 적다, 성공률(Success rate): 선형대수 문제에서 성공률이 35%이다(낮다), 선호도(Preference): 선형대수 문제보다는 확률 문제를 더 많이 연습하더라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 문제 해결 능력(Problem-Solving Ability): 수학적 사고 능력은 중급 수준이고, 개념 숙련도(Knowledge Proficiency): 행렬 개념 숙련도가 부족하더라라고 데이터 구성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이런 상황을 기반으로 Memory module과 공유되어 문제 난이도를 조정 해야함&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;u&gt;2. Memory Module&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Factual Memory에서 이수진이 과거 3번의 행렬 문제를 풀었는데, 정답을 맞춘 적이 1번 정도라는 것을 탐지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 단기 기억(Short-Memory)에서 최근 5개 문제 중 선형대수 문제는 없다는 것을 파악&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 장기 기억(Long-term Memory)에서 강화된 기억(Reinforced Fact)는 확률론 개념은 강하게 유지된다는 것을 체크하고, 학습 과정 요약(Learning Process Summary)에서 이수진은 선형대수 문제 풀이에서 연산 실수를 자주한다는 것을 인지. 또한, 지식 숙련도 추적(Knowledge Proficiency)에서 행렬 문제를 3개월 전에 풀었고, 이후 학습 기록이 없으므로 숙련도가 하락되었다고 파악하고 기억 검색(Memory Retrieval)에서 과거 유사한 행렬 문제를 불러올 가능성이 높다는 것을 인지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Action Module과 공유되어 지난 번 실수한 부분을 고려해 난이도를 낮출 수 있음&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;u&gt;3. Action module&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이수진은 문제를 풀 지 결정을 함. 이때 Agent는 메모리 모듈을 참조한 결과, 과거에 어려움을 겪었던 개념이라서 Agent4Edu가 난이도를 낮춘 문제를 추천할 가능성이 있음. 어쨌든 이수진은 이걸 풀기로 함. 이 과정이 Coginitive-driven Actions라고 볼 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이수진이 어떤 문제를 읽고 이해를 하기 시작함. 이때, Agent는 문제의 핵심 개념이 선형대수인지 정확히 매칭하는지 분석하고 문제 개념을 잘못 매칭할 경우 수정 반성(Corrective Reflection) 수행 --&amp;gt; 즉, Agent가 스스로 개념 매칭을 검토하고 오류를 발생시켰을 경우 이를 수정하는 과정을 거치게 됨. 다시 올바른 개념을 학습할 수 있도록 셀프 피드백&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Agent는 Chaint-of-Thought를 사용해서 이수진의 문제 풀이 과정을 시뮬레이션하기 시작함. 이때, Agent가 푼 정답과 이수진이 푼 정답이 틀렸다면 수정 반성(Corrective Reflection)이 적용하고 이수진에게 실수한 부분을 분석해 피드백을 제공함&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;u&gt;4. 학습 기록 업데이트 및 학습 패턴 반영&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 학습 결과를 Memory Module과 Learner Profile Module에 반영&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Factual Memory에는 새로운 응답 데이터를 저장하고, Long-term memory 등에는 행렬 문제 풀이 데이터를 업데이트 함. 또한, Learning process summary에는 &quot;실수를 줄이기 위한 추가 학습 필요&quot; 등의 요약 정보를 추가함&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;[4]. Experiment (실험 및 실험 결과)&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;논문의 실험 환경은 아래와 같이 구성됩니다.&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;- 데이터셋: EduDataset을 활용하며 수학 및 물리 과목으로 구성되어 있음. 이때 ExerciseID, Accuracy, Knowledge concepts 등이 존재함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 실험 설정: GPT-3.5-Turbo와 GPT-4를 사용하여 Agent를 구성하였음. 비용 문제로 GPT-4 설정에서 100명의 학습자만의 작업 기록을 시뮬레이션 하였으며, 3.5-Turbo로 했을 때는 모든 응답 데이터를 활용. Temperature는 0, 단기 메모리 크기는 5, 메모리 향상 입계값 F는 5, 장기 메모리에서 망각(Forgetting) 값은 0.99로 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 실제 응답을 거의 모방하는 시뮬레이션 학습자 응답 데이터를 생성하는 것을 목표. DAISIM과 KES를 포함한 전통적인 시뮬레이션 방법과 비교&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 학습자의 기록은 90%를 훈련 셋트로 구성하고 10%를 테스트로 분리. 에이전트는 훈련 데이터에 접근해 프로필을 생성하고 reflection을 통해 메모리를 업데이트 할 수 있음. 테스트에서는 못봤던 문제에 대해 학습자의 이진 응답을 예측&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 정확도와 F1-score를 사용해 예측 정확도를 측정하고 ROUGE-3를 사용해 시뮬레이션 데이터와 실제 데이터 분포 간의 유사성을 판단&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-filename=&quot;스크린샷 2025-02-15 오전 11.15.15.png&quot; data-origin-width=&quot;730&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HSLBL/btsMliTd7a8/TR6PkxF7gaB1Jv6G7sRzuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HSLBL/btsMliTd7a8/TR6PkxF7gaB1Jv6G7sRzuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HSLBL/btsMliTd7a8/TR6PkxF7gaB1Jv6G7sRzuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHSLBL%2FbtsMliTd7a8%2FTR6PkxF7gaB1Jv6G7sRzuk%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;578&quot; height=&quot;364&quot; data-filename=&quot;스크린샷 2025-02-15 오전 11.15.15.png&quot; data-origin-width=&quot;730&quot; data-origin-height=&quot;460&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;Table 1은 저자들이 공개한 평가 결과입니다. Agen4Edu가 좋은 성능을 보여주고 있는 것을 확인할 수 있습니다. 특히, GPT-3.5-turbo가 가장 좋은 성능을 보여주고 있는 것을 볼 수 있습니다. 이는 LLM 기반 AI Agent가 실제 데이터 셋과 매우 유사한 학습자 반응 데이터를 생성할 수 있는 잠재력을 가지고 있는 것이라고 저자들은 말합니다. 또한, 100명의 학습자를 대상으로 테스트를 한 것을 봐도 우수한 성능이 나왔고 특히 GPT-4가 이때 더 나은 성능을 보여주었습니다.&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-filename=&quot;스크린샷 2025-02-15 오전 11.15.24.png&quot; data-origin-width=&quot;1363&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJSfb6/btsMk1c4BKG/KsGxXssUcbksFKSu3NOA3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJSfb6/btsMk1c4BKG/KsGxXssUcbksFKSu3NOA3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJSfb6/btsMk1c4BKG/KsGxXssUcbksFKSu3NOA3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJSfb6%2FbtsMk1c4BKG%2FKsGxXssUcbksFKSu3NOA3K%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;738&quot; height=&quot;249&quot; data-filename=&quot;스크린샷 2025-02-15 오전 11.15.24.png&quot; data-origin-width=&quot;1363&quot; data-origin-height=&quot;460&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;또한, 에이전트의 연습 성공률의 시뮬레이션 분포가 학습자 데이터의 실제 분포와 매칭이 되는지 평가를 하는데요. 이에 대한 실험 결과는 Figure 2의 (a)에 나와있습니다. 실제 값과 에이전트의 결과를 비교한 결과, 시뮬레이션 데이터가 성공률과 관련된 학습자의 연습 패턴을 효과적으로 포착했다고 저자들은 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Agent4Edu가 사전 학습 데이터 없어도 즉, Zero-shot인 상황에서도 학습자의 응답을 얼마나 잘 시뮬레이션할 수 있는지도 검토했습니다. 이러한 상황은 콜드 스타트 상황이죠. 이때 AI가 얼마나 효과적으로 응답을 생성할 수 있는지 검증합니다. 그 결과는 Figure 2의 (b)에 나와있습니다. 이때 Agent4Edu win은 AI의 응답이 사람과 비교했을 때 AI가 이긴 경우, Tie는 그 영역을 구분하기 어려운 경우, Lose는 인간이 이긴 경우를 의미합니다. 이 결과에서 Agent의 결과가 실제 인간의 반응과 밀접하게 일치하여 둘을 구분하는 것이 어렵다고 합니다. 하지만, 문제 풀이 영역(Answering) 성능은 그렇게 좋지 않았는데요. 복잡한 문제 해결(추론 능력)은 여전히 한계가 있다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Figure 2의 (c)는 Agent4Edu의 구성 요소를 제거했을 경우 학습 성능에 어떤 영향을 미치는지 분석한 것입니다. w/o prof라면 학습자 프로필을 제거한 경우, w/o mem은 메모리 모듈을 제거한 것 등이라고 볼 수 있습니다. 저자들은 실험 결과에서 기능을 제거해도 지식 예측(knowledge prediction)에는 큰 영향을 미치지 않다고 말합니다. 왜냐하면, 이미 LLM이 방대한 지식을 가지고 있기 때문이라고 말하네요. 하지만, 응답 예측(Response prediction)에서는 어느정도 영향이 있는 것으로 보이죠.&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;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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 AI 에이전트를 교육(Education) 도메인에 적용하여, 학습자를 지원하는 접근 방법을 제안한 Agent4Edu라는 논문을 리뷰하였습니다. LLM을 기반으로 학습자의 사고 과정과 학습 패턴을 분석하고, 이를 바탕으로 맞춤형 학습 경험, 개인화 된(Personalized) 맞춤형 교육 경험을 제공하는 AI 에이전트(Agent) 시스템을 설계하는 방법을 제안한 논문이었습니다.&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와 교육 도메인이 어떻게 결합될 지 관심있으신 분들에게 도움이 되시길 바랍니다.&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;&lt;br /&gt;혹시라도 저에게 연락을 주시고 싶으시다면,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- Linkedin:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot;&gt;https://www.linkedin.com/in/lsjsj92/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 블로그 댓글 또는 방명록&lt;/p&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;으로 연락 남겨주시면 됩니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>agent4edu</category>
      <category>AI</category>
      <category>aiagent</category>
      <category>edtech</category>
      <category>Education</category>
      <category>edutech</category>
      <category>LLM</category>
      <category>교육</category>
      <category>에이전트</category>
      <category>인공지능</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/680</guid>
      <comments>https://lsjsj92.tistory.com/680#entry680comment</comments>
      <pubDate>Mon, 17 Feb 2025 09:11:28 +0900</pubDate>
    </item>
    <item>
      <title>프롬프트 관리 서비스 개발기 - LLM 프롬프트 관리 및 테스트 대시보드(코드 공유)</title>
      <link>https://lsjsj92.tistory.com/679</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대규모 언어 모델(Large Language Model, LLM) 서비스를 개발하면서, 회사에서건 개인적으로건 매번 프롬프트를 관리하는 페이지를 구성했었는데요. 이번 포스팅은 제가 매번 사용했던 LLM 프롬프트 관리 서비스를 개발한 과정과 후기를 정리하는 포스팅입니다. 또한, 이 서비스에 대해서 궁금하신 분들을 위해 원하신다면 사용이 가능하도록 코드도 github에 공개해두었고 사용하는 방법에 대해서도 정리를 진행한 포스팅입니다. 개인적으로는 이 프롬프트 관리 서비스를 기반으로 회사에서 또는 프로젝트 성격별로 다양하게 응용하여 사용하고 있습니다. 대단한 코드나 로직은 아니어서 조금 민망하기도 하고 부끄럽기도 한 내용이지만, 저 개인적으로 사용하는 것을 넘어서 누군가에게 도움이 되시길 바라는 마음으로 글을 작성합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본격적인 글 내용에 앞서, 프롬프트 관리 서비스 코드 링크 먼저 공유드립니다. 아래 github에서 확인할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lsjsj92/prompt-playground-lab&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/lsjsj92/prompt-playground-lab&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1738913533358&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 - lsjsj92/prompt-playground-lab: prompt tuning, management, playground lab(w/ Python Streamlit, FastAPI)&quot; data-og-description=&quot;prompt tuning, management, playground lab(w/ Python Streamlit, FastAPI) - lsjsj92/prompt-playground-lab&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/lsjsj92/prompt-playground-lab&quot; data-og-url=&quot;https://github.com/lsjsj92/prompt-playground-lab&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eyfmg/hyYb8E5g56/UKJNfDMfPI2IqQqxDacPX1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/BODkf/hyYcb2U2Nf/cMhUyj8K8n2h8Tqfjf08V1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/lsjsj92/prompt-playground-lab&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/lsjsj92/prompt-playground-lab&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eyfmg/hyYb8E5g56/UKJNfDMfPI2IqQqxDacPX1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/BODkf/hyYcb2U2Nf/cMhUyj8K8n2h8Tqfjf08V1/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 - lsjsj92/prompt-playground-lab: prompt tuning, management, playground lab(w/ Python Streamlit, FastAPI)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;prompt tuning, management, playground lab(w/ Python Streamlit, FastAPI) - lsjsj92/prompt-playground-lab&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;
&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;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅 개요에서 말씀드린 것처럼 본 포스팅은 제가 개인적으로 LLM의 프롬프트(Prompt) 템플릿 관리를 위해 만들어둔 서비스를 개발한 개발기를 작성합니다. 본격적인 내용에 앞서, 먼저 이 질문을 먼저 해야할 것 같습니다. &quot;&lt;b&gt;왜 만들었는가&lt;/b&gt;?&quot;&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;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;왜 LLM Prompt 관리 서비스를 만들었는가?&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ChatGPT나 Claude, Llama 그리고 요즘 이슈가 되고 있는 딥시크(Deepseek)와 같은 대규모 언어 모델(Large Language Model, LLM)을 활용한 서비스 및 시스템 개발이 정말 많이 이루어지고 있습니다. 아무래도 LLM을 활용하는 것이다보니 가장 중요한 것 중 하나가 프롬프트(Prompt)에 대한 관리였는데요. 이때, 제가 말씀드린 LLM 프롬프트 관리라는 것은 아래와 같은 것을 포함합니다.&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&gt;&lt;b&gt;새로운 프롬프트를 추가&lt;/b&gt;: 원하는 신규 프롬프트를 추가. 이때, 원하는 변수를 추가하고 이 값을 입력 받을 수 있도록 포멧을 설정함. 예를 들어, 사용자의 정보라던가, LLM에게 강조하는 중요사항 등이 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;만들어둔 프롬프트를 관리&lt;/b&gt;: 미리 만들어둔 프롬프트를 수정하고, 삭제할 수 있는 것. 추가된 프롬프트에 대한 유지보수나 오타 등을 방지하기 위한 목적&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프롬프트를 활용한 LLM 실행&lt;/b&gt;: 프롬프트를 설계할 때 만들어두었던 변수에 값을 넣고 LLM에게 제공하여 결과를 실행함. 이때, 실행한 결과의 히스토리도 저장되며, LLM의 실행 결과를 즉각 수정할 수도 있어야 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;LLM 실행 결과에 대한 평가&lt;/b&gt;: 만들어둔 프롬프트와 실행 결과에 대한 평가를 할 수 있음. 나만 마음에 들면 되는 것이 아니라, 다른 사람들의 의견도 필요할 수 있기 때문에 평가 페이지를 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 개인적으로 위와 같은 프롬프트 관리가 필요하다는 생각이 들었고, 해당 관리 서비스를 개인적인 목적으로 사용하기 위해서라도 간단하게 만들어야겠다고 생각했습니다.&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;/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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; background-color: #f6e199;&quot;&gt;&lt;b&gt;개발 환경 및 사전 데이터베이스 구성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738925070210&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- 개발 환경: Python 3.9
- 웹 화면: Streamlit
- 백엔드: FastAPI
- DB: MySQL or MariaDB
- LLM 활용: Langchain&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;이때, 저는 데이터베이스로 MySQL 또는 MariaDB를 사용했다고 위에 작성했는데요. 프롬프트 관리 서비스를 사용하기 위해서는 먼저 아래와 같이 DB 구성을 해주어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1738925298845&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. MySQL 또는 MariaDB 설치
2. 사용을 원하시는 계정과 비밀번호 셋팅
	- 저의 default 설정 값은 계정은 root, 비밀번호는 1234 입니다.
3. prompt_db 이름으로 데이터베이스 생성
	- create database prompt_db&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;/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 id=&quot;code_1738925616420&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. FastAPI 실행: uvicorn app.main:app --reload  
2. (선택 사항) 테스트 데이터 삽입 sql 실행
	- mysql -u root -p &amp;lt; insert_test_data.sql  
    - FastAPI를 먼저 실행하는 이유는, API 실행 시 테이블 등을 생성하기 때문입니다.
3. streamlit 서버 실행
    - streamlit run web/main.py --server.port 8501&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;/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;span style=&quot;color: #000000; background-color: #f6e199;&quot;&gt;&lt;b&gt;프롬프트 관리 시스템 정보 페이지&lt;/b&gt;&lt;/span&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-02-07 오후 7.55.24.png&quot; data-origin-width=&quot;1501&quot; data-origin-height=&quot;745&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZGaVN/btsMbA1OlSl/4339n6pYzQveMz2khkCfY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZGaVN/btsMbA1OlSl/4339n6pYzQveMz2khkCfY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZGaVN/btsMbA1OlSl/4339n6pYzQveMz2khkCfY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZGaVN%2FbtsMbA1OlSl%2F4339n6pYzQveMz2khkCfY0%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;1501&quot; height=&quot;745&quot; data-filename=&quot;스크린샷 2025-02-07 오후 7.55.24.png&quot; data-origin-width=&quot;1501&quot; data-origin-height=&quot;745&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; background-color: #f6e199;&quot;&gt;&lt;b&gt;프롬프트 추가 페이지&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 프롬프트 추가하기 페이지입니다. 이 페이지에서는 새로운 신규 LLM 프롬프트를 추가하는 페이지입니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.12.41.png&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;898&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ItHZ1/btsMbqyaN6m/qPqOVaIO3CgBKADfKHrK31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ItHZ1/btsMbqyaN6m/qPqOVaIO3CgBKADfKHrK31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ItHZ1/btsMbqyaN6m/qPqOVaIO3CgBKADfKHrK31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FItHZ1%2FbtsMbqyaN6m%2FqPqOVaIO3CgBKADfKHrK31%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;1508&quot; height=&quot;898&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.12.41.png&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;898&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;이 페이지의 특징은 아래와 같습니다.&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;프롬프트 제목&lt;/b&gt;: 말 그대로 프롬프트 템플릿의 대한 제목입니다. 나중에 프롬프트 템플릿을 찾을 때 유용하게 사용할 수 있도록 만들어두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;시스템 메세지&lt;/b&gt;: LLM에게 프롬프트를 구성할 때 시스템 메세지(System message)를 넣는 부분에 대한 값입니다. LLM이 어떤 역할로 수행하기를 원하는지 작성하는 것이죠. 이 부분은 추후 랭체인(Langchain)과 연동할 때 Langchain의 system message의 값으로 활용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;프롬프트 포멧&lt;/b&gt;: 프롬프트를 추가할 때 활용되는 메인 내용입니다. 원하는 프롬프트 템플릿을 만드는 과정이라고 보시면 되는데요. 예를 들어서, 저는 아래와 같이 템플릿을 구성했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.12.49.png&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;905&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nOBU8/btsMbKQMy9x/8JC3VFKsLRWqSOd8ouail1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nOBU8/btsMbKQMy9x/8JC3VFKsLRWqSOd8ouail1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nOBU8/btsMbKQMy9x/8JC3VFKsLRWqSOd8ouail1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnOBU8%2FbtsMbKQMy9x%2F8JC3VFKsLRWqSOd8ouail1%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;1508&quot; height=&quot;905&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.12.49.png&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;905&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1738926024738&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;아래와 같은 요구사항에 따라, 업무를 수행해주세요.

1. 목표
{target}

2. 내용
{desc}

3. 조건
{condition}&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;이때 중괄호 { }로 묶여저 있는 부분은 추후 '프롬프트 실행하기 메뉴'에서 실제 값으로 들어가는 변수들입니다. { }로 설정한 이유는 파이썬에서 제공하는 format 함수를 활용해서 텍스트와 값을 매칭시켜 LLM에게 제공하는 prompt를 완성하기 위한 목적이기 때문입니다.&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 id=&quot;code_1738926320735&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- 프롬프트 제목: 이수진의 테스트2

- 시스템 메세지: 당신은 행복하고 아름답게 말하는 AI입니다.

- 프롬프트 포멧:
아래 내용을 확인하시고, 멋진 문구를 만들어주세요.

1. 문구의 주제
{topic}

2. 조건
{condition}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.14.01.png&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;905&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CUU08/btsMbDRE3Bs/Rtdy9r5Ga4k885gwGfE9a1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CUU08/btsMbDRE3Bs/Rtdy9r5Ga4k885gwGfE9a1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CUU08/btsMbDRE3Bs/Rtdy9r5Ga4k885gwGfE9a1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCUU08%2FbtsMbDRE3Bs%2FRtdy9r5Ga4k885gwGfE9a1%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;1508&quot; height=&quot;905&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.14.01.png&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;905&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;p data-ke-size=&quot;size16&quot;&gt;저는 이렇게 '이수진의 테스트'와 '이수진의 테스트2'라는 프롬프트 포멧 제목으로 2개를 넣어두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; background-color: #f6e199;&quot;&gt;&lt;b&gt;만들어둔 프롬프트 관리 페이지&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 번째 페이지 메뉴는 프롬프트 관리 페이지입니다. 프롬프트 추가 페이지에서 저장해둔 프롬프트들을 수정 및 삭제할 수 있는 페이지입니다. 페이지에 들어가면 만들어두었던 프롬프트의 제목 리스트들이 나오게 되고, 그 제목을 누르면 시스템 메세지와 프롬프트 포멧 등의 상세 정보가 출력되게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JvoAs/btsMbFuWv3S/7dxzKSdHaUk2VXn80afB2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JvoAs/btsMbFuWv3S/7dxzKSdHaUk2VXn80afB2k/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;546&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.36.07.png&quot; style=&quot;width: 61.2046%; margin-right: 10px;&quot; data-widthpercent=&quot;61.92&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JvoAs/btsMbFuWv3S/7dxzKSdHaUk2VXn80afB2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJvoAs%2FbtsMbFuWv3S%2F7dxzKSdHaUk2VXn80afB2k%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;1510&quot; height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zbvn1/btsMaeMkQLN/QNMDHmEtwh4ntrK5quMHjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zbvn1/btsMaeMkQLN/QNMDHmEtwh4ntrK5quMHjk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;888&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.37.07.png&quot; style=&quot;width: 37.6326%;&quot; data-widthpercent=&quot;38.08&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zbvn1/btsMaeMkQLN/QNMDHmEtwh4ntrK5quMHjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzbvn1%2FbtsMaeMkQLN%2FQNMDHmEtwh4ntrK5quMHjk%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;1510&quot; height=&quot;888&quot;/&gt;&lt;/span&gt;&lt;/div&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;위 사진은 그 과정을 보여주는데요. 제가 방금 추가했던 '이수진의 프롬프트' 2개의 리스트를 볼 수 있습니다(왼). 이 리스트 중에서 하나를 클릭하면 해당 프롬프트의 상세 정보가 출력되게 됩니다(오).&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.37.16.png&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;899&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y7Aew/btsMbzaxWlS/lklKHpK47bDHVmTWo0vtr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y7Aew/btsMbzaxWlS/lklKHpK47bDHVmTWo0vtr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y7Aew/btsMbzaxWlS/lklKHpK47bDHVmTWo0vtr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy7Aew%2FbtsMbzaxWlS%2FlklKHpK47bDHVmTWo0vtr0%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;1510&quot; height=&quot;899&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.37.16.png&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;899&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;만약, 수정을 원하신다면 수정할 수 있는데요. 저는 위에서 만들어두었던 프롬프트 중 '이수진의 테스트2'의 내용을 살짝 변경했습니다. 프롬프트 포멧의 내용을 바꿔서 수정한 뒤 프롬프트 수정 버튼을 누르면 수정된 정보가 데이터베이스에 저장되게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삭제도 가능합니다. 맨 아래에 프롬프트 삭제 버튼을 누르면 프롬프트가 삭제가 되는데요. 단, 실제 로직을 보면 값을 delete하지는 않고 use_yn 값을 n으로 변경하도록 설정했습니다. 만약에라도 실수로 삭제한 것을 방지하는 목적도 있고 당시엔 필요없어서 삭제했는데 나중에 필요할 것 같을 때 다시 재사용할 수 있도록 하기 위해 이렇게 구성해두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; background-color: #f6e199;&quot;&gt;&lt;b&gt;만들어둔 프롬프트를 활용해 LLM을 실행하는 페이지&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 페이지는 만들어둔 프롬프트 템플릿을 활용해서 실제 LLM에게 메세지를 던져 결과를 받아오는 실행 페이지입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지에 들어가면 구성해둔 프롬프트 템플릿 리스트가 보이게 됩니다. 이 중 프롬프트를 선택하면 이제 실제 값을 입력하게 되는데요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QpKCY/btsMbYHVmlk/FWdZzruu6zoCoUDHZcaskK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QpKCY/btsMbYHVmlk/FWdZzruu6zoCoUDHZcaskK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;402&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.37.32.png&quot; style=&quot;width: 66.0546%; margin-right: 10px;&quot; data-widthpercent=&quot;66.83&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QpKCY/btsMbYHVmlk/FWdZzruu6zoCoUDHZcaskK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQpKCY%2FbtsMbYHVmlk%2FFWdZzruu6zoCoUDHZcaskK%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;1510&quot; height=&quot;402&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVrUcG/btsMbV5vm2r/q5Vx0ByPn978bUom2BAjx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVrUcG/btsMbV5vm2r/q5Vx0ByPn978bUom2BAjx1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;810&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.38.01.png&quot; style=&quot;width: 32.7826%;&quot; data-widthpercent=&quot;33.17&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVrUcG/btsMbV5vm2r/q5Vx0ByPn978bUom2BAjx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVrUcG%2FbtsMbV5vm2r%2Fq5Vx0ByPn978bUom2BAjx1%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;1510&quot; height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/div&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;&amp;nbsp;&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.58.21.png&quot; data-origin-width=&quot;1848&quot; data-origin-height=&quot;859&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blMI7D/btsMbJxpzo6/aNiV39pzk7fANkUROOFxBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blMI7D/btsMbJxpzo6/aNiV39pzk7fANkUROOFxBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blMI7D/btsMbJxpzo6/aNiV39pzk7fANkUROOFxBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblMI7D%2FbtsMbJxpzo6%2FaNiV39pzk7fANkUROOFxBk%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;1848&quot; height=&quot;859&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.58.21.png&quot; data-origin-width=&quot;1848&quot; data-origin-height=&quot;859&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;예를 들어, 저는 위에서 '이수진의 테스트2'라는 제목을 가진 프롬프트를 만들 때 '행복하고 아름다운 문구를 만들라'라는 시스템 메세지와 더불어 프롬프트 포멧에 문구의 주제 {topic} 조건 {condition}을 추가했었습니다. 아래와 같이 말이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1738931400643&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- 프롬프트 제목: 이수진의 테스트2
- 시스템 메세지: 당신은 행복하고 아름답게 말하는 AI입니다.
- 프롬프트 포멧:
아래 내용을 확인하시고, 멋진 문구를 만들어주세요.
1. 문구의 주제
{topic}

2. 조건
{condition}&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 '프롬프트 실행하기' 메뉴에 해당되는 streamlit 코드에서 자동으로 중괄호 영역의 변수명을 인식해, text를 입력할 수 있도록 아래와 같이 코드가 구성되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1738971986631&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# {} 안의 변수 추출
variable_names = re.findall(r&quot;\{(.*?)\}&quot;, prompt[&quot;prompt_format&quot;])

# 사용자 입력 폼
with st.form(&quot;execute_prompt_form&quot;):
    for var in variable_names:
        st.text_area(f&quot;{var} 값 입력&quot;, value=&quot;&quot;, height=200)&lt;/code&gt;&lt;/pre&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-filename=&quot;스크린샷 2025-02-07 오후 5.50.50.png&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;922&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HXett/btsL97NgEST/ErM3m03KZvYltUPUBaVpCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HXett/btsL97NgEST/ErM3m03KZvYltUPUBaVpCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HXett/btsL97NgEST/ErM3m03KZvYltUPUBaVpCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHXett%2FbtsL97NgEST%2FErM3m03KZvYltUPUBaVpCk%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;1510&quot; height=&quot;922&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.50.50.png&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;922&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;그래서 저는 위 사진과 같이 topic에 &quot;귀여운 고양이가 AI와 놀고있다&quot;라는 값을 넣었고 condition(조건) 값에 &quot;50자 이내로 작성해주세요&quot;, &quot;다른 말은 하지말고 역할만 수행해주세요&quot;라는 값을 입력하였습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item dable&quot; style=&quot;height: 250px;&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;300x250&lt;/div&gt;
    &lt;div id=&quot;dablewidget_Pl1aE8lE&quot; data-widget_id=&quot;Pl1aE8lE&quot;&gt;
      &lt;script&gt;(function(d,a,b,l,e,_) {
    if(d[b]&amp;&amp;d[b].q)return;d[b]=function(){(d[b].q=d[b].q||[]).push(arguments)};e=a.createElement(l);
    e.async=1;e.charset='utf-8';e.src='//static.dable.io/dist/plugin.min.js';
    _=a.getElementsByTagName(l)[0];_.parentNode.insertBefore(e,_);
    })(window,document,'dable','script');
dable('setService', 'lsjsj92.tistory.com');
dable('sendLogOnce');
dable('renderWidget', 'dablewidget_Pl1aE8lE', {ignore_items: true});&lt;/script&gt;
    &lt;/div&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;/p&gt;
&lt;pre id=&quot;code_1738931594511&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;당신은 행복하고 아름답게 말하는 AI입니다.
아래 내용을 확인하시고, 멋진 문구를 만들어주세요.
1. 문구의 주제
귀여운 고양이가 AI와 놀고있다

2. 조건
- 50자 이내로 작성해주세요
- 다른 말은 하지말고 역할만 수행해주세요&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;이렇게 셋팅된 프롬프트 값을 기반으로 이제 실행 버튼을 누르면 LLM에게 실행이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 현재, OpenAI의 API를 사용하는 방법과 Azure OpenAI를 사용하는 방법 2가지를 구현해두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, vLLM을 쓰신다거나 Claude 계열 모델(Sonnet, Haiku 등)또는 Ollama 등 다른 모델 API를 쓰신다면 코드에서 해당 로직을 추가하시면 될 것 같습니다.&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-filename=&quot;스크린샷 2025-02-07 오후 5.50.58.png&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;922&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfWcA4/btsMbsCLTN2/qBbn0Wf8fQ4BGHUXqFtjyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfWcA4/btsMbsCLTN2/qBbn0Wf8fQ4BGHUXqFtjyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfWcA4/btsMbsCLTN2/qBbn0Wf8fQ4BGHUXqFtjyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfWcA4%2FbtsMbsCLTN2%2FqBbn0Wf8fQ4BGHUXqFtjyk%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;1510&quot; height=&quot;922&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.50.58.png&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;922&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;저는 OpenAI의 API를 활용해 gpt-4o-mini 모델에 테스트를 해보았습니다. 그리고 gpt-4o-mini는 &quot;고양이의 호기심과 AI의 지혜, 함께하는 놀이터!&quot;와 같은 메세지를 전달해주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프롬프트를 실행한 직후 이 결과를 바로 수정해서 저장할 수 있도록 해놨습니다. 그 이유는, LLM의 결과가 마음에 들지 않을 시 그 즉시 수정할 수 있도록 처리하는게 개인적으로 편리한 부분이 있어(회사에서 소통했을 때도 이런 니즈가 있었어서) 이렇게 추가해두었습니다. 가령 아래 사진과 같이 수정할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-02-07 오후 6.01.08.png&quot; data-origin-width=&quot;1848&quot; data-origin-height=&quot;859&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1D95T/btsMbY8U7Up/G0ZreYI0GkU0nTqkFkGkdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1D95T/btsMbY8U7Up/G0ZreYI0GkU0nTqkFkGkdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1D95T/btsMbY8U7Up/G0ZreYI0GkU0nTqkFkGkdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1D95T%2FbtsMbY8U7Up%2FG0ZreYI0GkU0nTqkFkGkdk%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;1848&quot; height=&quot;859&quot; data-filename=&quot;스크린샷 2025-02-07 오후 6.01.08.png&quot; data-origin-width=&quot;1848&quot; data-origin-height=&quot;859&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;저는 LLM(OpenAI GPT-4o-mini)이 제공해준 결과에서 지혜를 조화로, 이모지가 있는 부분은 제거한 상태로 수정하고 이를 저장하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; background-color: #f6e199;&quot;&gt;&lt;b&gt;프롬프트 실행 결과를 평가하는 페이지&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막은 프롬프트 실행 결과를 평가하는 페이지입니다.&amp;nbsp;이 페이지의 목적은 실제 LLM의 실행 결과가 마음에 들었는지 여러 사람들의 의견을 들을 수 있게 일종의 설문이 가능한 형태로 제공한 것인데요. 제가 봤을 때는 프롬프트의 LLM 실행 결과가 좋을 수 있지만, 다른 사람이 보기엔 그렇지 않을 수 있으니 이를 위한 목적으로 만든 페이지입니다.&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-filename=&quot;스크린샷 2025-02-07 오후 5.51.40.png&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;922&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdj2w7/btsMbYnEPB9/oS2nTgKC6JJcvfzPKh8Kjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdj2w7/btsMbYnEPB9/oS2nTgKC6JJcvfzPKh8Kjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdj2w7/btsMbYnEPB9/oS2nTgKC6JJcvfzPKh8Kjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcdj2w7%2FbtsMbYnEPB9%2FoS2nTgKC6JJcvfzPKh8Kjk%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;1510&quot; height=&quot;922&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.51.40.png&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;922&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;위 사진을 보면 방금 실행한 프롬프트 실행 결과가 출력됩니다. 어떤 모델을 썼는지(openai-4o-mini) 그리고 환경이 무엇인지(OpenAI 또는 Azure 등)를 보여주고 그 결과가 어땠는지 출력되고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J2KOa/btsMceDKUBn/9O7grBKAp6MqoC7jAFCSS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J2KOa/btsMceDKUBn/9O7grBKAp6MqoC7jAFCSS1/img.png&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;922&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.51.52.png&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J2KOa/btsMceDKUBn/9O7grBKAp6MqoC7jAFCSS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ2KOa%2FbtsMceDKUBn%2F9O7grBKAp6MqoC7jAFCSS1%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;1510&quot; height=&quot;922&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/br3SBH/btsL90UYLaV/ETlSfaG3ZnWY20ektNVtIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/br3SBH/btsL90UYLaV/ETlSfaG3ZnWY20ektNVtIK/img.png&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;922&quot; data-filename=&quot;스크린샷 2025-02-07 오후 5.51.55.png&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/br3SBH/btsL90UYLaV/ETlSfaG3ZnWY20ektNVtIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbr3SBH%2FbtsL90UYLaV%2FETlSfaG3ZnWY20ektNVtIK%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;1510&quot; height=&quot;922&quot;/&gt;&lt;/span&gt;&lt;/div&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;프롬프트 실행 결과는 10점 척도와 더불어 피드백 내용을 작성하도록 구성되어 있습니다.&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;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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 제가 개인적으로 계속 활용하던 LLM의 프롬프트 관리 서비스 페이지 개발기를 정리하고 코드 등을 공유한 내용입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실, 복잡하거나 어려운 것은 아니어서 공개를 하는 게 민망하고 부끄럽기도 하지만, 단 1명이라도 도움이 되기를 바라며 자신감을 가지고 공유해봅니다.&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;긴 글 읽어주셔서 감사합니다.&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;p data-ke-size=&quot;size16&quot;&gt;- Linkedin: &lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.linkedin.com/in/lsjsj92/&lt;/a&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;p data-ke-size=&quot;size16&quot;&gt;으로 연락 남겨주시면 됩니다!&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>azure</category>
      <category>gpt4o</category>
      <category>LLM</category>
      <category>openai</category>
      <category>prompt</category>
      <category>prompttuning</category>
      <category>개발</category>
      <category>프롬프트관리</category>
      <category>프롬프트최적화</category>
      <category>프롬프트튜닝</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/679</guid>
      <comments>https://lsjsj92.tistory.com/679#entry679comment</comments>
      <pubDate>Mon, 10 Feb 2025 09:43:07 +0900</pubDate>
    </item>
    <item>
      <title>TALLRec 논문 리뷰 - LLM 기반 추천 시스템 (An Effective and Efficient Tuning Framework to Align Large Language Model with Recommendation)</title>
      <link>https://lsjsj92.tistory.com/678</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 LLM을 활용한 추천 시스템 논문인 TALLRec: An Effective and Efficient Tuning Framework to Align Large Language Model with Recommendation이라는 논문을 리뷰한 포스팅입니다. 글을 쓰고 있는 시점으로 300회가 넘는 인용이 있고 LLM을 추천(Recommendation) 테스크로 파인튜닝(Fine-tuning)을 한 방법을 제안하는 논문입니다. 이를 위해 LoRA 방법을 채택하였고 기존에 대규모 언어 모델(Large Language Model, LLM)이 추천 시스템 영역에 Alignment가 부족했는데, 이를 보완하여 LLM이 추천 시스템 영역으로 확장된 Large Recommendation Language Model을 제안합니다.&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;&lt;a href=&quot;https://arxiv.org/pdf/2305.00447&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/pdf/2305.00447&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-18 오후 8.13.05.png&quot; data-origin-width=&quot;3532&quot; data-origin-height=&quot;1284&quot;&gt;&lt;a href=&quot;https://arxiv.org/pdf/2305.00447&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CxCoM/btsLSQKgo0E/qWkrMfNr9EssCa3KGwzUv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCxCoM%2FbtsLSQKgo0E%2FqWkrMfNr9EssCa3KGwzUv1%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;3532&quot; height=&quot;1284&quot; data-filename=&quot;스크린샷 2025-01-18 오후 8.13.05.png&quot; data-origin-width=&quot;3532&quot; data-origin-height=&quot;1284&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;
&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;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅 개요에서도 언급하였듯 본 포스팅은 LLM을 활용한 추천 시스템 논문인 TALLRec: An Effective and Efficient Tuning Framework to Align Large Language Model with Recommendation 논문을 리뷰하는 포스팅입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 리뷰 포스팅은 논문의 핵심 요약부터 사전 지식, TALLRec 방법론, 실험 결과 그리고 결론 순으로 정리하겠습니다.&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;b&gt;1. 논문의 핵심 요약&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대규모 언어 모델(Large Language Models, LLM)은 자연어 처리(NLP), 정보 검색 등 다양한 분야에서 뛰어난 성능을 보여주며 빠르게 발전하고 있습니다. 그러나, 이러한 LLM의 능력을 추천 시스템에 적용하는 초기 시도들은 한계에 부딪혔는데요. 기존 연구들은 LLM의 풍부한 지식과 일반화 능력을 활용해 추천 작업을 In-contexst learning 방식으로 접근했지만, 이는 전통적인 추천 시스템과 비교해 큰 성과를 거두지 못했습니다. 이는 본질적으로 LLM의 학습 과정과 추천 작업 간의 데이터 차이가 부족하기 때문이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 한계를 극복하기 위해 저자들은 ALLRec(Tuning Framework to Aligning LLMs with Recommendation)을 제안했습니다. TALLRec은 LLM을 추천 task에 효과적으로 Align하기 위한 효율적인 튜닝 방법입니다. 이 프레임워크는 두 가지 주요 단계로 구성되어 있습니다. 첫 번째는 Self-instruct 데이터를 활용한 Alpaca Tuning으로 LLM의 일반화 능력을 강화합니다. 두 번째는 실제 추천 데이터를 Instruction tuning 방식으로 구성하여 LLM을 추가로 튜닝하는 Rec-tuning입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, 저자들은 LoRA(Low-Rank Adaptation)을 적용하여 경량화(Lightweight)된 튜닝을 구현함으로써 적은 자원으로도 충분히 높은 성능을 달성할 수 있도록 진행했습니다.&amp;nbsp;&amp;nbsp;&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;b&gt;2. Introduction&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대규모 언어 모델(LLM)은 다양한 분야에서 뛰어난 성능을 보여주고 있지만, 추천 시스템 분야에서는 아직 충분히 능력이 발휘되지 못하였습니다. 추천 시스템은 사용자의 선호도를 기반으로 개인화된 콘텐츠를 제공하는 방법으로, 사용자에 대한 선호 지식이 필요합니다. 그러나, LLM은 이러한 요구를 충분히 충족시키지 못하고 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존의 연구들은 LLM의 추천 시스템에 적용하기 위해 In-context learning 방식을 사용했습니다. 이 방법은 기존 전통적인 추천 모델(CF, MF, LightGCN 등)에서 필터링된 후보 아이템을 LLM이 재정렬 하는 정도의 역할로 사용했었죠. 하지만, 이런 접근 방법은 전통적인 추천 방법과 성능면에서 큰 차이가 없거나, 경우에 따라서는 추천을 거절하거나 항상 긍정적인 답변만 제공하는 형태도 보였습니다(Figure 1).&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-filename=&quot;스크린샷 2025-01-18 오후 8.13.15.png&quot; data-origin-width=&quot;3532&quot; data-origin-height=&quot;1488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JKgP2/btsLRSowequ/dwooEzVb5C2KyHgWwR5WY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JKgP2/btsLRSowequ/dwooEzVb5C2KyHgWwR5WY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JKgP2/btsLRSowequ/dwooEzVb5C2KyHgWwR5WY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJKgP2%2FbtsLRSowequ%2FdwooEzVb5C2KyHgWwR5WY0%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;3532&quot; height=&quot;1488&quot; data-filename=&quot;스크린샷 2025-01-18 오후 8.13.15.png&quot; data-origin-width=&quot;3532&quot; data-origin-height=&quot;1488&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;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&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;/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) 첫째 LLM의 훈련 과정과 추천 task 간의 차이로 인해 적합하지 않은 문제가 있었고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 둘째 LLM이 학습하는 데이터에 추천과 관련된 데이터가 부족하다는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 셋째 기본 추천 모델에 의해 효과가 제한되는 것&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;이라고 이야기합니다. 이에 저자들은 LLM을 추천 작업에 최적화하기 위해 대규모 추천 언어 모델(Large Recommendation Language Model)의 구축이 필요하다고 이야기 하면서 TALLRec 프레임워크에 대한 배경을 설명합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TALLRec은 뒷 부분에서 더 자세히 설명드리겠지만, 두 가지 튜닝 과정을 거치게 됩니다. 1) 알파카 튜닝(Alpaca Tuning) 과정에서 LLM의 일반화 능력을 강화하고 2) Rec-Tuning 단계에서 추천 task에 최적화를 진행합니다. 이때 경량화(Lightweight) 전략을 위해 LoRA를 활용하여 튜닝을 진행했으며 NVIDIA RTX 3090 GPU에서도 튜닝을 실행할 수 있었다고 합니다. 또한, 적은 수의 학습 데이터로도 우수한 성능을 보이며, 도메인 간 일반화 능력 또한 뛰어나다고 설명합니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 사전 지식(Preliminary)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM을 추천 시스템에 적용하기 위해서는 기존의 자연어 처리와는 다른 접근 방식이 필요합니다. 이를 위해 저자들은 Instruction Tuning과 Rec-Tuning이라는 개념을 도입했습니다.&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;TALLRec 논문에서 말하는 Instruction Tuning이란?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TALLRec 저자들은 Instruction tuning을 LLM이 특정 작업을 이해하고 수행할 수 있도록 자연어로 된 지시문과 입력 데이터를 학습시키는 방식을 의미한다고 이야기합니다. 예를 들어, &quot;이 영어 문장을 중국어로 번역하세요&quot;와 같은 지시문과 함께 번역할 문장을 제공하고, 이에 대한 번역 결과를 학습하도록 하는 것이죠. 즉, LLM의 일반화를 강화하는 과정으로 일반적인 LLM 튜닝 과정과 유사하다고 보시면 될 것 같습니다. 저자들은 Instruction Tuning에서 총 4단계의 과정이 있다고 말합니다.&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&gt;Step 1: Task 정의 및 지시문 작성을 진행합니다. 수행할 task를 정의하고 이 작업을 자연어로 설명하는 지시문(Task Instruction)을 작성하는 것이죠. &quot;이 영어 문장을 한국어로 번역하세요&quot;와 같은 문장이 그 예시가 되겠습니다.&lt;/li&gt;
&lt;li&gt;Step 2: 입력 및 출력 데이터를 구성합니다. 작업에 사용할 input과 예상되는 출력(task output)을 자연어 형래토 구성합니다. 예를 들어, 입력이 : &quot;Who am I&quot;?면 출력(output)은 &quot;내가 누구인가요&quot;가 될 수 있겠죠.&lt;/li&gt;
&lt;li&gt;Step 3: Instruction input을 통합합니다. 작성한 지시문(Task Instruction)과 입력(Task Input)을 결합해 Instruction input을 구성한다고 합니다. 이때 출력(Task output)은 Instruction output으로 설정합니다.&lt;/li&gt;
&lt;li&gt;Step 4: 튜닝을 수행합니다. Instruction input과 output을 쌍으로 사용해서 LLM을 튜닝합니다.&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;&lt;b&gt;TALLRec 논문에서 말하는 Rec-Tuning이란?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 Instruction Tuning된 LLM에 Rec-tuning 작업을 진행합니다. Rec-Tuning은 추천 시스템 작업에 특화된 LLM을 학습시키는 과정을 의미합니다. 이 과정은 아래 Table 2와 같은 과정으로 진행이 되는데요.&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-filename=&quot;스크린샷 2025-01-18 오후 8.13.32.png&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bR0UdG/btsLSMVmb8V/nR2cyVbpmhsGgLwJJexkp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bR0UdG/btsLSMVmb8V/nR2cyVbpmhsGgLwJJexkp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bR0UdG/btsLSMVmb8V/nR2cyVbpmhsGgLwJJexkp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbR0UdG%2FbtsLSMVmb8V%2FnR2cyVbpmhsGgLwJJexkp1%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;619&quot; height=&quot;380&quot; data-filename=&quot;스크린샷 2025-01-18 오후 8.13.32.png&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Task Instruction은 사용자의 상호작용을 바탕으로 대상 항목을 좋아하는지, &quot;예&quot; 또는 &quot;아니오&quot;로 대답하도록 모델에게 지시하는 Instruction 요소라고 보시면 됩니다.&lt;/li&gt;
&lt;li&gt;Task Input은 사용자가 과거에 상호작용한 아이템들을 평점에 따라 분류해서 제공합니다. 평점에 따라 분류한다는 것은 사용자가 좋아했던 아이템과 싫어했던 아이템에 대한 분류입니다. 이때, 아이템들은 상호작용한 시간에 따라 순차적으로 순위가 매겨지고 제목이나 간단한 소개(brief introduction)으로 표현된다고 합니다.&lt;/li&gt;
&lt;li&gt;이렇게 Task Instruction과 Task Input을 합쳐서 Instruction Input으로 설정합니다.&lt;/li&gt;
&lt;li&gt;마지막으로 Instruction output에는 모델이 예상하는 출력값으로 Yes or No로 나오도록 설정합니다.&lt;/li&gt;
&lt;/ul&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;b&gt;4. TALL-Rec Framework에 대해서&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TALLRec 저자들이 주장하는 것은 대규모 언어 모델(LLM)을 추천 시스템 영역에 활용하는 것입니다. 즉, LLM을 추천 시스템에 최적화하기 위해 설계된 프레임워크이므로, 저자들은 두 가지 주요 튜닝 단계를 소개합니다. 바로 알파카 튜닝(Alpaca-Tuning)과 추천 튜닝(Rec-Tuning)입니다. 이 프로세스에 대한 설명은 Figure 2에 잘 나와있습니다.&amp;nbsp;&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-filename=&quot;스크린샷 2025-01-18 오후 8.14.09.png&quot; data-origin-width=&quot;3306&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yJYkS/btsLRLQrUvM/fojjvRKOfegOg9kuJoH6C0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yJYkS/btsLRLQrUvM/fojjvRKOfegOg9kuJoH6C0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yJYkS/btsLRLQrUvM/fojjvRKOfegOg9kuJoH6C0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyJYkS%2FbtsLRLQrUvM%2FfojjvRKOfegOg9kuJoH6C0%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;3306&quot; height=&quot;900&quot; data-filename=&quot;스크린샷 2025-01-18 오후 8.14.09.png&quot; data-origin-width=&quot;3306&quot; data-origin-height=&quot;900&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;알파카 튜닝(Alpaca Tuning)은 LLM의 일반적인 문제 해결 능력을 강화하는 과정입니다. 즉, 일반화 능력을 향상시키는 과정이라고 보시면 됩니다. 이 과정은 위에서 소개한 것과 같이 self-instruction 데이터를 기반해 수행됩니다. 수식으로 표현하면 수식(1)과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-18 오후 8.13.55.png&quot; data-origin-width=&quot;1320&quot; data-origin-height=&quot;230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cI1Jtf/btsLRED0ZyF/TD7vVk0G4sxAEcQzphvSOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cI1Jtf/btsLRED0ZyF/TD7vVk0G4sxAEcQzphvSOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cI1Jtf/btsLRED0ZyF/TD7vVk0G4sxAEcQzphvSOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcI1Jtf%2FbtsLRED0ZyF%2FTD7vVk0G4sxAEcQzphvSOk%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;688&quot; height=&quot;120&quot; data-filename=&quot;스크린샷 2025-01-18 오후 8.13.55.png&quot; data-origin-width=&quot;1320&quot; data-origin-height=&quot;230&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수식 (1)을 보면 \(y_t\)는 \(t\)번째 토큰이라고 보시면 됩니다. \(y_{&amp;lt;t}\)는 \(y_t\)전까지의 토큰을 의미합니다. 즉, 주어진 입력 \(x\)와 이전 토큰들을 기반으로 \(y_t\)가 나올 확률을 학습하는 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 LLM을 그냥 이대로 학습시키는 것은 매우 계산 비용이 높은 작업입니다. 따라서, 논문의 저자들은 LoRA 방법을 채택해서 효율적으로 LLM 튜팅을 진행하도록 합니다. 그 수식은 수식 (2)와 같습니다.&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-filename=&quot;스크린샷 2025-01-18 오후 8.14.00.png&quot; data-origin-width=&quot;1320&quot; data-origin-height=&quot;230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A2FXY/btsLSRh9eD7/ep2y98tXnKlKKr1C6c3YhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A2FXY/btsLSRh9eD7/ep2y98tXnKlKKr1C6c3YhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A2FXY/btsLSRh9eD7/ep2y98tXnKlKKr1C6c3YhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA2FXY%2FbtsLSRh9eD7%2Fep2y98tXnKlKKr1C6c3YhK%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;688&quot; height=&quot;120&quot; data-filename=&quot;스크린샷 2025-01-18 오후 8.14.00.png&quot; data-origin-width=&quot;1320&quot; data-origin-height=&quot;230&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;\(\theta\)는 LoRA 파라미터이고 저자들은 오직 LoRA 파라미터만 학습 프로세스 때 업데이트 하는 방식으로 진행했다고 합니다.&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;Rec-tuning 단계는 LLM이 추천 시스템 task를 잘 수행할 수 있도록 튜닝하는 과정입니다. Rec-tuning도 마찬가지로 LoRA 기반으로 진행되었다고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 저자들은 Backbone으로 LLaMA 7b 모델을 활용했다고 합니다. 학습 데이터와 연구 결과 등이 모두 공개되어 있어 활용하기 유용하기에 LLaMA를 활용했다고 말합니다.&amp;nbsp;&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;b&gt;5. 실험(Experiments)&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;5-1. Experiments 환경 구성&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 TALLRec Framework의 성능을 평가하기 위해 다양한 실험을 진행했습니다. 특히, 실험의 주요 목표는 아래와 같은 질문에 답하는 것이라고 합니다.&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;- RQ1. TALLRec이 기존의 LLM 기반 추천 시스템과 전통적인 추천(Traditional recommendation) 방법과 비교해서 좋은 성능을 보이는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- RQ2. TALLRec의 구성 요소들이 모델 성능에 미치는 영향은 무엇인가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- RQ3. TALLRec이 cross domain 추천에서 얼마나 좋은 일반화 성능을 보여주는가?&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;TALLRec의 데이터 셋 &amp;amp; &lt;b&gt;Few-shot 학습 설정&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TALLRec에서는 MovieLens100K 데이터 셋, BookCrossing 데이터 셋 총 2가지 데이터를 사용했습니다. MovieLens100K 데이터 셋에서는 최근 10,000개의 interaction을 샘플링했고 학습:검증:테스트를 8:1:1 비율로 셋팅하였습니다. 또한, 사용자의 선호와 비선호를 구분하기 위해서 평점(rating)이 3점 이상이면 선호, 아니면 비선호로 표현했습니다. 그리고 영화의 제목이나 감독을 텍스트 설명으로 포함하였습니다. BookCrossing 데이터의 경우 사용자 평점이 1~10점 분포로 구성되어 있습니다. 또한, 책 제목이나 저자 정보를 텍스트 설명으로 포함하였으며, 평점 5점을 기준으로 선호, 비선호를 구분하였습니다. BookCrossing 데이터는 상호작용(interaction)의 타임스템프가 부족하기 때문에 random sampling 형식으로 사용자마다 무작위로 선태하여 히스토리컬 데이터를 구성하였다고 저자들은 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 few-shot 학습 설정이라는 것을 진행하는데요. 이는 학습 데이터셋에서 임의로 선택한 소량의 샘플(k개)만 사용하여 모델을 학습하는 과정을 진행하는 것입니다. 이렇게 제한된 수의 샘플로 훈련을 진행한 이유는 TALLRec 모델이 제한된 데이터만으로도 추천 시스템 task를 효과적으로 수행할 수 있는지 평가하기 위해서였다고 하네요.&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;베이스라인 모델(Baseline model), &lt;b&gt;평가 지표(Evaluation Metric)와 구현 세부사항(Implementation Details)&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TALLRec에서 베이스라인 모델은 LLM 기반 모델과 전통적인 추천 시스템 방법 2가지고 구분하였습니다. LLM 기반 모델은 In-context learning을 활용하고 Alpaca-LoRA, Text-Davinci-002, Text-Davinci-003, ChatGPT를 활용했다고 합니다. 전통적인 추천 시스템 방법은 GRU4Rec, Caser, SASRec, GRU-BERT 등을 활용했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평가 지표는 AUC를 활용했고 구현 세부사항은 Adam 등을 사용한 것인데 본 포스팅에서 자세한 것은 생략하며, 궁금하신 분들은 논문을 확인해주시면 되겠습니다.&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;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;5-2. Performance comparison(RQ1)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 저자들은 TALLRec Framework의 성능을 평가하기 위해 기존의 전통적인 추천 시스템 방법과 LLM 기반 추천 시스템 방법과 성능을 비교하였습니다. 이때, 제한된 데이터(few-shot) 환경에서도 TALLRec이 얼마나 우수한 성능을 보여주는지 확인합니다. Table 3는 다양한 Few-shot 설정(16 또는 64 또는 256)에서 기존 전통 추천 방법들과 비교한 결과를 보여줍니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-18 오후 8.14.17.png&quot; data-origin-width=&quot;3306&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxeqQf/btsLSPxNwvW/3fkb7B6CeiVGz1xUuxWnh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxeqQf/btsLSPxNwvW/3fkb7B6CeiVGz1xUuxWnh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxeqQf/btsLSPxNwvW/3fkb7B6CeiVGz1xUuxWnh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxeqQf%2FbtsLSPxNwvW%2F3fkb7B6CeiVGz1xUuxWnh0%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;3306&quot; height=&quot;900&quot; data-filename=&quot;스크린샷 2025-01-18 오후 8.14.17.png&quot; data-origin-width=&quot;3306&quot; data-origin-height=&quot;900&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;Movie 데이터셋과 Book 데이터셋 모두의 경우 TALLRec이 더 좋은 성능을 보여주었습니다. 이때, few-shot이 증가할수록 모델의 성능 또한 증가하는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Figure 3의 왼쪽 그림인 (a)영역에서는 TALLRec과 LLM 기반 모델들의 성능을 비교한 결과를 보여줍니다.&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-filename=&quot;스크린샷 2025-01-18 오후 8.14.26.png&quot; data-origin-width=&quot;3306&quot; data-origin-height=&quot;1218&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PBfEN/btsLQ5oDAlL/fKV9LGUmaqXer68aJjCKRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PBfEN/btsLQ5oDAlL/fKV9LGUmaqXer68aJjCKRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PBfEN/btsLQ5oDAlL/fKV9LGUmaqXer68aJjCKRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPBfEN%2FbtsLQ5oDAlL%2FfKV9LGUmaqXer68aJjCKRK%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;3306&quot; height=&quot;1218&quot; data-filename=&quot;스크린샷 2025-01-18 오후 8.14.26.png&quot; data-origin-width=&quot;3306&quot; data-origin-height=&quot;1218&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;비교된 모델은 앞서 설명드렸던 Alpaca-LoRA, Text-Davinci-002, Text-Davinci-003, ChatGPT인데요. 모든 결과에서 저자들이 제시한 TALLRec이 좋은 성능을 보여주었습니다. 특히, 저자들은 Alpaca-LoRA와 Text-Davinci 계열 모델들은 random guessing 정도의 수준이라면서 한계가 있음을 언급하였고 이는 추천 시스템 task와 언어 모델의 task 사이의 상당한 차이가 있음을 언급하였습니다. 그와 반면에 TALLRec은 우수한 성능을 보여주면서 LLM을 rec-tuning하는 과정이 중요하다는 것을 언급합니다.&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;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;5-3. Ablation study(RQ2)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 alpaca-tuning과 rec-tuning이 TALLRec 성능에 미치는 영향을 평가하기 위해 추가 Ablation study를 논문 3.2 섹션에서 진행합니다. 이때, AT는 Alpaca-tuning만 진행한 모델로 일반화 능력은 강화하지만, 추천 시스템 task에 훈련을 진행하지 않은 모델입니다. 또한, RT는 Rec-tuning만 수행한 모델로 Alpaca-tuning 없이 추천 시스템 task에 튜닝된 모델입니다. 동시에 few-shot sample 수에 따른 성능 평가를 진행하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ablation 실험 결과는 Figure 3의 오른쪽 그림인 (b)에 실험 결과가 나와있습니다. 이 실험 결과를 정리하자면 아래와 같습니다.&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. Alpaca 튜닝(AT)는 AUC가 매우 낮게 나오고 있습니다. 이는 일반화된 능력을 강화하더라도 추천 시스템 task에 기여하지 못하는 것을 보여주는 결과입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Rec 튜닝(RT)는 AT보다 더 좋은 결과가 나왔고 sample 수가 증가할 때마다 TALLRec에 버금가는 성능을 보여주었습니다. 다만, RT는 적은 샘플 수에서는 TALLRec보다 성능이 떨어지는 결과가 나왔습니다. 이는 Alpaca-tuning이 new task에서 LLM의 일반화 능력을 향상시킬 수 있음을 확인할 수 있다고 저자들은 주장합니다. 특히, new task의 학습 데이터가 충분하지 않을 때 더욱 그럴 것이라고 이야기합니다. 그리고 샘플의 수가 증가함에 따라 TALLRec에 가까워지는 것은 학습 데이터가 충분할 때 다른 task에서 도출된 일반화 능력이 감소하기 때문에 이는 합리적이라고 저자들은 말합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. TALLRec은 가장 좋은 성능을 보여주었습니다.&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;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;5-4. Cross-domain Generalization Analyses(RQ3)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 TALLRec Framework가 가지는 강점 중 하나가 다양한 도메인 간의 일반화 능력(cross domain generalization)이라고 합니다. 이를 평가하기 위해서 book 데이터만 학습한 모델, Movie 데이터로 학습한 모델, 두 데이터를 모두 학습한 모델을 활용해 두 가지 도메인 boo, movie에 대해서 평가를 진행했습니다. 그 결과는 Figure 4에 나와있습니다.&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-filename=&quot;스크린샷 2025-01-18 오후 8.14.53.png&quot; data-origin-width=&quot;3306&quot; data-origin-height=&quot;1016&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ByrGH/btsLS8KFNhO/YVyXD7YBAQ1hzyKVc2hhv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ByrGH/btsLS8KFNhO/YVyXD7YBAQ1hzyKVc2hhv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ByrGH/btsLS8KFNhO/YVyXD7YBAQ1hzyKVc2hhv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FByrGH%2FbtsLS8KFNhO%2FYVyXD7YBAQ1hzyKVc2hhv1%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;3306&quot; height=&quot;1016&quot; data-filename=&quot;스크린샷 2025-01-18 오후 8.14.53.png&quot; data-origin-width=&quot;3306&quot; data-origin-height=&quot;1016&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;Movie 데이터에서 학습된 TALLRec(Movie)와 book 데이터에서 학습된 TALLRec(book)이 서로 다른 도메인에서 어느정도 성능이 나오고 있음을 확인할 수 있습니다. 이를 통해 저자들은 TALLRec이 cross-domain 일반화 능력을 보여주고 있다고 주장합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(개인적으론 좀 받아드리기 어려운 주장입니다. 그 이유는, 이는 데이터 셋에 굉장히 민감할 것 같고 좀 더 다양한 테스트가 되어야 하지 않을까?싶습니다.)&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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 LLM을 활용한 추천 시스템 논문인 TALLRec: An Effective and Efficient Tuning Framework to Align Large Language Model with Recommendation 논문을 읽고 리뷰한 포스팅입니다. 대규모 언어 모델(LLM)과 추천 시스템 task를&amp;nbsp; Alignment 하는 시도를 보여주는 논문입니다. LLM과 추천 시스템의 결합에 관심이 있으신 분들께 조금이나마 도움이 되기를 바라겠습니다.&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;div&gt;
&lt;p style=&quot;text-align: left;&quot; 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;Linkedin :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot;&gt;https://www.linkedin.com/in/lsjsj92/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;github :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/lsjsj92&quot;&gt;https://github.com/lsjsj92&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;블로그 댓글 또는 방명록&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;으로 연락주세요!&lt;/p&gt;</description>
      <category>인공지능(AI)/추천시스템</category>
      <category>LLM</category>
      <category>lora</category>
      <category>NLP</category>
      <category>Recommendation</category>
      <category>recommender</category>
      <category>tallrec</category>
      <category>논문</category>
      <category>논문리뷰</category>
      <category>대규모언어모델</category>
      <category>추천시스템</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/678</guid>
      <comments>https://lsjsj92.tistory.com/678#entry678comment</comments>
      <pubDate>Mon, 20 Jan 2025 09:45:15 +0900</pubDate>
    </item>
    <item>
      <title>PGVector와 Python FastAPI를 연동하여 벡터 데이터 저장 및 유사도 기반 조회하기</title>
      <link>https://lsjsj92.tistory.com/677</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 PostgreSQL의 PGVector extension을 활용해 벡터 데이터베이스로 사용하여 파이썬(Python)의 FastAPI를 연동해 데이터를 저장하고 조회하는 방법에 대해 정리하는 포스팅입니다. 이때, PostgreSQL에 데이터를 저장하는 방법에는 벡터 데이터베이스로 활용하므로 일반 데이터를 저장하면서 동시에 임베딩 모델(embedding model)을 활용해 텍스트를 벡터(vector)로 변환하여 저장하게 됩니다. 또한, 데이터를 조회하는 과정은 1) 제목(title)과 완벽하게 일치하는 exact match 기반 검색과 2) 코사인 유사도(cosine similarity) 기반으로 텍스트 벡터 유사도 기반으로 검색을 하는 과정을 정리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PostgreSQL와 PGVecotor란 무엇인지 궁금하시거나 설치하는 방법이 궁금하시다면, 앞서 제가 작성한 PostgreSQL PGVector 설치 및 사용하기 포스팅(&lt;a href=&quot;https://lsjsj92.tistory.com/675&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/675&lt;/a&gt;)을 참고해주세요.&lt;/p&gt;
&lt;figure id=&quot;og_1735705223619&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;PostgreSQL PGVector 설치 및 사용하기(Feat. 벡터 데이터베이스(Vector Database) 구축)&quot; data-og-description=&quot;포스팅 개요이번 포스팅은 검색 증강 생성(Retrieval Augmented Generation, RAG)에서 많이 활용되는 벡터 데이터베이스 중 PostgreSQL의 PGVector에 대해서 작성하는 포스팅입니다. 이번 포스팅은 그 중, PostgreS&quot; data-og-host=&quot;lsjsj92.tistory.com&quot; data-og-source-url=&quot;https://lsjsj92.tistory.com/675&quot; data-og-url=&quot;https://lsjsj92.tistory.com/675&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jkhes/hyXSyrBa1s/3AhPCI4zTMJ7prLcJRxlAk/img.png?width=800&amp;amp;height=293&amp;amp;face=0_0_800_293,https://scrap.kakaocdn.net/dn/UDZ6j/hyXSCt3QOG/MfrJg2cHcXUi3ZkSXk0v9k/img.png?width=800&amp;amp;height=293&amp;amp;face=0_0_800_293,https://scrap.kakaocdn.net/dn/JMNtp/hyXWsccvex/qM78sMCZ5qiQhB2YfOzqhK/img.png?width=1856&amp;amp;height=1344&amp;amp;face=0_0_1856_1344&quot;&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/675&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://lsjsj92.tistory.com/675&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jkhes/hyXSyrBa1s/3AhPCI4zTMJ7prLcJRxlAk/img.png?width=800&amp;amp;height=293&amp;amp;face=0_0_800_293,https://scrap.kakaocdn.net/dn/UDZ6j/hyXSCt3QOG/MfrJg2cHcXUi3ZkSXk0v9k/img.png?width=800&amp;amp;height=293&amp;amp;face=0_0_800_293,https://scrap.kakaocdn.net/dn/JMNtp/hyXWsccvex/qM78sMCZ5qiQhB2YfOzqhK/img.png?width=1856&amp;amp;height=1344&amp;amp;face=0_0_1856_1344');&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;PostgreSQL PGVector 설치 및 사용하기(Feat. 벡터 데이터베이스(Vector Database) 구축)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 개요이번 포스팅은 검색 증강 생성(Retrieval Augmented Generation, RAG)에서 많이 활용되는 벡터 데이터베이스 중 PostgreSQL의 PGVector에 대해서 작성하는 포스팅입니다. 이번 포스팅은 그 중, PostgreS&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;lsjsj92.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;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;a href=&quot;https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pgvector/pgvector-python/blob/master/examples/hybrid_search/cross_encoder.py&quot;&gt;https://github.com/pgvector/pgvector-python/blob/master/examples/hybrid_search/cross_encoder.py&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pgvector/pgvector-python&quot;&gt;https://github.com/pgvector/pgvector-python&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1735705295221&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 - pgvector/pgvector-python: pgvector support for Python&quot; data-og-description=&quot;pgvector support for Python. Contribute to pgvector/pgvector-python development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/pgvector/pgvector-python&quot; data-og-url=&quot;https://github.com/pgvector/pgvector-python&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bb9Lh0/hyXWqSZcoS/y8BcpbjfFPZJXfuNkiwBrK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bepW1h/hyXWsJ2PLb/05HsUI2jrk1B4xmypEDmA1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/pgvector/pgvector-python&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/pgvector/pgvector-python&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bb9Lh0/hyXWqSZcoS/y8BcpbjfFPZJXfuNkiwBrK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bepW1h/hyXWsJ2PLb/05HsUI2jrk1B4xmypEDmA1/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 - pgvector/pgvector-python: pgvector support for Python&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;pgvector support for Python. Contribute to pgvector/pgvector-python 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;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅에서 사용한 코드는 아래 github에 올려두었으니 참고해주세요.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lsjsj92/pgvector-py-tutorial&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/lsjsj92/pgvector-py-tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1735708921918&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 - lsjsj92/pgvector-py-tutorial: pgvector tutorial with python&quot; data-og-description=&quot;pgvector tutorial with python. Contribute to lsjsj92/pgvector-py-tutorial development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/lsjsj92/pgvector-py-tutorial&quot; data-og-url=&quot;https://github.com/lsjsj92/pgvector-py-tutorial&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/lOY5l/hyXWycq5zj/dNINECKl1YwZzC8TSOdWH0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bCyO5s/hyXWrqOAZK/rWKCfDIPKdEJBPRBOskZJK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/lsjsj92/pgvector-py-tutorial&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/lsjsj92/pgvector-py-tutorial&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/lOY5l/hyXWycq5zj/dNINECKl1YwZzC8TSOdWH0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bCyO5s/hyXWrqOAZK/rWKCfDIPKdEJBPRBOskZJK/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 - lsjsj92/pgvector-py-tutorial: pgvector tutorial with python&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;pgvector tutorial with python. Contribute to lsjsj92/pgvector-py-tutorial 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;
&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;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅 개요에서도 언급하였듯, 이번 포스팅은 파이썬(Python)의 FastAPI를 활용해서 PGVector가 확장된 PostgreSQL과(Vector database) 연동하여 데이터를 저장 및 조회하는 과정을 정리하는 포스팅입니다. 본 포스팅은 아래와 같은 단계로 정리를 진행하겠습니다.&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. 임베딩 모델 준비 - 허깅페이스(HuggingFace) 임베딩 모델 활용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. FastAPI 환경 개발 - PostgreSQL과 연동하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. FastAPI 환경 개발 - 스키마 및 모델 구조 설정하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. FastAPI 환경 개발 - 데이터 저장하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. FastAPI 환경 개발 - 데이터 조회하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735705703006&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;참고사항: PostgreSQL 및 PGVector 그리고 Python FastAPI를 개발한 환경은 다음과 같습니다.

- MacOS(MacBook pro, 2019)
- PostgreSQL version: PostgreSQL@16
- PGVector version: pgvector 0.8.0
- Python version: Python 3.9
- Python library: langchaib, pydantic, fastapi, SQLAlchemy, huggingface, pgvector&lt;/code&gt;&lt;/pre&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;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;임베딩 모델 준비&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저, 임베딩 모델을 준비합니다. PGVector를 활용한다는 것은 벡터 데이터베이스(Vector Database)를 사용하는 것이기에 당연히 벡터로 변환해줄 임베딩 모델이 필요하죠. 저는 텍스트 데이터를 vector로 변환하여 저장할 것이기 때문에, 허깅페이스에서 모델을 선정하였습니다. 제가 선정한 모델은 다음과 같습니다.&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-filename=&quot;스크린샷 2025-01-01 오후 1.42.30.png&quot; data-origin-width=&quot;1028&quot; data-origin-height=&quot;644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVXVCo/btsLDvTmdjz/yO9Fz3Ly248QAegiCxVNF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVXVCo/btsLDvTmdjz/yO9Fz3Ly248QAegiCxVNF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVXVCo/btsLDvTmdjz/yO9Fz3Ly248QAegiCxVNF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVXVCo%2FbtsLDvTmdjz%2FyO9Fz3Ly248QAegiCxVNF1%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;1028&quot; height=&quot;644&quot; data-filename=&quot;스크린샷 2025-01-01 오후 1.42.30.png&quot; data-origin-width=&quot;1028&quot; data-origin-height=&quot;644&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;sentence-transformers/all-MiniLM-L6-v2라는 모델이며, 임베딩 벡터 차원수도 크지 않고(384차원) 준수한 성능을 보여주기에 해당 모델로 선정하였습니다.&amp;nbsp;&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;pre id=&quot;code_1735706690841&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;hf_embed_repo_id = 'sentence-transformers/all-MiniLM-l6-v2'
hf_embeddings = HuggingFaceHubEmbeddings(repo_id=hf_embed_repo_id)
query_result = hf_embeddings.embed_query(&quot;안녕하세요&quot;)
print(len(query_result)) # 384 차원&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;추후 FastAPI 환경에도 위와 같은 코드를 기반으로 코드 작업을 진행합니다. 벡터를 저장하는 컬럼에 같은 벡터 차원으로 설정하고(384차원) 이를 활용해 코사인 유사도와 같은 작업을 수행하게 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;FastAPI 개발: PostgreSQL과 Python 연동하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 본격적으로 벡터 데이터베이스(Vector Database)인 PGVector 확장자가 갖추어진 PostgreSQL과 연동하는 파이썬(Python) FastAPI 코드를 살펴보려고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째로는 Python 환경에서 PostgreSQL과 연동하기 위한 환경 설정을 진행합니다. 아래 코드는 데이터베이스 연결 설정, 세션 생성, 그리고 PGVector 확장을 초기화하는 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735709533723&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DB_USER = os.getenv(&quot;DB_USER&quot;, &quot;leesoojin&quot;)
DB_PASS = os.getenv(&quot;DB_PASS&quot;, &quot;&quot;)
DB_HOST = os.getenv(&quot;DB_HOST&quot;, &quot;localhost&quot;)
DB_PORT = os.getenv(&quot;DB_PORT&quot;, &quot;5432&quot;)
DB_NAME = os.getenv(&quot;DB_NAME&quot;, &quot;test&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;코드의 첫 번째 부분에는 데이터베이스 연결에 필요한 정보를 환경 변수에서 가져옵니다. 환경 변수를 사용하지 않을 경우 기본 값을 제공하는데요. 데이터베이스 유저와 호스트, 포트, 데이터베이스 이름 등을 작성합니다. 이 정보는 이전 포스팅에서 작성했던 정보를 기반으로 넣어두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 읽기 쉽게 위와 같이 작성하였지만, .env 파일을 활용해 사용하는 것을 권장드립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735710168732&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# PostgreSQL URL (asyncpg)
DATABASE_URL = f&quot;postgresql+asyncpg://{DB_USER}:{DB_PASS}@{DB_HOST}:{DB_PORT}/{DB_NAME}&quot;

# echo=True -&amp;gt; SQL 로그 출력
async_engine = create_async_engine(DATABASE_URL, echo=True)

# 세션 팩토리 (자동커밋/오토플러시 끔)
AsyncSessionLocal = sessionmaker(
    bind=async_engine,
    expire_on_commit=False,
    class_=AsyncSession,
    autoflush=False,
    autocommit=False
)

Base = declarative_base()&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;그리고 설정 정보를 기반으로 데이터베이스 연결을 설정합니다. DATABASE_URL에 관련 정보를 함께 넣어주고 이 정보를 기반으로 데이터베이스 엔진을 생성합니다. 저는 로그를 보기 위해서 echo를 True로 설정하였습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그 다음으로 세션 메이커(sessionmaker)를 이용해 세션 팩토리를 구성하고 declarative_base() 객체를 생성하여 SQLAlchemy의 ORM(Object Relational Mapping)을 사용해 데이터베이스 테이블을 Python 클래스에 매핑하기 위한 준비를 진행합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 Base라는 객체는 뒤에서 테이블 클래스에서 사용되게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735709024317&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async def init_db():
    &quot;&quot;&quot;
    pgvector 확장을 활성화하고, Base에 정의된 모든 테이블을 생성
    &quot;&quot;&quot;
    async with async_engine.begin() as conn:
        # pgvector extension
        await conn.execute(text(&quot;CREATE EXTENSION IF NOT EXISTS vector&quot;))
        # 테이블 생성
        await conn.run_sync(Base.metadata.create_all)

# FastAPI 의존성 주입용
async def get_db_session():
    &quot;&quot;&quot;
    DB 세션을 제공하는 Generator
    &quot;&quot;&quot;
    async with AsyncSessionLocal() as session:
        yield session&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;init_db 함수는 PGVector 확장을 활성화하고 위에서 생성한 SQLAlchemy의 Base 객체를 기반으로 모든 테이블을 생성하도록 수행하는 함수이고, get_db_session 함수는 데이터베이스 세션을 제공하는 함수입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 여러분들이 데이터베이스의 테이블을 생성하지 않아도, create_all이라는 것을 활용해 base가 가지고 있는 모든 테이블을 생성하는 것입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;FastAPI 개발: 데이터 스키마 및 데이터베이스 모델 구조 정의하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 PostgreSQL에 PGVector 확장을 활용하여 텍스트 데이터를 저장하고 벡터화된 임베딩을 함께 관리하기 위한 데이터 모델을 정의합니다. 데이터베이스 테이블, 데이터 스키마, 그리고 API 응답 모델을 정의합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 먼저, API 응답에 활용되는 2개의 클래스를 구성합니다. 이때 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Pydantic을 사용하여 데이터 검증 및 직렬화를 수행합니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1735709095583&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pydantic import BaseModel

class TextItemCreate(BaseModel):
    title: str
    content: str

class TextItemResponse(BaseModel):
    id: int
    title: str
    content: str

    class Config:
        orm_mode = True&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;TextItemCreate 클래스는 텍스트 데이터를 생성하거나 저장 요청을 할 때 사용되는 데이터 스키마입니다. 이때 제목(title)과 콘텐츠(content) 정보를 받도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TextItemResponse 클래스는 데이터 응답을 원할 때 사용되는 데이터 스키마입니다. 즉, 사용자의 요청(request)에 따라 응답(response)를 수행하는데, 이때 id와 title, content가 포함되어 응답하도록 정의된 데이터 스키마이죠.&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;또한, 데이터베이스 테이블에 대한 정보도 설정해두겠습니다. SQLAlchemy는 Python의 ORM 라이브러리인데요. 이를 활용하여 Python 클래스를 데이터베이스 테이블에 매핑하여 DB 작업을 처리할 수 있도록 해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1735710452663&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class TextItem(Base):
    __tablename__ = &quot;text_items&quot;

    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    title = Column(String, nullable=False)   # 제목
    content = Column(Text, nullable=False)   # 본문
    embed = Column(Vector(384), nullable=False)  # 384차원 벡터&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;위 클래스에서 TextItem(Base)라고 되어 있는데요. 이때 Base가 앞서 정의했던 declarative_base() 객체입니다. 이 클래스는 데이터베이스의 테이블 구조입니다. 이 테이블에는 id, title, content, embed 4개의 컬럼이 있는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, embed가 바로 벡터를 저장하는 컬럼입니다. 즉, 이를 활용해 벡터 데이터베이스(Vector Database) 역할을 수행할 수 있도록 하는 것이죠. 또한, 벡터 차원을 384으로 설정해두었는데 위에서 허깅페이스 임베딩 모델의 차원이 384차원의 모델이기 때문에 이와 같이 설정하였습니다.&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;FastAPI 개발: 데이터 저장하기&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 FastAPI를 활용하여 받은 데이터를 PostgreSQL에 저장하는 방법을 살펴봅니다. 이 작업은 입력 데이터 중 콘텐츠(content) 데이터를 앞서 정의한 임베딩 모델을 활용해 embedding vector로 변환한 뒤 PGVector를 통해 데이터베이스에 저장하는 과정을 포함합니다. 이렇게 데이터를 저장하면 벡터 데이터베이스로 활용할 준비 작업이 진행되는 것이죠.&lt;/p&gt;
&lt;pre id=&quot;code_1735709137634&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@router.post(&quot;/create-item&quot;, response_model=TextItemResponse, tags=[&quot;Items&quot;])
async def create_text_item(
    item: TextItemCreate,
    db: Session = Depends(get_db_session)
):
    &quot;&quot;&quot;
    입력 텍스트(title, content)를 임베딩 후 PostgreSQL에 저장
    &quot;&quot;&quot;
    vector = get_embedding(item.content)  # content 임베딩
    db_item = TextItem(
        title=item.title,
        content=item.content,
        embed=vector
    )
    db.add(db_item)
    
    await db.commit()
    await db.refresh(db_item)
    
    return db_item&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;이 API는 title과 content가 포함된 POST 요청을 /create-item 이라는 엔드포인트로 처리합니다. 요청 데이터는 Pydantic을 활용해 정의된 스키마 클래스 TextItemCreate를 기반으로 검증합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검증된 데이터는 먼저 get_embedding 함수를 사용해 content 텍스트 데이터를 임베딩합니다. 이 함수는 허깅페이스(HuggingFace) 임베딩 모델을 활용해 384차원의 벡터로 변환합니다. 이렇게 생성된 벡터는 데이터베이스에 저장될 PGVector 필드(embed)에 저장될 준비를 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 SQLAlchemy ORM 클래스 TextItem를 사용해 데이터베이스 테이블(text_Items)의 행을 정의합니다. 정의한다는 것은,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- title에는 요청 받은 item.title을 값을 저정하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- content에는 item.content 데이터를&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- embed 컬럼에는 방금 생성한 임베딩 벡터 값인 vector를 할당한다는 것을 의미합니다.&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;구성된 데이터는 db.add를 통해 데이터베이스 세션에 추가됩니다. 이후 commit을 호출하여 실제로 저장되게 되고 refresh를 사용해 데이터베이스에서 갱신된 객체를 가져오게 됩니다. 이 과정에서 DB에 자동으로 생성된 값(id)가 반영되죠.&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;실제로 실행한 결과를 살펴보겠습니다. 아래와 같이 데이터를 직접 넣었을 때 DB에 정상적으로 저장이 될까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsqjBq/btsLDfDf1iA/rSOlBsLseeLzRzge8hD2bK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsqjBq/btsLDfDf1iA/rSOlBsLseeLzRzge8hD2bK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1286&quot; data-origin-height=&quot;573&quot; data-filename=&quot;스크린샷 2025-01-01 오후 7.05.06.png&quot; style=&quot;width: 58.6144%; margin-right: 10px;&quot; data-widthpercent=&quot;59.3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsqjBq/btsLDfDf1iA/rSOlBsLseeLzRzge8hD2bK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsqjBq%2FbtsLDfDf1iA%2FrSOlBsLseeLzRzge8hD2bK%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;1286&quot; height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCmGZI/btsLCsXox4i/VYzL5SxVOiqqBAUD1RcyE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCmGZI/btsLCsXox4i/VYzL5SxVOiqqBAUD1RcyE1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1286&quot; data-origin-height=&quot;835&quot; data-filename=&quot;스크린샷 2025-01-01 오후 7.05.28.png&quot; style=&quot;width: 40.2228%;&quot; data-widthpercent=&quot;40.7&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCmGZI/btsLCsXox4i/VYzL5SxVOiqqBAUD1RcyE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCmGZI%2FbtsLCsXox4i%2FVYzL5SxVOiqqBAUD1RcyE1%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;1286&quot; height=&quot;835&quot;/&gt;&lt;/span&gt;&lt;/div&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;FastAPI에서 제공해주는 Swagger 화면에서 데이터를 직접 넣어보았습니다. title과 content에 알맞는 데이터를 넣고 실행해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LQDqU/btsLCFvEIUs/KOCoQyVI8f3nZnP20x3wBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LQDqU/btsLCFvEIUs/KOCoQyVI8f3nZnP20x3wBk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1286&quot; data-origin-height=&quot;835&quot; data-filename=&quot;스크린샷 2025-01-01 오후 7.05.35.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LQDqU/btsLCFvEIUs/KOCoQyVI8f3nZnP20x3wBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLQDqU%2FbtsLCFvEIUs%2FKOCoQyVI8f3nZnP20x3wBk%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;1286&quot; height=&quot;835&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kHZ40/btsLBY96Q3O/Yzl1zMzpyWL4CcZqSKMK41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kHZ40/btsLBY96Q3O/Yzl1zMzpyWL4CcZqSKMK41/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2572&quot; data-origin-height=&quot;1670&quot; data-filename=&quot;스크린샷 2025-01-01 오후 7.06.04.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kHZ40/btsLBY96Q3O/Yzl1zMzpyWL4CcZqSKMK41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkHZ40%2FbtsLBY96Q3O%2FYzl1zMzpyWL4CcZqSKMK41%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;2572&quot; height=&quot;1670&quot;/&gt;&lt;/span&gt;&lt;/div&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;그 결과 API 응답 코드가 200 코드가 나와서 정상적으로 동작되었음을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 실제 DB에 가보면 테이블을 초기에 생성하지 않았지만 Python 코드에서 명시한 로직 때문에 테이블이 생성되어 있고 실제 데이터도 들어간 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, 입력된 content가 벡터로 변환되어 embed 컬럼에 vector 형태로 저장된 것도 확인할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;FastAPI 개발: 데이터 조회하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 벡터로 저장된 데이터 등을 조회할 수 있는 API를 구축하겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 API는 특정 title 값을 기반으로 텍스트 데이터를 검색하는 로직을 수행합니다. /search/title 엔드포인트에 get 방식으로 요청이 들어오면 로직을 수행하게 되는데요. text_item 테이블에서 title값이 요청 받은 text와 정확히 일치하는( Exact Match ) 데이터를 가지고 오게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1735709168486&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@router.get(&quot;/search/title&quot;, response_model=List[TextItemResponse], tags=[&quot;Search&quot;])
async def search_by_title(title: str, db: AsyncSession = Depends(get_db_session)):
    &quot;&quot;&quot;
    title이 Exact Match인 레코드를 리스트로 반환
    &quot;&quot;&quot;
    # 1) SELECT 쿼리 준비
    stmt = select(TextItem).where(TextItem.title == title)
    
    # 2) 실행
    result = await db.execute(stmt)
    
    # 3) Query 결과
    items = result.scalars().all()
    
    return items&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;그럼 위 코드의 실제 결과를 확인해볼까요? FastAPI에서 제공해주는 Swagger UI에서 실행을 해보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cutvWE/btsLBt34VKl/3wKdyrS9PkTEKW3RTK80Ik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cutvWE/btsLBt34VKl/3wKdyrS9PkTEKW3RTK80Ik/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;961&quot; data-origin-height=&quot;607&quot; data-filename=&quot;스크린샷 2025-01-01 오후 7.12.24.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cutvWE/btsLBt34VKl/3wKdyrS9PkTEKW3RTK80Ik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcutvWE%2FbtsLBt34VKl%2F3wKdyrS9PkTEKW3RTK80Ik%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;961&quot; height=&quot;607&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6Eh7y/btsLBi8066s/MXgv0SQ78CWKRm7A7IQ8bk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6Eh7y/btsLBi8066s/MXgv0SQ78CWKRm7A7IQ8bk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;961&quot; data-origin-height=&quot;607&quot; data-filename=&quot;스크린샷 2025-01-01 오후 7.12.29.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6Eh7y/btsLBi8066s/MXgv0SQ78CWKRm7A7IQ8bk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6Eh7y%2FbtsLBi8066s%2FMXgv0SQ78CWKRm7A7IQ8bk%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;961&quot; height=&quot;607&quot;/&gt;&lt;/span&gt;&lt;/div&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;검색한 title을 '이수진입니다.'라는 제목으로 검색을 했고, 그 결과 3개의 결과 값이 나왔습니다. 3개의 데이터는 똑같이 '이수진입니다.'라는 제목을 가지고 있습니다. 다만, content 내용은 전부 다르죠. 이와 같이 위 API는 title이 정확히 일치 되는 것들을 가져오도록 수행하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item dable&quot; style=&quot;height: 250px;&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;300x250&lt;/div&gt;
    &lt;div id=&quot;dablewidget_Pl1aE8lE&quot; data-widget_id=&quot;Pl1aE8lE&quot;&gt;
      &lt;script&gt;(function(d,a,b,l,e,_) {
    if(d[b]&amp;&amp;d[b].q)return;d[b]=function(){(d[b].q=d[b].q||[]).push(arguments)};e=a.createElement(l);
    e.async=1;e.charset='utf-8';e.src='//static.dable.io/dist/plugin.min.js';
    _=a.getElementsByTagName(l)[0];_.parentNode.insertBefore(e,_);
    })(window,document,'dable','script');
dable('setService', 'lsjsj92.tistory.com');
dable('sendLogOnce');
dable('renderWidget', 'dablewidget_Pl1aE8lE', {ignore_items: true});&lt;/script&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 마지막으로 content에 대한 벡터 서치(vector search)를 진행하는 코드를 살펴보겠습니다. 시맨틱 서치(semantic search)라고 할 수도 있는 이 로직은 사실 vector database로 사용하기 위한 핵심적인 로직이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 API 코드는 입력 받은 쿼리(query)를 기반으로 의미적으로 유사한 텍스트를 코사인 유사도(cosine similarity)로 유사도 검색하여 결과를 제공하는 로직을 수행합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1735709180985&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@router.get(&quot;/search/semantic&quot;, tags=[&quot;Search&quot;])
async def semantic_search(query: str, limit: int = 5, db: AsyncSession = Depends(get_db_session)):
    &quot;&quot;&quot;
    1) query 문자열을 임베딩 (HuggingFace Hub)
    2) pgvector 메서드 방식 (cosine_distance)로 오름차순 정렬
    3) 상위 limit개 반환
    &quot;&quot;&quot;
    # (1) 임베딩
    query_embedding = get_embedding(query)

    # (2) 검색
    stmt = (
        select(TextItem)
        .order_by(TextItem.embed.cosine_distance(query_embedding))
        .limit(limit)
    )
    # 쿼리 실행
    result = await db.execute(stmt)

    # (3) 결과 추출
    items = result.scalars().all()

    # (4) dict로 변환
    return [
        {
            &quot;id&quot;: r.id,
            &quot;title&quot;: r.title,
            &quot;content&quot;: r.content
        }
        for r in items
    ]&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;사용자가 입력한 Query가 입력으로 들어오면 이를 앞서 정의한 임베딩 모델을 활용해 임베딩 벡터(embedding vector)로 변환해줍니다. 그리고 변환된 임베딩 벡터와 text_item 테이블이 가지고 있는 임베딩 벡터 컬럼인 embed와 코사인 유사도를 측정해 결과를 가져오게 되죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 실제 결과를 살펴보겠습니다. Swagger UI에서 실행시킨 결과는 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCT5ON/btsLBq0veQp/UQ4fDn6JIP045Y5MOU2xBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCT5ON/btsLBq0veQp/UQ4fDn6JIP045Y5MOU2xBk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;961&quot; data-origin-height=&quot;657&quot; data-filename=&quot;스크린샷 2025-01-01 오후 7.18.25.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCT5ON/btsLBq0veQp/UQ4fDn6JIP045Y5MOU2xBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCT5ON%2FbtsLBq0veQp%2FUQ4fDn6JIP045Y5MOU2xBk%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;961&quot; height=&quot;657&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UY3MG/btsLDvslm4G/oJBQQS7TiyuiyhvAGipo70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UY3MG/btsLDvslm4G/oJBQQS7TiyuiyhvAGipo70/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;961&quot; data-origin-height=&quot;657&quot; data-filename=&quot;스크린샷 2025-01-01 오후 7.18.31.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UY3MG/btsLDvslm4G/oJBQQS7TiyuiyhvAGipo70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUY3MG%2FbtsLDvslm4G%2FoJBQQS7TiyuiyhvAGipo70%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;961&quot; height=&quot;657&quot;/&gt;&lt;/span&gt;&lt;/div&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;저는 입력 쿼리로 '공부하고 있어요'라는 쿼리를 전달했고 limit은 1개 즉, 가장 유사도가 큰 1개만 가져오도록 했습니다.&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;이렇게 FastAPI를 구성하면 사용자의 입력에 따라 벡터 데이터베이스에 입력 데이터를 임베딩 모델을 활용해 벡터로 변환 후 저장할 수 있고 코사인 유사도와 같은 방법으로 벡터 검색(vector search)를 수행할 수 있습니다.&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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 pgvector 벡터 데이터베이스(vector database)를 활용해 파이썬 FastAPI와 연동하는 방법을 정리한 포스팅입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;허깅페이스의 embedding model을 활용해 사용자의 입력 데이터를 vector로 변환하여 저장하고, 벡터 서치와 타이틀 기반 완전 일치 검색을 수행할 수 있는 방법을 정리하였습니다.&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;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;p data-ke-size=&quot;size16&quot;&gt;- 링크드인 : &lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot;&gt;https://www.linkedin.com/in/lsjsj92/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- github : &lt;a href=&quot;https://github.com/lsjsj92&quot;&gt;https://github.com/lsjsj92&lt;/a&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;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>fastapi</category>
      <category>huggingface</category>
      <category>LLM</category>
      <category>pgvector</category>
      <category>PostgreSQL</category>
      <category>RAG</category>
      <category>vectordatabase</category>
      <category>vectordb</category>
      <category>벡터데이터베이스</category>
      <category>허깅페이스</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/677</guid>
      <comments>https://lsjsj92.tistory.com/677#entry677comment</comments>
      <pubDate>Mon, 6 Jan 2025 09:25:26 +0900</pubDate>
    </item>
    <item>
      <title>2024년 회고 - 나 자신에게 고생 많이 했다고 말하고 싶은 한 해</title>
      <link>https://lsjsj92.tistory.com/676</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 저 이수진의 2024년 회고를 작성한 글입니다.&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;2024년을 돌아보면서 솔직한 마음을 돌아보면서, 일기 형식으로 회고를 남겨봅니다.&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;2024년을 돌아보면서&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1000028934.jpg&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGIDb2/btsLAhCasHQ/KgyA9kJyEGLkpDSE65xSGK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGIDb2/btsLAhCasHQ/KgyA9kJyEGLkpDSE65xSGK/img.jpg&quot; data-alt=&quot;연말, 태국에서 휴가를 보낼 때 찍었던 일몰&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGIDb2/btsLAhCasHQ/KgyA9kJyEGLkpDSE65xSGK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGIDb2%2FbtsLAhCasHQ%2FKgyA9kJyEGLkpDSE65xSGK%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;4000&quot; height=&quot;3000&quot; data-filename=&quot;1000028934.jpg&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;연말, 태국에서 휴가를 보낼 때 찍었던 일몰&lt;/figcaption&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;2024년이 이제 거의 남지 않았다. 글을 쓰고 있는 시점이 12월 28일이니까, 3일 남았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간 정말 빠르다. 24년 초기에 조직 개편과 승진 등 여러 변화를 겪었는데, 어느덧 24년이 끝나간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2024년을 돌아보면 뭘 했지?라는 생각이 들 정도로 정말 정신없이 살아왔다. 중간중간 일기나, 기록을 하지 않았으면 정말 기억이 잘 나지 않았을 것 같다. 그만큼 여러 우여곡절과 상황이 계속 발생했고 그걸 이겨내왔다.&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;2024년을 한 줄로 요약하자면 이렇게 쓸 수 있지 않을까?&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;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;실패와 도전, 또 다시 실패와 재도전. 이것들의 반복&lt;/span&gt;&lt;/blockquote&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;그렇다. 2024년은 나에게 계속해서 실패와 도전을 반복하는 한 해였다. 실패라는게 여러 의미가 있는데, 기술적으로나, 가정적으로나, 일상적으로나 모든 것들이 다 포함된다. 나의 2024년 주요 이슈는 다음과 같다.&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&gt;결혼 후, 이전과 완전히 바뀐 삶&lt;/li&gt;
&lt;li&gt;2년 조기 승진&lt;/li&gt;
&lt;li&gt;도서 출판 (진행 중)&lt;/li&gt;
&lt;li&gt;생성형 AI의 시대&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;&amp;nbsp;&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;결혼 후, 바뀐 삶&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2024년을 돌아보면 여러 가지 변화나 적응의 상황이 있었는데, 사실 거의 대부분이 결혼 후의 삶이다.&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.9379%; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;구분&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.8915%; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;결혼 전(As-Is)&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 37.1705%; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;결혼 후(To-Be)&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.9379%; text-align: center;&quot;&gt;&lt;b&gt;출퇴근&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.8915%; text-align: center;&quot;&gt;왕복 1시간 30분&lt;/td&gt;
&lt;td style=&quot;width: 37.1705%; text-align: center;&quot;&gt;왕복 4시간&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.9379%; text-align: center;&quot;&gt;&lt;b&gt;야근&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.8915%; text-align: center;&quot;&gt;늦게까지 해도 상관 없음(대중교통 있음)&lt;/td&gt;
&lt;td style=&quot;width: 37.1705%; text-align: center;&quot;&gt;9시만 되어도 대중교통 막차&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.9379%; text-align: center;&quot;&gt;&lt;b&gt;퇴근 후의 시간&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.8915%; text-align: center;&quot;&gt;외부활동, 공부, 취미&lt;/td&gt;
&lt;td style=&quot;width: 37.1705%; text-align: center;&quot;&gt;와이프와의 시간, 집안일&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.9379%; text-align: center;&quot;&gt;&lt;b&gt;공부&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.8915%; text-align: center;&quot;&gt;출근 전 새벽공부, 퇴근 후 공부, 출퇴근 공부 등이 가능했음&lt;/td&gt;
&lt;td style=&quot;width: 37.1705%; text-align: center;&quot;&gt;결혼 전 3개가 전부 어려워짐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.9379%; text-align: center;&quot;&gt;&lt;b&gt;체력(피로도)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.8915%; text-align: center;&quot;&gt;공부를 해도 충분한 잠을 잘 수 있었고, 운동도 가능했음&lt;/td&gt;
&lt;td style=&quot;width: 37.1705%; text-align: center;&quot;&gt;출퇴근 피로도가 상당함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.9379%; text-align: center;&quot;&gt;&lt;b&gt;일상&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.8915%; text-align: center;&quot;&gt;평일엔 집-회사-외부 활동, 주말에 데이트, 뚜벅이 가능&lt;/td&gt;
&lt;td style=&quot;width: 37.1705%; text-align: center;&quot;&gt;각종 가족 행사 등을 고민해야함&lt;br /&gt;자동차, 집 등 새로운 것에 대한 고민을 많이 하게 됨(현실적인 고민)&lt;br /&gt;요리, 집안일 등&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.9379%; text-align: center;&quot;&gt;&lt;b&gt;운동&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.8915%; text-align: center;&quot;&gt;시간상 여유롭게 가능했음&lt;/td&gt;
&lt;td style=&quot;width: 37.1705%; text-align: center;&quot;&gt;운동을 하면 공부를 포기해야함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.9379%; text-align: center;&quot;&gt;&lt;b&gt;주말&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.8915%; text-align: center;&quot;&gt;외부 활동하거나, 공부하거나, 데이트&lt;/td&gt;
&lt;td style=&quot;width: 37.1705%; text-align: center;&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;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&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;그 외에도 상당히 많지만, 주요 핵심적인 것만 뽑자면 위와 같을 것 같다.&amp;nbsp;&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;그럼에도 출퇴근은 힘든 것은 맞고, 출퇴근 시간이 너무 길어졌기 때문에 퇴근 후에 투자했던 시간들이 완전히 뒤바뀐 것이 아직은 힘든 요소이다. 1년 정도면 적응이 될 줄 알았는데 아직 좀 더 적응해야 할 것 같다.&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;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;2년 조기 승진&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2024년에 또 다른 큰 변화 중 하나는 조기 승진이다. 무려 2년이나 빠르게 했다.&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;그럼에도, 나에게 또 다른 변화를 준 계기가 되었다. 이 중에서도 큰 변화가 실무자에서 관리자로 넘어간 것이지 않을까 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사내에서 AI를 하는 사람 중 유일한 책임급이기에 그에 맞는 역할을 수행해야 했다. 주니어들(사실 나도 주니어지만..)의 방향성을 잡아주고 프로젝트 일정 관리나, 팀 관리, R&amp;amp;R 조절, 타팀과의 조율 등을 수행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어찌보면, 24년에 진행한 프로젝트의 다음과 같은 것들을 관리했던 것 같다.&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&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;커뮤니케이션 및 R&amp;amp;R 조율 등&lt;/li&gt;
&lt;li&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;변화가&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;PM&amp;nbsp;역할까지&amp;nbsp;수행했다.&amp;nbsp;&lt;/p&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;&lt;/p&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;&lt;/p&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;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;이게&amp;nbsp;과연&amp;nbsp;무슨&amp;nbsp;역할일까?&amp;nbsp;내&amp;nbsp;커리어에는&amp;nbsp;문제가&amp;nbsp;없는&amp;nbsp;걸까?&quot;라는&amp;nbsp;질문이&amp;nbsp;계속해서&amp;nbsp;떠올랐다.&amp;nbsp;이&amp;nbsp;고민은&amp;nbsp;단순하지&amp;nbsp;않았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나에게는&amp;nbsp;정말&amp;nbsp;큰&amp;nbsp;고민이었다.&amp;nbsp;그래서&amp;nbsp;2024년은&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;해였다.&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;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;생성형 AI의 시대&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기술적으로 도전적인 영역은 생성형 AI의 시대이지 않을까 싶다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GenAI를 활용한 프로젝트들(LLM, 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;회사에서도 올해 GenAI 프로젝트에 대해서 여러 도전을 해왔다. 특히, 도메인 특성상 윤리적인 문제와 발생할 수 있는 여러 문제점을 고려하면서 개발하는 것이 매우 중요했었다. 또한, 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;동시에 엔지니어로서 고민도 있었다. 물론, GenAI를 잘 활용하면 내 생산성 향상 등이 일어날 수 있지만 문제는 시간이 지날수록 너무 의지하게 되는 것 같다. GenAI가 나오기 전의 내 삶이 어땠는지 잘 상상이 되지 않을 정도다.&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;/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;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;떠나간 동료들&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;p data-ke-size=&quot;size16&quot;&gt;이런 일이 3번째라 괜찮을 것 같았다. 하지만 전혀 괜찮지 않았다. 글을 쓰고 있는 현시점에도 괜찮지 않다.&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;p data-ke-size=&quot;size16&quot;&gt;떠나가는 친구들에게 난 이렇게 얘기했다. 나 같은 리더, 동료 말고 더 좋은 리더와 동료를 만나 날아가라고. 그 친구들은 어떻게 들었을지 모르겠지만 진심이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어려운 시기이지만, 잘 헤쳐나가서 서로 win-win 했으면 좋겠다.&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;style7&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2025년의 목표와 바람&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 2025년에는 아래와 같은 것을 목표로 열심히 살아가보려고 한다.&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&gt;독서 (경제, 경영, 뇌과학, 리더쉽 등 주제)&lt;/li&gt;
&lt;li&gt;영어&lt;/li&gt;
&lt;li&gt;LLM &amp;amp; RAG&lt;/li&gt;
&lt;li&gt;개인화(추천) 시스템 &amp;amp; LLM&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;/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;그렇기에, 2025년도 기대가 된다. 그리고 결코 가볍지 않을 것이고 어쩌면 2024년보다 힘들 수도 있을 것이다.&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;2024년에는 참으로 슬픈 소식도 많았다. 특히 연말에 더욱 슬픈 일들이 많고 마음 아픈 일들이 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2025년에는 모두 다 행복할 수 있기를.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갈등과 비난보다, 서로를 존중하고 조화를 이루어 협동하고 함께할 수 있기를.&lt;/p&gt;</description>
      <category>일상</category>
      <category>2024</category>
      <category>2024년</category>
      <category>2025년</category>
      <category>GenAI</category>
      <category>감사합니다</category>
      <category>개발자</category>
      <category>리더</category>
      <category>생성형ai</category>
      <category>일상</category>
      <category>회고</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/676</guid>
      <comments>https://lsjsj92.tistory.com/676#entry676comment</comments>
      <pubDate>Sat, 28 Dec 2024 16:01:04 +0900</pubDate>
    </item>
    <item>
      <title>PostgreSQL PGVector 설치 및 사용하기(Feat. 벡터 데이터베이스(Vector Database) 구축)</title>
      <link>https://lsjsj92.tistory.com/675</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 검색 증강 생성(Retrieval Augmented Generation, RAG)에서 많이 활용되는 벡터 데이터베이스 중 PostgreSQL의 PGVector에 대해서 작성하는 포스팅입니다. 이번 포스팅은 그 중, PostgreSQL 설치와 extension인 PGVector를 설치하고 실제 SQL query를 실행시켜 동작되는 것까지 작성하며 다음 글에서 실제 RAG 형식으로 동작되는 예제를 작성하겠습니다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.postgresql.org/download/&quot;&gt;https://www.postgresql.org/download/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://neon.tech/postgresql/tutorial&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://neon.tech/postgresql/tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pgvector/pgvector&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/pgvector/pgvector&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1733619188463&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 - pgvector/pgvector: Open-source vector similarity search for Postgres&quot; data-og-description=&quot;Open-source vector similarity search for Postgres. Contribute to pgvector/pgvector development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/pgvector/pgvector&quot; data-og-url=&quot;https://github.com/pgvector/pgvector&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/umS13/hyXKunP1Sc/JZWXfkqvf5iuNDyayksJW1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/fqxFp/hyXGKsixq9/6mevi8tDfQsh06jpdQma70/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/pgvector/pgvector&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/pgvector/pgvector&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/umS13/hyXKunP1Sc/JZWXfkqvf5iuNDyayksJW1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/fqxFp/hyXGKsixq9/6mevi8tDfQsh06jpdQma70/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 - pgvector/pgvector: Open-source vector similarity search for Postgres&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Open-source vector similarity search for Postgres. Contribute to pgvector/pgvector 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;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;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅 개요에서도 언급하였듯, 이번 포스팅은 벡터 데이터베이스(Vector Database)로 많이 활용하는 PGVector에 대해서 알아보는 포스팅입니다. 이를 위해서는 PostgreSQL을 설치하고 그 확장자(extension)으로 PGvector를 설치해야하는데요. 이번 글은 PostgreSQL을 설치하고 PGVector extension을 설치한 뒤 SQL로 실행하는 예시를 작성하는 포스팅입니다.&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;blockquote data-ke-style=&quot;style3&quot;&gt;참고사항 : 제가 설치를 진행한 환경은 아래와 같습니다.&lt;br /&gt;&lt;br /&gt;- MacOS(MacBook Pro, 2019)&lt;br /&gt;- PostgreSQL version : PostgreSQL@16&lt;br /&gt;- PGVector version : pgvector 0.8.0&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;PostgreSQL 설치&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PGVector를 설치하기에 앞서, PostgreSQL을 설치해야합니다. PostgreSQL이란 오픈 소스 데이터베이스로 20년도 더 넘은 데이터베이스입니다. MySQL이나 MariaDB, Oracle과 마찬가지로 많이 사용하는 데이터베이스 중 하나이죠.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 Mac 환경이기 때문에 Mac에서 PostgreSQL을 설치했습니다. 설치 방법은 포스팅 개요에 올려둔 posgresql download 페이지를 참고하시면 되는데요. 방법은 어렵지 않습니다. Mac에서는 아래와 같은 명령어로 쉽게 설치할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1733706296940&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install postgresql@16&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;커맨드 창에 brew를 활용해 설치하면 쉽게 설치될 수 있으며, 원하는 버전이 있다면 @을 활용해 버전을 명시해주시면 됩니다. 저는 PostgreSQL 16 버전을 설치하기 위해서 brew install postgresql@16이라고 명시하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치가 완료된 PostgreSQL을 실행시키기 위해서는 brew services 명령어를 활용해 실행하면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1733706376777&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew services start postgresql@16&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfG7vx/btsLbXbBS8j/okemKkWcsQtvsrP2fhP7KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfG7vx/btsLbXbBS8j/okemKkWcsQtvsrP2fhP7KK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2772&quot; data-origin-height=&quot;1016&quot; data-filename=&quot;스크린샷 2024-12-07 오전 9.42.01.png&quot; style=&quot;width: 43.9149%; margin-right: 10px;&quot; data-widthpercent=&quot;44.43&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfG7vx/btsLbXbBS8j/okemKkWcsQtvsrP2fhP7KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfG7vx%2FbtsLbXbBS8j%2FokemKkWcsQtvsrP2fhP7KK%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;2772&quot; height=&quot;1016&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oGx8N/btsLbYBzHPz/cZ9QBKZQcK63t49UYlGTY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oGx8N/btsLbYBzHPz/cZ9QBKZQcK63t49UYlGTY0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1788&quot; data-origin-height=&quot;524&quot; data-filename=&quot;스크린샷 2024-12-07 오전 9.44.54.png&quot; style=&quot;width: 54.9223%;&quot; data-widthpercent=&quot;55.57&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oGx8N/btsLbYBzHPz/cZ9QBKZQcK63t49UYlGTY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoGx8N%2FbtsLbYBzHPz%2FcZ9QBKZQcK63t49UYlGTY0%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;1788&quot; height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;/div&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;PostgreSQL이 잘 실행이 되었으면 sucessfully started postgresql 이라는 명령어가 나오게 될 것입니다. 그럼 실제로 잘 동작되는지 확인을 해봐야겠죠? 간단한 명령어로 실제 실행이 되는지 확인할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1733706471815&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;psql -v&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-12-07 오전 9.57.42.png&quot; data-origin-width=&quot;1992&quot; data-origin-height=&quot;260&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbe3Sm/btsLaDSWvdj/PKlcVvcKbSLUsrHuKSIpi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbe3Sm/btsLaDSWvdj/PKlcVvcKbSLUsrHuKSIpi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbe3Sm/btsLaDSWvdj/PKlcVvcKbSLUsrHuKSIpi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcbe3Sm%2FbtsLaDSWvdj%2FPKlcVvcKbSLUsrHuKSIpi1%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;1992&quot; height=&quot;260&quot; data-filename=&quot;스크린샷 2024-12-07 오전 9.57.42.png&quot; data-origin-width=&quot;1992&quot; data-origin-height=&quot;260&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;참고사항 : psql command not found 에러가 나온다면&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;psql 명령어를 실행하는데 psql command not found라는 에러가 나올 수도 있습니다. 만약 해당 에러가 나온다면 path가 제대로 설정이 안되었을 가능성이 매우 높습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, postgresql이 어디에 설치되었는지 확인을 해봐야겠죠?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-12-07 오전 9.53.21.png&quot; data-origin-width=&quot;1992&quot; data-origin-height=&quot;260&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3zMRn/btsK9AbNZri/ffwppTgrIHfy4GZwKkXYw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3zMRn/btsK9AbNZri/ffwppTgrIHfy4GZwKkXYw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3zMRn/btsK9AbNZri/ffwppTgrIHfy4GZwKkXYw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3zMRn%2FbtsK9AbNZri%2FffwppTgrIHfy4GZwKkXYw1%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;1992&quot; height=&quot;260&quot; data-filename=&quot;스크린샷 2024-12-07 오전 9.53.21.png&quot; data-origin-width=&quot;1992&quot; data-origin-height=&quot;260&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;저는 postgresql이 /usr/local/opt/postgresql@16에 설치되었음을 확인할 수 있었는데요.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같은 명령어를 통해 psql command not found 에러를 해결하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1733706792205&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export PATH=&quot;/usr/local/opt/postgresql@16/bin:$PATH&quot; &amp;gt;&amp;gt; ~/.zshrc
source ~/.zshrc


# 만약, 위 명령어로도 안되면 아래 명령어로 실행해보세요.

echo 'export PATH=&quot;/opt/homebrew/opt/postgresql@16/bin:$PATH&quot;' &amp;gt;&amp;gt; ~/.zshrc
source ~/.zshrc&lt;/code&gt;&lt;/pre&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;PostgreSQL 연결 테스트(Feat. DBeaver와 PostgreSQL 연결)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PostgreSQL이 제대로 설치된 것을 확인하였으면 실제로 연결이 되는지 테스트를 해봐야겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 DBeaver 툴을 활용해서 방금 설치한 PostgreSQL과 연결을 진행해보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-12-07 오전 10.04.02.png&quot; data-origin-width=&quot;1856&quot; data-origin-height=&quot;1344&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ReZ3S/btsLbmiQwmB/Qgwvk8RqK9jqGULVABO0J1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ReZ3S/btsLbmiQwmB/Qgwvk8RqK9jqGULVABO0J1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ReZ3S/btsLbmiQwmB/Qgwvk8RqK9jqGULVABO0J1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FReZ3S%2FbtsLbmiQwmB%2FQgwvk8RqK9jqGULVABO0J1%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;667&quot; height=&quot;483&quot; data-filename=&quot;스크린샷 2024-12-07 오전 10.04.02.png&quot; data-origin-width=&quot;1856&quot; data-origin-height=&quot;1344&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;DBeaver의 connect to database를 클릭하면, PostgreSQL이 있는 것을 알 수 있을겁니다. 해당 DB를 선택하고 넘어갑니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/daH8FC/btsLaLcmZre/fpMG6ipBpT877JClBT4300/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/daH8FC/btsLaLcmZre/fpMG6ipBpT877JClBT4300/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1856&quot; data-origin-height=&quot;1344&quot; data-filename=&quot;스크린샷 2024-12-07 오전 10.05.03.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/daH8FC/btsLaLcmZre/fpMG6ipBpT877JClBT4300/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdaH8FC%2FbtsLaLcmZre%2FfpMG6ipBpT877JClBT4300%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;1856&quot; height=&quot;1344&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bc57kK/btsLbQwZ69s/igB0cKirAFZQcyop7s0ibk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bc57kK/btsLbQwZ69s/igB0cKirAFZQcyop7s0ibk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1856&quot; data-origin-height=&quot;1344&quot; data-filename=&quot;스크린샷 2024-12-07 오전 10.05.06.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bc57kK/btsLbQwZ69s/igB0cKirAFZQcyop7s0ibk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbc57kK%2FbtsLbQwZ69s%2FigB0cKirAFZQcyop7s0ibk%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;1856&quot; height=&quot;1344&quot;/&gt;&lt;/span&gt;&lt;/div&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;여기서 PostgreSQL의 Host와 database 그리고 username을 설정하면 되는데요. Host는 저는 개인 PC에 설치했기 때문에 localhost로 지정하였고, database는 PostgreSQL을 설치하면 기본 DB가 postgres이기에 postgres로 설정하였습니다. 여기서 username을 잘 설정해줘야 하는데요. 만약, 여러분들이 username을 등록하시거나 postgres 계정에 비밀번호를 셋팅해두셨으면 해당 계정으로 접속하시면 됩니다. 저는 제 PC이름에 따라 leesoojin이라는 계정으로 생성되어서 이 계정을 활용하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, 생성된 계정을 알고 싶으시다면, psql postgres라는 명령어를 입력한 후 PostgreSQL 콘솔로 접속한 뒤 \du 명령어를 입력하셔서 확인하시면 됩니다.&amp;nbsp;&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-filename=&quot;스크린샷 2024-12-07 오전 10.05.23.png&quot; data-origin-width=&quot;1856&quot; data-origin-height=&quot;1344&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxYFFL/btsK9ykNEIR/KUpjvEV0vGszkTKOmcryHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxYFFL/btsK9ykNEIR/KUpjvEV0vGszkTKOmcryHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxYFFL/btsK9ykNEIR/KUpjvEV0vGszkTKOmcryHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxYFFL%2FbtsK9ykNEIR%2FKUpjvEV0vGszkTKOmcryHK%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;1856&quot; height=&quot;1344&quot; data-filename=&quot;스크린샷 2024-12-07 오전 10.05.23.png&quot; data-origin-width=&quot;1856&quot; data-origin-height=&quot;1344&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;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&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;DBeaver에 정상적으로 접속된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실, PostgreSQL에 접속하는 방법은 콘솔로 접속하는 방법이 가장 빠릅니다. psql 명령어가 정상적으로 실행되신다면 아래와 같은 명령어로 PostgreSQL 콘솔로 접속할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1733707627707&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;psql postgres&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-12-07 오전 10.07.24.png&quot; data-origin-width=&quot;1458&quot; data-origin-height=&quot;370&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVXRK3/btsLbBUmfAt/wRgkuyUTf2SSH6UyPOLmK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVXRK3/btsLbBUmfAt/wRgkuyUTf2SSH6UyPOLmK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVXRK3/btsLbBUmfAt/wRgkuyUTf2SSH6UyPOLmK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVXRK3%2FbtsLbBUmfAt%2FwRgkuyUTf2SSH6UyPOLmK0%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;1458&quot; height=&quot;370&quot; data-filename=&quot;스크린샷 2024-12-07 오전 10.07.24.png&quot; data-origin-width=&quot;1458&quot; data-origin-height=&quot;370&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;그러면 위와 같이 콘솔로 접속할 수 있게 되며, 저의 계정 등을 확인할 수 있습니다. 계정을 확인하는 방법은 위에서도 잠시 언급하였듯 \du 명령어를 입력하면 됩니다.&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-filename=&quot;스크린샷 2024-12-09 오전 10.27.33.png&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/18QGQ/btsLaGbwrvu/xASUZOYPF5VKnPtNkZNvu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/18QGQ/btsLaGbwrvu/xASUZOYPF5VKnPtNkZNvu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/18QGQ/btsLaGbwrvu/xASUZOYPF5VKnPtNkZNvu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F18QGQ%2FbtsLaGbwrvu%2FxASUZOYPF5VKnPtNkZNvu1%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;1422&quot; height=&quot;366&quot; data-filename=&quot;스크린샷 2024-12-09 오전 10.27.33.png&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;366&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;PGVector extension 설치 - brew를 활용한 설치&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 PostgreSQL에서 벡터(Vector)를 저장하고 이 벡터를 통해 코사인 유사도(Cosine Similarity), L2 거리(L2 Distance) 등의 연산을 수행할 수 있는 PosgreSQL의 extension인 PGVector를 설치하겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치하는 방법은 간단합니다. PostgreSQL이 정상적으로 설치 및 실행이 되었으면, 아래 명령어로 쉽게 설치할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1733725537658&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install pgvector&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-12-07 오전 10.36.33.png&quot; data-origin-width=&quot;2480&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buBq3F/btsLau9Pxuj/DmKZrf2MiaAnHAfzvK52NK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buBq3F/btsLau9Pxuj/DmKZrf2MiaAnHAfzvK52NK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buBq3F/btsLau9Pxuj/DmKZrf2MiaAnHAfzvK52NK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuBq3F%2FbtsLau9Pxuj%2FDmKZrf2MiaAnHAfzvK52NK%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;2480&quot; height=&quot;580&quot; data-filename=&quot;스크린샷 2024-12-07 오전 10.36.33.png&quot; data-origin-width=&quot;2480&quot; data-origin-height=&quot;580&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;다만, brew로 설치하는 것은 제가 글을 쓰는 24년 12월 초 기준, 아래와 같이 명시되어 있습니다. (&lt;a href=&quot;https://github.com/pgvector/pgvector?tab=readme-ov-file#homebrew&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/pgvector/pgvector?tab=readme-ov-file#homebrew&lt;/a&gt;)&lt;/p&gt;
&lt;pre id=&quot;code_1733725602241&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Note: This only adds it to the postgresql@17 and postgresql@14 formulas&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;즉, PostgreSQL 17과 14에만 적용되므로, 저와 같이 PostgreSQL 16버전을 설치할 경우 동작이 안될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 때는 아래와 같이 github을 활용해 설치해주면 간단하게 설치할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;PGVector extension 설치 - git clone을 활용한 설치&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PGVector 공식 github을 보시면, 아래 사진과 같이 installation 설명의 Linux and Mac 부분에서 아래와 같이 설치하라고 명시해주고 있습니다.&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-filename=&quot;스크린샷 2024-12-09 오후 3.28.16.png&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;469&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tCksU/btsLa3rwS88/FrJBTDdoKYS75WoKkxNG1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tCksU/btsLa3rwS88/FrJBTDdoKYS75WoKkxNG1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tCksU/btsLa3rwS88/FrJBTDdoKYS75WoKkxNG1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtCksU%2FbtsLa3rwS88%2FFrJBTDdoKYS75WoKkxNG1K%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;1066&quot; height=&quot;469&quot; data-filename=&quot;스크린샷 2024-12-09 오후 3.28.16.png&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;469&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;즉, git을 clone하고 make 및 make install을 활용해 설치하면 되는 것이죠.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 위에서 명시해준대로 /tmp 디렉토리에 들어가서 해당 경로에 설치를 진행했습니다. 똑같이 명령어를 입력했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1733725791395&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd /tmp
git clone --branch v0.8.0 https://github.com/pgvector/pgvector.git
cd pgvector
make
make install # may need sudo&lt;/code&gt;&lt;/pre&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-filename=&quot;스크린샷 2024-12-07 오전 10.51.34.png&quot; data-origin-width=&quot;2594&quot; data-origin-height=&quot;1188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GtnGY/btsLaW5N1iE/BquYBpcbKkHRseZJxoBeMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GtnGY/btsLaW5N1iE/BquYBpcbKkHRseZJxoBeMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GtnGY/btsLaW5N1iE/BquYBpcbKkHRseZJxoBeMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGtnGY%2FbtsLaW5N1iE%2FBquYBpcbKkHRseZJxoBeMk%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;2594&quot; height=&quot;1188&quot; data-filename=&quot;스크린샷 2024-12-07 오전 10.51.34.png&quot; data-origin-width=&quot;2594&quot; data-origin-height=&quot;1188&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;이후 위와 같이 순서대로 make install까지 진행하면 정상적으로 설치가 완료될 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자! 그러면 이제 pgvector가 실제로 동작되는지 테스트를 해봐야겠죠? 과연 벡터 데이터베이스로 활용할 수 있게 벡터 연산까지 수행할 수 있을까요?&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;저는 이를 위해서 먼저, test라는 데이터베이스를 만들고 여기에 vector extension을 추가해 활용하겠습니다. 아래와 같은 명령어를 입력해주시면 됩니다. 커맨드 명령어에 먼저 postgresql에 접속한 뒤 데이터베이스를 만들고 연결하면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1733725896048&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;psql postgres # postgresql 접속
create database test;
\connect test;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-12-07 오전 10.39.17.png&quot; data-origin-width=&quot;1204&quot; data-origin-height=&quot;324&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lRudd/btsK9TCeLjB/6hFEHT6hox5C64byFEEWE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lRudd/btsK9TCeLjB/6hFEHT6hox5C64byFEEWE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lRudd/btsK9TCeLjB/6hFEHT6hox5C64byFEEWE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlRudd%2FbtsK9TCeLjB%2F6hFEHT6hox5C64byFEEWE0%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;1204&quot; height=&quot;324&quot; data-filename=&quot;스크린샷 2024-12-07 오전 10.39.17.png&quot; data-origin-width=&quot;1204&quot; data-origin-height=&quot;324&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;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item dable&quot; style=&quot;height: 250px;&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;300x250&lt;/div&gt;
    &lt;div id=&quot;dablewidget_Pl1aE8lE&quot; data-widget_id=&quot;Pl1aE8lE&quot;&gt;
      &lt;script&gt;(function(d,a,b,l,e,_) {
    if(d[b]&amp;&amp;d[b].q)return;d[b]=function(){(d[b].q=d[b].q||[]).push(arguments)};e=a.createElement(l);
    e.async=1;e.charset='utf-8';e.src='//static.dable.io/dist/plugin.min.js';
    _=a.getElementsByTagName(l)[0];_.parentNode.insertBefore(e,_);
    })(window,document,'dable','script');
dable('setService', 'lsjsj92.tistory.com');
dable('sendLogOnce');
dable('renderWidget', 'dablewidget_Pl1aE8lE', {ignore_items: true});&lt;/script&gt;
    &lt;/div&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;그러면 위 사진과 같이 접속정보 데이터베이스 test 사용자 leesoojin이 나올 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 해당 데이터베이스에서 extension을 만들어주는데요. 이때 extension이 벡터(vector)가 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1733726059206&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE EXTENSION vector;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-12-07 오전 10.54.24.png&quot; data-origin-width=&quot;2594&quot; data-origin-height=&quot;396&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zdtgK/btsLaF4iWOi/jvCuaMN0xoHZkSfaFH3lN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zdtgK/btsLaF4iWOi/jvCuaMN0xoHZkSfaFH3lN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zdtgK/btsLaF4iWOi/jvCuaMN0xoHZkSfaFH3lN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzdtgK%2FbtsLaF4iWOi%2FjvCuaMN0xoHZkSfaFH3lN0%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;2594&quot; height=&quot;396&quot; data-filename=&quot;스크린샷 2024-12-07 오전 10.54.24.png&quot; data-origin-width=&quot;2594&quot; data-origin-height=&quot;396&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Cik5z/btsLa8ybSsy/bqXNhOtSkqmeFJhObNL2s0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Cik5z/btsLa8ybSsy/bqXNhOtSkqmeFJhObNL2s0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3650&quot; data-origin-height=&quot;1116&quot; data-filename=&quot;스크린샷 2024-12-07 오전 10.57.24.png&quot; style=&quot;width: 33.9535%; margin-right: 10px;&quot; data-widthpercent=&quot;34.35&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Cik5z/btsLa8ybSsy/bqXNhOtSkqmeFJhObNL2s0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCik5z%2FbtsLa8ybSsy%2FbqXNhOtSkqmeFJhObNL2s0%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;3650&quot; height=&quot;1116&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmYW9u/btsLbU0f5Po/XwlqXDKLAfODWud14eHHX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmYW9u/btsLbU0f5Po/XwlqXDKLAfODWud14eHHX1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;320&quot; data-filename=&quot;스크린샷 2024-12-07 오후 2.15.00.png&quot; style=&quot;width: 64.8837%;&quot; data-widthpercent=&quot;65.65&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmYW9u/btsLbU0f5Po/XwlqXDKLAfODWud14eHHX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmYW9u%2FbtsLbU0f5Po%2FXwlqXDKLAfODWud14eHHX1%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;2000&quot; height=&quot;320&quot;/&gt;&lt;/span&gt;&lt;/div&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;정상적으로 생성이 되었따면 create extension이 출력될겁니다. 이후 postgresql에서 \dx 명령어를 통해 extension에서 vector가 설치된 것을 확인할 수 있고 dbeaver의 extension 탭에서도 vector가 추가된 것을 확인할 수 있습니다.&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;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;PGVector 실행 테스트&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 PostgreSQL을 벡터 데이터베이스(Vector database)로 활용할 수 있도록 vector extension 설치 및 extension 등록까지 완성했습니다. 그럼, 임의의 데이터를 임시로 넣어서 실제로 벡터 연산(유사도 계산 등)이 가능한지 확인해보겠습니다.&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;pre id=&quot;code_1733726634765&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE TABLE tb_sj_test ( id SERIAL PRIMARY KEY, name TEXT, embed VECTOR(3) );

INSERT INTO tb_sj_test (name, embed) VALUES  ('이수진', '[0.1, 0.2, 0.3]'), ('leesoojin', '[0.5, 0.6, 0.1]');&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-12-07 오후 2.19.06.png&quot; data-origin-width=&quot;2168&quot; data-origin-height=&quot;320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lq4q1/btsLa8kBLZF/LWmjAQI5CeY7pPX6Ni7Bok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lq4q1/btsLa8kBLZF/LWmjAQI5CeY7pPX6Ni7Bok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lq4q1/btsLa8kBLZF/LWmjAQI5CeY7pPX6Ni7Bok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flq4q1%2FbtsLa8kBLZF%2FLWmjAQI5CeY7pPX6Ni7Bok%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;2168&quot; height=&quot;320&quot; data-filename=&quot;스크린샷 2024-12-07 오후 2.19.06.png&quot; data-origin-width=&quot;2168&quot; data-origin-height=&quot;320&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;그 다음, SQL query를 날려서 실제 쿼리가 동작하는지 살펴보겠습니다. 먼저, 가장 기본적인 전체 데이터 조회입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-12-07 오후 2.25.46.png&quot; data-origin-width=&quot;2166&quot; data-origin-height=&quot;818&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dh5p7Y/btsK9O11xA2/Kr4bCpvHlBBRZbtt9rppLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dh5p7Y/btsK9O11xA2/Kr4bCpvHlBBRZbtt9rppLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dh5p7Y/btsK9O11xA2/Kr4bCpvHlBBRZbtt9rppLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdh5p7Y%2FbtsK9O11xA2%2FKr4bCpvHlBBRZbtt9rppLk%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;2166&quot; height=&quot;818&quot; data-filename=&quot;스크린샷 2024-12-07 오후 2.25.46.png&quot; data-origin-width=&quot;2166&quot; data-origin-height=&quot;818&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;p data-ke-size=&quot;size16&quot;&gt;그러면, 벡터 연산은 잘 될까요? 공식 github에 벡터 연산 방법에 대해서 아래와 같이 명시되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1733726884249&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;-&amp;gt; : L2 distance (L2 거리, 유클리드 거리)
&amp;lt;#&amp;gt; : (negative) inner product ( 내적 )
&amp;lt;=&amp;gt; : cosine distance ( 코사인유사도 )
&amp;lt;+&amp;gt; : L1 distance (added in 0.7.0) ( L1 거리, 맨하탄 거리 )
&amp;lt;~&amp;gt; : Hamming distance (binary vectors, added in 0.7.0)( 해밍 거리 )
&amp;lt;%&amp;gt; : Jaccard distance (binary vectors, added in 0.7.0) (자카드 거리)&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;자세한 것은 공식 github을 확인하시면 됩니다.&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_1733726932528&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select * from tb_sj_test where id &amp;lt; 5 order by embed &amp;lt;=&amp;gt; '[0.2, 0.3, 0.4]' limit 1&lt;/code&gt;&lt;/pre&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-filename=&quot;스크린샷 2024-12-07 오후 2.31.49.png&quot; data-origin-width=&quot;1976&quot; data-origin-height=&quot;592&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpSu9B/btsLbTHf90n/Z3LhkL5NIWQLhdvmT7KH00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpSu9B/btsLbTHf90n/Z3LhkL5NIWQLhdvmT7KH00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpSu9B/btsLbTHf90n/Z3LhkL5NIWQLhdvmT7KH00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcpSu9B%2FbtsLbTHf90n%2FZ3LhkL5NIWQLhdvmT7KH00%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;1976&quot; height=&quot;592&quot; data-filename=&quot;스크린샷 2024-12-07 오후 2.31.49.png&quot; data-origin-width=&quot;1976&quot; data-origin-height=&quot;592&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;&amp;lt;=&amp;gt; 기호를 사용했기 때문에 코사인 유사도를 활용했고 limit 1개만 노출되도록 했습니다. 가장 가까운 데이터 1개가 나온 것을 확인할 수 있습니다.&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 벡터 데이터베이스 활용을 위해 PGVector를 설치하기 위한 과정을 정리한 포스팅입니다. 이를 위해서 PostgreSQL에 대해서 알아보고 설치를 진행하였습니다. 이후 Vector를 사용할 수 있게 PGVector를 설치하여 extension을 생성하는 과정을 정리하였고 예시 쿼리로 실제 동작되는 과정을 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 포스팅에서는 PGVector를 활용하여 실제 파이썬(Python) 코드 레벨에서 활용할 수 있는지, RAG를 어떻게 구축할 수 있는지 알아보도록 하겠습니다.&amp;nbsp;&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;저에게 연락을 원하신다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 링크드인 : &lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot;&gt;https://www.linkedin.com/in/lsjsj92/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- github : &lt;a href=&quot;https://github.com/lsjsj92&quot;&gt;https://github.com/lsjsj92&lt;/a&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;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>pgvector</category>
      <category>pgvector설치</category>
      <category>PostgreSQL</category>
      <category>postgreSQL설치</category>
      <category>Python</category>
      <category>RAG</category>
      <category>vector</category>
      <category>vectordb</category>
      <category>검생증강생성</category>
      <category>벡터데이터베이스</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/675</guid>
      <comments>https://lsjsj92.tistory.com/675#entry675comment</comments>
      <pubDate>Mon, 9 Dec 2024 15:52:53 +0900</pubDate>
    </item>
    <item>
      <title>vLLM OpenAI API 서버와 랭체인(LangChain) 연동하여 RAG 구축하기</title>
      <link>https://lsjsj92.tistory.com/674</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 대규모 언어 모델(Large Language Models, LLM)을 쉽고 빠르게 배포 및 서빙할 수 있는 vLLM 글의 3번째 글(vLLM Langchain Tutorial)로, OpenAI API 서버로 배포된 vLLM과 랭체인(Langchain) 라이브러리를 연동해 RAG를 간단하게 구현하는 방법과 예제(example)를 알아보는 포스팅입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 글들에서 vLLM이란 무엇이고, 사용법, 설치 방법, API로 배포하는 방법 등을 정리해두었으니 vLLM에 익숙하지 않으신 분들은 이전 글들을 참고 부탁드립니다.&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;vLLM과 관련된 포스팅은 아래와 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;vLLM 사용법과 소개 : &lt;a href=&quot;https://lsjsj92.tistory.com/668&quot;&gt;https://lsjsj92.tistory.com/668&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vLLM을 OpenAI 서버(server)로 배포하는 방법 : &lt;a href=&quot;https://lsjsj92.tistory.com/673&quot;&gt;https://lsjsj92.tistory.com/673&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OpenAI 서버로 배포된 vLLM을 랭체인(LangChain)과 연동하는 방법 : 현재 글&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;이번 포스팅을 작성하면서 참고한 문서 및 자료는 아래와 같습니다.&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&gt;&lt;a href=&quot;https://docs.vllm.ai/en/v0.6.0/getting_started/quickstart.html&quot;&gt;https://docs.vllm.ai/en/v0.6.0/getting_started/quickstart.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://huggingface.co/MLP-KTLim/llama-3-Korean-Bllossom-8B&quot;&gt;https://huggingface.co/MLP-KTLim/llama-3-Korean-Bllossom-8B&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vllm-project/vllm&quot;&gt;https://github.com/vllm-project/vllm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://platform.openai.com/docs/quickstart?language-preference=python&quot;&gt;https://platform.openai.com/docs/quickstart?language-preference=python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://python.langchain.com/docs/integrations/llms/openai/&quot;&gt;https://python.langchain.com/docs/integrations/llms/openai/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1730286922977&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;OpenAI |  ️  LangChain&quot; data-og-description=&quot;You are currently on a page documenting the use of OpenAI text completion models. The latest and most popular OpenAI models are chat completion models.&quot; data-og-host=&quot;python.langchain.com&quot; data-og-source-url=&quot;https://python.langchain.com/docs/integrations/llms/openai/&quot; data-og-url=&quot;https://python.langchain.com/docs/integrations/llms/openai/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cOaUK4/hyXprTBPKm/GRzU4D5F1wcfXrCcvbUt2k/img.png?width=800&amp;amp;height=418&amp;amp;face=0_0_800_418,https://scrap.kakaocdn.net/dn/coOX1A/hyXpDfpXlV/yN2T1YXGgjMQD7prTPLVkK/img.png?width=800&amp;amp;height=418&amp;amp;face=0_0_800_418,https://scrap.kakaocdn.net/dn/bihaVJ/hyXpxzuuks/vjgu1T13AZDaF7WO7MGYUK/img.png?width=1586&amp;amp;height=251&amp;amp;face=0_0_1586_251&quot;&gt;&lt;a href=&quot;https://python.langchain.com/docs/integrations/llms/openai/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://python.langchain.com/docs/integrations/llms/openai/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cOaUK4/hyXprTBPKm/GRzU4D5F1wcfXrCcvbUt2k/img.png?width=800&amp;amp;height=418&amp;amp;face=0_0_800_418,https://scrap.kakaocdn.net/dn/coOX1A/hyXpDfpXlV/yN2T1YXGgjMQD7prTPLVkK/img.png?width=800&amp;amp;height=418&amp;amp;face=0_0_800_418,https://scrap.kakaocdn.net/dn/bihaVJ/hyXpxzuuks/vjgu1T13AZDaF7WO7MGYUK/img.png?width=1586&amp;amp;height=251&amp;amp;face=0_0_1586_251');&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;OpenAI |  ️  LangChain&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;You are currently on a page documenting the use of OpenAI text completion models. The latest and most popular OpenAI models are chat completion models.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;python.langchain.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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 LLM 모델을 vLLM 라이브러리를 활용해 OpenAI API 형태로 배포한 후 랭체인(Langchain)과 연동하여 RAG를 구성하는 예제(example)를 정리한 포스팅입니다. 본 포스팅의 순서는 아래와 같이 진행됩니다.&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. 필요한 라이브러리 가져오기(import)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. vLLM의 API를 활용한 간단한 랭체인 예시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. RAG 구성 및 구현&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;1. 라이브러리 가져오기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저,&amp;nbsp;랭체인(LangChain)을 활용하기 때문에 랭체인과 관련된 라이브러리들을 로드합니다. 저는 RAG를 구성할 때 FAISS를 이용해서 벡터 검색(vector search)를 진행할 것이라서 faiss를 import 했습니다. 또한, 임베딩도 허깅페이스(HuggingFace) 모델을 활용하기에 허깅페이스 임베딩을 가져왔습니다. 그리고 RAG에서 사용되는 데이터는 제 블로그 글을 활용하려고 해서 WebBaseLoader로 데이터를 가져올 것입니다. 나머지는 프롬프트 템플릿(Prompt Template)과 텍스트를 분할(Split)할 때 사용하는 재귀적 문자 분할(RecursiveCharacterTextSplitter) 등을 import했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729913713985&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_community.vectorstores.faiss import FAISS
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.document_loaders import WebBaseLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain_openai  import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage

openai_api_key = &quot;EMPTY&quot;
openai_api_base = &quot;http://localhost:8007/v1&quot;
model_path = &quot;/llm_models&quot;
model_code = &quot;llama-3-Korean-Bllossom-8B&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;뿐만 아니라, 이전 글에서 설정하고 테스트 해봤던 vLLM의 OpenAI API 서버와 통신하기 위해서 openai_api_key는 empty로 설정하고 url과 사용하는 모델들을 설정하였습니다. 이때, LLM으로 사용하는 모델은 Korean-Bllossom-8B 모델을 감사히 사용했습니다.&amp;nbsp;&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;2. vLLM의 API를 활용한 간단한 랭체인 연동 예시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 본격적으로 랭체인 기반으로 vLLM의 OpenAI API 서버와 연동해서 LLM의 결과를 가져와보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 간단한 예시로는 랭체인에서 제공해주는 시스템 메세지(SystemMessage)와 휴먼메세지(HumanMessage)를 이용한 통신 방법이 있는데요. 아래 코드와 같이 적용할 수 있을겁니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729913740520&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;llm = ChatOpenAI(
    model=f&quot;{model_path}/{model_code}&quot;,
    openai_api_key=openai_api_key,
    openai_api_base=openai_api_base,
    max_tokens=850,
    temperature=0,
)

messages = [
    SystemMessage(
        content=&quot;당신은 유능한 AI 어시스턴트 입니다. 사용자의 질문에 대해 친절하게 답변해주세요.&quot;
    ),
    HumanMessage(
        content=&quot;안녕하세요. 저는 이수진입니다.&quot;
    ),
]
msg = llm.invoke(messages)
print(msg.content)
print(msg.response_metadata['token_usage'])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-10-30 오후 8.28.07.png&quot; data-origin-width=&quot;1085&quot; data-origin-height=&quot;286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0HIz0/btsKqx6BjIk/4PfE2IFiVf7B9GpGkkieR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0HIz0/btsKqx6BjIk/4PfE2IFiVf7B9GpGkkieR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0HIz0/btsKqx6BjIk/4PfE2IFiVf7B9GpGkkieR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0HIz0%2FbtsKqx6BjIk%2F4PfE2IFiVf7B9GpGkkieR1%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;1085&quot; height=&quot;286&quot; data-filename=&quot;스크린샷 2024-10-30 오후 8.28.07.png&quot; data-origin-width=&quot;1085&quot; data-origin-height=&quot;286&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;시스템 메세지에는 AI의 시스템 메세지를 적용하면 되고, 휴먼 메세지에는 질문 등 원하는 질의를 넣어주시면 됩니다. 이렇게 구성된 llm을 llm.invoke로 통신하게 되면 vLLM에 올라가있는 llm 모델(저는 Korean-Bllossom-8B 모델)과 통신하여 답을 얻을 수 있습니다.&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;또 다른 랭체인의 간단한 예시는 바로 프롬프트 템플릿(PromptTemplate)을 활용한 코드일 것입니다. 이때, 템플릿을 함께 제공해서 from_template에 셋팅해준 뒤 원하는 질의를 제공하여 LLM과 통신할 수 있는데요.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 아래 코드와 같은 형태로 동작이 될 것입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729913748637&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template = &quot;&quot;&quot;Question: {question}
Answer: &quot;&quot;&quot;

prompt = PromptTemplate.from_template(template)
llm_chain = LLMChain(prompt=prompt, llm=llm)


question = &quot;안녕하세요. 저는 이수진입니다. 당신은 누구인가요? 저와 대화할 수 있나요?&quot;
print(llm_chain.invoke(question))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-10-30 오후 8.31.50.png&quot; data-origin-width=&quot;1085&quot; data-origin-height=&quot;286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4qe6E/btsKqsqJInz/qVEvksoK1YW9JCBSbUDwT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4qe6E/btsKqsqJInz/qVEvksoK1YW9JCBSbUDwT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4qe6E/btsKqsqJInz/qVEvksoK1YW9JCBSbUDwT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4qe6E%2FbtsKqsqJInz%2FqVEvksoK1YW9JCBSbUDwT0%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;1085&quot; height=&quot;286&quot; data-filename=&quot;스크린샷 2024-10-30 오후 8.31.50.png&quot; data-origin-width=&quot;1085&quot; data-origin-height=&quot;286&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;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&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;이때 저는 LLMChain을 활용해 prompt에는 셋팅한 프롬프트를 넣어주고 llm은 vLLM을 통신하는 llm 정보를 넣어주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;질의로 저는 이수진입니다. 당신은 누구인가요? 대화할 수 있나요?라고 제공했을 때 LLM이 적절한 답을 제공하는 것을 확인할 수 있습니다.&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;자, 이렇게 간단하게 랭체인(Lanchain)을 이용해서 vLLM의 OpenAI API 서버와 통신하는 방법을 알아봤습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 한 스텝 더 나아가서 RAG를 구성해서 vLLM에 올려져 있는 LLM 모델이 결과를 제대로 제공해주는지 결과를 확인해보겠습니다.&amp;nbsp;&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;3. RAG 구성 및 구현 예시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 RAG 구성을 위해서 임베딩 모델(embedding model)은 bge-m3 모델을 활용했습니다. 이 모델은 허깅페이스에서 제공해주는 모델이기 때문에 랭체인에서 제공해주는 허깅페이스 임베딩(HuggingFaceEmbeddings) 클래스를 사용하여 모델을 준비합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, RAG에 사용되는 데이터는 제 블로그 668번 vLLM 사용법 블로그 글을 활용합니다. 이를 위해서 랭체인의 웹 문서 로더(WebBaseLoader)를 활용해서 게시글 데이터를 가져왔습니다. 이를 RecursiveCharacterTextSplitter로 텍스트를 분할한 뒤 FAISS를 사용해 임베딩화 하여 retriever로 사용합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정을 담은 코드는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729913764286&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;model_path = &quot;/llm_models&quot;
embed_model_name = 'bge-m3'
encode_kwargs = {&quot;normalize_embeddings&quot;: True}
model_kwargs = {
            &quot;device&quot;: &quot;cuda:0&quot;
        }

embeddings = HuggingFaceEmbeddings(
                    model_name=f'{model_path}/{embed_model_name}',
                    model_kwargs=model_kwargs,
                    encode_kwargs=encode_kwargs,
                )



loader = WebBaseLoader(&quot;https://lsjsj92.tistory.com/668&quot;)
# loader.requests_kwargs = {'verify':False}  #  [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed 와 같은 에러가 날 경우 임시방편
data = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=350, chunk_overlap=50)
texts = text_splitter.split_documents(data)
db = FAISS.from_documents(texts, embeddings)
db_retriever = db.as_retriever(search_kwargs={&quot;k&quot;: 2})&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;이제 vLLM과 통신해서 답을 가져오기 위해 템플릿을 구성합니다. 구성한 템플릿은 간단하게 랭체인의 PromptTemplate을 사용하며 {ref}라는 곳에 검색기(retriever)가 가져온 데이터를 넣어서 답변을 해주는 형태로 프롬프트 템플릿을 구성했습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729913784621&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template = &quot;&quot;&quot;당신은 유능한 AI 어시스턴트 입니다. [Ref] 문서를 참고하여, 사용자의 질문에 대해 친절하게 답변해주세요. 문서에 없는 내용은 말하지 말아주시고, 문서에 내용이 없다면 내용이 없다고 말해주세요.
Question: {question}
[Ref]
{ref}
Answer: &quot;&quot;&quot;

prompt = PromptTemplate(input_variables=[&quot;question&quot;, &quot;ref&quot;], template=template)
llm_chain = LLMChain(prompt=prompt, llm=llm)

print(prompt)
llm_chain&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-10-30 오후 8.32.19.png&quot; data-origin-width=&quot;1085&quot; data-origin-height=&quot;533&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6M8Lu/btsKqZIiOJK/KaNGA2I9m6RWpjdays21GK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6M8Lu/btsKqZIiOJK/KaNGA2I9m6RWpjdays21GK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6M8Lu/btsKqZIiOJK/KaNGA2I9m6RWpjdays21GK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6M8Lu%2FbtsKqZIiOJK%2FKaNGA2I9m6RWpjdays21GK%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;1085&quot; height=&quot;533&quot; data-filename=&quot;스크린샷 2024-10-30 오후 8.32.19.png&quot; data-origin-width=&quot;1085&quot; data-origin-height=&quot;533&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;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item dable&quot; style=&quot;height: 250px;&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;300x250&lt;/div&gt;
    &lt;div id=&quot;dablewidget_Pl1aE8lE&quot; data-widget_id=&quot;Pl1aE8lE&quot;&gt;
      &lt;script&gt;(function(d,a,b,l,e,_) {
    if(d[b]&amp;&amp;d[b].q)return;d[b]=function(){(d[b].q=d[b].q||[]).push(arguments)};e=a.createElement(l);
    e.async=1;e.charset='utf-8';e.src='//static.dable.io/dist/plugin.min.js';
    _=a.getElementsByTagName(l)[0];_.parentNode.insertBefore(e,_);
    })(window,document,'dable','script');
dable('setService', 'lsjsj92.tistory.com');
dable('sendLogOnce');
dable('renderWidget', 'dablewidget_Pl1aE8lE', {ignore_items: true});&lt;/script&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 구성한 템플릿은 위 사진과 같습니다. 유능한 AI 어시스턴트이며 [Ref]의 문서를 참고해서 사용자의 질문(Question 영역)에 따라 답변을 수행하도록 구성해두었습니다.&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;자! 이제 간단하게 RAG를 사용하기 위한 준비가 완료되었습니다. 이제 질의를 던져서 vLLM의 답변을 확인하면 되는데요. 랭체인의 LCEL으로 확인하기 전에 먼저, 검색(retriever)을 해보고 거기에서 나온 답변을 LLM에게 전달하는 과정 하나하나를 살펴보면서 답변이 vLLM이 답변을 잘 해주는지 확인해보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729913802789&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;question = &quot;vllm이란 무엇인가요?&quot;
docs = db_retriever.invoke(question)
llm_result = llm_chain.invoke({&quot;question&quot;: question, &quot;ref&quot;: docs})['text']
llm_result&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-10-30 오후 8.32.44.png&quot; data-origin-width=&quot;1085&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Z4vMs/btsKp1mymvi/ossLnC2ijWpjyG6c5abCck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Z4vMs/btsKp1mymvi/ossLnC2ijWpjyG6c5abCck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Z4vMs/btsKp1mymvi/ossLnC2ijWpjyG6c5abCck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZ4vMs%2FbtsKp1mymvi%2FossLnC2ijWpjyG6c5abCck%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;1085&quot; height=&quot;377&quot; data-filename=&quot;스크린샷 2024-10-30 오후 8.32.44.png&quot; data-origin-width=&quot;1085&quot; data-origin-height=&quot;377&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-10-30 오후 8.32.54.png&quot; data-origin-width=&quot;1085&quot; data-origin-height=&quot;174&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQKahu/btsKoSElTTt/ozFkCidHofRuREodnFi0Y0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQKahu/btsKoSElTTt/ozFkCidHofRuREodnFi0Y0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQKahu/btsKoSElTTt/ozFkCidHofRuREodnFi0Y0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQKahu%2FbtsKoSElTTt%2FozFkCidHofRuREodnFi0Y0%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;1085&quot; height=&quot;174&quot; data-filename=&quot;스크린샷 2024-10-30 오후 8.32.54.png&quot; data-origin-width=&quot;1085&quot; data-origin-height=&quot;174&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;위 코드를 실행하면 먼저, db_retriever로 &quot;vLLM이란 무엇인가요?&quot;라는 질문에 적합한 문서를 찾아줍니다. 이때 문서는 WebBaseLoader로 가져온 블로그 글의 내용입니다. 그리고 찾아준 문서를 llm_chain의 invoke에 인자 값으로 넣어줘서 vLLM 모델이 제공해주는 결과를 확인할 수 있습니다. vLLM이란 무엇인가요?라는 질문에 vLLM은 대규모 언어모델(LLM)의 추론, 서빙을 쉽고 빠르게 도와주는 라이브러리라는 답변을 잘 찾아주어 제공해주었습니다.&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;그럼 마지막으로 랭체인의  LCEL(LangChain Expression Language) 문법으로 실행해보겠습니다. 프롬프트나 모델 구성 방법은 똑같으며 chain 형식으로 묶은 것만 차이점이 있습니다. 이때, 사용자의 Question은 RunnablePassThrough로 넘어가도록 설정하였고 ref는 db_retriever를 사용하도록 했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729913817023&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template = &quot;&quot;&quot;당신은 유능한 AI 어시스턴트 입니다. [Ref] 문서를 참고하여, 사용자의 질문에 대해 친절하게 답변해주세요. 문서에 없는 내용은 말하지 말아주시고, 문서에 내용이 없다면 내용이 없다고 말해주세요.
Question: {question}
[Ref]
{ref}
Answer: &quot;&quot;&quot;

prompt = PromptTemplate(input_variables=[&quot;question&quot;, &quot;ref&quot;], template=template)

llm = ChatOpenAI(
    model=f&quot;{model_path}/{model_code}&quot;,
    openai_api_key=&quot;EMPTY&quot;,
    openai_api_base=openai_api_base,
    max_tokens=850,
    temperature=0,
)

chain = (
    {&quot;ref&quot;: db_retriever, &quot;question&quot;: RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser()
)

question = &quot;vllm이란 무엇인가요?&quot;
res = chain.invoke(question)
print(res)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-10-30 오후 8.33.34.png&quot; data-origin-width=&quot;1085&quot; data-origin-height=&quot;174&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chydxQ/btsKreyqfzz/te5pLrV5ZdKGAgh2J6BO50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chydxQ/btsKreyqfzz/te5pLrV5ZdKGAgh2J6BO50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chydxQ/btsKreyqfzz/te5pLrV5ZdKGAgh2J6BO50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchydxQ%2FbtsKreyqfzz%2Fte5pLrV5ZdKGAgh2J6BO50%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;1085&quot; height=&quot;174&quot; data-filename=&quot;스크린샷 2024-10-30 오후 8.33.34.png&quot; data-origin-width=&quot;1085&quot; data-origin-height=&quot;174&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;똑같이 vLLM이란 무엇인가요?라는 질문에 vLLM에 대한 설명을 블로그 글에서 잘 찾아내어 설명하는 것을 확인할 수 있습니다.&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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 vLLM을 OpenAI API 서버로 서빙(serving)하여 랭체인(LangChain)과 연동하는 예제를 살펴본 포스팅입니다. 3번에 걸쳐서 vLLM Langchain 튜토리얼(Tutorial) 예제를 살펴보았는데요. 부디 도움되시길 바랍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;긴 글 읽어주셔서 감사합니다.&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>API</category>
      <category>GenAI</category>
      <category>huggingface</category>
      <category>langchain</category>
      <category>openai</category>
      <category>RAG</category>
      <category>vllm</category>
      <category>랭체인</category>
      <category>생성형ai</category>
      <category>허깅페이스</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/674</guid>
      <comments>https://lsjsj92.tistory.com/674#entry674comment</comments>
      <pubDate>Sat, 2 Nov 2024 10:20:17 +0900</pubDate>
    </item>
    <item>
      <title>vLLM을 OpenAI API server(OpenAI-Compatible Server)로 배포하는 방법 및 예제(example)</title>
      <link>https://lsjsj92.tistory.com/673</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 대규모 언어 모델(Large Language Models, LLM)을 쉽고 빠르게 배포할 수 있는 vLLM 라이브러리를 활용해서 OpenAI API Server(OpenAI-Compatible Server)로 배포하여 모델을 서빙(serving)할 수 있는 방법을 알아봅니다. 이전 포스팅(&lt;a href=&quot;https://lsjsj92.tistory.com/668&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/668&lt;/a&gt;)에서는 vLLM에 대한 설명과 설치 방법에 대해서 알아보았는데요. 이 vLLM을 마치 OpenAI의 API 서버처럼 활용해서 LangChain이나 OpenAI 라이브러리에도 연동하여 사용할 수 있습니다.&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;vLLM과 관련된 포스팅은 아래와 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;vLLM 사용법과 소개 : &lt;a href=&quot;https://lsjsj92.tistory.com/668&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/668&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;vLLM을 OpenAI 서버(server)로 배포하는 방법(현재 포스팅 글) : &lt;a href=&quot;https://lsjsj92.tistory.com/673&quot;&gt;https://lsjsj92.tistory.com/673&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OpenAI 서버로 배포된 vLLM을 랭체인(LangChain)과 연동하는 방법 : &lt;a href=&quot;https://lsjsj92.tistory.com/674&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/674&lt;/a&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;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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.vllm.ai/en/v0.6.0/getting_started/quickstart.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.vllm.ai/en/v0.6.0/getting_started/quickstart.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://huggingface.co/MLP-KTLim/llama-3-Korean-Bllossom-8B&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://huggingface.co/MLP-KTLim/llama-3-Korean-Bllossom-8B&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vllm-project/vllm&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/vllm-project/vllm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://platform.openai.com/docs/quickstart?language-preference=python&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://platform.openai.com/docs/quickstart?language-preference=python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://python.langchain.com/docs/integrations/llms/openai/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://python.langchain.com/docs/integrations/llms/openai/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-10-26 오전 11.08.48.png&quot; data-origin-width=&quot;1686&quot; data-origin-height=&quot;568&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYteQ3/btsKllyrW0z/Fuzi7M3eKTNNez0EPdU5X0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYteQ3/btsKllyrW0z/Fuzi7M3eKTNNez0EPdU5X0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYteQ3/btsKllyrW0z/Fuzi7M3eKTNNez0EPdU5X0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYteQ3%2FbtsKllyrW0z%2FFuzi7M3eKTNNez0EPdU5X0%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;1686&quot; height=&quot;568&quot; data-filename=&quot;스크린샷 2024-10-26 오전 11.08.48.png&quot; data-origin-width=&quot;1686&quot; data-origin-height=&quot;568&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;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;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅 개요에서도 언급하였듯이, 이번 포스팅은 vLLM을 활용해 OpenAI API 서버(server)로 배포하고 서빙(serving) 할 수 있는 방법에 대해 알아보겠습니다. 그리고 Python을 활용한 간단한 예제 들과 curl로 통신하는 방법 등 각종 예제(example) 코드로 결과도 확인해보겠습니다.&amp;nbsp;&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;1. vLLM이란 무엇인가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. OpenAI 서버로 활용한다는 것은?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. vLLM을 OpenAI 서버로 활용하기 (OpenAI-Compatible server)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. OpenAI 파이썬(Python) 라이브러리 예제와 Curl 예제로 결과 확인하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 랭체인(LangChain)에서 vLLM OpenAI server와 통신하여 RAG 구성하기 (&lt;u&gt;&lt;b&gt; 다음글로 이어집니다.&lt;/b&gt;&lt;/u&gt; )&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;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. vLLM이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 포스팅(&lt;a href=&quot;https://lsjsj92.tistory.com/668&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/668&lt;/a&gt;)에서 vLLM을 소개해드렸지만, 못 보고 오신 분들을 위해 간략하게 vLLM에 대해서 정리해보겠습니다. vLLM은 LLM 추론(inference) 및 서빙(serving)을 쉽고 빠르게 도와주는 라이브러리입니다. vLLM의 주요 특징은&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;- 페이지 어텐션(page attention) 방법으로 key, value 메모리를 효과적으로 관리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 입력 요청(request)에 대해서 지속적인 배치(Continuous batching) 처리 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 양자화(Quantization) 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 허깅페이스(HuggingFace)와 월활하게 인기있는 LLM 모델을 사용할 수 있음&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;등등 다양한 장점과 특징을 가지고 있는 라이브러리입니다. 이렇게 vLLM을 사용한다면 쉽고 빠르게 LLM 모델들을 서빙할 수 있는 것입니다. 자세한 것은 vLLM의 Github나 도큐먼트(docs) 등을 확인해보시면 좋을 것 같습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style8&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. OpenAI API 서버로 배포 및 serving 한다는 것은?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅의 주제는 vLLM을 OpenAI API 서버로 활용하여 LLM을 추론 및 서빙하는 방법에 대해 정리합니다. 그러면, vLLM을 OpenAI API 서버로 활용한다는 것의 의미는 무엇일까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 LLM을 활용하시는 분들은 아래와 같은 코드를 보셨던 경험, 사용해보셨던 경험이 있을 것이라 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729910139162&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from openai import OpenAI
client = OpenAI()

completion = client.chat.completions.create(
    model=&quot;gpt-4o-mini&quot;,
    messages=[
        {&quot;role&quot;: &quot;system&quot;, &quot;content&quot;: &quot;You are a helpful assistant.&quot;},
        {
            &quot;role&quot;: &quot;user&quot;,
            &quot;content&quot;: &quot;Write a haiku about recursion in programming.&quot;
        }
    ]
)

print(completion.choices[0].message)&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;위 파이썬(Python) 코드는 OpenAI 라이브러리를 활용해 OpenAI에서 제공해주는 gpt-4o나 gpt-4o-mini와 같은 LLM 모델들을 API 형태로 사용하는 코드입니다. 이때 OpenAI에서 받은 key들을 적용하기도 하죠.&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;또 다른 코드도 있습니다. LLM 및 RAG를 활용하시는 분들에게 인기가 많은 랭체인(LangChain)에서도 이와 비슷한 방식의 코드가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729910360000&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model=&quot;gpt-4o-mini&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;위 파이썬 코드는 랭체인(LangChain)에서 OpenAI 모델을 사용하는 예제 코드입니다. 즉, OpenAI에서 제공해주는 모델을 API로 받아서 사용하는 것이죠.&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;이렇게 OpenAI 라이브러리를 활용하면 OpenAI에서 제공해주는 각종 모델들을 활용해(API 통신을 받아) RAG 구축이나 서빙(serving) 등에 활용할 수 있는 것입니다. 문제는, OpenAI의 API를 활용하는 것이다보니 비용 등이 발생할 수 있고 새롭게 올라온 다양한 Llama3 파인튜닝 모델들을 사용하기엔 번거롭다는 것이 있습니다.&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;vLLM을 OpenAI API 서버로 활용한다는 것의 의미는 이 부분을 vLLM으로 활용하는 것입니다. OpenAI의 라이브러리 형태로 그대로 사용할 수 있지만, 사용되는 모델은 vLLM에서 실행하여 inference에 쓰고 있는 LLM을 활용하는 것입니다.&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;그럼 vLLM을 어떻게 OpenAI 서버로 사용할 수 있을까요?&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style8&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. vLLM을 OpenAI API 서버로 활용하기(OpenAI-Compatible server)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 vLLM을 어떻게 실행시키면 OpenAI API 서버처럼 활용할 수 있을까요? 먼저 살펴볼 것은 OpenAI의 API 포멧입니다. OpenAI의 API는 아래와 같은 포멧으로 API를 제공해주고 있으며, 이에 맞춰서 파이썬 라이브러리가 제공되고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729911439480&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 파이썬 OpenAI 라이브러리 활용 시
client.chat.completions.create(model=&quot;gpt-4o-mini&quot;, ... )

# curl 활용시
curl https://api.openai.com/v1/chat/completions \
  -H &quot;Content-Type: application/json&quot; \
  -H &quot;Authorization: Bearer $OPENAI_API_KEY&quot; \
  -d '{
     &quot;model&quot;: &quot;gpt-4o-mini&quot;,
     &quot;messages&quot;: [{&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;안녕하세요. 이수진입니다.&quot;}],
     &quot;temperature&quot;: 0.7
   }'&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;즉, chat 포멧으로 지원해주면서 completions 경로를 따르고 있습니다. 즉, vLLM에서도 이와 같이 제공해줘야 OpenAI 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;vLLM에서 OpenAI API 형태로 제공해주는 방법은 아래와 같이 실행하면 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729911582717&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;python -m vllm.entrypoints.openai.api_server --model /llm_models/llama-3-Korean-Bllossom-8B --max-model-len=2048 --port 8007 --tensor-parallel-size 2&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;명령어는 vLLM이 Python에 설치되었다고 했을 때 vllm.entrypoints.openai.api_server 형태로 실행을 시켜주시면 됩니다. 즉, 이미 명령어에서 openai의 api server로 사용한다(openai.api_server)라고 명시가 되어있죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 저는 Bllossom팀에서 제공해주신 매우 훌륭한 Bllossom-8B 모델을 사용했습니다. (좋은 모델 만들어주셔서 감사합니다!)&amp;nbsp; 이 모델을 활용해 OpenAI API처럼 제공할 수 있도록 할 것이고 포트는 8007번, 병렬 텐서는 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;정상적으로 잘 실행이 되었다면, 아래 사진처럼 실행한 터미널에 API 서버가 실행될 것입니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-10-25 오후 8.31.25.png&quot; data-origin-width=&quot;3174&quot; data-origin-height=&quot;738&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBXiPj/btsKkjuI2iF/w7AmW680ZjSKE0kkCobY5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBXiPj/btsKkjuI2iF/w7AmW680ZjSKE0kkCobY5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBXiPj/btsKkjuI2iF/w7AmW680ZjSKE0kkCobY5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBXiPj%2FbtsKkjuI2iF%2Fw7AmW680ZjSKE0kkCobY5K%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;3174&quot; height=&quot;738&quot; data-filename=&quot;스크린샷 2024-10-25 오후 8.31.25.png&quot; data-origin-width=&quot;3174&quot; data-origin-height=&quot;738&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;또한, 이렇게 제공되는 API는 FastAPI로 제공해주기 때문에 swagger 형태로도 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API가 실행된 경로의 /docs를 확인하면 (ex. localhost:8007/docs) 아래 사진과 같은 Swagger 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;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-10-26 오전 10.30.04.png&quot; data-origin-width=&quot;1641&quot; data-origin-height=&quot;746&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bekloI/btsKkpakEJy/TkQEoaktM55pSNBsji9J20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bekloI/btsKkpakEJy/TkQEoaktM55pSNBsji9J20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bekloI/btsKkpakEJy/TkQEoaktM55pSNBsji9J20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbekloI%2FbtsKkpakEJy%2FTkQEoaktM55pSNBsji9J20%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;732&quot; height=&quot;333&quot; data-filename=&quot;스크린샷 2024-10-26 오전 10.30.04.png&quot; data-origin-width=&quot;1641&quot; data-origin-height=&quot;746&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style8&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. OpenAI 파이썬(Python) 라이브러리 예제와 Curl 예제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자! 이제 vLLM을 OpenAI 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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;curl로 통신하는 방법&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저, 간단하게 curl 명령어로 통신하는 방법입니다. API 서버가 올라가 있으니, API 서버에 curl로 통신을 하는 방법이죠. 아래와 같이 통신을 해서 사용할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729912583197&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;curl http://localhost:8007/v1/completions \
    -H &quot;Content-Type: application/json&quot; \
    -d '{
        &quot;model&quot;: &quot;/llm_models/llama-3-Korean-Bllossom-8B&quot;,
        &quot;prompt&quot;: &quot;안녕하세요. 겨울이 오나봐요. 오늘 날씨는 운동하기 좋아요. 운동을 하면&quot;,
        &quot;max_tokens&quot;: 250,
        &quot;temperature&quot;: 0
    }'&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;curl 명령어로 API 서버가 올라가 있는 쪽에 통신을 하면 되는데요. 이때, API 통신 경로는 host/v1/completions 를 따르게 됩니다. 즉 앞에서 봤던 OpenAI 경로와 매칭이 되죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 모델을 어떤 모델을 쓰는지에 대한 것과 프롬프트(prompt), 최대 토큰(max_token), temperature를 설정할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 curl로 vLLM OpenAI API 서버를 호출한 결과는 아래와 같습니다.&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-filename=&quot;스크린샷 2024-10-26 오전 10.39.17.png&quot; data-origin-width=&quot;2938&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VEZF8/btsKlzpIPFd/6dX0k2eLkHyapJSOk1EKCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VEZF8/btsKlzpIPFd/6dX0k2eLkHyapJSOk1EKCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VEZF8/btsKlzpIPFd/6dX0k2eLkHyapJSOk1EKCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVEZF8%2FbtsKlzpIPFd%2F6dX0k2eLkHyapJSOk1EKCk%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;2938&quot; height=&quot;460&quot; data-filename=&quot;스크린샷 2024-10-26 오전 10.39.17.png&quot; data-origin-width=&quot;2938&quot; data-origin-height=&quot;460&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;Python의 OpenAI 라이브러리로 통신하는 방법&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 Python OpenAI 라이브러리를 활용해서 통신하는 방법도 있습니다. 포스팅 앞쪽에서 소개해드린 OpenAI 코드와 매우 유사한 방법입니다.&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_1729912911944&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from openai import OpenAI

openai_api_key = &quot;EMPTY&quot;
openai_api_base = &quot;http://localhost:8007/v1&quot;
model_path = &quot;/llm_models&quot;
model_code = &quot;llama-3-Korean-Bllossom-8B&quot;

client = OpenAI(
    api_key=openai_api_key,
    base_url=openai_api_base,
)
completion = client.completions.create(model=f'{model_path}/{model_code}',
                                      prompt=&quot;안녕하세요? 날씨가 춥네요.&quot;)

print(&quot;Completion result:&quot;, completion)&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;먼저, 단순히 문장을 생성해주는 방법입니다. Python에 있는 OpenAI 라이브러리를 활용하면 쉽게 통신할 수 있는데요. 여기서 특징은 아래와 같습니다.&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;- openai_api_key 값은 EMPTY라는 값으로 넣어줍니다. 원래 OpenAI를 사용하면 OpenAI에서 제공해주는 key를 넣어주는데요.&amp;nbsp; vLLM 환경에서 실행하는 것이다보니 Key라는 것이 딱히 존재하지 않기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 또한 url을 vLLM이 OpenAI server로 올라간 host로 넣어주면 되는데 v1이라는 경로까지 넣어주면 됩니다.&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;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item dable&quot; style=&quot;height: 250px;&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;300x250&lt;/div&gt;
    &lt;div id=&quot;dablewidget_Pl1aE8lE&quot; data-widget_id=&quot;Pl1aE8lE&quot;&gt;
      &lt;script&gt;(function(d,a,b,l,e,_) {
    if(d[b]&amp;&amp;d[b].q)return;d[b]=function(){(d[b].q=d[b].q||[]).push(arguments)};e=a.createElement(l);
    e.async=1;e.charset='utf-8';e.src='//static.dable.io/dist/plugin.min.js';
    _=a.getElementsByTagName(l)[0];_.parentNode.insertBefore(e,_);
    })(window,document,'dable','script');
dable('setService', 'lsjsj92.tistory.com');
dable('sendLogOnce');
dable('renderWidget', 'dablewidget_Pl1aE8lE', {ignore_items: true});&lt;/script&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-10-26 오후 12.11.29.png&quot; data-origin-width=&quot;1209&quot; data-origin-height=&quot;383&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cx93Jb/btsKliPkrZz/Iz4oDyhpFknmKNKzZ0a3ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cx93Jb/btsKliPkrZz/Iz4oDyhpFknmKNKzZ0a3ak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cx93Jb/btsKliPkrZz/Iz4oDyhpFknmKNKzZ0a3ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcx93Jb%2FbtsKliPkrZz%2FIz4oDyhpFknmKNKzZ0a3ak%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;1209&quot; height=&quot;383&quot; data-filename=&quot;스크린샷 2024-10-26 오후 12.11.29.png&quot; data-origin-width=&quot;1209&quot; data-origin-height=&quot;383&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 다른 방법은 chat 형태로 사용하는 방법입니다. 일반적으로 많이 사용하는 방법이죠. 이때는 아래와 같은 Python 코드로 실행할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729913160177&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;openai_api_key = &quot;EMPTY&quot;
openai_api_base = &quot;http://localhost:8007/v1&quot;
model_path = &quot;/llm_models&quot;
model_code = &quot;llama-3-Korean-Bllossom-8B&quot;

client = OpenAI(
    api_key=openai_api_key,
    base_url=openai_api_base,
)

chat_response = client.chat.completions.create(
    model=f'{model_path}/{model_code}',
    messages=[
        {&quot;role&quot;: &quot;system&quot;, &quot;content&quot;: &quot;당신은 친절하게 저를 돕는 어시스턴트입니다.&quot;},
        {&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;안녕하세요? 날씨가 춥네요.&quot;},
    ]
)
print(&quot;Chat response:&quot;, chat_response)&lt;/code&gt;&lt;/pre&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-filename=&quot;스크린샷 2024-10-26 오후 12.11.40.png&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;284&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t8PmB/btsKltiIucv/Z303XuhwX6pi2xNHDuCoMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t8PmB/btsKltiIucv/Z303XuhwX6pi2xNHDuCoMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t8PmB/btsKltiIucv/Z303XuhwX6pi2xNHDuCoMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft8PmB%2FbtsKltiIucv%2FZ303XuhwX6pi2xNHDuCoMK%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;1220&quot; height=&quot;284&quot; data-filename=&quot;스크린샷 2024-10-26 오후 12.11.40.png&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;284&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;chat으로 실행할 때는 system role이나 user role과 같은 값을 추가로 명시할 수 있고 대화를 하는 형태로 결과를 주고받고 할 수 있습니다.&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;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 vLLM을 OpenAI api server로 실행시키고 curl 및 Python openai 라이브러리에서 활용할 수 있는 방법에 대해 알아보았습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다음 글에서는&amp;nbsp;랭체인(LangChain)에서 vLLM API server를 활용하는 방법에 대해서 알아보겠습니다.&lt;/p&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;긴 글 읽어주셔서 감사합니다.&lt;/p&gt;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>API</category>
      <category>GenAI</category>
      <category>GPT</category>
      <category>langchain</category>
      <category>llama3</category>
      <category>LLM</category>
      <category>openai</category>
      <category>Python</category>
      <category>vllm</category>
      <category>생성형ai</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/673</guid>
      <comments>https://lsjsj92.tistory.com/673#entry673comment</comments>
      <pubDate>Sat, 26 Oct 2024 12:52:35 +0900</pubDate>
    </item>
    <item>
      <title>글쓰는 개발자 모임, 글또 10기를 시작하며 작성하는 글또 다짐글</title>
      <link>https://lsjsj92.tistory.com/672</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;본 포스팅은 글또 10기(글쓰는 또라이가 세상을 바꾼다, 글쓰는 개발자 모임)를 시작하면서 다짐하는 다짐글입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4기부터 시작한 글또를 어느덧 10기까지 참여하게 되었는데요(중간에 9기는 결혼 스케줄 때문에 참석 못하였음).&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번 기수까지 진행하면 3년이라는 시간을 채우게 될 것 같습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;글또 10기에는 어떻게 활동하고 싶은지, 어떤 생각과 마음을 가지고 있는지 정리해보려고 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #5c5c5c; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #6bacce;&quot; href=&quot;https://www.facebook.com/groups/geultto/&quot;&gt;www.facebook.com/groups/geultto/&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 4기 다짐글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #6bacce;&quot; href=&quot;https://lsjsj92.tistory.com/576&quot;&gt;lsjsj92.tistory.com/576&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 4기 회고글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #6bacce;&quot; href=&quot;https://lsjsj92.tistory.com/595&quot;&gt;lsjsj92.tistory.com/595&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 5기 다짐글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/603&quot;&gt;https://lsjsj92.tistory.com/603&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 5기 회고글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/614&quot;&gt;https://lsjsj92.tistory.com/614&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 6기 다짐글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/619&quot;&gt;https://lsjsj92.tistory.com/619&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 6기 회고글 : 21년 회고글과 함께 작성 (&lt;a href=&quot;https://lsjsj92.tistory.com/630&quot;&gt;https://lsjsj92.tistory.com/630&lt;/a&gt;)&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 7기 다짐글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/635&quot;&gt;https://lsjsj92.tistory.com/635&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;글또 7기 회고글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/646&quot;&gt;https://lsjsj92.tistory.com/646&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;글또 8기 다짐글 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/654&quot;&gt;https://lsjsj92.tistory.com/654&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;글또 8기 회고글 : &lt;a href=&quot;https://lsjsj92.tistory.com/658&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/658&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1728170889771&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;5번째 글또 기수 마무리, 글또 8기 회고글(글쓰는 개발자)&quot; data-og-description=&quot;포스팅 개요 본 포스팅은 글또 8기(글쓰는 또라이가 세상을 바꾼다, 글쓰는 개발자 모임)를 마무리하면서 쓰는 회고글입니다. 어느덧 글또 활동을 한 지, 기수 시간(1기수당 6개월)기준으로 2년 &quot; data-og-host=&quot;lsjsj92.tistory.com&quot; data-og-source-url=&quot;https://lsjsj92.tistory.com/658&quot; data-og-url=&quot;https://lsjsj92.tistory.com/658&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bPqqMA/hyXec8731e/6lt8KpjMDUmLzkrwUaL310/img.png?width=566&amp;amp;height=153&amp;amp;face=0_0_566_153,https://scrap.kakaocdn.net/dn/PGNkW/hyXd7fF4MG/jck0atH3epao8MQ20O17KK/img.png?width=566&amp;amp;height=153&amp;amp;face=0_0_566_153,https://scrap.kakaocdn.net/dn/btGiu1/hyXd8FEa42/vRMoPfBvxTULEmJFaecLx1/img.jpg?width=2160&amp;amp;height=2880&amp;amp;face=1026_1170_1309_1480&quot;&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/658&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://lsjsj92.tistory.com/658&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bPqqMA/hyXec8731e/6lt8KpjMDUmLzkrwUaL310/img.png?width=566&amp;amp;height=153&amp;amp;face=0_0_566_153,https://scrap.kakaocdn.net/dn/PGNkW/hyXd7fF4MG/jck0atH3epao8MQ20O17KK/img.png?width=566&amp;amp;height=153&amp;amp;face=0_0_566_153,https://scrap.kakaocdn.net/dn/btGiu1/hyXd8FEa42/vRMoPfBvxTULEmJFaecLx1/img.jpg?width=2160&amp;amp;height=2880&amp;amp;face=1026_1170_1309_1480');&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;5번째 글또 기수 마무리, 글또 8기 회고글(글쓰는 개발자)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 개요 본 포스팅은 글또 8기(글쓰는 또라이가 세상을 바꾼다, 글쓰는 개발자 모임)를 마무리하면서 쓰는 회고글입니다. 어느덧 글또 활동을 한 지, 기수 시간(1기수당 6개월)기준으로 2년&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;lsjsj92.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;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;포스팅 본문&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-09-29 오후 8.59.06.png&quot; data-origin-width=&quot;3068&quot; data-origin-height=&quot;1730&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckiv3N/btsJV3Fagst/oAUhsi9l8Ut5RsLHCn1Xy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckiv3N/btsJV3Fagst/oAUhsi9l8Ut5RsLHCn1Xy1/img.png&quot; data-alt=&quot;글또 OT PPT(출처 : 카일스쿨 Youtube)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckiv3N/btsJV3Fagst/oAUhsi9l8Ut5RsLHCn1Xy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fckiv3N%2FbtsJV3Fagst%2FoAUhsi9l8Ut5RsLHCn1Xy1%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;3068&quot; height=&quot;1730&quot; data-filename=&quot;스크린샷 2024-09-29 오후 8.59.06.png&quot; data-origin-width=&quot;3068&quot; data-origin-height=&quot;1730&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;글또 OT PPT(출처 : 카일스쿨 Youtube)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;글또의 마지막 기수, 10기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글또(글 쓰는 개발자 모임)는 4기부터 시작해서 8기까지 참여했었고, 이번 10기에 다시 참여하게 되었다. 사실 9기도 참석하고 싶은 마음이 컸지만, 결혼 과정과 신혼 초기 생활 그리고 여러 가지 변화된 환경에 집중하고 적응하기 위해 잠시 쉬어가기로 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 1기수, 시간으로 따지면 대략 1년 정도 시간 만에 글또를 참여하게 되었는데, 이전에 2년 반 동안 활동했던 것과는 사뭇 다른 느낌이 드는 이번 10기이다.&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;평소 해오던 글또 활동인데도, 이번 기수는 왜 이렇게 다른 느낌이 드는 걸까? 이런 생각이 글또 OT 때부터 머릿속에서 멈추지 않았다. 성격상 이런 것 정리 안 하면 계속 생각이 나는 타입이라, 그냥 솔직하게 정리할 겸 기록해 본다. (지극히 개인적인 생각이다)&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&gt;&lt;b&gt;사람이 많다&lt;/b&gt; : 사람이 정말 많다. 630~640명이 넘는 것으로 알고 있는데, 그 많아짐이 느껴진다. 예전에는 비슷한 다른 채널(데분데싸a, 데분데싸b 등)에 다 참가해서 봤었다면 이제는 이건 좀 힘들 것 같다는 생각도 든다 ㅎㅎㅎ 그래도 그만큼 글또라는 커뮤니티가 많이 성장한 것 같아서(내가 뭐 한 것은 없지만) 기분은 좋다!&lt;/li&gt;
&lt;li&gt;&lt;b&gt;여러 활동들이 많이 생겼다&lt;/b&gt; : 사람이 많은 만큼 여러 가지 활동들이 정말 많이 생겼다. 8기 때도 여러 채널에 들어가서 눈팅도하고 어떨 때는 글도 쓰고 했는데, 이제는 너무 많아서 어디를 눈팅하고 어디에서 글을 쓸까 고민이 된다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;활동마다 룰이 있는데, 개인적으로 팔로우가 잘 안되고 늦었다(슬픔 ㅠ)&lt;/b&gt; : 마음에 드는 활동들이 있는데, 룰이 팔로우가 잘 안되는 것들도 많다. 이게 지난 기수부터 이어진 것들이 있어 이미 알고 있는 사람들은 잘하시는 것 같다. 그리고 어떤 활동들은 월별로 신청을 받아서 하는 것도 있는 것 같아, 놓친 것도 있다 ㅠ. 아무래도 글또 시작하자마자 기념일이니 뭐니 해서 정신이 없어서 활동 공지를 놓쳤더니 잘 못 따라가는 것 같다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;나의 상황&lt;/b&gt; : 결혼 전/후로 활동들에 참여할 수 있는 상태(?)가 달라져서 그런 것도 있는 것 같다. 예를 들어, 기존에는 출/퇴근 거리가 짧았다면 결혼 후에는 거의 2배 가까이 늘어나서 체력적으로나 시간적 상황이나 등등 상황이 변했다. 개인적으로는 오프라인 모임이 너무 좋지만(되도록 참석하려고 하겠지만) 기존보다는 온라인 비중이 늘어날 것 같기는 하다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;마지막 기수&lt;/b&gt; : 10기까지의 여정을 끝으로 글또는 마무리가 된다. 그동안 글또 활동을 토대로 내 블로그가 성장한 것, 나의 글쓰기가 성장한 것을 기억하면 시원섭섭하다. 그래서 이번 기수는 조금 더 여러 가지 생각이 드는 것 같다.&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;h3 data-ke-size=&quot;size23&quot;&gt;목표와 다짐&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 개인적으로 많이 달라졌다고 생각되는 10기의 상황에서 나는 그럼 어떻게 글또 활동에 참여할까? 어떻게 적극적으로 참여하고 또 새로운 인연을 이어갈 수 있을까? 음 뭔가 다양한 목표보다는 2~3개의 목표에 집중하는 것이 나을 것 같다는 생각이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 크게 2개 '글'에 집중하는 것과 '그 외 활동'으로 구분할 수 있을 것 같다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;글의 주제와 글을 작성하는 주기&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 블로그 글을 잘 작성하지 못했다. 블로그 글을 작성하지 못했던 이유는 명확하다. 결혼 후의 출퇴근 시간과 가족과의 시간, 그리고 회사에서의 바쁨이다. 더 자세한 것은 너무 개인적인 이야기라 생략하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 글또 10기 활동을 하면서 다시 '글'에 집중하고 싶다. 내가 원하는 글과 공부한 것을 작성하고 싶다. '글'과 관련된 목표는 다음과 같을 것 같다.&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&gt;&lt;b&gt;주기적인 글 작성&lt;/b&gt; : 최근 글 작성 패턴이 너무 틀어졌다. 이걸 다시 2주에 한 번이라는 주기로 맞추고자 한다. 그래서 다시 글 쓰는 것이 습관화되고 내 삶의 패턴이 되었으면 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;글의 주제&lt;/b&gt; : 요즘 관심이 많은 주제들에 대해서 글을 작성하고 싶다. 요즘 나의 관심사는 1) 여전히 추천 시스템이고 2) LLM 및 RAG 시스템이다. 특히 LLM과 RAG에 대해서 어떻게 글을 작성하면 좋을지 고민이다. Langchain을 활용한 실습 위주의 글을 작성할지, 논문 리뷰도 포함할 지 이거는 조금 더 고민을 해봐야겠다!&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ChatGPT 사용에 대해서&lt;/b&gt; : ChatGPT 등의 GenAI 서비스 성능이 올라가면서 글을 작성할 때나 무엇인가 작업할 때 어느새인가 이 서비스에 의존하는 경향이 많아졌다. 그래서 적어도 글또 활동을 할 때 블로그 글 작성은 ChatGPT에 의존하지 않으려고 노력하고 싶다. 물론 오타 검토나 자연스러운 글로 다시 작성하는 것, 틀린 게 있는지 검토하는 것 등은 사용하겠지만 글 작성 자체는 내가 스스로 사고하고 공부하고 구조화하여 작성하려고 노력하려고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;그 외 다양한 활동&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글또의 큰 장점이자 자랑거리 중 하나는 글을 쓰는 것 외에 다양한 활동이 있다는 것이다. 특히, 이번 10기에는 너무나도 재밌는 활동들이 많이 보인다 ㅎㅎ 마음 같아서는 다 참석하고 싶지만! 현실을 고려해서 몇 가지 주제에서 활동하고 참석해 보고자 한다.&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&gt;&lt;b&gt;감사 및 회고(+일기)&lt;/b&gt; : 지난 기수에서부터 자주 참석했던 활동이다. 어떨 때는 하루가 정신없이 흘러가서 뭘 했는지 기억이 잘 안날때도 있을 정도로 바쁜데, 바쁜 하루를 돌아보면서 감사했던 일과 회고를 짧게 작성하는 활동이다. 이 활동 덕분에 오늘 하루를 어떻게 살아왔는지 돌아볼 수 있어 너무 좋았었다. 그리고 마침 일기를 쓰는 활동도 있길래 이것도 같이 해보려고 한다. 일기를 감사 및 회고 형태로 작성하고 공유하는 방식으로 활동하면 좋을 것 같다!&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다짐 &amp;amp; 기상 &amp;amp; 운동&lt;/b&gt; : 이 활동들은 원래 각각 3개의 활동으로 구분되어 있다. 이거를 하나로 묶어서 활동해보려고 한다. 매번 새벽에 일어나서 운동가고 출근길에 다짐하는 것들이 있는데 이걸 글또 활동에 공유해보려고 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결혼&lt;/b&gt; : 이번 기수 활동 중 가장 신기했던 채널이다! 마침 신혼이라서 여러가지 결혼 생활에 대한 정보를 공유 하고 받고 싶다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커피챗&lt;/b&gt; : 글또하면 커피챗은 빠질 수 없는 요소이다. 기존 사람들을 만나 커피챗을 하는 것도 좋고 새로운 다양한 사람들을 만나는 것도 좋다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 글또 10기를 시작하면서 다짐하는 다짐글입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 가지 바쁜 상황도 있지만, 마지막 기수인만큼 열심히 해보고자 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시나 10기 진행하시는 분들께서 이 글을 보신다면, 같이 커피챗도 하고 인사도해요!&lt;/p&gt;</description>
      <category>일상</category>
      <category>ChatGPT</category>
      <category>GenAI</category>
      <category>글또</category>
      <category>글쓰는개발자</category>
      <category>블로그</category>
      <category>생성형ai</category>
      <category>일상</category>
      <category>추천시스템</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/672</guid>
      <comments>https://lsjsj92.tistory.com/672#entry672comment</comments>
      <pubDate>Sun, 6 Oct 2024 10:30:38 +0900</pubDate>
    </item>
    <item>
      <title>인공지능 윤리(AI Ethics)란 무엇일까? AI개발자가 바라본 AI윤리(Feat. AI 기획자 Day 발표)</title>
      <link>https://lsjsj92.tistory.com/671</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 시간이 지날수록 중요성이 부각되고 있는 인공지능 윤리(AI 윤리, AI Ethics)에 대해서 AI 개발자의 입장에서 정리해본 생각을 작성한 포스팅입니다. 본 포스팅은 지극히 개인적인 생각과 입장을 정리한 포스팅이니, 부족한 점이 있으면 양해 부탁드리면서 피드백 주시면 좋을 것 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 본 포스팅의 내용은 당근대장(당근=당연히 대장님)님께서 주최하시는 AI 기획자 Day에서 발표한 자료를 기반으로 작성하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 발표 자료는 포스팅 하단에 첨부하였습니다.&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;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅 개요에서도 언급하였듯, 본 포스팅은 AI 윤리에 대해서 AI 개발자의 입장에서 간단하게 생각을 정리한 포스팅입니다.&amp;nbsp;&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;AI 기술이 지속적으로 발전하면서, AI 윤리에 대한 이야기가 계속 강조되고 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vMc6M/btsIQnEyrAI/tvYs8kvUNyKp8X1WY7BGLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vMc6M/btsIQnEyrAI/tvYs8kvUNyKp8X1WY7BGLK/img.png&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.49.18.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3174&quot; data-origin-height=&quot;1996&quot; style=&quot;width: 48.9136%; margin-right: 10px;&quot; data-widthpercent=&quot;49.49&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vMc6M/btsIQnEyrAI/tvYs8kvUNyKp8X1WY7BGLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvMc6M%2FbtsIQnEyrAI%2FtvYs8kvUNyKp8X1WY7BGLK%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;3174&quot; height=&quot;1996&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcCob6/btsIP0pr0UH/aDWN3Dd2qnsQo9MVuftPg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcCob6/btsIP0pr0UH/aDWN3Dd2qnsQo9MVuftPg1/img.png&quot; data-origin-width=&quot;3272&quot; data-origin-height=&quot;2016&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.49.36.png&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.9236%;&quot; data-widthpercent=&quot;50.51&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcCob6/btsIP0pr0UH/aDWN3Dd2qnsQo9MVuftPg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcCob6%2FbtsIP0pr0UH%2FaDWN3Dd2qnsQo9MVuftPg1%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;3272&quot; height=&quot;2016&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;출처 : https://www.igloo.co.kr/security-information/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5ai-%EC%A0%84%EB%AC%B8%EA%B0%80%EB%93%A4%EC%9D%80-%EC%99%9C-%EC%9C%84%ED%97%98%ED%95%98%EB%8B%A4%EA%B3%A0-%ED%95%A0%EA%B9%8C/&lt;/figcaption&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;가령 왼쪽 사진은 생성형 AI가 만든 가짜 이미지인데요. AI가 만든 펜타곤 근처 폭발 사고 이미지 때문에 미국 증시도 하락한 사건이 있었습니다. 또한, 오른쪽은 요즘 우리나라 뿐만 아니라 각 나라에서 집중하고 있는 선거 때문에 만들어진 영상입니다. 이도 AI가 만들었으며, 이를 통해 허위 정보를 전달할 수 있는 가능성이 보여지는 것이죠.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.50.08.png&quot; data-origin-width=&quot;3816&quot; data-origin-height=&quot;2076&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d09lny/btsIPs05Rwr/hLCvZjQOFjUYSjYwxe3kak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d09lny/btsIPs05Rwr/hLCvZjQOFjUYSjYwxe3kak/img.png&quot; data-alt=&quot;출처 : https://v.daum.net/v/574eaac6ed94d200018facbb&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d09lny/btsIPs05Rwr/hLCvZjQOFjUYSjYwxe3kak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd09lny%2FbtsIPs05Rwr%2FhLCvZjQOFjUYSjYwxe3kak%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;599&quot; height=&quot;326&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.50.08.png&quot; data-origin-width=&quot;3816&quot; data-origin-height=&quot;2076&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://v.daum.net/v/574eaac6ed94d200018facbb&lt;/figcaption&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;좀 옛날이긴 하지만, 구글 포토(Google Photo)가 만든 윤리적 이슈도 있었습니다. 어떤 사람이 가지고 있는 사진 중 흑인 친구를 구글 포토가 고릴라로 인식한 사건입니다. 이렇게 AI의 사소한 실수로 인해 자칫 사회적 문제나, 기업의 문제, 서비스의 문제가 발생할 수 있습니다.&amp;nbsp;&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.50.21.png&quot; data-origin-width=&quot;3896&quot; data-origin-height=&quot;1976&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u4Flm/btsIOTScI8a/6suBlAkGkkcpRQgxkk8mc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u4Flm/btsIOTScI8a/6suBlAkGkkcpRQgxkk8mc0/img.png&quot; data-alt=&quot;출처 : https://www.aitimes.com/news/articleView.html?idxno=135396&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u4Flm/btsIOTScI8a/6suBlAkGkkcpRQgxkk8mc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu4Flm%2FbtsIOTScI8a%2F6suBlAkGkkcpRQgxkk8mc0%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;698&quot; height=&quot;354&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.50.21.png&quot; data-origin-width=&quot;3896&quot; data-origin-height=&quot;1976&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://www.aitimes.com/news/articleView.html?idxno=135396&lt;/figcaption&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;그것 외에도 다양한 AI윤리적 문제가 발생할 수 있습니다. 남녀차별, 인종, 세대, 소득 등 다양한 방면에서 윤리적 문제가 발생할 수 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 문제는 왜 발생하게 될까요? 다양한 문제가 발생할 수 있지만, AI개발자의 시각에서 정리를 한 번 해보려고 합니다.&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-filename=&quot;스크린샷 2024-07-28 오후 3.50.54.png&quot; data-origin-width=&quot;3944&quot; data-origin-height=&quot;2046&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xDa4u/btsIPwPLIMY/QgVpEIDxrnvng3YLkpP6ek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xDa4u/btsIPwPLIMY/QgVpEIDxrnvng3YLkpP6ek/img.png&quot; data-alt=&quot;출처 : https://arxiv.org/pdf/1810.04805&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xDa4u/btsIPwPLIMY/QgVpEIDxrnvng3YLkpP6ek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxDa4u%2FbtsIPwPLIMY%2FQgVpEIDxrnvng3YLkpP6ek%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;713&quot; height=&quot;370&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.50.54.png&quot; data-origin-width=&quot;3944&quot; data-origin-height=&quot;2046&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://arxiv.org/pdf/1810.04805&lt;/figcaption&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;요즘 다양한 AI 서비스들이 나오고 있습니다. ChatGPT나 Gemini 등 다양한 LLM 모델들을 활용한 서비스가 나오고 있죠. AI 서비스들은 LLM 뿐만 아니라 멀티모달(Multi Modal) 등 다양한 모델들이 존재하지만 우리에게 친숙한 것은 LLM이니 먼저 LLM 기준으로 살펴보겠습니다. 최근 LLM의 근간이 되는 것은 2017년에 나온 Attnention is all you need라는 논문의 Transformer 구조입니다. 이 구조에서 BERT, GPT 등 다양한 모델들이 탄생하게 되었죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bATloA/btsIRvV39OO/z9IHWLT4iYIn42528VFlK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bATloA/btsIRvV39OO/z9IHWLT4iYIn42528VFlK0/img.png&quot; data-origin-width=&quot;3944&quot; data-origin-height=&quot;2046&quot; data-is-animation=&quot;false&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.51.11.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bATloA/btsIRvV39OO/z9IHWLT4iYIn42528VFlK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbATloA%2FbtsIRvV39OO%2Fz9IHWLT4iYIn42528VFlK0%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;3944&quot; height=&quot;2046&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eqIVyU/btsIQ3S9hE6/PK9XUWjKegs9McPEvnvAzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eqIVyU/btsIQ3S9hE6/PK9XUWjKegs9McPEvnvAzk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3944&quot; data-origin-height=&quot;2046&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.51.26.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eqIVyU/btsIQ3S9hE6/PK9XUWjKegs9McPEvnvAzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeqIVyU%2FbtsIQ3S9hE6%2FPK9XUWjKegs9McPEvnvAzk%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;3944&quot; height=&quot;2046&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;출처 : (왼)https://jalammar.github.io/illustrated-transformer/ (오)https://jalammar.github.io/visualizing-neural-machine-translation-mechanics-of-seq2seq-models-with-attention/&lt;/figcaption&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 이 NLP 모델들, LLM 모델들은 이 단어 다음에 어떤 단어가 나올 지 확률적으로 생성하는 모델들입니다. 그 확률적으로 나오도록 학습된 모델들이 자신의 task에 맞게 점점 더 고도화 되는 것이죠. 그 고도화 과정은 어떻게 이루어질까요?&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-filename=&quot;스크린샷 2024-07-28 오후 3.51.39.png&quot; data-origin-width=&quot;3944&quot; data-origin-height=&quot;1790&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LMHkP/btsIPvXDXQr/Kce2nVR7IPIrNL7M5CzxD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LMHkP/btsIPvXDXQr/Kce2nVR7IPIrNL7M5CzxD0/img.png&quot; data-alt=&quot;출처 : https://huggingface.co/blog/trl-peft&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LMHkP/btsIPvXDXQr/Kce2nVR7IPIrNL7M5CzxD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLMHkP%2FbtsIPvXDXQr%2FKce2nVR7IPIrNL7M5CzxD0%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;666&quot; height=&quot;302&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.51.39.png&quot; data-origin-width=&quot;3944&quot; data-origin-height=&quot;1790&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://huggingface.co/blog/trl-peft&lt;/figcaption&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;먼저, Pretrain이라는 사전 학습 이라는 과정이 있습니다. 사전 학습이라는 것은 많은 데이터를 통해서 일반적인 언어를 사전에 학습하는 것을 의미합니다. 즉, 사전 모델을 미리 훈련하는 것이죠. 다음은 Fine-tuning 과정이 있습니다. 대화를 하는 언어 모델을 기준으로 생각해보면 fine-tuning 과정은 방대한 지식을 학습한 pretrain 모델을 사용해서 대화 방식을 배우는 과정이라고 보면 될 것 같습니다. 그 다음 RLHF라는 방법도 소개되는데요. 이는 대화 수준 향상을 위한 더 조리있게 학습하는 방법이라고 보면 됩니다. 이 과정에서는 보상 모델(강화 학습)을 활용해 사람의 피드백을 반영하는 과정입니다. 모델이 생성한 문장이 좋을수록 더 보상을 주어서 좋은 문장이 나오도록 하는 것이죠.&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-filename=&quot;스크린샷 2024-07-28 오후 3.51.56.png&quot; data-origin-width=&quot;2914&quot; data-origin-height=&quot;2138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8Xqcw/btsIRcJef5q/yh58Fz9XyhRZCl1wvki980/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8Xqcw/btsIRcJef5q/yh58Fz9XyhRZCl1wvki980/img.png&quot; data-alt=&quot;출처 : https://github.com/Mooler0410/LLMsPracticalGuide&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8Xqcw/btsIRcJef5q/yh58Fz9XyhRZCl1wvki980/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8Xqcw%2FbtsIRcJef5q%2Fyh58Fz9XyhRZCl1wvki980%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;718&quot; height=&quot;527&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.51.56.png&quot; data-origin-width=&quot;2914&quot; data-origin-height=&quot;2138&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://github.com/Mooler0410/LLMsPracticalGuide&lt;/figcaption&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;자연어 처리 모델은 위 사진과 같이 예전에 정말 많이 사용했던(저도 많이 사용했었던) word2vec, FastText부터 시작해 BERT 계열은 BERT, RoBERTa, ALBERT, DilstilBERT 등이 연구가 되었었습니다. GPT 계열은 GPT-1, GPT-2, GPT-3, InstructGPT, ChatGPT등으로 확장되었고 요즘 핫하고 3.1까지 나온 Meta의 LLaMA 모델들, 구글의 PaLM 모델 등 다양한 모델이 확장되고 연구되고 있습니다.&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;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-filename=&quot;스크린샷 2024-07-28 오후 3.52.11.png&quot; data-origin-width=&quot;3594&quot; data-origin-height=&quot;2056&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvw95M/btsIPZYmItv/NHvSf0lzLIvSZRreoUiQ31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvw95M/btsIPZYmItv/NHvSf0lzLIvSZRreoUiQ31/img.png&quot; data-alt=&quot;출처 : https://www.sciencedirect.com/science/article/pii/S0950584923001222&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvw95M/btsIPZYmItv/NHvSf0lzLIvSZRreoUiQ31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbvw95M%2FbtsIPZYmItv%2FNHvSf0lzLIvSZRreoUiQ31%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;764&quot; height=&quot;437&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.52.11.png&quot; data-origin-width=&quot;3594&quot; data-origin-height=&quot;2056&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://www.sciencedirect.com/science/article/pii/S0950584923001222&lt;/figcaption&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;AI 모델은 결국 데이터로 훈련합니다. 근데, 이 데이터는 어떤 데이터일까요? 위 표에서 보면 Amazon review, IMDB 와 같은 데이터를 사용한 것을 알 수 있습니다. 이것 뿐만 아니라 다양한 데이터를 LLM이 학습하게 됩니다. 근데 이 데이터가 과연 정제되어 있는 깔끔한 데이터일까요? 과연 밸런스가 갖추어진 데이터일까요?&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-filename=&quot;스크린샷 2024-07-28 오후 3.52.41.png&quot; data-origin-width=&quot;3962&quot; data-origin-height=&quot;1542&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cH5W8i/btsIPUJC3HU/GLbkzl670TmknekrpWwkX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cH5W8i/btsIPUJC3HU/GLbkzl670TmknekrpWwkX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cH5W8i/btsIPUJC3HU/GLbkzl670TmknekrpWwkX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcH5W8i%2FbtsIPUJC3HU%2FGLbkzl670TmknekrpWwkX1%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;734&quot; height=&quot;286&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.52.41.png&quot; data-origin-width=&quot;3962&quot; data-origin-height=&quot;1542&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;전통적인 데이터나 소셜 데이터, 글로벌 관점에서 보았을 때 밸런스가 잘 갖추어지지 않았거나, 정제되어 있지 않은 데이터가 반영될 수 있습니다. 요즘 시대는 굉장히 빠르게 변화하고 있습니다. 그렇기에 불과 몇 년전에 만들어진 데이터와 지금의 데이터는 관점이 많이 바뀔 수 있는 것이죠. 그러므로 세대갈등, 남녀갈등, 비윤리적 용어 등이 섞여져 있을 가능성이 높다고 생각합니다.(계속 언급하듯, 이것은 지극히 개인적인 생각입니다.) 만약, 이런 데이터를 사용해서 LLM 모델들이 학습을 하게 된다면, 당연히 윤리적인 이슈가 발생할 수 있을 것입니다.&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;그런데 이게 과연 LLM에서만 문제점이 될까요? 멀티 모달을 사용하게 되면 음성, 이미지 등으로 데이터 확장될탠데 이럴 때는 어떻게 될까요? 그리고 다른 AI 서비스들은 어떨까요?&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-filename=&quot;스크린샷 2024-07-28 오후 3.53.15.png&quot; data-origin-width=&quot;3642&quot; data-origin-height=&quot;1782&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKrDSc/btsIP5xo40r/OBMV2fqbLkZYLRMUpRKvGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKrDSc/btsIP5xo40r/OBMV2fqbLkZYLRMUpRKvGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKrDSc/btsIP5xo40r/OBMV2fqbLkZYLRMUpRKvGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKrDSc%2FbtsIP5xo40r%2FOBMV2fqbLkZYLRMUpRKvGk%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;650&quot; height=&quot;318&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.53.15.png&quot; data-origin-width=&quot;3642&quot; data-origin-height=&quot;1782&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 추천 시스템, 개인화 시스템을 많이 연구했습니다. 추천 시스템에서도 이런 윤리적인 문제가 발생할 수 있습니다. 제가 2023년도에 진행한 유데미 큐레이션 프로젝트를 진행할 때도(이때 기획 리딩을 해주신 분이 AI 기획자 Day를 주최하신 대장님이십니다.) 이런 고민을 정말 많이 했었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추천 시스템 입장에서는 고객이 좋아하는 것을 계속 노출시켜서 클릭이 많이 발생하도록 하는게 좋습니다. 그러나, 이게 AI 서비스를 개발하는 제 입장에서는 과연 이게 UX 관점에서 좋을까?라는 고민을 많이 했었죠. 고객이 선호하는 것만 제공하면 편향(bias)가 생길거니까요. 그래서 제가 이 자료를 발표한 AI 기획자 Day를 주최하신 리더님과 당시 이 고민에 대해 많이 이야기 나눴었습니다.&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-filename=&quot;스크린샷 2024-07-28 오후 7.34.46.png&quot; data-origin-width=&quot;2162&quot; data-origin-height=&quot;1296&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIfZLm/btsIPLe5qmE/DfwOlrI2SCZGINE2hIaUDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIfZLm/btsIPLe5qmE/DfwOlrI2SCZGINE2hIaUDk/img.png&quot; data-alt=&quot;출처 : https://youtu.be/PzcvhHWN7h0?si=s2IVrfGCWubxQcrE&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIfZLm/btsIPLe5qmE/DfwOlrI2SCZGINE2hIaUDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIfZLm%2FbtsIPLe5qmE%2FDfwOlrI2SCZGINE2hIaUDk%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;647&quot; height=&quot;388&quot; data-filename=&quot;스크린샷 2024-07-28 오후 7.34.46.png&quot; data-origin-width=&quot;2162&quot; data-origin-height=&quot;1296&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://youtu.be/PzcvhHWN7h0?si=s2IVrfGCWubxQcrE&lt;/figcaption&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;유데미 큐레이션 프로젝트에서는 크게 5가지 스텝으로 동작되었습니다. 1. 사용자 이력을 수집하고 2. 사용자 선호도 및 AI를 활용한 각종 메타 추출 3. 선호도 기반 후보 아이템 추출 4. 다양한 관점의 데이터 셋 추가 추출 5. Re-Ranking 작업입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzdSs5/btsIQKzsHup/MGrAXYomWtZvi2NOJUHiuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzdSs5/btsIQKzsHup/MGrAXYomWtZvi2NOJUHiuk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2148&quot; data-origin-height=&quot;1260&quot; data-filename=&quot;스크린샷 2024-07-28 오후 7.34.18.png&quot; style=&quot;width: 49.9541%; margin-right: 10px;&quot; data-widthpercent=&quot;50.54&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzdSs5/btsIQKzsHup/MGrAXYomWtZvi2NOJUHiuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzdSs5%2FbtsIQKzsHup%2FMGrAXYomWtZvi2NOJUHiuk%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;2148&quot; height=&quot;1260&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUNodW/btsIQEzk5tN/0R7Spy3ksktUqZPHx4bGY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUNodW/btsIQEzk5tN/0R7Spy3ksktUqZPHx4bGY0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2162&quot; data-origin-height=&quot;1296&quot; data-filename=&quot;스크린샷 2024-07-28 오후 7.34.29.png&quot; style=&quot;width: 48.8831%;&quot; data-widthpercent=&quot;49.46&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUNodW/btsIQEzk5tN/0R7Spy3ksktUqZPHx4bGY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUNodW%2FbtsIQEzk5tN%2F0R7Spy3ksktUqZPHx4bGY0%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;2162&quot; height=&quot;1296&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;출처 : https://youtu.be/PzcvhHWN7h0?si=s2IVrfGCWubxQcrE&lt;/figcaption&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, 가장 중요하게 생각한 것이 바로 사용자 이력 부분입니다. 이 사용자 이력에서 윤리적인 이슈가 발생하지 않도록 데이터 로깅 설계를 어떻게 할 것인가를 많이 고민했었죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 데이터를 수집할까? 개인정보는 없을까? 편향된 데이터가 발생할 수 있는가? 등 다양한 관점에 대해서 고민하면서 데이터를 수집했습니다. 이 단계 뿐만 아니라 두 번째 단계에서도 사용자 선호도를 추출할 때 다시 재검토를 수행하는 방향으로 개발을 진행했었습니다. 그리고 AI를 활용한 데이터를 추출 할 때도 이상한 데이터가 생성되지 않는지 검토했었죠.&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3HgG8/btsIRwgnnJg/aA0OurekdfFlKrcjP8iC21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3HgG8/btsIRwgnnJg/aA0OurekdfFlKrcjP8iC21/img.png&quot; data-origin-width=&quot;3642&quot; data-origin-height=&quot;2054&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.54.02.png&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.9187%; margin-right: 10px;&quot; data-widthpercent=&quot;50.51&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3HgG8/btsIRwgnnJg/aA0OurekdfFlKrcjP8iC21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3HgG8%2FbtsIRwgnnJg%2FaA0OurekdfFlKrcjP8iC21%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;3642&quot; height=&quot;2054&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pva82/btsIQhR0Y9j/asq3EMrrWcgXCwrsYLi9JK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pva82/btsIQhR0Y9j/asq3EMrrWcgXCwrsYLi9JK/img.png&quot; data-origin-width=&quot;3642&quot; data-origin-height=&quot;2096&quot; data-is-animation=&quot;false&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.54.09.png&quot; style=&quot;width: 48.9185%;&quot; data-widthpercent=&quot;49.49&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pva82/btsIQhR0Y9j/asq3EMrrWcgXCwrsYLi9JK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpva82%2FbtsIQhR0Y9j%2Fasq3EMrrWcgXCwrsYLi9JK%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;3642&quot; height=&quot;2096&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;출처 : https://arxiv.org/pdf/2312.10997&lt;/figcaption&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;요즘 검생 증강 생성(Retrieval-Augmented Generation, RAG) 기술도 굉장히 핫합니다. RAG를 사용하는 다양한 이유가 있겠지만, 저는 AI 윤리적인 이슈를 고려하기 위함도 어느정도 있지 않을까 싶습니다. 그래야 LLM이 이상한 소리를 안하고(할루시네이션이 안 나오고) 올바른 대답을 할태니까요. RAG를 구축할 때 프롬프트(Prompt)를 CoT 방법으로 사용할까 등등도 성능을 올릴려는 측면도 있지만, 이렇게 함으로써 신뢰도를 향상시킬 수 있지 않을까 싶습니다.&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-filename=&quot;스크린샷 2024-07-28 오후 3.54.30.png&quot; data-origin-width=&quot;2524&quot; data-origin-height=&quot;2096&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TLWco/btsIPxVqX6a/iFAgr8zIOg7kU6ZB9l8m3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TLWco/btsIPxVqX6a/iFAgr8zIOg7kU6ZB9l8m3K/img.png&quot; data-alt=&quot;출처 : https://arxiv.org/pdf/2307.03172&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TLWco/btsIPxVqX6a/iFAgr8zIOg7kU6ZB9l8m3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTLWco%2FbtsIPxVqX6a%2FiFAgr8zIOg7kU6ZB9l8m3K%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;463&quot; height=&quot;384&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.54.30.png&quot; data-origin-width=&quot;2524&quot; data-origin-height=&quot;2096&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://arxiv.org/pdf/2307.03172&lt;/figcaption&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;그리고 Lost in the middle과 같은 연구를 보면 LLM은 아직 불완전성 요소가 많이 남아 있는 것 같습니다. 그러니 더더욱 AI 윤리적인 것을 고민해야겠죠. 만약, 우리가 fine-tuning 과정을 통해서 sLLM을 만들거나 할 때도 우리 데이터에 비윤리적인 데이터가 있는지 검토할 필요가 있는 것입니다. 그래야 LLM이 올바르게 동작할 확률이 높아지지 않을까요?&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-filename=&quot;스크린샷 2024-07-28 오후 3.54.43.png&quot; data-origin-width=&quot;1912&quot; data-origin-height=&quot;2096&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Xjx3Z/btsIQZQHQ9Z/VUXvoFcNciahkm1oNhKqe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Xjx3Z/btsIQZQHQ9Z/VUXvoFcNciahkm1oNhKqe0/img.png&quot; data-alt=&quot;출처 : https://www.linkedin.com/posts/denis-panjuta_%3F%3F%3F%3F%3F%3F%3F%3F%3F-%3F%3F-%3F%3F%3F-%3F%3F%3F%3F-%3F%3F%3F%3F%3F-activity-7157737667835625472-0LSb?utm_source=share&amp;amp;amp;utm_medium=member_desktop&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Xjx3Z/btsIQZQHQ9Z/VUXvoFcNciahkm1oNhKqe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXjx3Z%2FbtsIQZQHQ9Z%2FVUXvoFcNciahkm1oNhKqe0%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;372&quot; height=&quot;408&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.54.43.png&quot; data-origin-width=&quot;1912&quot; data-origin-height=&quot;2096&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://www.linkedin.com/posts/denis-panjuta_%3F%3F%3F%3F%3F%3F%3F%3F%3F-%3F%3F-%3F%3F%3F-%3F%3F%3F%3F-%3F%3F%3F%3F%3F-activity-7157737667835625472-0LSb?utm_source=share&amp;amp;utm_medium=member_desktop&lt;/figcaption&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;요즘 AI data에 보면 큰 특징이 하나 있습니다. 예전에는 빅데이터(Big data), 딥러닝(Deep Learning), 머신러닝(Machine Learning), 데이터 사이언스, 텍스트 분석, 피처 엔지니어링(Feature Engineering) 등이 크게 있었습니다. 하지만, 어느순간부터 Ai Ethics라는 것이 생겼습니다. 위 그림에서 왼쪽 상단에 보면 AI 윤리가 자리잡고 있죠. 그만큼 이제 AI와 데이터에서 AI 윤리도 하나의 중요한 측면으로 자리잡게 되었다는 것을 의미하는게 아닐까 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d2tinF/btsIRubNeLh/Knvm83ocQksbDKhjiRfkuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d2tinF/btsIRubNeLh/Knvm83ocQksbDKhjiRfkuk/img.png&quot; data-origin-width=&quot;2038&quot; data-origin-height=&quot;1992&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.55.46.png&quot; data-is-animation=&quot;false&quot; width=&quot;440&quot; height=&quot;430&quot; style=&quot;width: 52.9241%; margin-right: 10px;&quot; data-widthpercent=&quot;53.55&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d2tinF/btsIRubNeLh/Knvm83ocQksbDKhjiRfkuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd2tinF%2FbtsIRubNeLh%2FKnvm83ocQksbDKhjiRfkuk%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;2038&quot; height=&quot;1992&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1pVIW/btsIOSFNIGq/w0c7I5QyD5uIC328sWmj31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1pVIW/btsIOSFNIGq/w0c7I5QyD5uIC328sWmj31/img.png&quot; data-origin-width=&quot;1784&quot; data-origin-height=&quot;2010&quot; data-filename=&quot;스크린샷 2024-07-28 오후 3.55.55.png&quot; data-is-animation=&quot;false&quot; width=&quot;419&quot; height=&quot;472&quot; style=&quot;width: 45.9132%;&quot; data-widthpercent=&quot;46.45&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1pVIW/btsIOSFNIGq/w0c7I5QyD5uIC328sWmj31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1pVIW%2FbtsIOSFNIGq%2Fw0c7I5QyD5uIC328sWmj31%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;1784&quot; height=&quot;2010&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;출처(왼) : https://blog.naver.com/kcc1335/223396015153 (오)https://www.mk.co.kr/news/it/11070688&lt;/figcaption&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;AI 윤리에 대해서 이제 각국의 규제나 표준이 만들어지고 있습니다. 우리나라 방송통신위원회에서도 생성형 AI 윤리 가이드라는 것이 나왔고 EU는 특히 정밀하게 윤리적인 것을 규정하고 있습니다. 이걸 지키지 못하면 서비스를 출시할 수도 없죠.&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-filename=&quot;스크린샷 2024-07-28 오후 7.14.41.png&quot; data-origin-width=&quot;1964&quot; data-origin-height=&quot;1238&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tqLZF/btsIRvu2Gvv/B4AF6WkgFQ0dKq4i7xsMP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tqLZF/btsIRvu2Gvv/B4AF6WkgFQ0dKq4i7xsMP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tqLZF/btsIRvu2Gvv/B4AF6WkgFQ0dKq4i7xsMP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtqLZF%2FbtsIRvu2Gvv%2FB4AF6WkgFQ0dKq4i7xsMP0%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;574&quot; height=&quot;362&quot; data-filename=&quot;스크린샷 2024-07-28 오후 7.14.41.png&quot; data-origin-width=&quot;1964&quot; data-origin-height=&quot;1238&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;그럼 AI 윤리는 데이터에서만, 모델 관점에서만 주의해야할까요? 저는 그렇게 생각하지 않습니다. 아무리 데이터가 잘 정제되고 잘 서비스가 나가도 사용자들이 악용하면 문제가 발생하게 될 수 있습니다. 그리고 국가나 기관에서도 다양한 교육이나 표준화 작업 등을 통해서 AI 윤리에 대한 프로세스를 만들어야 할 것입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 저와 같은 개발자나, AI 기획자 Day에 참석해주셨던 분들과 같은 기획자 등 서비스에 기여하는 모든 사람이 AI윤리에 대해 같이 고민하고 힘써야 할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정을 통해서 더 훌륭한 AI, 더 가치있는 AI 서비스가 나올 수 있지 않을까요? 저는 그렇게 기대하면서 포스팅 마무리 하겠습니다.&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 AI 기획자 Day에서 발표한 AI 윤리에 대해서 AI 개발자의 관점에서 정리해본 포스팅입니다.&amp;nbsp;&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;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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Linkedin :&amp;nbsp;&lt;span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot;&gt;https://www.linkedin.com/in/lsjsj92/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;github :&amp;nbsp;&lt;span&gt;&lt;/span&gt;&lt;a href=&quot;https://github.com/lsjsj92&quot;&gt;https://github.com/lsjsj92&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;블로그 댓글 또는 방명록&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;으로 연락주세요!&lt;/p&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&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/cy90G0/btsIRU9C3zW/14wYkUDk98k8cyeuvXfJI0/240727_%E1%84%8B%E1%85%B5%E1%84%89%E1%85%AE%E1%84%8C%E1%85%B5%E1%86%AB_%E1%84%87%E1%85%A1%E1%86%AF%E1%84%91%E1%85%AD%E1%84%8C%E1%85%A1%E1%84%85%E1%85%AD%28%E1%84%80%E1%85%A9%E1%86%BC%E1%84%8B%E1%85%B2%E1%84%8B%E1%85%AD%E1%86%BC%29.pdf?attach=1&amp;amp;knm=tfile.pdf&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;240727_이수진_발표자료(공유용).pdf&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;12.00MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>인공지능(AI)/deep learning(딥러닝)</category>
      <category>aiethics</category>
      <category>ai개발자</category>
      <category>ai기획자</category>
      <category>AI윤리</category>
      <category>GenAI</category>
      <category>GPT</category>
      <category>NLP</category>
      <category>RAG</category>
      <category>생성형ai</category>
      <category>인공지능윤리</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/671</guid>
      <comments>https://lsjsj92.tistory.com/671#entry671comment</comments>
      <pubDate>Mon, 29 Jul 2024 08:37:12 +0900</pubDate>
    </item>
    <item>
      <title>LLM과 추천 시스템을 결합해 설명가능성(Explainability) 제공하기(Feat. LangChain, GPT-4o)</title>
      <link>https://lsjsj92.tistory.com/670</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 OpenAI에서 GPT-4o 등이 나오는 등 LLM(Large Language Models)의 발전은 계속 진행되고 있습니다. 그러면서 동시에 LLM과 다양한 application, 다양한 domain, 다양한 downstream task와 어떻게 연계할 수 있는가도 지속적으로 연구되고 있는데요. 본 포스팅은 추천 시스템(Recommendation System) 영역에서 LLM을 어떻게 연결시킬 수 있는지를 고민합니다. 그리고 추천 시스템 연구에서 가장 중요하게 고민되고 있는 설명가능성(Explainbility)를 해결하기 위해 LLM과 결합해하여 설명가능성을 부여하는 방법 에 대해 알아보고 파이썬(Python) 코드로 예제(example)를 구현해보겠습니다.&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;본 포스팅 외에도 저는 이전에 OpenAI ChatGPT API를 활용한 추천 시스템 포스팅을 작성한 적이 있습니다. 비록 시간이 꽤나 지난 글이지만, 해당 글의 확장 버전이라고 생각해주시면 감사하겠습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/657&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/657&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1717206965749&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;OpenAI ChatGPT API를 활용해 추천 시스템 구현하기(feat. HuggingFace)&quot; data-og-description=&quot;포스팅 개요 최근 OpenAI에서 ChatGPT의 공식 API가 드디어 공개되었습니다. ChatGPT는 계속해서 이슈가 대두되고 있는 굉장한 모델인데요. 이번 포스팅에서는 파이썬(Python) 환경에서 OpenAI의 ChatGPT API&quot; data-og-host=&quot;lsjsj92.tistory.com&quot; data-og-source-url=&quot;https://lsjsj92.tistory.com/657&quot; data-og-url=&quot;https://lsjsj92.tistory.com/657&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cgxbHx/hyWdnkwslc/IrpvWmFq8xMaxlK5ATg5XK/img.png?width=800&amp;amp;height=406&amp;amp;face=0_0_800_406,https://scrap.kakaocdn.net/dn/Ej7um/hyWdoDJSYW/CKQMagdFf1XwPUeOm9Fo0k/img.png?width=800&amp;amp;height=406&amp;amp;face=0_0_800_406,https://scrap.kakaocdn.net/dn/eRnvq/hyWdiwMsVA/xScNDIuJKzmvs2mkq8Z8wK/img.png?width=762&amp;amp;height=733&amp;amp;face=0_0_762_733&quot;&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/657&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://lsjsj92.tistory.com/657&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cgxbHx/hyWdnkwslc/IrpvWmFq8xMaxlK5ATg5XK/img.png?width=800&amp;amp;height=406&amp;amp;face=0_0_800_406,https://scrap.kakaocdn.net/dn/Ej7um/hyWdoDJSYW/CKQMagdFf1XwPUeOm9Fo0k/img.png?width=800&amp;amp;height=406&amp;amp;face=0_0_800_406,https://scrap.kakaocdn.net/dn/eRnvq/hyWdiwMsVA/xScNDIuJKzmvs2mkq8Z8wK/img.png?width=762&amp;amp;height=733&amp;amp;face=0_0_762_733');&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;OpenAI ChatGPT API를 활용해 추천 시스템 구현하기(feat. HuggingFace)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 개요 최근 OpenAI에서 ChatGPT의 공식 API가 드디어 공개되었습니다. ChatGPT는 계속해서 이슈가 대두되고 있는 굉장한 모델인데요. 이번 포스팅에서는 파이썬(Python) 환경에서 OpenAI의 ChatGPT API&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;lsjsj92.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;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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://grouplens.org/datasets/movielens/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://grouplens.org/datasets/movielens/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/langchain-ai/langchain&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/langchain-ai/langchain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://platform.openai.com/docs/models/gpt-4o&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://platform.openai.com/docs/models/gpt-4o&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1717207207611&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 - langchain-ai/langchain:   Build context-aware reasoning applications&quot; data-og-description=&quot;  Build context-aware reasoning applications. Contribute to langchain-ai/langchain development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/langchain-ai/langchain&quot; data-og-url=&quot;https://github.com/langchain-ai/langchain&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/OV1Jg/hyWde8YIkI/RdRMKTdWJ3xOawFiISmaBk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/langchain-ai/langchain&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/langchain-ai/langchain&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/OV1Jg/hyWde8YIkI/RdRMKTdWJ3xOawFiISmaBk/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 - langchain-ai/langchain:   Build context-aware reasoning applications&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  Build context-aware reasoning applications. Contribute to langchain-ai/langchain 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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅에서 사용한 코드(code)는 아래 github에 10번으로 올려두었습니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lsjsj92/recommender_system_with_Python&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/lsjsj92/recommender_system_with_Python&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1717207017813&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 - lsjsj92/recommender_system_with_Python: recommender system tutorial with Python&quot; data-og-description=&quot;recommender system tutorial with Python. Contribute to lsjsj92/recommender_system_with_Python development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/lsjsj92/recommender_system_with_Python&quot; data-og-url=&quot;https://github.com/lsjsj92/recommender_system_with_Python&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bTBUD5/hyWdk2pVFT/xQS7QSvexGyuEbJAphRTPK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/lsjsj92/recommender_system_with_Python&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/lsjsj92/recommender_system_with_Python&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bTBUD5/hyWdk2pVFT/xQS7QSvexGyuEbJAphRTPK/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 - lsjsj92/recommender_system_with_Python: recommender system tutorial with Python&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;recommender system tutorial with Python. Contribute to lsjsj92/recommender_system_with_Python 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;
&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;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 제가 생각하는 LLM과 추천 시스템을 결합하는 연구 방법에 대해서 간단히 알아보고 LLM이 추천 시스템에 활용될 수 있는 다양한 방법 중 추천 시스템에 설명가능성(Explainability of the recommender system)을 부여하는 방법을 파이썬(Python) 코드 예제(example)로 구현해보고자 합니다.&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;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;LLM과 추천 시스템을 결합하는 연구 방향&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 LLM과 추천 시스템을 같이 활용하는 논문들을 읽으면서, 관련 연구의 추세는 크게 다음 2가지로 분류되고 있다고 생각됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;1. LLM(Large Language Models)를 추천 시스템으로 사용하는 방법&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법은 LLM을 추천 시스템 모델로써 기능을 수행하도록 하는 방법입니다. 자연어 기반 쿼리를 활용해서 LLM에 직접 추천을 요청하는 방법이죠. LLM을 파인튜닝(Fine-tuning)해서 사용하기도 합니다. 사용자와 아이템간의 interaction을 텍스트 prompt로 변환해 LLM을 학습시키는 방법이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;2. LLM이 가지고 있는 추론 능력과 방대한 지식으로 추천 시스템을 강화하는 방법&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법은 LLM이 가지고 있는 reasoning ability(추론 능력)과 모델이 가지고 있는 방대언 지식을 활용해 추천 시스템을 강화하는 방법입니다. 예를 들어서, 메타 데이터를 더 다양하게 만들어주거나, 요약 정보를 만들어주거나, LLM에서 나오는 embedding을 활용한다던가 등 다양하게 활용하는 것이죠.&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;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;추천 시스템과 설명가능성(Recommender System and Explainability)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추천 시스템에서 설명가능성(Explainability)는 사용자가 왜 이 아이템이 나에게 추천 되었는지를 이해할 수 있도록 도와주는 방법입니다. 이는 추천 시스템과 추천 시스템을 제공하는 서비스 입장에서 사용자에게 어떤 신뢰(Trust)를 주기도 합니다. 사용자가 이 추천을 받았던 것에서 reasonable하게 이해한다면, 서로간의 신뢰감을 쌓을 수 있기 때문이죠.&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;반면, LLM은 방대한 양의 텍스트 데이터를 학습한 모델입니다. 그렇기에 다양한 자연어(NLP) 문제들을 해결할 수 있으며 생성형(Generation) 모델이기 때문에 언어를 이해하고 생성할 수 있죠. 특히, 요약, 정리 등의 task는 우수하다고 익히 알려져 있습니다. 즉, LLM과 추천 시스템(recommender system with LLM)을 활용하면 LLM이 가지고 있는 지식을 활용해서 추천 시스템의 설명력을 제공할 수 있을 것입니다. 또한, RAG(Retrieval-Augmented Generation)을 활용하면 LLM의  할루시네이션을 방지하면서도 설명력을 제공할 수 있을 것입니다. 즉, 추천 시스템과 LLM을 결합하는 방법 중 2번 방법에 해당된다고 할 수 있습니다.&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;LLM을 활용한 추천 시스템 설명가능성 Python으로 구현하기&lt;br /&gt;(Implementing the explainability of recommener system using LLM in Python)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 본격적으로 LLM을 활용해 추천 시스템의 설명가능성을 부여할 수 있도록 Python 코드로 간단히 구현해보겠습니다. 앞서 소개에서 말씀드렸듯, 본 코드는 github에 올려두었으니 참고해주시면 감사하겠습니다.&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;파이썬으로  LLM기반 추천 시스템 설명가능성(LLM based explainability recommender system)을 구현하기 위해서 본 포스팅에서는 총 6단계를 거쳐서 진행하게 됩니다.&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. 활용 데이터 셋팅&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 훈련된 사전 랭킹 모델(NCF 모델) 가져오기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 사용자에게 제공되는 추천 셋 구성(model prediction)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 사용자 이력 기반의 text prompt 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 사용자 요약 정보와 페르소나 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. LLM 기반 추천 시스템 결과 설명 가능성 제공&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&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;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;1. 활용 데이터 셋팅(Set data)&lt;/b&gt;&lt;/span&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;가장 먼저, 사용할 데이터를 셋팅합니다. 본 포스팅에서 사용하는 추천 시스템 데이터는 MovieLens1M을 사용합니다. MovieLens1M 데이터는 추천 시스템 데이터에서 널리 알려진 데이터입니다. MovieLens 데이터는 사용자가 영화를 시청하고 평가한 데이터가 저장되어 있는데요. 저는 사용자가 평가를 진행했으면, 상호작용(Interaction) 했다고 가정하고 1로 셋팅해두었습니다. 그리고 사용자가 상호작용 하지 않은 데이터 중에서 negative sampling을 수행했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 예시는 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gl6Vw/btsHKIwHsRN/LrmSbHrInSguWwgDXqEPn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gl6Vw/btsHKIwHsRN/LrmSbHrInSguWwgDXqEPn0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;658&quot; data-filename=&quot;스크린샷 2024-06-01 오후 12.29.06.png&quot; width=&quot;536&quot; style=&quot;width: 31.6667%; margin-right: 10px;&quot; data-widthpercent=&quot;32.04&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gl6Vw/btsHKIwHsRN/LrmSbHrInSguWwgDXqEPn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGl6Vw%2FbtsHKIwHsRN%2FLrmSbHrInSguWwgDXqEPn0%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;1568&quot; height=&quot;658&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d07cuR/btsHJCKWzid/KNSNMvaLqF9H2prFEB2L21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d07cuR/btsHJCKWzid/KNSNMvaLqF9H2prFEB2L21/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3326&quot; data-origin-height=&quot;658&quot; data-filename=&quot;스크린샷 2024-06-01 오후 12.30.28.png&quot; width=&quot;734&quot; style=&quot;width: 67.1705%;&quot; data-widthpercent=&quot;67.96&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d07cuR/btsHJCKWzid/KNSNMvaLqF9H2prFEB2L21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd07cuR%2FbtsHJCKWzid%2FKNSNMvaLqF9H2prFEB2L21%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;3326&quot; height=&quot;658&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;영화 및 사용자-아이템 상호작용 정보&lt;/figcaption&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;2. 훈련된 추천 시스템 모델 셋팅(Set recommender system)&lt;/b&gt;&lt;/span&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;사용자에게 최종 추천을 ranking을 수행하는 추천 모델을 셋팅합니다. 본 포스팅에서는 NCF(Neural Collaborative Filtering) 모델을 활용하는데요. 저는 지면상의 이유로 미리 MovieLens1M 데이터로 학습된 NCF 모델을 가져와서 사용합니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-06-01 오후 12.34.35.png&quot; data-origin-width=&quot;3596&quot; data-origin-height=&quot;1052&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMynH6/btsHLv4oL2O/mnUk3edyJyHK1dXe2DSJXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMynH6/btsHLv4oL2O/mnUk3edyJyHK1dXe2DSJXK/img.png&quot; data-alt=&quot;사전 학습된 모델을 가져옴. 해당 모델은 사용자에게 추천을 제공할 ranker로 동작됨&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMynH6/btsHLv4oL2O/mnUk3edyJyHK1dXe2DSJXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMynH6%2FbtsHLv4oL2O%2FmnUk3edyJyHK1dXe2DSJXK%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;3596&quot; height=&quot;1052&quot; data-filename=&quot;스크린샷 2024-06-01 오후 12.34.35.png&quot; data-origin-width=&quot;3596&quot; data-origin-height=&quot;1052&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사전 학습된 모델을 가져옴. 해당 모델은 사용자에게 추천을 제공할 ranker로 동작됨&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1717212904989&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;config = {
    'num_users': 6040,
    'num_items': 3706,
    'latent_dim_mf': 8,
    'latent_dim_mlp': 16,
    'layers': [32, 16, 8]
}
model = NeuMF(config)
model.load_state_dict(torch.load('./model/ncf_mlm'))&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;사전 학습된 NCF 모델은 MovieLens1M 데이터를 사용해 학습한 모델입니다. 해당 모델을 MovieLens1M 데이터로 학습하는 과정은 공개되어 있는 자료가 많으니, 참고해주시면 되겠습니다. 본 포스팅에서는 내용이 길어지므로 해당 과정은 생략하겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 저는 NCF 모델을 사용했지만, 다른 추천 시스템 모델을 사용하셔도 상관 없습니다. Ranker로써 동작할 수 있는 모델과 방법은 전부 사용가능하니 여러분들이 편하시고 익숙한 것을 사용하시길 바랍니다.&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;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;3. 사용자에게 제공할 추천 데이터 셋팅(Set item list of recommender system prediction output, Ranking result)&lt;/b&gt;&lt;/span&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번과 2번 과정에서 사용자 이력 정보와 추천 모델을 가져왔으니 이제 추천 모델의 예측 결과를 셋팅하겠습니다. 추천 모델의 예측 결과라는 것은 결국 사용자에게 추천 될 아이템 추천 리스트(recommended item list)라고 보시면 될 것 같습니다. 저는 테스트 셋 기준으로 사용자의 추천 셋을 구성하였습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1717214047159&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for user, data_info in tqdm(ncf_user_pred_info.items(), total=len(ncf_user_pred_info), position=0, leave=True):
    # sorted by high prop and slice by top(10)
    ranklist = sorted(data_info, key=lambda s : s[1], reverse=True)[:top]
    # to list
    ranklist = list(dict.fromkeys([r[0] for r in ranklist]))
    user_pred_info[str(user)] = ranklist&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;이렇게 추천 리스트를 저장하면 아래와 같이 파이썬 딕셔너리(Python dictionary) 형태로 데이터가 저장되게 됩니다.&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-filename=&quot;스크린샷 2024-06-01 오후 12.54.58.png&quot; data-origin-width=&quot;1684&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Pt7xj/btsHKLz4pMk/XEIMYAx1Nqa34ZQzPS172k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Pt7xj/btsHKLz4pMk/XEIMYAx1Nqa34ZQzPS172k/img.png&quot; data-alt=&quot;사용자에게 제공되는 영화(아이템) 추천 리스트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Pt7xj/btsHKLz4pMk/XEIMYAx1Nqa34ZQzPS172k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPt7xj%2FbtsHKLz4pMk%2FXEIMYAx1Nqa34ZQzPS172k%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;698&quot; height=&quot;121&quot; data-filename=&quot;스크린샷 2024-06-01 오후 12.54.58.png&quot; data-origin-width=&quot;1684&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사용자에게 제공되는 영화(아이템) 추천 리스트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item dable&quot; style=&quot;height: 250px;&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;300x250&lt;/div&gt;
    &lt;div id=&quot;dablewidget_Pl1aE8lE&quot; data-widget_id=&quot;Pl1aE8lE&quot;&gt;
      &lt;script&gt;(function(d,a,b,l,e,_) {
    if(d[b]&amp;&amp;d[b].q)return;d[b]=function(){(d[b].q=d[b].q||[]).push(arguments)};e=a.createElement(l);
    e.async=1;e.charset='utf-8';e.src='//static.dable.io/dist/plugin.min.js';
    _=a.getElementsByTagName(l)[0];_.parentNode.insertBefore(e,_);
    })(window,document,'dable','script');
dable('setService', 'lsjsj92.tistory.com');
dable('sendLogOnce');
dable('renderWidget', 'dablewidget_Pl1aE8lE', {ignore_items: true});&lt;/script&gt;
    &lt;/div&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;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;4. 사용자 이력 기반의 Text Prompt template 작성(Set user interaction history based Text Prompt template)&lt;/b&gt;&lt;/span&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;이제 본격적으로 LLM과 추천 시스템을 결합해 설명가능성을 추출하는 작업을 시작합니다. 가장 먼저, 사용자 이력을 기준으로 사용자의 특징(페르소나, persona) 정보를 추출하고 요약하려고 합니다. 이 과정을 수행하는 이유는 사용자의 페르소나와 요약 정보를 기반으로 LLM이 추천 된 결과와 비교해서 타당(reasonable)한지 타당하다면 이유가 무엇인지를 설명하도록 하려고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 크게 2가지 정보를 활용해서 사용자 페르소나 및 요약 정보를 추출하려고 하는데요. 이를 위해서 각각 text prompt template을 사용자 이력 기반으로 구성합니다.&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. 사용자 최근 이력 기반의 text prompt template&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1717214202266&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Recent user info
recent_ratio = int(sample_user_history.shape[0] * 0.1)
user_data = movielens_rcmm_origin[movielens_rcmm_origin['user_id'] == random_user[0]].fillna('non data')[['movie_decade', 'movie_year', 'rating_year', 'rating_decade', 'genre1', 'genre2', 'gender', 'age', 'zip']].values[:recent_ratio]
recent_user_hist_info = &quot;#### Item interaction information\n\n- (item) : metadata information of items \n- (user) : metadata information of users&quot;
for cnt, rows in enumerate(user_data):
    recent_user_hist_info += f&quot;\n\n{cnt+1}th.\n- (Item) Movie Release Decade (ex. 1990s movies): {rows[0]}\n- (Item) Movie Release Year: {rows[1]}\n- (User) Rating Year: {rows[2]}\n- (User) Rating Decade (e.g., 1990s ratings): {rows[3]}\n- (Item) Genre 1: {rows[4]}\n- (Item) Genre 2: {rows[5]}\n- (User) Gender: {rows[6]}\n- (User) Age: {rows[7]}\n- (User) Address Information (zipcode): {rows[8]}\n##### End of {cnt+1}th item interaction information&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;위 코드는 사용자의 최근 이력을 활용해서 텍스트 프롬프트를 구성하는 코드입니다. 이를 위해 최근 10%정도의 이력만 가져와서 text prompt를 구성합니다. text prompt에 들어가는 내용은 다음과 같습니다.&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;- Movie Release Decade : 00년대 영화와 같은 정보입니다. 예를 들어 1990년대 영화 형태이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Movie Release Year : 영화가 개봉한 년도입니다. 1994년과 같이 구체적인 년도 정보를 보여줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Rating decade : 사용자가 평점을 남긴 년대입니다. 1990년대에 평점을 남겼다 이런 정보를 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Rating year : 사용자가 평가를 남긴 년도입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Genre 1 : 영화가 가지고 있는 장르 정보입니다. MovieLens1M 데이터에서 영화가 가지고 있는 장르 정보 중 첫 번째 장르입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Genre 2 : Genre 1과 마찬가지로 장르 정보이며, MovieLens1M 데이터에서 영화가 가지고 있는 장르 정보 중 두 번째 장르입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Gender : 사용자의 성별입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Age : 사용자의 연령 정보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- zipcode :&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;이 정보를 text prompt에 구성해서 사용자의 최근 관심사 정보를 저장합니다.&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. 사용자의 전체 이력 기반의 text prompt template&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;이번에는 사용자의 전체 이력을 기준으로 text prompt template을 구성합니다. prompt에 들어가는 내용은 바로 위 1번과 동일합니다. 다만, 이력이 전체 이력 정보인 것만 다릅니다.&lt;/p&gt;
&lt;pre id=&quot;code_1717214222751&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Entire user history information
user_data = movielens_rcmm_origin[movielens_rcmm_origin['user_id'] == random_user[0]].fillna('non data')[['movie_decade', 'movie_year', 'rating_year', 'rating_decade', 'genre1', 'genre2', 'gender', 'age', 'zip']].values
user_all_hist_info = &quot;#### Item interaction information\n\n- (item) : metadata information of items \n- (user) : metadata information of users&quot;
for cnt, rows in enumerate(user_data):
    user_all_hist_info += f&quot;\n\n{cnt+1}th.\n- (Item) Movie Release Decade (ex. 1990s movies): {rows[0]}\n- (Item) Movie Release Year: {rows[1]}\n- (User) Rating Year: {rows[2]}\n- (User) Rating Decade (e.g., 1990s ratings): {rows[3]}\n- (Item) Genre 1: {rows[4]}\n- (Item) Genre 2: {rows[5]}\n- (User) Gender: {rows[6]}\n- (User) Age: {rows[7]}\n- (User) Address Information (zipcode): {rows[8]}\n##### End of {cnt+1}th item interaction information&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;아래 사진은 이렇게 구성된 텍스트 프롬프트 예시입니다. 이렇게 구성된 prompt template은 LLM의 입력으로 들어가게 되며 사용자의 요약 정보와 페르소나 정보를 추출하도록 LLM에게 지시하여 LLM이 관련 데이터를 구성하고 만들도록 합니다.&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-filename=&quot;스크린샷 2024-06-01 오후 12.57.26.png&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;1690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brVbuJ/btsHJCEbfQL/AWmu4Y8lM5F59FyMzOKOj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brVbuJ/btsHJCEbfQL/AWmu4Y8lM5F59FyMzOKOj1/img.png&quot; data-alt=&quot;text prompt 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brVbuJ/btsHJCEbfQL/AWmu4Y8lM5F59FyMzOKOj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrVbuJ%2FbtsHJCEbfQL%2FAWmu4Y8lM5F59FyMzOKOj1%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;491&quot; height=&quot;540&quot; data-filename=&quot;스크린샷 2024-06-01 오후 12.57.26.png&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;1690&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;text prompt 예시&lt;/figcaption&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;5.&amp;nbsp; 사용자 요약 정보와 페르소나 셋팅(Set user summary information and persona)&lt;/b&gt;&lt;/span&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;사용자의 interaction 이력 기반의 text prompt template 구성이 완료되었다면 이제 LLM에게 입력 데이터로 제공하여 사용자 요약 정보와 페르소나(persona) 정보를 생성하도록 지시합니다. 요약 정보를 구성하기 위한 데이터는 사용자 전체 이력 기반 text prompt를 사용합니다. 사용자의 전체 이력 기반으로 구성된 text prompt는 구성된 내용이 전체 이력 기반이므로 내용이 길 수 밖에 없습니다. 또한, 전체 이력이므로 전반적인 사용자의 선호 정보를 구성할 수 있을거라 가정하고 전체 이력 기반 text prompt template을 활용해 사용자 요약 정보를 생성합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1717214296870&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docs = []
text_splitter = RecursiveCharacterTextSplitter(chunk_size=550, chunk_overlap=100)
texts = text_splitter.split_text(user_all_hist_info)
docs += [Document(page_content=t) for t in texts]


template = '''Below is the user's past history information. Considering the user's main characteristics, persona, preferences, and meaningful patterns, please summarize the user information within 700 characters.\n\n##### User history information: {text}.'''
prompt = PromptTemplate(template=template, input_variables=['text'])
llm = ChatOpenAI(temperature=0, model='gpt-4o')


chain = load_summarize_chain(llm, 
                             chain_type='map_reduce', 
                             map_prompt=prompt, combine_prompt=prompt,
                             verbose=False)
summary = chain.run(docs)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&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;위 코드는 사용자의 요약 정보를 생성하기 위한 langchain 코드입니다. 텍스트 내용이 길기 때문에 RecursiveCharacterTextSpliter를 사용해서 텍스트를 chunk 단위로 잘라줍니다. 저는 chunk_size를 550, overlap을 100으로 설정하였습니다. 요약(summary)을 수행하기 위한 text prompt template에는 사용자의 주된 특징, 페르소나 선호도 등을 고려해서 700글자 내로 요약을 해달라고 지시하는 템플릿을 구성하였습니다. 이때 요약을 수행하는 LLM 모델로 이번에 새로 나온 GPT-4o를 활용하였으며 langchain에서 제공해주는 load_summarize_chain 함수를 사용해서 map_reduce 방법으로 사용자 정보 요약을 진행하였습니다. 요약을 수행한 결과는 아래와 같이 나오게 됩니다.&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-filename=&quot;스크린샷 2024-06-01 오후 12.58.32.png&quot; data-origin-width=&quot;3370&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cueHvw/btsHKR1bDVI/iykDkdtafpPJGtvFWMuwTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cueHvw/btsHKR1bDVI/iykDkdtafpPJGtvFWMuwTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cueHvw/btsHKR1bDVI/iykDkdtafpPJGtvFWMuwTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcueHvw%2FbtsHKR1bDVI%2FiykDkdtafpPJGtvFWMuwTK%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;3370&quot; height=&quot;424&quot; data-filename=&quot;스크린샷 2024-06-01 오후 12.58.32.png&quot; data-origin-width=&quot;3370&quot; data-origin-height=&quot;424&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;또한, 최근 이력 기반으로도 사용자의 선호 정보, 메인 특징, 페르소나를 추출하도록 합니다. 해당 데이터는 최근 이력 기반이라서 내용이 짧기 때문에 langchain의 LLMChain을 사용해서 실행하였습니다. LLM에게 수행하도록 하는 prompt template은 앞선 템플릿과 거의 동일합니다. 마찬가지로 사용자 정보를 추출할 때 사용하는 LLM은 gpt-4o를 사용하였으며 아래와 같이 chain.invoke 함수를 실행하면 LLM의 실행 결과를 받아볼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1717214374062&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template = &quot;&quot;&quot;Below is the user's item interaction history information. Using this data, please derive the user's main characteristics, persona, preferences, and meaningful patterns.

# User history information
{user_hist}

Please output in the following format:

- Main characteristics of the user: string
- User persona: string
- User preferences: string
- Meaningful patterns of the user: string

&quot;&quot;&quot;
prompt = PromptTemplate(template=template, input_variables=['user_hist'])

llm = ChatOpenAI(temperature=0, model='gpt-4o')
chain = LLMChain(llm=llm, prompt=prompt)
user_recent_summary = chain.invoke({'user_hist': recent_user_hist_info})&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;아래 사진은 LLMChain으로 실행된 최근 사용자 이력 기반의 특징 및 페르소나 정보입니다. 이제 이렇게 구성된 데이터를 활용해서 추천 시스템과 LLM을 결합한 설명가능성을 생성해보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-06-01 오후 12.59.46.png&quot; data-origin-width=&quot;3370&quot; data-origin-height=&quot;920&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxKUT9/btsHKmnermj/8L1twFErQOlnICcDcDKLj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxKUT9/btsHKmnermj/8L1twFErQOlnICcDcDKLj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxKUT9/btsHKmnermj/8L1twFErQOlnICcDcDKLj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxKUT9%2FbtsHKmnermj%2F8L1twFErQOlnICcDcDKLj1%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;3370&quot; height=&quot;920&quot; data-filename=&quot;스크린샷 2024-06-01 오후 12.59.46.png&quot; data-origin-width=&quot;3370&quot; data-origin-height=&quot;920&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;&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;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;6. LLM기반 추천 시스템 설명가능성 제공(Provide LLM-based recommendation system explainability)&lt;/b&gt;&lt;/span&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;드디어 본 포스팅의 마지막 단계인 LLM 기반 추천 시스템 설명가능성을 생성하는 단계입니다. 저희는 앞서&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;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;p data-ke-size=&quot;size16&quot;&gt;과정을 수행했습니다. 이제 사용자에게 추천되는 추천 리스트와 사용자의 요약, 페르소나 정보를 사용해서 recommender system이 사용자에게 아이템을 추천한 explainabiltiy를 생성해보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 사용자에게 추천 된 정보를 text prompt template으로 다시 변환해줍니다. 사용자의 추천 리스트가 무엇이고, 추천 된 item의 정보가 무엇인지 text로 구성해두는 것입니다. 이때 아이템의 정보는 제목, 장르, 개봉 년도와 같은 데이터입니다. 해당 작업을 진행하는 코드는 아래와 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1717214925885&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;user_data = user_recom_result[['title', 'movie_decade', 'genre']].values

user_recom_info = &quot;#### User Recommendation List\n\n&quot;
for cnt, rows in enumerate(user_data):
    user_recom_info += f&quot;\n\nRecommendation {cnt+1}:\n- Item Title: {rows[0]}\n- (Item) Movie Release Decade (e.g., 1990s movie): {rows[1]}\n- Item Genre (Category): {rows[2]}\n##### End of Recommendation {cnt+1} Information&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;이제 사용자의 persona 정보와 사용자에게 추천 된 item들로 만든 text template을 사용해 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;LLM에게&lt;span&gt; 왜 추천이 되었는지를 설명하도록 유도하는 prompt template을 구성합니다. 이 template은 LLM이 보기에 아이템이 사용자에게 적합한 추천이라면 추천 사유를 말해주도록 합니다. 만약, LLM이 판단하기에 이 아이템은 사용자에게 적합한 추천이 아니다라고 판단하면 적합한 추천이 아니라고 말하도록 합니다. prompt template 내용이 길어서 자세한 것은 코드를 참고해주시길 바랍니다. prompt template의 핵심은 다음과 같습니다.&lt;/span&gt;&lt;/span&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;- LLM 너의 역할은 사용자의 정보와 추천 시스템에서 제공하는 추천 결과를 비교하여 추천 이유를 작성하는 것이다.&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-06-01 오후 1.09.17.png&quot; data-origin-width=&quot;3370&quot; data-origin-height=&quot;1626&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpRBib/btsHKCXEDKp/sBZkbEjCGqyAloxnyaPdJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpRBib/btsHKCXEDKp/sBZkbEjCGqyAloxnyaPdJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpRBib/btsHKCXEDKp/sBZkbEjCGqyAloxnyaPdJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpRBib%2FbtsHKCXEDKp%2FsBZkbEjCGqyAloxnyaPdJK%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;3370&quot; height=&quot;1626&quot; data-filename=&quot;스크린샷 2024-06-01 오후 1.09.17.png&quot; data-origin-width=&quot;3370&quot; data-origin-height=&quot;1626&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;이렇게 text prompte를 작성하고 나서 Langchain의 PromptTemplate와 매칭시켜 LLM에게 해당 작업을 수행하도록 지시합니다. 그리고 그 결과는 아래와 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-06-01 오후 1.11.47.png&quot; data-origin-width=&quot;3496&quot; data-origin-height=&quot;1178&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUeDVA/btsHLOo8ZK1/HNU8gJLVVmJJzir77QIKWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUeDVA/btsHLOo8ZK1/HNU8gJLVVmJJzir77QIKWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUeDVA/btsHLOo8ZK1/HNU8gJLVVmJJzir77QIKWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUeDVA%2FbtsHLOo8ZK1%2FHNU8gJLVVmJJzir77QIKWK%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;3496&quot; height=&quot;1178&quot; data-filename=&quot;스크린샷 2024-06-01 오후 1.11.47.png&quot; data-origin-width=&quot;3496&quot; data-origin-height=&quot;1178&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;LLM이 판단하기에(여기서 LLM은 gpt-4o) 해당 추천 아이템이 적합하다면 적합하다고 말해줍니다. 그리고 추천이 적합하다는 이유도 말해주죠. 예를 들어서, 사용자의 decade를 기반으로 선호도가 있을 것이고 장르 기반으로도 봤을 때 사용자 선호도가 있을 것이라 판단된다고 말해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면, 적합하지 않다면 LLM은 does not aligh with the user's preference라고 말해줍니다. 또한, less suitable 또는 less fitting 이라고 하면서 그 추천에 적합하지 않은 이유를 말해주는 것을 확인할 수 있습니다.&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 추천 시스템 연구에서 자주 다뤄지는 설명가능성(Explainability of recommender system)을 LLM으로 시도해보는 간단한 방법과 example을 정리한 포스팅입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM과 추천 시스템을 결합할 수 있는 방법에 대해서 조금이라도 도움이 되시길 바랍니다.&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;저에게 연락을 주시고 싶으신 것이 있으시다면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Linkedin :&amp;nbsp;&lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot;&gt;&lt;span&gt;https://www.linkedin.com/in/lsjsj92/&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;github :&amp;nbsp;&lt;a href=&quot;https://github.com/lsjsj92&quot;&gt;&lt;span&gt;https://github.com/lsjsj92&lt;/span&gt;&lt;/a&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;</description>
      <category>인공지능(AI)/추천시스템</category>
      <category>explainability</category>
      <category>GenAI</category>
      <category>gpt-4o</category>
      <category>langchain</category>
      <category>LLM</category>
      <category>Python</category>
      <category>recommendationsystem</category>
      <category>recommendersystem</category>
      <category>설명가능성</category>
      <category>추천시스템</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/670</guid>
      <comments>https://lsjsj92.tistory.com/670#entry670comment</comments>
      <pubDate>Tue, 4 Jun 2024 09:35:15 +0900</pubDate>
    </item>
    <item>
      <title>개인화를 고려한 LLM 모델 기반 추천 시스템 - PALR 추천 시스템 논문 리뷰</title>
      <link>https://lsjsj92.tistory.com/669</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 추천 시스템 방법 중 추천(Recommendation)을 위해 개인화를 고려한 LLM 모델 및 방법을 소개한 PALR: Personalization Aware LLMs for Recommendation 논문을 리뷰하고 정리하는 포스팅입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대규모 언어 모델(Large Language models, LLM)을 활용한 다양한 추천 시스템 방법들이 소개되고 있는데요. 본 논문은 LLM을 통해 사용자 정보를 추출하고 LLM에서 발생할 수 있는 할루시네이션 등을 방지할 수 있도록 후보 셋을 제공하는 등의 방법론을 제시합니다. 또한, 저자들은 추천 시스템을 수행하기 위한 LLM 파인튜닝(fine-tuning) 방법도 소개합니다. 본 논문은 저자들이 아마존 알렉사(Amazon Alexa) 소속인 것이 큰 특징이며 본 논문을 통해 해당 조직에서 고민하고 있는 추천 시스템과 LLM의 결합에 대해서 간접적으로나마 살펴볼 수도 있습니다. 본 논문은 아래 링크에서 확인할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/pdf/2305.07622&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/pdf/2305.07622&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-05-19 오전 12.37.06.png&quot; data-origin-width=&quot;3104&quot; data-origin-height=&quot;988&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QVgLH/btsHunTd5Iq/dJ3lXmcNbgLeWfiEYAah3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QVgLH/btsHunTd5Iq/dJ3lXmcNbgLeWfiEYAah3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QVgLH/btsHunTd5Iq/dJ3lXmcNbgLeWfiEYAah3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQVgLH%2FbtsHunTd5Iq%2FdJ3lXmcNbgLeWfiEYAah3k%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;3104&quot; height=&quot;988&quot; data-filename=&quot;스크린샷 2024-05-19 오전 12.37.06.png&quot; data-origin-width=&quot;3104&quot; data-origin-height=&quot;988&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 추천 시스템을 위해 개인화를 고려한 LLM 모델 및 방법을 소개한 논문, PALR(Personalization Aware LLMs for Recommendation)을 리뷰하는 포스팅입니다. 먼저, 논문의 핵심 요약부터 정리한 후 논문이 진행되는 순서대로 Introduction부터 실험 결과까지 살펴보겠습니다.&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;본 논문은 클릭, 구매, 평점과 같은 사용자 행동 이력을 대규모 언어 모델(Large Language Models, LLM)과 통합하여 사용자가 선호하는 아이템 리스트를 생성하는 PALR(Personalization Awareness LLMs for Recommendation)을 소개합니다. 이때, 사용자 아이템 상호 작용을 사용해서 후보 검색(candidate retrieval)을 검색하기 위한 가이드로 사용하고 그 다음 LLM 모델 기반 랭킹 모델을 사용해 추천 리스트를 생성하도록 제안합니다. 이때 저자들은 llama 7b 모델을 사용해서 파인 튜닝(fine-tuning)을 진행해서 랭킹 모델을 구성합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, 아래와 같이 3가지 핵심 과정을 수행합니다. 1) Natural Language user profile 과정은 사용자의 선호도를 추출하는 프로세스이며, 사용자의 과거 히스토리를 활용해 추출합니다. 2) Candidate retrieval 과정은 할루시네이션 등의 LLM의 불완전성을 해결하기 위해 LLM 모델에게 후보 셋을 제공해주는 것입니다. 이때, retrieval model로는 다양한 모델을 사용할 수 있습니다. 3) Item recommendation 과정은 사용자 interaction과 프로필, candidate set(후보셋)에 기반해서 prompt를 생성해 LLM에 넣어줘 랭킹을 수행하게 합니다.&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;/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;Introduction&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 LLM을 추천 시스템에 사용하면 몇 가지 장점을 보인다고 말합니다.&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) LLM을 사용하면 아이템에 대해 사전에 훈련된 임베딩(pre-trained embeddings)의 필요성을 무효화할 수 있고 아이템을 텍스트로 표시할 수 있습니다. 이 장점은 특히, 새로운 아이템이 지속적으로 등장하는 industry에서 중요하다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) LLM을 사용하면 메타데이터, 컨텍스트와 같은 다양한 데이터를 모델의 프롬프트(prompt)에 활용해서 recommendation process에 쉽게 통합할 수 있다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) LLM은 광범위한 사전 훈련(extensive pre-training)을 통해 가지고 있는 방대한 지식과 우수한 추론(reasoning) 능력을 보유하고 있습니다. 이에 사람이 읽을 수 있는 설명으로 추천을 제공해서 사용자의 신뢰(trust)와 참여(engagement)를 향상 시킬 수 있다고 합니다.&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;그러나 저자들은 범용 목적(general purpose) LLM에 저장된 지식을 직접 활용해 추천 아이템을 생성하는 것은 어렵다고 하는데요. 그 이유는 아래와 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) LLM과 추천 해야할 아이템 사이의 지식 차이(knowledge gap)이 있을 수 있습니다. 예를 들어서 새로 출시된 아이템은 LLM이 모를 수 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) LLM은 불완전하고 할루시네이션 결과를 생성하는 경향이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) LLM은 입력 토큰 길이와 더불어 효율성에 대한 제한이 있습니다. 그렇기 때문에 최근 연구들에서는 LLM을 recommendation system의 시나리오 지식 기반이 아닌, 요약(summary) 및 추론 엔진(reasoning engine)으로 다루고 있었다고 합니다.&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;따라서, 저자들은 본 논문에서 사용자 행동과 LLM을 결합한 개인화 된 추천 방법인 PALR을 제안합니다. 처음에는 사용자 행동(user behavior)을 LLM의 입력으로 넣어 사용자 프로필 키워드를 생성하고 이후 검색 모듈을 사용해 사용자 프로필을 기반으로 아이템 풀에서 후보 아이템(candidate item)을 필터링합니다. 최종적으로 LLM을 사용해 사용자 행동 히스토리를 기반으로 candidate로부터 추천을 제공하게 됩니다. 이때 사용되는 LLM은 일반적으로 범용적으로 사용되는 LLM(general-purpose LLM)을 recommendation에 맞게 조절하기 위해서 파인튜닝(fine-tuning) 작업을 진행합니다. 이를 통해 사용자 행동 데이터를 LLM의 reasoning process에 통합하고 사용자와 unseen item에 대해 효과적으로 일반화 할 수 있다고 말합니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-05-19 오전 12.35.41.png&quot; data-origin-width=&quot;1726&quot; data-origin-height=&quot;1836&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bn2xKe/btsHujjdwf6/H1JcTloQLPWLoIkv7neKfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bn2xKe/btsHujjdwf6/H1JcTloQLPWLoIkv7neKfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bn2xKe/btsHujjdwf6/H1JcTloQLPWLoIkv7neKfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbn2xKe%2FbtsHujjdwf6%2FH1JcTloQLPWLoIkv7neKfK%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;465&quot; height=&quot;495&quot; data-filename=&quot;스크린샷 2024-05-19 오전 12.35.41.png&quot; data-origin-width=&quot;1726&quot; data-origin-height=&quot;1836&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;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item dable&quot; style=&quot;height: 250px;&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;300x250&lt;/div&gt;
    &lt;div id=&quot;dablewidget_Pl1aE8lE&quot; data-widget_id=&quot;Pl1aE8lE&quot;&gt;
      &lt;script&gt;(function(d,a,b,l,e,_) {
    if(d[b]&amp;&amp;d[b].q)return;d[b]=function(){(d[b].q=d[b].q||[]).push(arguments)};e=a.createElement(l);
    e.async=1;e.charset='utf-8';e.src='//static.dable.io/dist/plugin.min.js';
    _=a.getElementsByTagName(l)[0];_.parentNode.insertBefore(e,_);
    })(window,document,'dable','script');
dable('setService', 'lsjsj92.tistory.com');
dable('sendLogOnce');
dable('renderWidget', 'dablewidget_Pl1aE8lE', {ignore_items: true});&lt;/script&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;PALR Framework&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Figure 1은 저자들이 제시한 PALR 프레임워크입니다. 저자들이 제시한 추천 시스템을 위한 LLM 프레임워크를 보면, 중요한 3개의 스텝이 있는데요. 하나는 Natural Language User Profile이라고 칭하는 초록색 박스 부분입니다. 두 번째는 Candidate retrieval이며, 마지막 세 번째는 아이템을 추천하는 Item recommendation 파트입니다. 각 기능이 무엇인지 하나하나 살펴보겠습니다.&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;Nature Language user profile generation(자연어로 생성하는 사용자 프로필)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 다양한 아이템들과 상호작용하고 복잡해지면 사용자 행동 데이터만을 사용해 정확한 추천을 제공하는 것이 어려울 수 있습니다. 이런 상황에서는 어찌보면 사용자 선호도를 요약(summarization)하는 것이 나을 수 있죠. 저자들은 대규모 언어 모델(LLM)을 활용해서 사용자의 선호도를 요약하는 방법을 제시합니다. 예를 들어서, 사용자의 음악 및 TV 시청 기록을 분석해 '팝 음악'을 선호한다던가, '판타지 영화'를 선호한다던가 등의 요약을 생성할 수 있죠. 사용자 선호 프로필은 아래와 같은 prompt를 사용해 추출했다고 저자들은 말합니다.&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-filename=&quot;스크린샷 2024-05-19 오전 12.35.58.png&quot; data-origin-width=&quot;3288&quot; data-origin-height=&quot;1616&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfqLYE/btsHtYzIBQ6/O9d6hBrqUnNuAbh2Pk35f1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfqLYE/btsHtYzIBQ6/O9d6hBrqUnNuAbh2Pk35f1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfqLYE/btsHtYzIBQ6/O9d6hBrqUnNuAbh2Pk35f1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfqLYE%2FbtsHtYzIBQ6%2FO9d6hBrqUnNuAbh2Pk35f1%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;685&quot; height=&quot;337&quot; data-filename=&quot;스크린샷 2024-05-19 오전 12.35.58.png&quot; data-origin-width=&quot;3288&quot; data-origin-height=&quot;1616&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Candidate retrieval(후보 검색)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM이 가지고 있는 본질적인 문제인 할루시네이션(환각)과 불완정성 문제를 해결하기 위해 검색 모듈을 사용합니다. LLM이 가지고 있는 지식을 사용하되, 후보 기반으로 필터링해서 관련이 없는 결과가 나오지 않도록 하는 것이죠. 이때 사용되는 후보 모델은 sequential recommendation model과 같은 다양한 모델을 사용할 수 있습니다.&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;Item recommendation(아이템 추천)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자의 아이템 상호작용 히스토리와 LLM이 생성한 사용자 프로필(Natural Language user profile) 그리고 검색된 후보 셋(retrieved candidates)를 결합해 추천을 위해 LLM에 제공할 수 있는 프롬프트(prompt)를 생성할 수 있습니다. LLM 모델은 reasoning 능력을 기반해서 후보 풀ㄹ에서 사용자 프로필에 가장 잘 맞는 아이템을 선택해 추천을 진행하게 됩니다. 사용자 프로필을 LLM으로 생성하는 프로세스와 마찬가지로 아이템 추천 단계에서도 LLM에 들어갈 prompt 설계가 필요하게 됩니다. 이 프롬프트 디자인은 다음, 파인튜닝 단계에서 살펴보겠습니다.&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;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;파인튜닝(Fine-tuning)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 1) 합리적으로 좋은 성능을 획득할 수 있고 2) 우리가 예상한대로 검색을 수행하게 하려면 파인튜닝(fine-tuning) 과정이 필요하다고 말합니다. 저자들은 그 중 instruction-base fine-tuning을 진행했다고 합니다. 저자들은 이 파인튜닝 단계에서 Recommend와 Recommend_Retrieval 두 가지 유형의 instruction을 만들었습니다.&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;Recommend&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Recommend 작업에는 사용자가 과거에 interaction한 아이템 목록이 최대 20개까지 표현되며, 이 작업에서의 모델의 목표는 사용자가 interaction할 'future' 아이템 리스트를 생성하는 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-05-19 오전 12.36.10.png&quot; data-origin-width=&quot;1540&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TDqfn/btsHueh1RhT/kvWJB9N6r44z63YfbBAa2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TDqfn/btsHueh1RhT/kvWJB9N6r44z63YfbBAa2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TDqfn/btsHueh1RhT/kvWJB9N6r44z63YfbBAa2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTDqfn%2FbtsHueh1RhT%2FkvWJB9N6r44z63YfbBAa2k%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;547&quot; height=&quot;168&quot; data-filename=&quot;스크린샷 2024-05-19 오전 12.36.10.png&quot; data-origin-width=&quot;1540&quot; data-origin-height=&quot;472&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;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&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;위 사진은 recommend fine-tuning 유형에서 사용하는 LLM의 prompt 예제입니다. Task Instruction에는 recommend 10 other movies base on user's watching history 즉, 사용자 히스토리 기반으로 10개의 영화를 추천하라는 instruction 문구가 있습니다. 입력 값으로는 사용자가 봤던 영화 히스토리를 넣어주고 그 결과로 사용자가 미래에 interaction 할 아이템 리스트를 추천하도록 프롬프트를 설계해뒀습니다. 저자들은 이를 PALR-v1이라고 칭합니다.&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;Recommend_Retrieval&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Recommend_retrieval이라고 불리우는 작업은 candidate items 목록에서 사용자가 미래에 상호작용할 아이템을 검색(retrieval)하도록 프롬프트를 셋팅합니다. candiate items 목록에는 후보로 지정된 아이템과 더불어서 negative item도 넣어져 있습니다.&amp;nbsp;&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-filename=&quot;스크린샷 2024-05-19 오전 12.36.15.png&quot; data-origin-width=&quot;1540&quot; data-origin-height=&quot;602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0zftg/btsHu6pWcQ0/RFlLibMP9x5CTWKyd6AXEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0zftg/btsHu6pWcQ0/RFlLibMP9x5CTWKyd6AXEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0zftg/btsHu6pWcQ0/RFlLibMP9x5CTWKyd6AXEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0zftg%2FbtsHu6pWcQ0%2FRFlLibMP9x5CTWKyd6AXEK%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;514&quot; height=&quot;201&quot; data-filename=&quot;스크린샷 2024-05-19 오전 12.36.15.png&quot; data-origin-width=&quot;1540&quot; data-origin-height=&quot;602&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;위 사진은 Recommend_retrieval 작업의 LLM 입력으로 넣는 prompt 예시입니다. 앞서 살펴본 Recommend와 차이가 있는 것을 알 수 있는데요. Task Instruction 메세지를 보면 Recommend 10 other movies based on user's watching history from the candidate list로 되어 있습니다. 즉, 사용자 히스톨 기반으로 10개의 영화를 추천하라는 것인데, 후보 리스트에 기반해서 추천하라는 것이죠. 그렇기에 Input에는 사용자가 과거에 interaction 했던 아이템 리스트 뿐만 아니라, candidates 리스트도 넣어주고 있습니다. output은 사용자가 interaction 할 아이템들을 추천하도록 리스트업 하는 것이죠. 저자들은 이를 PALR-v2라고 지정합니다.&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 과정이 retrieval-layer에 종속되지 않다는 것을 강조합니다. fine-tuning을 위한 목록의 구성은 retrieval layer와 바운딩 되어 있지 않는 것이죠. 또한, 사용자의 20%에 대해서만 파인튜닝을 진행했다고 저자들은 말합니다.&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;저자들은 개인화 추천 시스템을 구성하기 위해 개인화를 고려한 LLM 방법을 2개의 데이터 셋으로 평가를 진행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 셋은 Amazon beauty 데이터 셋과 다른 하나는 MovieLens-1m 데이터 셋입니다. 저자들은 이 데이터를 리뷰나 평가가 있으면 1, 아니면 0의 형식으로 변환하고 사용자가 interaction 했던 아이템을 시간 순서대로 정렬해 사용했습니다. 또한, 5개 미만인 사용자나 아이템은 삭제하였다고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평가는 NDCG(Normalized Discounted Cumulative Gain)과 HR(Hit Ratio)를 사용했으며, baseline 모델들은 BPR-MF, NCF, GRU4Rec, Caser, SASRec과 비교하여 평가를 측정했습니다.&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-filename=&quot;스크린샷 2024-05-19 오전 12.36.31.png&quot; data-origin-width=&quot;1626&quot; data-origin-height=&quot;1300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dyTHLQ/btsHt4s5xk6/N482uaBwpPZ6rBTka8U9j1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dyTHLQ/btsHt4s5xk6/N482uaBwpPZ6rBTka8U9j1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dyTHLQ/btsHt4s5xk6/N482uaBwpPZ6rBTka8U9j1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdyTHLQ%2FbtsHt4s5xk6%2FN482uaBwpPZ6rBTka8U9j1%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;429&quot; height=&quot;343&quot; data-filename=&quot;스크린샷 2024-05-19 오전 12.36.31.png&quot; data-origin-width=&quot;1626&quot; data-origin-height=&quot;1300&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;Table 2는 저자들이 실행한 실험의 결과를 보여줍니다. PALR-v2는 다른 모든 베이스라인 모델보다 두 개의 데이터 셋 모두에서 뛰어난 성능을 보여주는 것을 알 수 있습니다. PALR-v1과 v2를 비교해 봤을 때 후보 셋을 제공해주는 것이 중요하다는 것도 알 수 있죠. 저자들은 이상적으로 다양한 retrieval 방법과 PALR이 결합되어 효과적인 ranking model의 성능을 보여줄 수 있다고 하는데요. 저자들은 여기서 retrieval 모델을 SASRec를 사용했다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 SASRec와 PALR-v2의 성능 비교는 어떨까요? PALR-v2가 성능이 더 좋게 나오는데 이는 SASRec에서 제공하는 추천 결과보다 LLM을 적용 했을 때 더 우수하게 나왔다는 것을 보여줍니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 저자들은 fine-tuning에 대해서 중요한 고찰을 얻을 수 있었다고 하는데요. PALR-v1의 경우 fine-tuning 이전에는 추천 시스템 역할로써 인기 영화만 추천하는 경향이 있었다고 합니다. 하지만, fine-tuning 이후 LLM 모델은 사용자와 아이템 간의 미래에 상호 작용할 것을 고려해 추천을 해주는 것을 확인할 수 있었다고 합니다. 또한, PALR-v2는 additional instruction의 효과를 입증한 것도 보여줍니다.&amp;nbsp;&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;본 포스팅은 대규모 언어 모델(LLM)이 개인화된 추천을 생성하기 위한 프레임우크인 PALR 논문을 정리한 포스티입니다. 저자들은 추천 시스템 작업에서 LLM을 사용하는 이점을 1) 다양한 외부 지식을 쉽게 통합할 수 있다는 것 2) 복잡한 추천 시스템 시나리오에서 더 쉬운 경로(easier pathway)를 제공할 수 있다는 것입니다. 예를 들어서, 설명가능성(explainable)과 같은 것이 되겠죠.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들이 고민한 PALR 프레임워크를 기반으로 recommender system 영역에 LLM을 어떻게 통합하고 활용할 것인지에 대한 인사이트를 얻으셨으면 좋겠습니다.&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;저에게 연락을 원하신다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 링크드인 : &lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.linkedin.com/in/lsjsj92/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- github : &lt;a href=&quot;https://github.com/lsjsj92&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/lsjsj92&lt;/a&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;</description>
      <category>인공지능(AI)/추천시스템</category>
      <category>Finetuning</category>
      <category>GenAI</category>
      <category>LLM</category>
      <category>NLP</category>
      <category>Python</category>
      <category>recommendationsystem</category>
      <category>recommendersystem</category>
      <category>대규모언어모델</category>
      <category>자연어처리</category>
      <category>추천시스템</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/669</guid>
      <comments>https://lsjsj92.tistory.com/669#entry669comment</comments>
      <pubDate>Tue, 21 May 2024 09:54:12 +0900</pubDate>
    </item>
    <item>
      <title>vLLM 사용법 - LLM을 쉽고 빠르게 추론(inference) 및 API 서빙(serving)하기</title>
      <link>https://lsjsj92.tistory.com/668</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 대규모 언어 모델(Large Language Models, LLM)을 쉽고 빠르게 배포(deploy), 추론(inference) 및 서빙(serving)할 수 있는 vLLM 라이브러리에 대해서 알아봅니다. vLLM이란 무엇이고, vLLM을 사용해서 어떻게 LLM을 배포하고 실행하는지 예제(example) 형태로 정리합니다. 결과적으로 vLLM을 사용하면 빠른 속도로 LLM들을 API 형태로 서빙 및 배포할 수 있습니다.&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;vLLM과 관련된 글들은 아래와 같이 주제별로 분리되어 있습니다.&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&gt;vLLM 사용법과 소개 : 본 포스팅&lt;/li&gt;
&lt;li&gt;vLLM을 OpenAI 서버(server)로 배포하는 방법 : &lt;a style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot; href=&quot;https://lsjsj92.tistory.com/673&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/673&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OpenAI 서버로 배포된 vLLM을 랭체인(LangChain)과 연동하는 방법 : &lt;a href=&quot;https://lsjsj92.tistory.com/674&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lsjsj92.tistory.com/674&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1730236245019&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;vLLM을 OpenAI API server(OpenAI-Compatible Server)로 활용하는 방법 및 예제(example)&quot; data-og-description=&quot;포스팅 개요이번 포스팅은 대규모 언어 모델(Large Language Models, LLM)을 쉽고 빠르게 배포할 수 있는 vLLM 라이브러리를 활용해서 OpenAI API Server(OpenAI-Compatible Server)로 활용할 수 있는 방법을 알아봅니&quot; data-og-host=&quot;lsjsj92.tistory.com&quot; data-og-source-url=&quot;https://lsjsj92.tistory.com/673&quot; data-og-url=&quot;https://lsjsj92.tistory.com/673&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/9TE9z/hyXpzcNcz7/jeNfK8SD64EVETiuLqVO7K/img.png?width=800&amp;amp;height=269&amp;amp;face=0_0_800_269,https://scrap.kakaocdn.net/dn/bfOBDU/hyXpw1qiIZ/PkaYfOHmNhEKZNZsKc8ByK/img.png?width=800&amp;amp;height=269&amp;amp;face=0_0_800_269,https://scrap.kakaocdn.net/dn/RGWVC/hyXpq1cp64/7B61ObcEmRuBkOatVB8hwk/img.png?width=3174&amp;amp;height=738&amp;amp;face=0_0_3174_738&quot;&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/673&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://lsjsj92.tistory.com/673&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/9TE9z/hyXpzcNcz7/jeNfK8SD64EVETiuLqVO7K/img.png?width=800&amp;amp;height=269&amp;amp;face=0_0_800_269,https://scrap.kakaocdn.net/dn/bfOBDU/hyXpw1qiIZ/PkaYfOHmNhEKZNZsKc8ByK/img.png?width=800&amp;amp;height=269&amp;amp;face=0_0_800_269,https://scrap.kakaocdn.net/dn/RGWVC/hyXpq1cp64/7B61ObcEmRuBkOatVB8hwk/img.png?width=3174&amp;amp;height=738&amp;amp;face=0_0_3174_738');&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;vLLM을 OpenAI API server(OpenAI-Compatible Server)로 활용하는 방법 및 예제(example)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 개요이번 포스팅은 대규모 언어 모델(Large Language Models, LLM)을 쉽고 빠르게 배포할 수 있는 vLLM 라이브러리를 활용해서 OpenAI API Server(OpenAI-Compatible Server)로 활용할 수 있는 방법을 알아봅니&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;lsjsj92.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;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이번 포스팅을 작성하면서 참고한 자료는 아래와 같습니다.&lt;br /&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&gt;&lt;a href=&quot;https://docs.vllm.ai/en/latest/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;https://docs.vllm.ai/en/latest/&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vllm-project/vllm?tab=readme-ov-file&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;https://github.com/vllm-project/vllm?tab=readme-ov-file&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://python.langchain.com/docs/integrations/document_loaders/web_base/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;https://python.langchain.com/docs/integrations/document_loaders/web_base/&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://huggingface.co/yanolja/EEVE-Korean-Instruct-10.8B-v1.0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;https://huggingface.co/yanolja/EEVE-Korean-Instruct-10.8B-v1.0&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/pdf/2309.06180&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;https://arxiv.org/pdf/2309.06180&lt;/span&gt;&lt;/a&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;802&quot; data-origin-height=&quot;434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uNuDz/btsHcafpXRv/7sgU5dRUPhkjsKPk4wWF70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uNuDz/btsHcafpXRv/7sgU5dRUPhkjsKPk4wWF70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uNuDz/btsHcafpXRv/7sgU5dRUPhkjsKPk4wWF70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuNuDz%2FbtsHcafpXRv%2F7sgU5dRUPhkjsKPk4wWF70%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;802&quot; height=&quot;434&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;434&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅 개요에서도 언급하였듯이, 이번 포스팅은 vLLM을 이용해 쉽고 빠르게 대규모 언어 모델(LLM)을 배포하고 서빙할 수 있는 과정을 예제(example) 형태로 정리합니다. 본 포스팅의 순서는 다음과 같습니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;1. vLLM이란? vLLM이 무엇일까?&lt;br /&gt;2. vLLM 사용법&lt;br /&gt;2-1. vLLM 설치 방법&lt;br /&gt;2-2. vLLM 실행 예제 - 간단한 방법&lt;br /&gt;2-3. vLLM 실행 예제 - API 형태로 서빙 및 배포하기&lt;br /&gt;2-4. vLLM 실행 예제 - 채팅 템플릿으로 chatbot 포멧 구성&lt;br /&gt;2-5. vLLM 실행 예제 - 랭체인(LangChain)과 결합해 RAG 구성&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. vLLM이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 문서에 보면 vLLM에 대해서 다음과 같이 소개하고 있습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;vLLM is a fast and easy-to-user library for LLM inference and serving&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;즉, vLLM은 LLM 추론(inference) 및 서빙(serving)을 쉽고 빠르게 도와주는 라이브러리라는 것이죠. vLLM의 주요 특징을 정리하자면 다음과 같습니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;- state-of-the-art serving throughput을 보여줌. 즉, 서빙 처리 속도가 좋음&lt;br /&gt;- 페이지 어텐션(page attention) 방법으로 key, value 메모리를 효과적으로 관리&lt;br /&gt;- 입력으로 들어오는 요청(request)에 대해서 지속적인 배치(Continuous batching) 처리 가능&lt;br /&gt;- 양자화(Quantization) : GPTQ, AWQ, FP8 KV Cache 등&lt;br /&gt;- 허깅페이스(huggingface)와의 원할한 통합으로 인기 있는 LLM 모델을 사용할 수 있음&lt;br /&gt;- 분산 추론(distributed inference) 지원&lt;br /&gt;&amp;nbsp;&lt;br /&gt;등등 다양한 장점과 특징을 가지고 있는 라이브러리입니다. 이러한 vLLM을 사용한다면, LLM을 정말 빠르고 간단하게 추론 및 서빙할 수 있죠. vLLM은 논문도 나와있습니다. 주요 기법인 page attention 방법에 대해서 작성한 논문인데요. page attention 방법에 대해서 더 자세히 알고 싶으신 분들은 해당 논문을 참고하시면 되겠습니다. 포스팅 개요의 참고 자료에 arxiv 링크를 올려두었습니다.&amp;nbsp;&lt;br /&gt;이번 포스팅은 vLLM의 page attention 방법보다, 라이브러리를 사용해 LLM을 배포하는 과정에 대해서 집중하겠습니다.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. vLLM 사용법(vLLM example)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 본격적으로 vLLM 사용 방법에 대해서 예제를 살펴보겠습니다. 설치 방법부터 API 형태로 LLM을 서빙하는 예제를 하나씩 살펴보겠습니다.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;2-1. vLLM 설치 방법(vLLM install)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vLLM을 사용하는 방법은 간단합니다. 단순히 pip install로 설치하면 됩니다. 다만, 주의할 점이 있습니다. 바로 아래 사진과 같은 주의사항인데요.&lt;br /&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;705&quot; data-origin-height=&quot;229&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTf28J/btsHb7iMVE2/BxECkxkrwKoxq5SngJmE8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTf28J/btsHb7iMVE2/BxECkxkrwKoxq5SngJmE8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTf28J/btsHb7iMVE2/BxECkxkrwKoxq5SngJmE8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTf28J%2FbtsHb7iMVE2%2FBxECkxkrwKoxq5SngJmE8K%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;643&quot; height=&quot;209&quot; data-origin-width=&quot;705&quot; data-origin-height=&quot;229&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;글을 작성하고 있는 현재(24.5월 초) vLLM은 linux에서만 설치가 가능합니다. 즉, mac과 같은 OS에서는 지원을 해주지가 않습니다. 따라서 저도 리눅스 환경에서 vLLM을 배포했는데요. 만약 Mac에서 설치하려고 하면 다음과 같이 에러 메세지를 마주하게 됩니다.&lt;br /&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;1930&quot; data-origin-height=&quot;1266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXK7wQ/btsHaWbHpxm/DMobOXxIl8KX05KrbO0ZKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXK7wQ/btsHaWbHpxm/DMobOXxIl8KX05KrbO0ZKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXK7wQ/btsHaWbHpxm/DMobOXxIl8KX05KrbO0ZKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXK7wQ%2FbtsHaWbHpxm%2FDMobOXxIl8KX05KrbO0ZKK%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;694&quot; height=&quot;455&quot; data-origin-width=&quot;1930&quot; data-origin-height=&quot;1266&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;에러 메세지는 vLLM only supports Linux platform (including WSL)이라고 나오죠.&lt;br /&gt;그렇기에 vLLM은 linux에서 설치하고 실행할 수 있다는 점 참고해주시면 좋을 것 같습니다. 글을 작성한 이후에 언젠가는 mac 등 에서도 가능하도록 지원해주지 않을까 기대하고 있습니다.&lt;br /&gt;저는 ubuntu 20.04에서 vLLM을 설치한 후 진행했습니다.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;2-2. vLLM 실행 예제 - 간단한 사용법&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 본격적으로 vLLM을 사용해봅시다. 저는 vLLM을 활용해 huggingface 모델을 inference 및 서빙에 사용하려고 합니다. 제가 사용한 모델은 야놀자에서 제공해주신 EEVE instruct 10b 모델입니다. EEVE 모델은 뛰어난 한국어 성능을 가지고 있는 모델인데요. 이런 훌륭한 모델을 연구하고 올려주신 야놀차 측에 감사한 말씀드립니다.&lt;br /&gt;저는 허깅페이스에서 EEVE-Korean-Insstruct-10.8b-v1.0 모델을 제 ubuntu 환경 로컬에 다운로드 받아놨습니다. 제가 다운로드 받은 경로는 /home/lsjsj92/models 입니다. 이 경로는 여러분들이 원하시는 경로로 바꾸시면 됩니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;간단한 사용법을 먼저 살펴보겠습니다. 여기서 간단하게 vLLM을 사용하는 것은 API 형태로 serving 하는 것이 아니라, python 환경에서 vLLM을 사용해 LLM 모델을 로드하고 사용하는 방법입니다.&amp;nbsp;&lt;br /&gt;vLLM으로 모델을 불러오는 것은 아래와 같은 코드 1줄이면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;from vllm import LLM
llm = LLM(model=&quot;/home/lsjsj92/models/EEVE-Korean-Instruct-10.8B-v1.0&quot;, max_model_len=2048, tensor_parallel_size=2)&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;1165&quot; data-origin-height=&quot;452&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFfjnZ/btsHcSrOQc5/KjVx7IhkKY7mAkWgZ4tGeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFfjnZ/btsHcSrOQc5/KjVx7IhkKY7mAkWgZ4tGeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFfjnZ/btsHcSrOQc5/KjVx7IhkKY7mAkWgZ4tGeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFfjnZ%2FbtsHcSrOQc5%2FKjVx7IhkKY7mAkWgZ4tGeK%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;1165&quot; height=&quot;452&quot; data-origin-width=&quot;1165&quot; data-origin-height=&quot;452&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;위 코드를 실행하면 사진과 같이 어떤 실행 메세지가 나오면서 vLLM이 구동되는 것을 확인할 수 있습니다. 저는 vLLM을 호출할 때 max_model_len과 tensor_parallel_size를 사용했는데요. 각각의 의미는 다음과 같습니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;- &lt;b&gt;max_model_len&lt;/b&gt; : 모델이 지원해주는 최대 시퀀스 길이입니다. 더 짧게도 가능하며, 모델이 지원해주는 가장 큰 값으로도 가능합니다. 저는 2048로 임의로 셋팅했습니다.&lt;br /&gt;- &lt;b&gt;tensor_parallel_size&lt;/b&gt; : 앞서 vLLM을 소개할 때 vLLM은 분산 추론(distrubuted inference)를 지원한다고 언급했는데요. 더 자세히 말하면 분산 텐서 병렬(distributed tenwor parallel)기반 inference 및 serving을 지원하는 것입니다. 이때 vLLM은 Ray를 활용해 분산 런타임을 지원합니다. 따라서 Python Ray가 설치되어 있어야하며, 이를 활용하면 쉽고 간단하게 gpu 등을 병렬로 처리할 수 있습니다. 저는 2라고 셋팅해서 2개의 gpu를 사용하도록 설정했습니다.&lt;br /&gt;이렇게 올라온 모델을 사용해 이제 텍스트를 생성하는 text generate를 실행해보겠습니다. 다음과 같이 실행하면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;output = llm.generate(&quot;쓰고 싶으신 말&quot;)&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;1205&quot; data-origin-height=&quot;298&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lLvPO/btsHaR2BVB9/jynIEYA1jIhPUVaqYJgrF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lLvPO/btsHaR2BVB9/jynIEYA1jIhPUVaqYJgrF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lLvPO/btsHaR2BVB9/jynIEYA1jIhPUVaqYJgrF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlLvPO%2FbtsHaR2BVB9%2FjynIEYA1jIhPUVaqYJgrF0%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;1205&quot; height=&quot;298&quot; data-origin-width=&quot;1205&quot; data-origin-height=&quot;298&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;저는 llm.generate(&quot;안녕하세요. 저는 이수진이라고 합니다. 오늘 날씨는&quot;)까지 입력해두었습니다. 그리고 뒷 부분은 vLLM이 띄운 EEVE 10b 모델이 생성하도록 둔 것이죠. LLM은 저의 입력을 받고 &quot;쌀쌀하고 건조해서 자켓을 입고 나왔어요&quot;라는 문장을 생성해줍니다.&lt;br /&gt;어떤가요? 정말 간단하지 않나요? 단 코드 2~3줄로 LLM 추론(inference)에 성공했습니다.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;2-3. vLLM 실행 예제 - API 형태로 배포하기&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위처럼 간단하게 vLLM을 사용할 수 있지만, 사실 API 형태로 serving 및 배포해야 RAG 구성이나 실제 사용자, 개발자들이 사용하기 용이할 것입니다. vLLM의 큰 장점은 API 형태로 쉽고 간편하게 LLM을 서빙해서 inference할 수 있다는 것인데요. vLLM이 설치된 환경에서 CLI에 다음과 같이 명령어를 입력하면 LLM api server 형태로 serving 할 수 있습니다.&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;python -m vllm.entrypoints.api_server \
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--model /home/lsjsj92/models/EEVE-Korean-Instruct-10.8B-v1.0 \
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--max-model-len=2048 \
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--tensor-parallel-size 2&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;548&quot; data-origin-height=&quot;104&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EaUPM/btsHcbZG2sZ/UAc8FIxvQI4pvNsudp8Ji1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EaUPM/btsHcbZG2sZ/UAc8FIxvQI4pvNsudp8Ji1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EaUPM/btsHcbZG2sZ/UAc8FIxvQI4pvNsudp8Ji1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEaUPM%2FbtsHcbZG2sZ%2FUAc8FIxvQI4pvNsudp8Ji1%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;548&quot; height=&quot;104&quot; data-origin-width=&quot;548&quot; data-origin-height=&quot;104&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;위 명령어는 다음과 같이 해석할 수 있을 것입니다.&lt;br /&gt;- vllm entropoint로 api server를 사용할 것&lt;br /&gt;- &lt;b&gt;model&lt;/b&gt; : 내가 사용하고자 하는 모델. 저는 현재 local에 받아놓은 EEVE-korean-instruct-10.8B-v1.0을 사용합니다.&lt;br /&gt;- &lt;b&gt;max-model-len&lt;/b&gt; : 간단한 예제에서 살펴본 max_model_len과 동일한 기능&lt;br /&gt;- &lt;b&gt;tensor-parallel-size&lt;/b&gt; : 간단한 예제에서 살펴본 분산 텐서 병렬(distributed tenwor parallel)기반 inference 환경&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0AHC1/btsHaWv1kYD/ZprgOcJxuDdO2ftkJlQfJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0AHC1/btsHaWv1kYD/ZprgOcJxuDdO2ftkJlQfJK/img.png&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;165&quot; style=&quot;width: 60.4696%;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0AHC1/btsHaWv1kYD/ZprgOcJxuDdO2ftkJlQfJK/img.png&quot; alt=&quot;&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0AHC1%2FbtsHaWv1kYD%2FZprgOcJxuDdO2ftkJlQfJK%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;846&quot; height=&quot;165&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOYUGT/btsHcIitOVq/b4qOxq1W8ttGQDnK2MEYH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOYUGT/btsHcIitOVq/b4qOxq1W8ttGQDnK2MEYH0/img.png&quot; data-origin-width=&quot;1259&quot; data-origin-height=&quot;387&quot; style=&quot;width: 38.3676%;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOYUGT/btsHcIitOVq/b4qOxq1W8ttGQDnK2MEYH0/img.png&quot; alt=&quot;&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOYUGT%2FbtsHcIitOVq%2Fb4qOxq1W8ttGQDnK2MEYH0%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;1259&quot; height=&quot;387&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;명령어 입력이 잘 실행되었다면, 위 사진과 같이 FastAPI 형태로 vLLM serving 환경이 구성되어질 것입니다. 즉, vLLM을 사용하면 간단하게 LLM 모델들을 API 형태로 서빙이 가능하게 되는 것이죠. 이제 이 API를 호출해서 결과를 받아오면 됩니다. 만약 다음과 같이 입력을 넣었다면, vLLM으로 API serving한 콘솔에 아래 사진과 같은 로그가 남는 것을 확인할 수 있을겁니다.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;vllm_host = &quot;http://localhost:8000&quot;
url = f&quot;{vllm_host}/generate&quot;

headers = {&quot;Content-Type&quot;: &quot;application/json&quot;}
data = {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;prompt&quot;: &quot;안녕하세요. 나는 이수진입니다. 당신은 누구인가요?&quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;max_tokens&quot;: 2048,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;temperature&quot;: 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;1288&quot; data-origin-height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4MLaY/btsHcLfddPU/B0O3LgchKimoHZVM7oEwLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4MLaY/btsHcLfddPU/B0O3LgchKimoHZVM7oEwLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4MLaY/btsHcLfddPU/B0O3LgchKimoHZVM7oEwLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4MLaY%2FbtsHcLfddPU%2FB0O3LgchKimoHZVM7oEwLk%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;1288&quot; height=&quot;216&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;216&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;API 서버에서 사용자가 입력한 값을 받고 generation하는 과정을 볼 수 있습니다. 위 사진에서는 throughput으로 token이 어떻게 되고 있는지 running 상태를 확인할 수 있죠. 그러면 어떻게 실행했는지 궁금하실 겁니다. 아래 코드를 통해 vLLM을 통해 serving되고 있는 LLM의 결과를 받아올 수 있습니다.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;import requests
import json

# 호스트는 변경 가능합니다.
vllm_host = &quot;http://localhost:8000&quot;
url = f&quot;{vllm_host}/generate&quot;

headers = {&quot;Content-Type&quot;: &quot;application/json&quot;}
data = {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;prompt&quot;: &quot;안녕하세요. 나는 이수진입니다. 당신은 누구인가요?&quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;max_tokens&quot;: 2048,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;temperature&quot;: 0
}

response = requests.post(url, headers=headers, data=json.dumps(data))
print(response)
print(response.json())&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&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;711&quot; data-origin-height=&quot;864&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cb5t40/btsHapL0eKa/Lc5VabrpLejth7G6f80hA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cb5t40/btsHapL0eKa/Lc5VabrpLejth7G6f80hA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cb5t40/btsHapL0eKa/Lc5VabrpLejth7G6f80hA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcb5t40%2FbtsHapL0eKa%2FLc5VabrpLejth7G6f80hA1%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;711&quot; height=&quot;864&quot; data-origin-width=&quot;711&quot; data-origin-height=&quot;864&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;저는 시각적으로 잘 보여드리기 위해서 주피터 노트북 환경에서 실행해봤습니다. API 요청(request)에 필요한 헤더와 데이터를 넣어주는데요. 이때 데이터로는 vLLM serving으로 배포되어진 host와 입력하고 싶은 prompt 등이 있습니다. 제가 입력한 값은 다음과 같습니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;- &lt;b&gt;url&lt;/b&gt; : 본 예제애서는 localhost(127.0.0.1)로 해두었습니다. 이 값은 IP 주소로도 접근이 가능합니다.&lt;br /&gt;- &lt;b&gt;data&lt;/b&gt; : prompt에 원하는 메세지를 입력하시면 됩니다. 그리고 토큰과 temperature와 같은 요소를 지정할 수도 있습니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;그 결과는 request.post 함수를 실행해 받아올 수 있는데요. 정상적이라면 http 200 코드가 나올 것입니다. 또한, 모델이 생성한(본 예제에서는 EEVE 모델) 결과는 response.json()으로 볼 수 있습니다. 본 예제에서는 제가 입력한 &quot;안녕하세요. 나는 이수진입니다. 당신은 누구인가요?&quot;라는 말 이후로 LLM 모델이 생성한 텍스트를 확인할 수 있습니다.&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;또한, OpenAI API 형태로 배포할 수도 있는데요. 해당 방법은 &lt;a href=&quot;https://lsjsj92.tistory.com/673&quot;&gt;https://lsjsj92.tistory.com/673&lt;/a&gt; 를 참고해주시면 감사하겠습니다.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1730236208676&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;vLLM을 OpenAI API server(OpenAI-Compatible Server)로 활용하는 방법 및 예제(example)&quot; data-og-description=&quot;포스팅 개요이번 포스팅은 대규모 언어 모델(Large Language Models, LLM)을 쉽고 빠르게 배포할 수 있는 vLLM 라이브러리를 활용해서 OpenAI API Server(OpenAI-Compatible Server)로 활용할 수 있는 방법을 알아봅니&quot; data-og-host=&quot;lsjsj92.tistory.com&quot; data-og-source-url=&quot;https://lsjsj92.tistory.com/673&quot; data-og-url=&quot;https://lsjsj92.tistory.com/673&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/9TE9z/hyXpzcNcz7/jeNfK8SD64EVETiuLqVO7K/img.png?width=800&amp;amp;height=269&amp;amp;face=0_0_800_269,https://scrap.kakaocdn.net/dn/bfOBDU/hyXpw1qiIZ/PkaYfOHmNhEKZNZsKc8ByK/img.png?width=800&amp;amp;height=269&amp;amp;face=0_0_800_269,https://scrap.kakaocdn.net/dn/RGWVC/hyXpq1cp64/7B61ObcEmRuBkOatVB8hwk/img.png?width=3174&amp;amp;height=738&amp;amp;face=0_0_3174_738&quot;&gt;&lt;a href=&quot;https://lsjsj92.tistory.com/673&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://lsjsj92.tistory.com/673&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/9TE9z/hyXpzcNcz7/jeNfK8SD64EVETiuLqVO7K/img.png?width=800&amp;amp;height=269&amp;amp;face=0_0_800_269,https://scrap.kakaocdn.net/dn/bfOBDU/hyXpw1qiIZ/PkaYfOHmNhEKZNZsKc8ByK/img.png?width=800&amp;amp;height=269&amp;amp;face=0_0_800_269,https://scrap.kakaocdn.net/dn/RGWVC/hyXpq1cp64/7B61ObcEmRuBkOatVB8hwk/img.png?width=3174&amp;amp;height=738&amp;amp;face=0_0_3174_738');&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;vLLM을 OpenAI API server(OpenAI-Compatible Server)로 활용하는 방법 및 예제(example)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 개요이번 포스팅은 대규모 언어 모델(Large Language Models, LLM)을 쉽고 빠르게 배포할 수 있는 vLLM 라이브러리를 활용해서 OpenAI API Server(OpenAI-Compatible Server)로 활용할 수 있는 방법을 알아봅니&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;lsjsj92.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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;2-4. vLLM 실행 예제 - 채팅(chat) 템플릿으로 chatbot 포멧 구성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 예제에서는 vLLM을 통해 서빙된 모델이 huggingface 모델을 사용합니다. 그렇기 때문에 transformers 라이브러리에서 지원해주는 토크나이저(tokenizer)를 사용할 수 있는데요. 토크나이저에서 지원해주는 채팅 템플릿(chat template)을 사용하면 성능 좋은 채팅 형태의 LLM 결과를 받아올 수 있습니다. 이를 위해 필요한 핵심 코드는 다음과 같습니다.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;# huggingface 모델에서 토크나이저를 가져옴
tokenizer = AutoTokenizer.from_pretrained(&quot;/home/lsjsj92/models/EEVE-Korean-Instruct-10.8B-v1.0&quot;)

# 토크나이저에서 지원해주는 채팅 탬플릿 사용
text = tokenizer.apply_chat_template(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;messages,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tokenize=False,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;add_generation_prompt=True
)

# vLLM으로 서빙되고 있는 모델 호출
headers = {&quot;Content-Type&quot;: &quot;application/json&quot;}
data = {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;prompt&quot;: text,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;max_tokens&quot;: 2048,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;temperature&quot;: 0
}

response = requests.post(url, headers=headers, data=json.dumps(data))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;먼저, transformers 라이브러리에서 지원해주는 AutoTokenzier를 통해 huggingface 모델에서 사용된 토크나이저를 가지고 옵니다. 이 토크나이저는 apply_chat_template라는 함수를 제공해주는데요. apply_chat_template를 사용하면 본 모델에 적합한 채팅 형태의 포멧을 구성해줍니다. 이 포멧이 중요한 이유는 start와 end를 정확히 잡아내, 모델이 불필요한 말을 생성하지 않도록 구성할 수 있습니다. 이렇게 구성된 채팅 템플릿을 vLLM으로 서빙중인 LLM API로 보내면 LLM은 그에 맞은 답을 생성해줍니다.&lt;br /&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;1011&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IFqMN/btsHccdfkQn/09CFbBrUjngYCdwk0X5f5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IFqMN/btsHccdfkQn/09CFbBrUjngYCdwk0X5f5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IFqMN/btsHccdfkQn/09CFbBrUjngYCdwk0X5f5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIFqMN%2FbtsHccdfkQn%2F09CFbBrUjngYCdwk0X5f5K%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;1011&quot; height=&quot;708&quot; data-origin-width=&quot;1011&quot; data-origin-height=&quot;708&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;토크나이저를 생성한 뒤 apply_chat_template으로 채팅 탬플릿을 구성합니다. 채팅 탬플릿을 보면 im_start, im_end와 같이 어떤 포멧을 구성해준 것을 확인할 수 있습니다. 이렇게 구성된 템플릿을 vllm host에 API request를 보낼 때 data prompt로 보내주면 됩니다. 그 결과는 사진 아래쪽에 나와있는데요. 2-3에서 봤던 결과와 확연하게 차이가 나는 것을 보실 수 있을겁니다. 즉, 채팅 탬플릿을 적용했더니 결과가 채팅 형식으로 결과가 나오는 것을 확인할 수 있죠.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;2-5. vLLM 실행 예제 - LangChain과 결합하여 RAG 구성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 vLLM으로 배포된 LLM 모델을 활용해서 LangChain과 결합해 RAG를 간단하게 구성해보는 예제를 소개하겠습니다. 저는 langchain에서 지원해주는 webaseloader를 활용해 제 블로그 포스팅 자료를 벡터 DB(vectordb)로 구성하려고 합니다. 제가 webbaseloader로 가져오는 포스팅 글은, 이전에 작성한 LLM 기반 추천 시스템 논문인 LlamaRec 이라는 논문의 포스팅 글입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1085&quot; data-origin-height=&quot;395&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Qlzzo/btsHbkJT58i/9MOeKW92hl8KtxNpCg8z8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Qlzzo/btsHbkJT58i/9MOeKW92hl8KtxNpCg8z8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Qlzzo/btsHbkJT58i/9MOeKW92hl8KtxNpCg8z8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQlzzo%2FbtsHbkJT58i%2F9MOeKW92hl8KtxNpCg8z8K%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;1085&quot; height=&quot;395&quot; data-origin-width=&quot;1085&quot; data-origin-height=&quot;395&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;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item dable&quot; style=&quot;height: 250px;&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;300x250&lt;/div&gt;
    &lt;div id=&quot;dablewidget_Pl1aE8lE&quot; data-widget_id=&quot;Pl1aE8lE&quot;&gt;
      &lt;script&gt;(function(d,a,b,l,e,_) {
    if(d[b]&amp;&amp;d[b].q)return;d[b]=function(){(d[b].q=d[b].q||[]).push(arguments)};e=a.createElement(l);
    e.async=1;e.charset='utf-8';e.src='//static.dable.io/dist/plugin.min.js';
    _=a.getElementsByTagName(l)[0];_.parentNode.insertBefore(e,_);
    })(window,document,'dable','script');
dable('setService', 'lsjsj92.tistory.com');
dable('sendLogOnce');
dable('renderWidget', 'dablewidget_Pl1aE8lE', {ignore_items: true});&lt;/script&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;저는 langchain을 이용해서 아래와 같이 데이터 셋팅을 진행했습니다.&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;loader = WebBaseLoader(&quot;https://lsjsj92.tistory.com/667&quot;)

text_splitter = RecursiveCharacterTextSplitter(chunk_size=700, chunk_overlap=50)
texts = text_splitter.split_documents(data)


db = FAISS.from_documents(texts, embeddings)
db_retriever =&amp;nbsp;db.as_retriever(search_kwargs={&quot;k&quot;: 3})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&lt;b&gt;1.&lt;/b&gt; &lt;b&gt;loader&lt;/b&gt; :&amp;nbsp; 블로그의 글을 가져오기 위해서 webbaseloader를 사용했습니다.&lt;br /&gt;&lt;b&gt;2. Text Split&lt;/b&gt; : Langchain에서 지원해주는 RecursiveCharacterTextSplitter를 사용했습니다.&lt;br /&gt;&lt;b&gt;3. embedding&lt;/b&gt; : openAI embedding 등 원하시는 임베딩을 사용하시면 됩니다. 본 포스팅은 OpenAI embedding을 사용했습니다.&lt;br /&gt;&lt;b&gt;4. vector database&lt;/b&gt; : Langchain에서 지원해주는 벡터 데이터베이스를 사용하시면 됩니다. 본 포스팅은 FAISS를 사용했습니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;또한, 아래와 같이 사용자 질문이 발생하면 연관되어 있는 document를 가져오도록 했습니다. 이때, 가져온 document 내용을 하나의 문자열로 재구성하였습니다.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;user_query = &quot;Two-Stage Recommendation 방법이 뭐야?&quot;
docs = db_retriever.get_relevant_documents(f&quot;{user_query}&quot;)
temp_str = &quot;&quot;
for d in docs:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;temp_str += f&quot;내용 : {d.page_content}\n&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;이제 vLLM으로 serving중인 LLM에 API request를 보내면 되는데요. 저는 여기서 프롬프트를 좀 더 자세히 작성해봤습니다. 제가 작성한 프롬프트는 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;325&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z3B7G/btsHaULHsEY/JyRoLxuFeY5HKKV7CLw6Fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z3B7G/btsHaULHsEY/JyRoLxuFeY5HKKV7CLw6Fk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z3B7G/btsHaULHsEY/JyRoLxuFeY5HKKV7CLw6Fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz3B7G%2FbtsHaULHsEY%2FJyRoLxuFeY5HKKV7CLw6Fk%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;676&quot; height=&quot;325&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;325&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;위에서 소개한 간단한 prompt가 아니라, 불필요한 말은 하지 말아달라, 아래 내용을 참고해서 말을 해주세요 등의 구체적인 지시를 설정했습니다.&amp;nbsp;&lt;br /&gt;이제 이 결과를 LLM API로 request를 보내면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbPRTK/btsHbr24HxB/2PlzjaBv8xq5ubVKOCsbFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbPRTK/btsHbr24HxB/2PlzjaBv8xq5ubVKOCsbFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbPRTK/btsHbr24HxB/2PlzjaBv8xq5ubVKOCsbFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbPRTK%2FbtsHbr24HxB%2F2PlzjaBv8xq5ubVKOCsbFK%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;676&quot; height=&quot;240&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;240&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 LLM 모델을 쉽고 빠르게 배포, 서빙(serving) 및 추론(inference)할 수 있는 vLLM 라이브러리 사용 방법에 대해서 알아보았습니다.&lt;br /&gt;vLLM이 무엇인지, vLLM을 어떻게 사용하는지에 대한 예제(example)도 같이 작성해두었으니, vLLM을 사용하시는데 조금이라도 도움되시길 바랍니다. 감사합니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;저에게 연락을 주시고 싶으신 것이 있으시다면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Linkedin :&amp;nbsp;&lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot; target=&quot;_self&quot;&gt;&lt;span&gt;https://www.linkedin.com/in/lsjsj92/&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;github :&amp;nbsp;&lt;a href=&quot;https://github.com/lsjsj92&quot; target=&quot;_self&quot;&gt;&lt;span&gt;https://github.com/lsjsj92&lt;/span&gt;&lt;/a&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;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>GenAI</category>
      <category>huggingface</category>
      <category>LLM</category>
      <category>llm serving</category>
      <category>llm 배포</category>
      <category>NLP</category>
      <category>Python</category>
      <category>vllm</category>
      <category>대규모언어모델</category>
      <category>자연어처리</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/668</guid>
      <comments>https://lsjsj92.tistory.com/668#entry668comment</comments>
      <pubDate>Mon, 6 May 2024 10:12:58 +0900</pubDate>
    </item>
    <item>
      <title>LLM 기반 추천 시스템 논문 리뷰 - LlamaRec: Two-Stage Recommendation using LLM for ranking</title>
      <link>https://lsjsj92.tistory.com/667</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 추천 시스템에 대규모 언어 모델(Large Language Models, LLM)을 결합해 연구한 LlamaRec: Two-Stage Recommendation using Large Language Models for ranking이라는 논문을 읽고 정리한 포스팅입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 논문은 검색 단계인 retrieval 단계와 LLM 기반으로 만든 Ranking 단계로 구성되어 Two-Stage 방법을 제안하는데요. 그 결과로 효율성도 좋은 LLM 기반 추천 시스템을 구성할 수 있었다고 합니다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2311.02089&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/abs/2311.02089&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1714201420535&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;LlamaRec: Two-Stage Recommendation using Large Language Models for Ranking&quot; data-og-description=&quot;Recently, large language models (LLMs) have exhibited significant progress in language understanding and generation. By leveraging textual features, customized LLMs are also applied for recommendation and demonstrate improvements across diverse recommendat&quot; data-og-host=&quot;arxiv.org&quot; data-og-source-url=&quot;https://arxiv.org/abs/2311.02089&quot; data-og-url=&quot;https://arxiv.org/abs/2311.02089v1&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/baXSbY/hyVVBCM7G2/Is3HzaMbKfWD6Hsmpl1Z20/img.png?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/b5uUzS/hyVVMK6yI8/720nzdaj6UxyjdPFyFMNO0/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/2311.02089&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://arxiv.org/abs/2311.02089&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/baXSbY/hyVVBCM7G2/Is3HzaMbKfWD6Hsmpl1Z20/img.png?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/b5uUzS/hyVVMK6yI8/720nzdaj6UxyjdPFyFMNO0/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;LlamaRec: Two-Stage Recommendation using Large Language Models for Ranking&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Recently, large language models (LLMs) have exhibited significant progress in language understanding and generation. By leveraging textual features, customized LLMs are also applied for recommendation and demonstrate improvements across diverse recommendat&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-04-27 오후 4.03.53.png&quot; data-origin-width=&quot;2272&quot; data-origin-height=&quot;922&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qyM8M/btsGZ1C218P/SX9VouKksCe9KGh0BxBsn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qyM8M/btsGZ1C218P/SX9VouKksCe9KGh0BxBsn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qyM8M/btsGZ1C218P/SX9VouKksCe9KGh0BxBsn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqyM8M%2FbtsGZ1C218P%2FSX9VouKksCe9KGh0BxBsn0%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;759&quot; height=&quot;308&quot; data-filename=&quot;스크린샷 2024-04-27 오후 4.03.53.png&quot; data-origin-width=&quot;2272&quot; data-origin-height=&quot;922&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;포스팅 본문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; 본 포스팅은 추천 시스템과 대규모 언어 모델(LLM)을 결합한 방법인 LlamaRec 논문을 리뷰하는 포스팅입니다. LlamaRec 저자들이 주장하는 LLM 기반 추천 시스템 방법은 Two-Stage Recommendation 방법인데요. 어떻게 연구를 진행했고 주장하는지 아래와 같은 순서로 살펴보겠습니다.&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;p data-ke-size=&quot;size16&quot;&gt;2. 소개(Introduction)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 방법론(Methodology)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 실험(Experiment)&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;1. 핵심 요약&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Text feature를 활용해서 LLM도 추천 시스템에 도입되고 있고 다양한 추천 시나리오에서 성능 향상을 보여주고 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 그러나, 대부분의 기존 방법은 훈련이 없는(Training-free) 추천 방법을 실행했고 이는 pretrained knowledge에 크게 의존하게 됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 또한, autoregressive generation 때문에 추론(Inference)가 느려 실시간 추천 방법에 효과적이지 못함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 따라서, 저자들은 Two-Stage recommednation 방법을 제안함. 이 방법은 LLM 모델을 사용하고 ranking based 추천 방법임&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 사용자들의 interaction history에 기반해서 candidate들을 retrieve하는 sequential recommender를 사용하고 그 다음 LLM의 input으로 텍스트 형태로 넣어 랭킹을 수행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이때, LLM 모델은 next item title을 생성하는 것 대신 verbalizer 방법을 채택해서 candidate item들의 출력 logit의 확률 분포로 변환함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이런 구조 때문에 LlamaRec은 긴 텍스트를 생성하지 않고도 item의 순위를 효과적으로 매길 수 있음&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;h3 data-ke-size=&quot;size23&quot;&gt;2. Introduction&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 기존에도 추천 시스템에 대규모 언어 모델(Large Language Model, LLM)을 결합한 다양한 연구가 있었지만, 대부분 추천에 LLM을 적용하는데 focus하고 효율적인 inference의 필요성을 무시하고 있다고 주장합니다. 즉, LLM의 autoregressive generation 방법은 real-time recommendation에 너무 느리기 때문에 실제 시나리오에서는 효과적이지 않는다고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 추천의 효율성을 향상시키기 위해 한 가지 가능한 해결책은 토큰 생성을 피하기 위해서 LLM 위에 classification 또는 regression head를 활용하는 것이라고 하는데요. 그러나, 이런 헤드는 추가적인 매개변수를 도입하게 되고 specific settings에 따라 훈련되므로 추천 시스템 applicability에는 부적합하다고 합니다.&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;그러므로, 저자들은 LlamaRec을 제안하는데요. retrieval과 ranking을 모두 포함하는 솔루션을 제공할 뿐만 아니라 추천 성능과 inference 효율성이 향상된 방법이라고 합니다. 이때, sequential recommender를 도입해 ID 기반 item 검색(retrieval)을 수행하게 해서 사용자 history 길이에 관계없이 효율적으로 candidate를 생성할 수 있다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음으로 사용자 히스토리와 후보를 텍스트로 변환하는 템플릿을 설계하였고 이를 사용해 ranking을 구성합니다. 이렇게 구성된 text prompt는 pretrained(사전 학습된) LLM에서 Parameter Efficient Fine-Tuning(PEFT)를 수행하는데 사용되고 model은 candidate item의 index에 점수를 생성해서 ranking을 매기게 됩니다. 이때 저자들은 LLM 헤드의 출력을 추가 파라미터 없이 probabiltiy distribution(확률 분포)로 변환하기 위해 verbalizer를 사용한다고 합니다. verbalizer를 사용하게 되면 다음과 같은 이점을 얻게 된다고 하네요.&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;Verbalizer approach ranking 방법의 이점&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) autoregressive generation을 우회해서 LLM의 추론 시간을 크게 단축한다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 한 번의 순방향 패스(One forward pass)내에서 모든 candidate에 대한 score를 생성하고 beam search와 같은 memory-intensive decoding process를 피할 수 있다고 합니다.&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;따라서, 저자들이 주장하는 Llamarec은 two-stage framework 구조를 통해 LLM 기반 추천 시스템을 효율적으로 훈련하고 추론할 수 있으며 기존 방법보다 향상된 성능을 제공할 수 있다고 합니다. 그러므로, 아래와 같이 3가지로 저자들이 주장하는 LlamaRec을 요약할 수 있습니다.&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) retrieval과 ranking을 모두 갖춘 솔루션을 제공하는 LLM 기반 two-stage recommendation 제안&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) ID 기반의 sequential recommender는 retriever로 사용하고 verbalizer 접근 방법으로 LLM 기반 Ranking 수행하여 추천의 시간과 메모리 효율성을 크게 향상&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(3) 벤치마크 데이터 세트와 비교해 LlamaRec의 성능을 입증함&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-filename=&quot;스크린샷 2024-04-27 오후 4.38.54.png&quot; data-origin-width=&quot;1674&quot; data-origin-height=&quot;858&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LhuEe/btsGZlISseG/TC09daV3PgNCgcRo3uuHn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LhuEe/btsGZlISseG/TC09daV3PgNCgcRo3uuHn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LhuEe/btsGZlISseG/TC09daV3PgNCgcRo3uuHn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLhuEe%2FbtsGZlISseG%2FTC09daV3PgNCgcRo3uuHn1%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;599&quot; height=&quot;307&quot; data-filename=&quot;스크린샷 2024-04-27 오후 4.38.54.png&quot; data-origin-width=&quot;1674&quot; data-origin-height=&quot;858&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Methodology&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;3-1. Setup&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 논문에서 저자들은 본인들이 제안한 추천 시스템은 LlamaRec을 설명하기 전에 아래와 같이 수식을 먼저 정리해놨습니다.&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;- 사용자 상호작용 히스토리 : \(x\)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터 셋 : \(\chi_i\)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 사용자의 시퀀스 기반 상호 작용 : \([x_1, x_2, \ldots, x_T]\)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이때, 상호작용은 순서대로 정렬함 : \(I (\chi_i \in I, i = 1,2,\ldots,T)\)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 랭킹 점수(Ranking score) : \(\hat{y} \in \mathbb{R}^{|I|}\)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Optimizer : \(\theta \quad (\text{i.e.,} \hat{y} = f(\theta; x))\)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Efficient retrieval model : \(f_{retriever}\)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- LLM 기반 랭킹 모델 : \(f_{rankder}(f = f_{ranker} \circ f_{retriever})\)&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;다음 정리에서 이 수식들을 참고하시길 바랍니다. 또한, 저자들이 주장하는 LlamaRec은 다음과 같은 아키텍처를 가지고 있습니다.&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-filename=&quot;스크린샷 2024-04-28 오전 9.38.50.png&quot; data-origin-width=&quot;3284&quot; data-origin-height=&quot;1364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N00uB/btsGZT6iQre/pgYBVlwiJAJAok6XekyzWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N00uB/btsGZT6iQre/pgYBVlwiJAJAok6XekyzWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N00uB/btsGZT6iQre/pgYBVlwiJAJAok6XekyzWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN00uB%2FbtsGZT6iQre%2FpgYBVlwiJAJAok6XekyzWK%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;3284&quot; height=&quot;1364&quot; data-filename=&quot;스크린샷 2024-04-28 오전 9.38.50.png&quot; data-origin-width=&quot;3284&quot; data-origin-height=&quot;1364&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&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;Figure 1은 저자들이 제안한 LlamaRec입니다. 왼쪽이 retrieval stage이며 two-stage framework중 첫 번째 stage입니다. 이렇게 구성된 retriever을 통해 instruction template을 구성하고 사용자 히스토리와 후보 아이템 셋을 텍스트 형태로 변환해 Llama 2 기반의 ranking model로 넣어 랭킹을 매기게 됩니다. 이게 two-stage framework 중 두 번째 stage라고 보시면 되겠습니다.&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;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;3-2. Proposed LlamaRec - Retrieval&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 논문에서 저자들은 two-stage framework를 제안합니다. 그 중 하나가 Retrieval인데요. 저자들은 본 stage에서 recurrence 기반 추천 시스템 모델인 LRURec를 채택했다고 합니다. LRURec는 small-scale sequential recommender로 선형(linear) recurrent unit 단위를 활용해 입력 시퀀스를 효율적으로 처리할 수 있다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 LRURec를 통해 사용자 transition 패턴을 캡처하고 predicted 아이템의 feature를 생성하기 위해 autoregressivie training을 통해서 최적화 한다고 합니다. inference를 위해서 LURRec는 아이템 임베딩과 예측된 feature 사이의 dot product(내적)을 통해 score를 계산하다고 하네요. 이렇게 추천을 진행한 뒤 다음 ranking stage를 위해 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;20개 정도의&lt;span&gt; 후보 셋을 저장한다고 합니다.&lt;/span&gt;&lt;/span&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;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;3-3. Proposed LlamaRec - LLM ranker&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논문의 저자들은 LLM 모델 중 라마(Llama 2) 모델을 베이스 모델로 사용합니다. Llama 2 모델 중 7b 모델을 사용했으며 이를 활용해 retrieval 단계에서 나온 candidate item들의 랭킹을 매깁니다. 이때, LLM 입력으로 넣을 프롬프트 탬플릿을 설정하는데요. 그 프롬프트는 아래 사진과 같니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-04-28 오전 9.39.17.png&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dflwkI/btsGY230kEk/wwW75yxjBbqhLofl5tKgX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dflwkI/btsGY230kEk/wwW75yxjBbqhLofl5tKgX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dflwkI/btsGY230kEk/wwW75yxjBbqhLofl5tKgX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdflwkI%2FbtsGY230kEk%2FwwW75yxjBbqhLofl5tKgX0%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;569&quot; height=&quot;168&quot; data-filename=&quot;스크린샷 2024-04-28 오전 9.39.17.png&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;460&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;Instruction에는 사용자 이력이 시간 순서로 정렬되어 있고 candidate pool에서 index letter와 함께 아이템을 추천하도록 설정해놓습니다. 그리고 input에는 사용자 히스토리 및 candidate pool을 넣어주고 response를 예측받도록 해놨습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 LLM이 생성하는 출력 값은 candidate에 대한 랭킹 점수를 직접 제공하지 않도록 해놨는데요. 이를 위해서 기존에는 LLM에게 candidate 아이템의 ranking list를 생성하도록 했었다고 합니다. 하지만, 저자들은 이렇게 하면 계산 비용도 많이 들고 제목이 정확하지 않을 수 있기 때문에 추가 처리가 필요하다며, 계산 효율성 등 candidate list에 대한 ranking score를 효율적으로 변환하기 위해 아래 그림과 같이 verbalizer를 사용했다고 합니다.&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-filename=&quot;스크린샷 2024-04-28 오전 9.39.09.png&quot; data-origin-width=&quot;1680&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Cm7FK/btsGZATuYL6/pumKEomK4e49LuPPrZuqIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Cm7FK/btsGZATuYL6/pumKEomK4e49LuPPrZuqIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Cm7FK/btsGZATuYL6/pumKEomK4e49LuPPrZuqIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCm7FK%2FbtsGZATuYL6%2FpumKEomK4e49LuPPrZuqIK%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;1680&quot; height=&quot;494&quot; data-filename=&quot;스크린샷 2024-04-28 오전 9.39.09.png&quot; data-origin-width=&quot;1680&quot; data-origin-height=&quot;494&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item dable&quot; style=&quot;height: 250px;&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;300x250&lt;/div&gt;
    &lt;div id=&quot;dablewidget_Pl1aE8lE&quot; data-widget_id=&quot;Pl1aE8lE&quot;&gt;
      &lt;script&gt;(function(d,a,b,l,e,_) {
    if(d[b]&amp;&amp;d[b].q)return;d[b]=function(){(d[b].q=d[b].q||[]).push(arguments)};e=a.createElement(l);
    e.async=1;e.charset='utf-8';e.src='//static.dable.io/dist/plugin.min.js';
    _=a.getElementsByTagName(l)[0];_.parentNode.insertBefore(e,_);
    })(window,document,'dable','script');
dable('setService', 'lsjsj92.tistory.com');
dable('sendLogOnce');
dable('renderWidget', 'dablewidget_Pl1aE8lE', {ignore_items: true});&lt;/script&gt;
    &lt;/div&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;즉, candidate item(예, (A) Private school(1983) (B)Real Genius(1985) (C)...)을 식별할 수 있도록 하고 해당 ground truth를 index letter에 매핑하도록 합니다. 그렇게 한 다음 candidate score는 LLM 헤드에서 inex letter의 logit을 검색해 계산할 수 있게 되는데요. 즉, 검색된 score는 index letter내의 next token 확률 분포에 해당된다고 저자들은 주장합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들은 이를 적용하기 위해 모델을 훈련시키는데요. ground truth item의 index letter를 label로 사용해 ground truth item score를 최대화하도록 합니다. 즉, 저자들은 LLM에서 사용하는 next-token prediction 작업과 동일하다고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추론할 때는 one single forward pass만을 사용해 LLM 헤드 출력을 얻을 수 있게 되고 verbalizer로 logit을 검색해 item의 ranking을 매기는 것입니다. 이렇게 one forward pass만을 사용하니까 효율성이 크게 향상되기도 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로, 이를 훈련할 때 LLM의 입력 길이를 줄이기 위해 사용자 히스토리 아이템에 대해 최대 값을 20으로 설정하고 retrieval 모델에서 상위 20개의 아이템에 순위를 매기도록 했다고 합니다. 실험에서는 QLoRA를 채택하여 효율적인 훈련을 수행하였다고 저자들은 주장합니다.&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;4. Experiments&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;4-1. Datasets&lt;span style=&quot;color: #000000;&quot;&gt; &amp;amp;&lt;/span&gt; Baseline methods&lt;span style=&quot;color: #000000;&quot;&gt; &amp;amp;&lt;/span&gt; Evaluation&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들이 주장한 LLM 기반 추천 시스템이 정말 효과가 있는지 실험적으로 증명합니다. 먼저, 평가를 위해 데이터 셋을 구성하는데요. 저자들이 사용하는 데이터 셋은 MovieLens-100K, Amazon Beauty, Amazon Games 데이터를 사용했다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 사용자의 시간 순서대로 정렬을 해서 사용했으며 5개 미만의 인터렉션은 제거했다고 합니다.&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-filename=&quot;스크린샷 2024-04-28 오후 3.56.49.png&quot; data-origin-width=&quot;1650&quot; data-origin-height=&quot;840&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/99qpD/btsG0VJmIwd/m4txChA2ZvMK3BYrkjutH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/99qpD/btsG0VJmIwd/m4txChA2ZvMK3BYrkjutH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/99qpD/btsG0VJmIwd/m4txChA2ZvMK3BYrkjutH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F99qpD%2FbtsG0VJmIwd%2Fm4txChA2ZvMK3BYrkjutH0%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;658&quot; height=&quot;335&quot; data-filename=&quot;스크린샷 2024-04-28 오후 3.56.49.png&quot; data-origin-width=&quot;1650&quot; data-origin-height=&quot;840&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;또한, 비교를 위해 선택한 baseline model은 NARM(RNN 기반 추천 시스템), SASRec(Sequential 및 unidirectional 어텐션 기반 recommendation system), BERT4Rec(BERT 기반 추천 시스템), LRURec을 사용했다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평가 지표는 leave-one-out을 사용해 NDCG@K, MRR@K, Recall@K를 사용해서 평가를 진행했습니다.&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;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;4-2. Implementation&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자들이 주장한 방법은 two-stage이기 때문에, 첫 번째 단계인 retriever과 두 번째 단계인 ranker 두 개의 구현체가 존재합니다. 먼저, retriever은 앞서 소개한 것처럼 LRURec 추천 모델을 활용합니다. 이때, optimizer로 AdamW, learning rate는 0.001 그리고 epoch는 500으로 설정했다고 하네요. 또한, MovieLens 100K 데이터셋의 경우 최대 길이를 200, 다른 데이터 같은 경우 50으로 설정했다고 합니다. Ranker의 경우 최대 20개의 history를 사용하고 이들의 랭킹을 매깁니다. title은 32 토큰을 초과하면 자르고 Llama 2기반 ranker를 quantize하기 위해 QLoRA를 사용하였습니다. 이외 자세한 구현 방법은 논문을 참고해주세요.&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;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;4-3. Main result &amp;amp; Comparison to LLM based Baseline&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;저자들은 실험 결과를 Table 1과 Table 3, Table 4에 걸쳐서 정리해두었습니다. Table 1은 저자들이 주장한 LlamaRec과 baseline 모델들의 전반적인 비교를 나타내 것입니다. bold로 칠해진 것이 가장 좋은 결과이고 밑줄이 그어진 것이 그 다음으로 성능이 잘 나온 모델입니다. Table 3은 retrieval된 상위 20개의 아이템 중 실제 아이템이 포함된 유효한 retrieval subset에 대한 추천 시스템 성능을 나타낸 것입니다. Table 4는 LLM 기반 추천 시스템 모델들과 비교 했을 때의 성능을 비교한 것입니다.&lt;/span&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RpHcm/btsGYL9ywSm/MvX7G5kOZGiAcVPBNRzLWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RpHcm/btsGYL9ywSm/MvX7G5kOZGiAcVPBNRzLWK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3396&quot; data-origin-height=&quot;796&quot; data-filename=&quot;스크린샷 2024-04-28 오후 5.17.33.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RpHcm/btsGYL9ywSm/MvX7G5kOZGiAcVPBNRzLWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRpHcm%2FbtsGYL9ywSm%2FMvX7G5kOZGiAcVPBNRzLWK%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;3396&quot; height=&quot;796&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqkdQj/btsGZA68hLG/fqXD5TChtpEdFmL3zjdBSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqkdQj/btsGZA68hLG/fqXD5TChtpEdFmL3zjdBSK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3396&quot; data-origin-height=&quot;796&quot; data-filename=&quot;스크린샷 2024-04-28 오후 5.17.44.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqkdQj/btsGZA68hLG/fqXD5TChtpEdFmL3zjdBSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqkdQj%2FbtsGZA68hLG%2FfqXD5TChtpEdFmL3zjdBSK%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;3396&quot; height=&quot;796&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-04-28 오후 5.17.56.png&quot; data-origin-width=&quot;1694&quot; data-origin-height=&quot;796&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TTZSC/btsG0G6DcEp/KaeDcmjWFmgqpxqCmWzYt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TTZSC/btsG0G6DcEp/KaeDcmjWFmgqpxqCmWzYt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TTZSC/btsG0G6DcEp/KaeDcmjWFmgqpxqCmWzYt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTTZSC%2FbtsG0G6DcEp%2FKaeDcmjWFmgqpxqCmWzYt1%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;579&quot; height=&quot;272&quot; data-filename=&quot;스크린샷 2024-04-28 오후 5.17.56.png&quot; data-origin-width=&quot;1694&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과를 보면 저자들이 제시한 추천 시스템 방법이 가장 좋은 성능을 보여준 것을 확인할 수 있습니다. 특히, MovieLens-100K에서 가장 좋은 성능을 보여주는데요. 저자들은 그 이유가 LLM에 이미 MovieLens-100K에 대한 광범위한 지식이 이미 있기 때문에 사용자의 interaction 등을 포괄적으로 이해할 수 있는데 도움이 되었을 것이라고 주장합니다. 또한, LLM 기반 추천 시스템 모델들과의 비교는 최대한 유사한 연구와 비교를 하였고 구현체가 공개되지 않은 것들이 많기 때문에 해당 연구에서 제시된 수치와 비교했다고 합니다. LLM 기반 추천 시스템을 비교 했을 때 Recall@5의 경우 GPT4Rec가 더 좋은 성능을 보여주었지만, 저자들은 GPT4Rec는 5개의 쿼리를 전부 계산하지만, LlamaRec은 one forward pass라는 것을 강조합니다.&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;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;4-4. Efficiency of LlamaRec&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 저자들은 LlamaRec의 inference 효율성을 평가합니다. Figure 3는 LlamaRec와 Llama CausalLM의 비교를 진행한 것입니다. 여기서 CausalLM은 Llama 2 모델을 사용한 것을 뜻합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-04-28 오후 5.18.02.png&quot; data-origin-width=&quot;1694&quot; data-origin-height=&quot;1066&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HnhNk/btsGZW29jd1/bOEt1gkch6H3Rk5k3J97s1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HnhNk/btsGZW29jd1/bOEt1gkch6H3Rk5k3J97s1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HnhNk/btsGZW29jd1/bOEt1gkch6H3Rk5k3J97s1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHnhNk%2FbtsGZW29jd1%2FbOEt1gkch6H3Rk5k3J97s1%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;556&quot; height=&quot;350&quot; data-filename=&quot;스크린샷 2024-04-28 오후 5.18.02.png&quot; data-origin-width=&quot;1694&quot; data-origin-height=&quot;1066&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Figure 3를 보면 LlamaRecdms inference time이 1초 미만인 반면에 Llama CausalLM의 경우 추론 시간이 계속 증가함을 보여줍니다. 이게 가능한 이유는 LlamaRec은 candidate item에 대해 ranking score를 얻기 위해서는 one forward pass만 있으면 되기 때문이라고 하며, 반대로 Llama CausalLM은 generation하는 시간이 계속 걸리기 때문에 효율성 측면에서 LlamaRec보다 뒤쳐진다고 합니다.&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 추천 시스템과 대규모 언어 모델(LLM)을 결합한 LlamaRec: Two-Stage Recommendation using Large Language Models for ranking이라는 논문을 읽고 정리한 포스팅입니다. 저자들은 Candidate item들을 효율적으로 검색하기 위해 sequential recommender를 도입한 retrieval stage와 사용자의 선호도를 반영해 랭킹을 지정하는 ranking stage로 구성된 two-stage recommendation 방법을 제안합니다.&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;p style=&quot;text-align: left;&quot; 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;Linkedin :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot;&gt;https://www.linkedin.com/in/lsjsj92/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;github :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/lsjsj92&quot;&gt;https://github.com/lsjsj92&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;블로그 댓글 또는 방명록&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>인공지능(AI)/추천시스템</category>
      <category>GenAI</category>
      <category>Llama</category>
      <category>llamarec</category>
      <category>LLM</category>
      <category>NLP</category>
      <category>recommendationsystem</category>
      <category>recommendersystem</category>
      <category>대규모언어모델</category>
      <category>자연어처리</category>
      <category>추천시스템</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/667</guid>
      <comments>https://lsjsj92.tistory.com/667#entry667comment</comments>
      <pubDate>Tue, 30 Apr 2024 09:46:13 +0900</pubDate>
    </item>
    <item>
      <title>Ollama 사용법 - 개인 로컬 환경에서 LLM 모델 실행 및 배포하기</title>
      <link>https://lsjsj92.tistory.com/666</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;포스팅 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 대규모 언어 모델(Large Language Model, LLM)을 개인 로컬 환경에서 실행하고 배포하기 위한 Ollama 사용법을 정리하는 포스팅입니다. Ollama를 사용하면 유명한 모델들인 LLaMA나 Mistral와 같은 LLM 모델들을 쉽게 사용할 수 있도록 로컬에서 서버 형식으로 구성할 수 있는데요. Ollama가 무엇인지, 어떻게 설치하고 사용하는지를 정리해보고자 합니다.&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;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&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/ollama/ollama&quot;&gt;https://github.com/ollama/ollama&lt;/a&gt;&lt;/span&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/ollama/ollama-python&quot;&gt;https://github.com/ollama/ollama-python&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ollama.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ollama.com/&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ollama/ollama/blob/main/docs/modelfile.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/ollama/ollama/blob/main/docs/modelfile.md&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1714040872621&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;Ollama&quot; data-og-description=&quot;Get up and running with large language models.&quot; data-og-host=&quot;ollama.com&quot; data-og-source-url=&quot;https://ollama.com/&quot; data-og-url=&quot;https://ollama.com&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/pVWM5/hyVVy6HpCZ/wQ8txB0fgD4Vzk6Cw7emk0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://ollama.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ollama.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/pVWM5/hyVVy6HpCZ/wQ8txB0fgD4Vzk6Cw7emk0/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;Ollama&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Get up and running with large language models.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ollama.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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-04-25 오후 8.08.14.png&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;311&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eyN1jD/btsGWQ9yKvj/ArLOh3rtQESlX6ZnJ1SQ4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eyN1jD/btsGWQ9yKvj/ArLOh3rtQESlX6ZnJ1SQ4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eyN1jD/btsGWQ9yKvj/ArLOh3rtQESlX6ZnJ1SQ4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeyN1jD%2FbtsGWQ9yKvj%2FArLOh3rtQESlX6ZnJ1SQ4k%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;874&quot; height=&quot;311&quot; data-filename=&quot;스크린샷 2024-04-25 오후 8.08.14.png&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;311&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;포스팅 개요에서 언급하였듯, 본 포스팅은 Ollama를 이용해 대규모 언어 모델(LLM)을 로컬 환경에서 서버를 구성하고 배포하는 과정을 예제(example) 형식으로 다음과 같은 순서로 정리합니다.&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. Ollama란? Ollama란 무엇일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Ollama 설치 방법 및 Python Ollama 연동 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Ollama 실행 및 API 실행 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Modelfile을 활용해 GGUF 파일 연동 방법&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;Ollama란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Ollama를 소개하고 있습니다.&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;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Get up and running with large language models locally&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, Ollama란 Llama 2, Llama 3, Phi, Mistral, Solar와 같은 대규모 언어 모델(LLM)을 로컬 환경에서 실행할 수 있는 프레임워크입니다. 사용하는 방법도 쉬워, 누구나 손쉽게 Ollama를 이용해 LLM을 로컬 환경에서 실행하고 서버 형태로도 배포할 수 있죠.&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;Ollama 설치 및 Python Ollama 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 Ollama를 실행해볼까요? 먼저, 실행하기 전에 Ollama를 설치해줘야 합니다. 설치 방법은 Ollama github나 공식 홈페이지에 나와있습니다. 먼저, github에 내용을 보면 아래와 같이 구성되어 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-04-25 오전 5.59.47.png&quot; data-origin-width=&quot;953&quot; data-origin-height=&quot;691&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q7y2G/btsGVt0zBIy/hRwdFJZyTKOZJgK7iNToWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q7y2G/btsGVt0zBIy/hRwdFJZyTKOZJgK7iNToWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q7y2G/btsGVt0zBIy/hRwdFJZyTKOZJgK7iNToWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ7y2G%2FbtsGVt0zBIy%2FhRwdFJZyTKOZJgK7iNToWk%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;480&quot; height=&quot;348&quot; data-filename=&quot;스크린샷 2024-04-25 오전 5.59.47.png&quot; data-origin-width=&quot;953&quot; data-origin-height=&quot;691&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MacOS의 경우 다운로드 링크를 들어가서 Ollama를 다운받도록 되어있습니다. Linux 환경 같은 경우에는 curl 명령어(curl&amp;nbsp;-fsSL&amp;nbsp;&lt;a href=&quot;https://ollama.com/install.sh&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ollama.com/install.sh&lt;/a&gt; |&amp;nbsp;sh)를 통해 다운을 받을 수 있습니다. 윈도우도 마찬가지로 다운로드 링크가 제공되지만, 글을 쓰는 시점 기준(24.4.25) preview 상태이기 때문에 불안정할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nuaTG/btsGUWISa2U/AWMmAsafFiJsOzZe7OtOXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nuaTG/btsGUWISa2U/AWMmAsafFiJsOzZe7OtOXK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1906&quot; data-origin-height=&quot;1382&quot; data-filename=&quot;스크린샷 2024-04-25 오전 5.59.58.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nuaTG/btsGUWISa2U/AWMmAsafFiJsOzZe7OtOXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnuaTG%2FbtsGUWISa2U%2FAWMmAsafFiJsOzZe7OtOXK%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;1906&quot; height=&quot;1382&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kCI5I/btsGVyndKj5/7mt25kl1nydE8VUxIlDQJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kCI5I/btsGVyndKj5/7mt25kl1nydE8VUxIlDQJK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1906&quot; data-origin-height=&quot;1382&quot; data-filename=&quot;스크린샷 2024-04-25 오전 6.00.06.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kCI5I/btsGVyndKj5/7mt25kl1nydE8VUxIlDQJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkCI5I%2FbtsGVyndKj5%2F7mt25kl1nydE8VUxIlDQJK%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;1906&quot; height=&quot;1382&quot;/&gt;&lt;/span&gt;&lt;/div&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;Ollama 홈페이지를 가도 친절하게 설명이 나와있습니다. github에서 설명한 것과 마찬가지로 MacOS와 Linux 등 나눠서 다운로드 받을 수 있도록 안내 되어져 있습니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;Ollama 실행 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자! 이제 Ollama를 설치했다면 실행을 해보겠습니다. 본 포스팅에서의 예제는 제 PC 환경이 MacOS라서 mac을 기준으로 설명이 된다는 것 이점 참고해서 봐주시면 될 것 같습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Ollama 자체 실행 방법&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Ollama가 정상적으로 설치가 되었다면 ollama 라는 명령어가 동작이 될 것입니다. 먼저, ollama list를 입력을 해봅시다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-04-22 오후 10.13.15.png&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UHgFs/btsGUV4iLc2/kEWc2SVZoI479WKK3sKb40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UHgFs/btsGUV4iLc2/kEWc2SVZoI479WKK3sKb40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UHgFs/btsGUV4iLc2/kEWc2SVZoI479WKK3sKb40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUHgFs%2FbtsGUV4iLc2%2FkEWc2SVZoI479WKK3sKb40%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;503&quot; height=&quot;165&quot; data-filename=&quot;스크린샷 2024-04-22 오후 10.13.15.png&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;264&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;아마, 위처럼 ollama list를 입력하면 NAME ID SIZE 등만 나오고 아무것도 나오지 않을겁니다. 이유는 아직 로컬에 ollama 환경으로 설치된 LLM 모델들이 없기 때문입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 그러면 맨 처음으로 LLM 모델을 하나 받아서, 실행해보겠습니다. 본 예제에서는 mistral 모델로 진행하겠습니다. 아래와 같은 명령어를 입력해봅니다.&lt;/p&gt;
&lt;pre id=&quot;code_1714041658687&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ollama run mistral&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;그러면, 현재 제 PC 환경에는 mistral 모델이 없기 때문에 다운로드가 시작될 것입니다.&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-filename=&quot;스크린샷 2024-04-22 오후 10.21.55.png&quot; data-origin-width=&quot;1684&quot; data-origin-height=&quot;464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpfwhR/btsGWbd5tIZ/oB7XqcAT3q4OHeYA4rvQj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpfwhR/btsGWbd5tIZ/oB7XqcAT3q4OHeYA4rvQj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpfwhR/btsGWbd5tIZ/oB7XqcAT3q4OHeYA4rvQj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpfwhR%2FbtsGWbd5tIZ%2FoB7XqcAT3q4OHeYA4rvQj1%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;646&quot; height=&quot;178&quot; data-filename=&quot;스크린샷 2024-04-22 오후 10.21.55.png&quot; data-origin-width=&quot;1684&quot; data-origin-height=&quot;464&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;그리고 다운로드가 완료되면 verifying이라는 메세지가 뜨면서 마지막에 success가 나올겁니다. 이후 &amp;gt;&amp;gt;&amp;gt; 커멘드 라인 옆에 send a message가 보이게 됩니다.&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-filename=&quot;스크린샷 2024-04-22 오후 10.22.44.png&quot; data-origin-width=&quot;2334&quot; data-origin-height=&quot;622&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfdev7/btsGTyhu4Uf/IqZakaPTUdQWFOxZl93do0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfdev7/btsGTyhu4Uf/IqZakaPTUdQWFOxZl93do0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfdev7/btsGTyhu4Uf/IqZakaPTUdQWFOxZl93do0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdfdev7%2FbtsGTyhu4Uf%2FIqZakaPTUdQWFOxZl93do0%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;785&quot; height=&quot;209&quot; data-filename=&quot;스크린샷 2024-04-22 오후 10.22.44.png&quot; data-origin-width=&quot;2334&quot; data-origin-height=&quot;622&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;저는 &amp;gt;&amp;gt;&amp;gt; 프롬프트에 Hello, I'm soojin! 이라고 입력해보았습니다. 그러니, mistral 모델이 저에게 인사를 하면서 어떻게 도와줄까?부터 시작해 쭉쭉 메시지를 생성하기 시작합니다. 신기하죠? 이렇게 쉽고 간단하게 LLM 모델을 제 local 환경에서 사용할 수 있게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프롬프트에서 빠져나가고 싶다면 /bye 를 입력하면 빠져나갈 수 있습니다.&amp;nbsp;&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-filename=&quot;스크린샷 2024-04-22 오후 10.26.56.png&quot; data-origin-width=&quot;1140&quot; data-origin-height=&quot;370&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VCmU8/btsGVgg6rTm/dXZKjqXMYFW0C5kol8FS50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VCmU8/btsGVgg6rTm/dXZKjqXMYFW0C5kol8FS50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VCmU8/btsGVgg6rTm/dXZKjqXMYFW0C5kol8FS50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVCmU8%2FbtsGVgg6rTm%2FdXZKjqXMYFW0C5kol8FS50%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;579&quot; height=&quot;188&quot; data-filename=&quot;스크린샷 2024-04-22 오후 10.26.56.png&quot; data-origin-width=&quot;1140&quot; data-origin-height=&quot;370&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;그리고 ollama list를 입력하면 방금 받아놓은 mistral 모델이 latest 태그로 보여지는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;(&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;아마, Docker에 익숙하신 분들이라면, 위 출력 등이 굉장히 Docker와 유사하다는 것을 느낄 수도 있을 것 같습니다. )&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;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Ollama API 실행 방법&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 실행된 ollama 모델은 API 형식으로도 불러올 수 있습니다. 본 포스팅의 ollama 튜토리얼을 따라오셨다면 ollama가 실행중이실거고 mistral 모델을 다운 받아졌을 겁니다. 그리고 위에서 실행했던 프롬프트는 빠져나와 아래와 같이 python을 실행해 Ollama API 통신 테스트를 진행해보겠습니다. 이를 위해, 먼저 python에서 ollama를 실행시키기 위해 패키지를 하나 설치해줍니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1714042086662&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install ollama&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;그러면 파이썬에서 ollama와 통신하기 위한 패키지 설치가 완료될겁니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한,&amp;nbsp; ollama가 실행중이시다면, localhost:11434와 같이 url을 입력해 웹 브라우저에서 들어가면 ollama is running을 볼 수 있을겁니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-04-22 오후 10.28.52.png&quot; data-origin-width=&quot;570&quot; data-origin-height=&quot;185&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nQqHf/btsGVg9esCh/ikKyUtdwYmKjExQlcSad3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nQqHf/btsGVg9esCh/ikKyUtdwYmKjExQlcSad3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nQqHf/btsGVg9esCh/ikKyUtdwYmKjExQlcSad3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnQqHf%2FbtsGVg9esCh%2FikKyUtdwYmKjExQlcSad3K%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;570&quot; height=&quot;185&quot; data-filename=&quot;스크린샷 2024-04-22 오후 10.28.52.png&quot; data-origin-width=&quot;570&quot; data-origin-height=&quot;185&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;이제, python ollama도 설치했고 ollama도 실행중이니 아래와 같이 코드를 입력해볼까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1714042136547&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import ollama
response = ollama.chat(model=&amp;lsquo;mistral&amp;rsquo;, messages=[
  {
    'role': 'user',
    'content': 'Why is the sky blue?',
  },
])
print(response['message']['content'])&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;span style=&quot;color: #333333;&quot;&gt;위 코드는 ollama의 chat 기능을 유도하는 함수입니다. 이때, 사용하는 모델은 저희가 방금 위에서 사용했던 mistral 모델을 지정합니다. 또한, role을 user로 정하고 content에 우리가 원하는 질문을 하나 입력합니다. 그러면 어떤 결과가 나올까요?&lt;/span&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-filename=&quot;스크린샷 2024-04-22 오후 10.25.05.png&quot; data-origin-width=&quot;2566&quot; data-origin-height=&quot;704&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yrphj/btsGVcLAkg1/IU6hZXVmMSXkGLWK9yTxE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yrphj/btsGVcLAkg1/IU6hZXVmMSXkGLWK9yTxE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yrphj/btsGVcLAkg1/IU6hZXVmMSXkGLWK9yTxE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fyrphj%2FbtsGVcLAkg1%2FIU6hZXVmMSXkGLWK9yTxE1%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;754&quot; height=&quot;207&quot; data-filename=&quot;스크린샷 2024-04-22 오후 10.25.05.png&quot; data-origin-width=&quot;2566&quot; data-origin-height=&quot;704&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;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5781979379344093&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&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;Ollama가 대답한 결과가 출력이 됩니다! 만약에, stream 형식으로 출력하고 싶다면 코드를 다음과 같이 수정하시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1714042227133&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;stream = ollama.chat(
    model=&amp;lsquo;mistral&amp;rsquo;,
    messages=[{'role': 'user', 'content': 'Why is the sky blue?'}],
    stream=True,
)

for chunk in stream:
  print(chunk['message']['content'], end='', flush=True)&lt;/code&gt;&lt;/pre&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-filename=&quot;스크린샷 2024-04-22 오후 10.26.10.png&quot; data-origin-width=&quot;2566&quot; data-origin-height=&quot;414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgKA2s/btsGVud7Z20/KfqZXy0Nj6VBUjhCkkKRN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgKA2s/btsGVud7Z20/KfqZXy0Nj6VBUjhCkkKRN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgKA2s/btsGVud7Z20/KfqZXy0Nj6VBUjhCkkKRN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgKA2s%2FbtsGVud7Z20%2FKfqZXy0Nj6VBUjhCkkKRN0%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;767&quot; height=&quot;124&quot; data-filename=&quot;스크린샷 2024-04-22 오후 10.26.10.png&quot; data-origin-width=&quot;2566&quot; data-origin-height=&quot;414&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;그러면 위에는 사진이라 정적으로 보이지만, 실제로 스트리밍(streamlng) 형식으로 문자열이 출력되는 것을 확인할 수 있을겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;굳이 파이썬 ollama를 설치하지 않고 curl로도 ollama API를 호출할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1714042513289&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;curl http://localhost:11434/api/generate -d '{
  &quot;model&quot;: &amp;ldquo;mistral&amp;rdquo;,
  &quot;prompt&quot;:&quot;Why is the sky blue?&quot;
}'



curl http://localhost:11434/api/chat -d '{
  &quot;model&quot;: &quot;mistral&quot;,
  &quot;messages&quot;: [
    { &quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;why is the sky blue?&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 curl은 localhost:11434에 떠있는 ollama의 API를 호출하면서 generate 하도록 호출합니다. 이때 모델은 mistral을 사용하도록 하죠. 두 번째 curl은 마찬가지로 ollama의 API를 호출하는데 chat 형식으로 호출합니다. 마찬가지로 LLM 모델은 mistral을 사용하도록 지정했습니다. 그 결과는 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baEyR3/btsGS9Cp1oa/TF0MtQT1k1b8MHpGCP0hr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baEyR3/btsGS9Cp1oa/TF0MtQT1k1b8MHpGCP0hr0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1516&quot; data-origin-height=&quot;1688&quot; data-filename=&quot;스크린샷 2024-04-22 오후 10.37.37.png&quot; width=&quot;613&quot; height=&quot;683&quot; data-widthpercent=&quot;46.68&quot; style=&quot;width: 46.1396%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baEyR3/btsGS9Cp1oa/TF0MtQT1k1b8MHpGCP0hr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaEyR3%2FbtsGS9Cp1oa%2FTF0MtQT1k1b8MHpGCP0hr0%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;1516&quot; height=&quot;1688&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Y1dXt/btsGTddAy63/Uuyz9GRz90lgIU4wuCKya0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Y1dXt/btsGTddAy63/Uuyz9GRz90lgIU4wuCKya0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1832&quot; data-origin-height=&quot;1786&quot; data-filename=&quot;스크린샷 2024-04-22 오후 10.38.32.png&quot; style=&quot;width: 52.6976%;&quot; data-widthpercent=&quot;53.32&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Y1dXt/btsGTddAy63/Uuyz9GRz90lgIU4wuCKya0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FY1dXt%2FbtsGTddAy63%2FUuyz9GRz90lgIU4wuCKya0%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;1786&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item dable&quot; style=&quot;height: 250px;&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;300x250&lt;/div&gt;
    &lt;div id=&quot;dablewidget_Pl1aE8lE&quot; data-widget_id=&quot;Pl1aE8lE&quot;&gt;
      &lt;script&gt;(function(d,a,b,l,e,_) {
    if(d[b]&amp;&amp;d[b].q)return;d[b]=function(){(d[b].q=d[b].q||[]).push(arguments)};e=a.createElement(l);
    e.async=1;e.charset='utf-8';e.src='//static.dable.io/dist/plugin.min.js';
    _=a.getElementsByTagName(l)[0];_.parentNode.insertBefore(e,_);
    })(window,document,'dable','script');
dable('setService', 'lsjsj92.tistory.com');
dable('sendLogOnce');
dable('renderWidget', 'dablewidget_Pl1aE8lE', {ignore_items: true});&lt;/script&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Modelfile을 활용해 Ollama에 모델 배포&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 마지막으로 Modelfile을 활용해 ollama에 모델을 배포하는 예제를 살펴보겠습니다. Modelfile이란 Dockerfile과 유사하게 내가 어떤 모델을 사용할 것이고 탬플릿 형태는 어떠한지, 파라미터는 어떠한지 등을 지정해 모델을 셋팅할 수 있는 파일입니다. Modelfile를 통해 모델 구성을 간편하게 셋팅할 수 있는것이죠. 마찬가지로 mistrial 모델을 활용하되, 저는 mistral-7b-instruct-v0.2Q2_K.gguf 파일을 활용하겠습니다.&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-filename=&quot;스크린샷 2024-04-23 오전 5.54.00.png&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MHB12/btsGSR9Us4y/k77D9D0VCqhoQAgNZbYPV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MHB12/btsGSR9Us4y/k77D9D0VCqhoQAgNZbYPV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MHB12/btsGSR9Us4y/k77D9D0VCqhoQAgNZbYPV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMHB12%2FbtsGSR9Us4y%2Fk77D9D0VCqhoQAgNZbYPV1%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;465&quot; height=&quot;149&quot; data-filename=&quot;스크린샷 2024-04-23 오전 5.54.00.png&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;184&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;본 예제에서는 Modelfile을 이용해 gguf 파일의 모델을 ollama에 셋팅하기 때문에 Modelfile과 내가 사용하고자 하는 모델을 같은 경로의 디렉토리에 넣어줍니다. 그리고 저는 mistral 모델을 사용하기 위한 modelfile 내용으로 다음과 같이 구성하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1714042923781&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM mistral-7b-instruct-v0.2.Q2_K.gguf

TEMPLATE &quot;&quot;&quot;[INST] {{ .System }} {{ .Prompt }} [/INST]&quot;&quot;&quot;

PARAMETER stop &quot;[INST]&quot;
PARAMETER stop &quot;[/INST]&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;Modelfile에 있는 위 내용은 어떤 모델을 사용할 것이며, 템플릿은 어떻게 되는지, 파라미터는 어떻게 구성되어 있는지로 내용이 구성되어 있습니다. Modelfile에 어떻게 내용을 넣으면 되는지는 huggingface에 있는 temple format 등을 참고하시면 됩니다.&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-filename=&quot;스크린샷 2024-04-23 오전 5.54.11.png&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsV2fp/btsGTdknkEF/ZsfWtfLw3rWdMM3uL0ymTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsV2fp/btsGTdknkEF/ZsfWtfLw3rWdMM3uL0ymTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsV2fp/btsGTdknkEF/ZsfWtfLw3rWdMM3uL0ymTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsV2fp%2FbtsGTdknkEF%2FZsfWtfLw3rWdMM3uL0ymTK%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;589&quot; height=&quot;172&quot; data-filename=&quot;스크린샷 2024-04-23 오전 5.54.11.png&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;282&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-04-23 오전 5.56.14.png&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baJjQO/btsGUOYoPKy/ySak201XvlYSNyAzHxHaiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baJjQO/btsGUOYoPKy/ySak201XvlYSNyAzHxHaiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baJjQO/btsGUOYoPKy/ySak201XvlYSNyAzHxHaiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaJjQO%2FbtsGUOYoPKy%2FySak201XvlYSNyAzHxHaiK%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;612&quot; height=&quot;84&quot; data-filename=&quot;스크린샷 2024-04-23 오전 5.56.14.png&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;132&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;이렇게 구성된 modelfile을 활용해 ollama 환경에 LLM 모델을 배포해보겠습니다. 명령어는 간단합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1714043036949&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ollama create mistral-7b -f Modelfile&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;ollama create는 생성하겠다는 명령어이고 그 다음 mistral-7b는 ollama에 지정할 이름이라고 보시면 됩니다. 그리고 이때 file을 Modelfile로 사용하겠다!라고 해석하시면 될 것 같습니다. 이렇게 명령어를 입력하면 다음과 같이 ollama에 모델이 새롭게 셋팅 및 배포가 될 것입니다.&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-filename=&quot;스크린샷 2024-04-23 오전 5.56.53.png&quot; data-origin-width=&quot;1572&quot; data-origin-height=&quot;586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSpKrd/btsGVfnSAdO/XE1ASIYC9U3tGeRNskgkPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSpKrd/btsGVfnSAdO/XE1ASIYC9U3tGeRNskgkPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSpKrd/btsGVfnSAdO/XE1ASIYC9U3tGeRNskgkPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSpKrd%2FbtsGVfnSAdO%2FXE1ASIYC9U3tGeRNskgkPK%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;627&quot; height=&quot;234&quot; data-filename=&quot;스크린샷 2024-04-23 오전 5.56.53.png&quot; data-origin-width=&quot;1572&quot; data-origin-height=&quot;586&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;아까 설치했던 것은 mistral:latest였는데요. 이번에는 이름을 mistral-7b로 지정했기 때문에 mistrlal-7b:latest로 ollama list에 나오는 것을 확인할 수 있습니다. 마찬가지로 이렇게 구성된 모델을 run으로 실행하면&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-filename=&quot;스크린샷 2024-04-23 오전 5.57.24.png&quot; data-origin-width=&quot;1572&quot; data-origin-height=&quot;174&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p4DrM/btsGTeQ87cK/KFLaqEckViix8MdRJKs4qk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p4DrM/btsGTeQ87cK/KFLaqEckViix8MdRJKs4qk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p4DrM/btsGTeQ87cK/KFLaqEckViix8MdRJKs4qk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp4DrM%2FbtsGTeQ87cK%2FKFLaqEckViix8MdRJKs4qk%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;733&quot; height=&quot;81&quot; data-filename=&quot;스크린샷 2024-04-23 오전 5.57.24.png&quot; data-origin-width=&quot;1572&quot; data-origin-height=&quot;174&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;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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 대규모 언어 모델(LLM)을 로컬에서 쉽게 배포하고 실행할 수 있도록 도와주는 Ollama에 대해서 알아보았습니다. Ollama란 무엇인지, 어떻게 설치하는지, 어떻게 실행하는지에 대한 전반적인 내용을 확인해보았습니다.&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;p style=&quot;text-align: left;&quot; 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;Linkedin :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.linkedin.com/in/lsjsj92/&quot;&gt;https://www.linkedin.com/in/lsjsj92/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;github :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/lsjsj92&quot;&gt;https://github.com/lsjsj92&lt;/a&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;</description>
      <category>인공지능(AI)/LLM&amp;amp;RAG</category>
      <category>GenAI</category>
      <category>huggingface</category>
      <category>largelanguagemodels</category>
      <category>Llama</category>
      <category>LLM</category>
      <category>NLP</category>
      <category>Ollama</category>
      <category>Python</category>
      <category>대규모언어모델</category>
      <category>자연어처리</category>
      <author>이수진의 블로그</author>
      <guid isPermaLink="true">https://lsjsj92.tistory.com/666</guid>
      <comments>https://lsjsj92.tistory.com/666#entry666comment</comments>
      <pubDate>Thu, 25 Apr 2024 20:08:44 +0900</pubDate>
    </item>
  </channel>
</rss>