<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>오리의 대학원 준비일지</title>
    <link>https://easy1nhard2.tistory.com/</link>
    <description>https://github.com/orieasy1</description>
    <language>ko</language>
    <pubDate>Mon, 10 Aug 2026 01:29:59 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>orieasy1</managingEditor>
    <image>
      <title>오리의 대학원 준비일지</title>
      <url>https://tistory1.daumcdn.net/tistory/7052882/attach/c2eff3265cb54947bd281151fdbf841f</url>
      <link>https://easy1nhard2.tistory.com</link>
    </image>
    <item>
      <title>Zotero + Obsidian 사용해서 논문 읽는 방법</title>
      <link>https://easy1nhard2.tistory.com/36</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt; Zotero 하이라이트 Obsidian으로 가져오는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Zotero &amp;amp; Obsidian 사용법&lt;/p&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xq1gH/dJMcaalUNQ4/lbztXwjn0q7XMhphkmLk51/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xq1gH/dJMcaalUNQ4/lbztXwjn0q7XMhphkmLk51/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xq1gH/dJMcaalUNQ4/lbztXwjn0q7XMhphkmLk51/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxq1gH%2FdJMcaalUNQ4%2FlbztXwjn0q7XMhphkmLk51%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;321&quot; height=&quot;242&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;388&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;안녕하세요, 이번엔 지난 포스팅에 이어서 Obsidian과 Zotero를 활용해서 논문 읽는 방법을 마저 설명드리려 해요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적인 Zotero 사용법과 기본설정, 논문 읽는 방법(공학계열)은 이전 포스팅을 참고해주세요!!&lt;/p&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;a href=&quot;https://easy1nhard2.tistory.com/35&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://easy1nhard2.tistory.com/35&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1786227462092&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;영국 방문연구원의 Zotero로 논문 읽는 방법!&quot; data-og-description=&quot; ️ 공학계열 논문 읽는법, Zotero 사용법 안녕하세요..?오랜만입니다.... 껄껄 저는 25년도 중반까지, 그리고 특히 24년에 개발자가 되겠다는 꿈을 안고,,최대한 부지런히 tech blog를 썼던 사람입니&quot; data-og-host=&quot;easy1nhard2.tistory.com&quot; data-og-source-url=&quot;https://easy1nhard2.tistory.com/35&quot; data-og-url=&quot;https://easy1nhard2.tistory.com/35&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/v9HOx/dJMb8QMrO1h/K4MXEK5bisB9IqolaNid80/img.png?width=800&amp;amp;height=933&amp;amp;face=0_0_800_933,https://scrap.kakaocdn.net/dn/bfWJ2N/dJMb8RR7wJ3/JDLwZWmO29HyDCqbl6CxO0/img.png?width=800&amp;amp;height=933&amp;amp;face=0_0_800_933,https://scrap.kakaocdn.net/dn/Mmk8T/dJMb8UafrI0/cIK6akNKDE3hR0T2tEXx61/img.png?width=1460&amp;amp;height=1776&amp;amp;face=0_0_1460_1776&quot;&gt;&lt;a href=&quot;https://easy1nhard2.tistory.com/35&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://easy1nhard2.tistory.com/35&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/v9HOx/dJMb8QMrO1h/K4MXEK5bisB9IqolaNid80/img.png?width=800&amp;amp;height=933&amp;amp;face=0_0_800_933,https://scrap.kakaocdn.net/dn/bfWJ2N/dJMb8RR7wJ3/JDLwZWmO29HyDCqbl6CxO0/img.png?width=800&amp;amp;height=933&amp;amp;face=0_0_800_933,https://scrap.kakaocdn.net/dn/Mmk8T/dJMb8UafrI0/cIK6akNKDE3hR0T2tEXx61/img.png?width=1460&amp;amp;height=1776&amp;amp;face=0_0_1460_1776');&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;영국 방문연구원의 Zotero로 논문 읽는 방법!&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt; ️ 공학계열 논문 읽는법, Zotero 사용법 안녕하세요..?오랜만입니다.... 껄껄 저는 25년도 중반까지, 그리고 특히 24년에 개발자가 되겠다는 꿈을 안고,,최대한 부지런히 tech blog를 썼던 사람입니&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;easy1nhard2.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;&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;위 포스팅과 아래 이미지에서 보실 수 있다시피 Zotero는 논문을 읽어 내려가면서 하이라이트를 바로 칠할 수 있고, 본인의 느낀 점을 comment로 바로바로 달 수 있다는 장점이 있습니다.&lt;/p&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;&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;742&quot; data-origin-height=&quot;1478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HD62S/dJMcafnmVia/PGtgFgFHJOWsqF2gJ0WizK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HD62S/dJMcafnmVia/PGtgFgFHJOWsqF2gJ0WizK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HD62S/dJMcafnmVia/PGtgFgFHJOWsqF2gJ0WizK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHD62S%2FdJMcafnmVia%2FPGtgFgFHJOWsqF2gJ0WizK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;562&quot; height=&quot;1119&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;1478&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;그러나 이렇게 comment가 길어질 경우에는 내용이 끊기고, comment가 많아지면 많아질수록 한눈에 파악하기 힘들어집니다.&lt;/p&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;내가 작성한 모든 comment를 한 번에! 가져와서 볼 수 있다면 정말 편리하겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럴 때 사용할 수 있는 게 바로 Obsidian이라는 애플리케이션입니다!&lt;/p&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;Obsidian(옵시디언 설치 바로가기)&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://obsidian.md/download&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://obsidian.md/download&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1786227797460&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;Download&quot; data-og-description=&quot;Obsidian is available on all major platforms. Download Obsidian for iOS, Android, macOS, Windows and Linux.&quot; data-og-host=&quot;obsidian.md&quot; data-og-source-url=&quot;https://obsidian.md/download&quot; data-og-url=&quot;https://obsidian.md/download&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/csjcyS/dJMb8UH4RDe/YCmyGqOKU7MQJPYH7i7Zo1/img.png?width=1200&amp;amp;height=688&amp;amp;face=0_0_1200_688,https://scrap.kakaocdn.net/dn/sJ4DK/dJMb8Z3G7Ds/BBWnDr3ULaklELQhtBlJOk/img.png?width=1200&amp;amp;height=688&amp;amp;face=0_0_1200_688&quot;&gt;&lt;a href=&quot;https://obsidian.md/download&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://obsidian.md/download&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/csjcyS/dJMb8UH4RDe/YCmyGqOKU7MQJPYH7i7Zo1/img.png?width=1200&amp;amp;height=688&amp;amp;face=0_0_1200_688,https://scrap.kakaocdn.net/dn/sJ4DK/dJMb8Z3G7Ds/BBWnDr3ULaklELQhtBlJOk/img.png?width=1200&amp;amp;height=688&amp;amp;face=0_0_1200_688');&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;Download&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Obsidian is available on all major platforms. Download Obsidian for iOS, Android, macOS, Windows and Linux.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;obsidian.md&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Obsidian은 차세대 Notion으로 각광받고 있는 서비스입니다.&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-origin-width=&quot;2976&quot; data-origin-height=&quot;2042&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bg1g8M/dJMcadCR2bw/n32rKPBdM8aWutUbSJHpZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bg1g8M/dJMcadCR2bw/n32rKPBdM8aWutUbSJHpZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bg1g8M/dJMcadCR2bw/n32rKPBdM8aWutUbSJHpZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbg1g8M%2FdJMcadCR2bw%2Fn32rKPBdM8aWutUbSJHpZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2976&quot; height=&quot;2042&quot; data-origin-width=&quot;2976&quot; data-origin-height=&quot;2042&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;Obsidian에서는 Zotero와 관련한 커뮤니티 플러그인을 지원하는데요, 해당 플러그인을 사용하여 내가 Zotero에서 작성한 메모들을 한꺼번에 불러들일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2204&quot; data-origin-height=&quot;1610&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UMoDc/dJMcadQtQkq/5WtMjSpe1F7WR5QRUnkdTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UMoDc/dJMcadQtQkq/5WtMjSpe1F7WR5QRUnkdTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UMoDc/dJMcadQtQkq/5WtMjSpe1F7WR5QRUnkdTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUMoDc%2FdJMcadQtQkq%2F5WtMjSpe1F7WR5QRUnkdTK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2204&quot; height=&quot;1610&quot; data-origin-width=&quot;2204&quot; data-origin-height=&quot;1610&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;그럼 이제부터 저의 Zotero, Obsidian을 사용한 논문 읽기 방법을 본격적으로 소개해 드리도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwNi3p/dJMcag0JwpN/LVB5VZRHZL9K6kpwKeoiOk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwNi3p/dJMcag0JwpN/LVB5VZRHZL9K6kpwKeoiOk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwNi3p/dJMcag0JwpN/LVB5VZRHZL9K6kpwKeoiOk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwNi3p%2FdJMcag0JwpN%2FLVB5VZRHZL9K6kpwKeoiOk%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;402&quot; height=&quot;303&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;388&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;h2 data-ke-size=&quot;size26&quot;&gt;1. Obsidian(옵시디언) 시작하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 Obsidian 설치를 완료하시고 보관선(볼트)까지 만들었다는 전제하에 시작하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(아래 영상의 해당 영상의 1:45까지)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Obsidian의 전반적인 세팅은 아래 영상을 참고해 주시면 좋을 것 같습니다!&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;a href=&quot;https://youtu.be/ZuEu8SDqHOE?is=RU7V66ibiRnkx62f&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/ZuEu8SDqHOE?is=RU7V66ibiRnkx62f&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=ZuEu8SDqHOE&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/ewsXpG/dJMb9ia6tTo/ZphnsPXJKQwkiBs9o6ygLK/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/bcf2gZ/dJMb9b37nU9/0jqDoULgzSFf1YneGdR5Mk/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;15분만에 훑어보는 옵시디언 사용법&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/ZuEu8SDqHOE&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;(전 이것 저것 플러그인을 설치한게 있어서 조금 다르긴 합니다만..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3420&quot; data-origin-height=&quot;2214&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NmeuG/dJMcahL9FJ0/KbMSUSJetfObc8XFXU4QIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NmeuG/dJMcahL9FJ0/KbMSUSJetfObc8XFXU4QIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NmeuG/dJMcahL9FJ0/KbMSUSJetfObc8XFXU4QIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNmeuG%2FdJMcahL9FJ0%2FKbMSUSJetfObc8XFXU4QIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3420&quot; height=&quot;2214&quot; data-origin-width=&quot;3420&quot; data-origin-height=&quot;2214&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 '3. Papers'라고 이름 붙였습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;716&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CVrZT/dJMcaiqLc45/cOuFd8kobObXikUKfuu221/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CVrZT/dJMcaiqLc45/cOuFd8kobObXikUKfuu221/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CVrZT/dJMcaiqLc45/cOuFd8kobObXikUKfuu221/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCVrZT%2FdJMcaiqLc45%2FcOuFd8kobObXikUKfuu221%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;356&quot; height=&quot;296&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;716&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;&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;저희가 오늘 사용할 건 모두 '커뮤니티 플러그인'이에요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Obsidian &amp;gt; Preferences &amp;gt; 커뮤니티 플러그인 &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/bMR7wp/dJMcadiMsL8/xgPjG5WKrtoyxMEfZMc0IK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMR7wp/dJMcadiMsL8/xgPjG5WKrtoyxMEfZMc0IK/img.png&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;612&quot; data-is-animation=&quot;false&quot; style=&quot;width: 43.7779%; margin-right: 10px;&quot; data-widthpercent=&quot;44.29&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMR7wp/dJMcadiMsL8/xgPjG5WKrtoyxMEfZMc0IK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMR7wp%2FdJMcadiMsL8%2FxgPjG5WKrtoyxMEfZMc0IK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;612&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDM33F/dJMcajb5zyP/7WxWoCGCVpyUM8VRuCRXI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDM33F/dJMcajb5zyP/7WxWoCGCVpyUM8VRuCRXI1/img.png&quot; data-origin-width=&quot;1810&quot; data-origin-height=&quot;1416&quot; data-is-animation=&quot;false&quot; style=&quot;width: 55.0593%;&quot; data-widthpercent=&quot;55.71&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDM33F/dJMcajb5zyP/7WxWoCGCVpyUM8VRuCRXI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDM33F%2FdJMcajb5zyP%2F7WxWoCGCVpyUM8VRuCRXI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1810&quot; height=&quot;1416&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;총 2개의 플러그인을 설치할껀데요,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Templater&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Zotero Integration 입니다&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&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/cRRFt3/dJMcaij2faj/jfylc4KaOQ2p7wdlXPTCJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRRFt3/dJMcaij2faj/jfylc4KaOQ2p7wdlXPTCJ1/img.png&quot; data-origin-width=&quot;2200&quot; data-origin-height=&quot;1610&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.3092%; margin-right: 10px;&quot; data-widthpercent=&quot;49.89&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRRFt3/dJMcaij2faj/jfylc4KaOQ2p7wdlXPTCJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRRFt3%2FdJMcaij2faj%2Fjfylc4KaOQ2p7wdlXPTCJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2200&quot; height=&quot;1610&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHluaT/dJMb998qAaN/zbOZnFkkgyIAZAuCBNIxjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHluaT/dJMb998qAaN/zbOZnFkkgyIAZAuCBNIxjK/img.png&quot; data-origin-width=&quot;2218&quot; data-origin-height=&quot;1616&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.528%;&quot; data-widthpercent=&quot;50.11&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHluaT/dJMb998qAaN/zbOZnFkkgyIAZAuCBNIxjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHluaT%2FdJMb998qAaN%2FzbOZnFkkgyIAZAuCBNIxjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;1616&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;&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;이후 Preferences(설정)창으로 돌아와서 좌측하단에 플러그인이 뜨는지 확인해주세요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lIE7u/dJMcaiK1PM0/gNMUGBnsGYfAXKM7KVVkTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lIE7u/dJMcaiK1PM0/gNMUGBnsGYfAXKM7KVVkTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lIE7u/dJMcaiK1PM0/gNMUGBnsGYfAXKM7KVVkTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlIE7u%2FdJMcaiK1PM0%2FgNMUGBnsGYfAXKM7KVVkTk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;495&quot; data-origin-width=&quot;1070&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;&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;Zotero와의 연결을 위해선 Templater 설정이 많이 필요하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Zotero에 단 우리의 코멘트를 들고와서 어떻게 보여줄지를 설정하기 위한 플러그인이예요 :)&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/bnl6kQ/dJMcagmaDMQ/76jLbmU6WfpRg8ZMUyWK71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnl6kQ/dJMcagmaDMQ/76jLbmU6WfpRg8ZMUyWK71/img.png&quot; data-origin-width=&quot;1712&quot; data-origin-height=&quot;1986&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.5427%; margin-right: 10px;&quot; data-widthpercent=&quot;50.13&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnl6kQ/dJMcagmaDMQ/76jLbmU6WfpRg8ZMUyWK71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbnl6kQ%2FdJMcagmaDMQ%2F76jLbmU6WfpRg8ZMUyWK71%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1712&quot; height=&quot;1986&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6GFqb/dJMcajpz7qb/zwHyyMIjM03B4F6YEDoVG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6GFqb/dJMcajpz7qb/zwHyyMIjM03B4F6YEDoVG0/img.png&quot; data-origin-width=&quot;1712&quot; data-origin-height=&quot;1996&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.2945%;&quot; data-widthpercent=&quot;49.87&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6GFqb/dJMcajpz7qb/zwHyyMIjM03B4F6YEDoVG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6GFqb%2FdJMcajpz7qb%2FzwHyyMIjM03B4F6YEDoVG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1712&quot; height=&quot;1996&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Zotero Integration 설정을 하기 전에 위에서 'Template folder location' 칸에 작성한 이름과 동일한 폴더를 하나 만들어주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Zotero Template 이라는 파일을 하나 만들어줍니다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;376&quot; data-origin-height=&quot;122&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d9QkkB/dJMcabE9En7/mkQ12EAdk7ewTVQvcXJkwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d9QkkB/dJMcabE9En7/mkQ12EAdk7ewTVQvcXJkwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d9QkkB/dJMcabE9En7/mkQ12EAdk7ewTVQvcXJkwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd9QkkB%2FdJMcabE9En7%2FmkQ12EAdk7ewTVQvcXJkwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;376&quot; height=&quot;122&quot; data-origin-width=&quot;376&quot; data-origin-height=&quot;122&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;우선 본인이 설정한 논문들을 불러고오자 하는 폴더명 (저의 경우엔 3. Papers)를 아래 사진처럼 칸에 작성해주세요.&lt;/p&gt;
&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;Name: 우리가 하려는 동작(Zotero에서 내용 불러와서 Obsidian에 저장) 이름 (자유)&lt;/li&gt;
&lt;li&gt;Output Path: 저장경로, 본인이 설정한 폴더 이름/@{{citekey}}.md 형식으로 설정해주세요&lt;/li&gt;
&lt;li&gt;Image Output Path: 이미지 저장 경로, 본인이 설정한 폴더 이름/images/{{citekey}}/&lt;/li&gt;
&lt;li&gt;Template File: 논문들을 불러올 때 적용할 템플릿: templates/Zotero Template.md&lt;/li&gt;
&lt;li&gt;Bibliography Style: 인용스타일, 본인이 연구하는 분야의 형식으로 지정해주시면 됩니다! (저는 컴공이라 히히)&lt;/li&gt;
&lt;/ul&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/DXOsz/dJMcabE9Eg1/R6l21JCKRlWVXylkeGCyS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DXOsz/dJMcabE9Eg1/R6l21JCKRlWVXylkeGCyS0/img.png&quot; data-origin-width=&quot;1716&quot; data-origin-height=&quot;1988&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.5219%; margin-right: 10px;&quot; data-widthpercent=&quot;50.1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DXOsz/dJMcabE9Eg1/R6l21JCKRlWVXylkeGCyS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDXOsz%2FdJMcabE9Eg1%2FR6l21JCKRlWVXylkeGCyS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1716&quot; height=&quot;1988&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NPrmg/dJMcafOsJUt/J5nXcsdpCoApwhkCTbvAN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NPrmg/dJMcafOsJUt/J5nXcsdpCoApwhkCTbvAN0/img.png&quot; data-origin-width=&quot;1714&quot; data-origin-height=&quot;1994&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.3153%;&quot; data-widthpercent=&quot;49.9&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NPrmg/dJMcafOsJUt/J5nXcsdpCoApwhkCTbvAN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNPrmg%2FdJMcafOsJUt%2FJ5nXcsdpCoApwhkCTbvAN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1714&quot; height=&quot;1994&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Zotero 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Zotero에서 Obsidian으로 내용을 들고 올 때 필요한 citekey설정을 진행하겠습니다.&lt;/p&gt;
&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;a href=&quot;https://retorque.re/zotero-better-bibtex/installation/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://retorque.re/zotero-better-bibtex/installation/index.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1786230732199&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;Installation :: Better BibTeX for Zotero&quot; data-og-description=&quot;Install by downloading the latest release &amp;ndash; if you use Firefox, make sure to right-click and save the XPI file, not just clicking it &amp;ndash; and then in Zotero: In the main menu go to Tools &amp;gt; Plugins Select &amp;lsquo;Plugins&amp;rsquo; Click on the gear in the top-right co&quot; data-og-host=&quot;retorque.re&quot; data-og-source-url=&quot;https://retorque.re/zotero-better-bibtex/installation/index.html&quot; data-og-url=&quot;https://retorque.re/zotero-better-bibtex/installation/index.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://retorque.re/zotero-better-bibtex/installation/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://retorque.re/zotero-better-bibtex/installation/index.html&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;Installation :: Better BibTeX for Zotero&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Install by downloading the latest release &amp;ndash; if you use Firefox, make sure to right-click and save the XPI file, not just clicking it &amp;ndash; and then in Zotero: In the main menu go to Tools &amp;gt; Plugins Select &amp;lsquo;Plugins&amp;rsquo; Click on the gear in the top-right co&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;retorque.re&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;latest release를 클릭하셔서 xpi 확장자 파일을 다운받아주세요.&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/deCD4J/dJMcad31xtv/rzgmX6duOzixRzqQZD7fH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/deCD4J/dJMcad31xtv/rzgmX6duOzixRzqQZD7fH1/img.png&quot; data-origin-width=&quot;1954&quot; data-origin-height=&quot;1718&quot; data-is-animation=&quot;false&quot; style=&quot;width: 46.4219%; margin-right: 10px;&quot; data-widthpercent=&quot;46.97&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/deCD4J/dJMcad31xtv/rzgmX6duOzixRzqQZD7fH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdeCD4J%2FdJMcad31xtv%2FrzgmX6duOzixRzqQZD7fH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1954&quot; height=&quot;1718&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckieAM/dJMcagfqqyn/gdWgSoaJ4cRwUGLEoPfVi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckieAM/dJMcagfqqyn/gdWgSoaJ4cRwUGLEoPfVi0/img.png&quot; data-origin-width=&quot;1952&quot; data-origin-height=&quot;1520&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.4153%;&quot; data-widthpercent=&quot;53.03&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckieAM/dJMcagfqqyn/gdWgSoaJ4cRwUGLEoPfVi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckieAM%2FdJMcagfqqyn%2FgdWgSoaJ4cRwUGLEoPfVi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1952&quot; height=&quot;1520&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;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;Zotero &amp;gt; Tools &amp;gt; Plugins에 들어가신 뒤, Install Plugins Form File &amp;gt; 다운받은 xpi &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&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-origin-width=&quot;1644&quot; data-origin-height=&quot;566&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CPAqO/dJMb99UTHn2/NQRxK9N1a65s7149DoVuc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CPAqO/dJMb99UTHn2/NQRxK9N1a65s7149DoVuc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CPAqO/dJMb99UTHn2/NQRxK9N1a65s7149DoVuc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCPAqO%2FdJMb99UTHn2%2FNQRxK9N1a65s7149DoVuc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1644&quot; height=&quot;566&quot; data-origin-width=&quot;1644&quot; data-origin-height=&quot;566&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;702&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beHxfS/dJMb991IWTG/TyPMwOdLXZlg7fkFPxfJDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beHxfS/dJMb991IWTG/TyPMwOdLXZlg7fkFPxfJDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beHxfS/dJMb991IWTG/TyPMwOdLXZlg7fkFPxfJDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeHxfS%2FdJMb991IWTG%2FTyPMwOdLXZlg7fkFPxfJDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;369&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;702&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;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;해당 창을 닫고 Settings 창에 들어가셔서 citation key formula를 수정해 주셔도 되고 안 해 주셔도 됩니다.&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 data-ke-size=&quot;size16&quot;&gt;제가 제공해드리는 템플릿을 사용하게 되면 이 citekey가 노트 제목으로 오게 되는데요,&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;p data-ke-size=&quot;size16&quot;&gt;shorttitle(3,3) + &quot;_&quot; + auth + &quot;_etal&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MRMdx/dJMcaazzpwH/psquUyzjcFgrz2giGz5WFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MRMdx/dJMcaazzpwH/psquUyzjcFgrz2giGz5WFK/img.png&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;826&quot; data-is-animation=&quot;false&quot; style=&quot;width: 47.0129%; margin-right: 10px;&quot; data-widthpercent=&quot;47.57&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MRMdx/dJMcaazzpwH/psquUyzjcFgrz2giGz5WFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMRMdx%2FdJMcaazzpwH%2FpsquUyzjcFgrz2giGz5WFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;950&quot; height=&quot;826&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYSdJR/dJMcaf8AmKD/Byo2281rS6OCJMyLEVmp21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYSdJR/dJMcaf8AmKD/Byo2281rS6OCJMyLEVmp21/img.png&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;1262&quot; data-is-animation=&quot;false&quot; style=&quot;width: 51.8243%;&quot; data-widthpercent=&quot;52.43&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYSdJR/dJMcaf8AmKD/Byo2281rS6OCJMyLEVmp21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYSdJR%2FdJMcaf8AmKD%2FByo2281rS6OCJMyLEVmp21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1600&quot; height=&quot;1262&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;아까 설치했던 사이트에 가면 다른 Citation key formula도 있으니 한번 구경해보시고 마음에 드는 걸로 설정하셔도 좋을 것 같습니다.&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://retorque.re/zotero-better-bibtex/citing/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://retorque.re/zotero-better-bibtex/citing/index.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1786231550674&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;Citation Keys :: Better BibTeX for Zotero&quot; data-og-description=&quot;Generating citekeys for your items The BibTeX citations keys generated by the standard Zotero exporters are always generated at time of export, using an algorithm that usually generates unique keys. For serious LaTeX users, &amp;ldquo;usually&amp;rdquo; presents the follo&quot; data-og-host=&quot;retorque.re&quot; data-og-source-url=&quot;https://retorque.re/zotero-better-bibtex/citing/index.html&quot; data-og-url=&quot;https://retorque.re/zotero-better-bibtex/citing/index.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://retorque.re/zotero-better-bibtex/citing/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://retorque.re/zotero-better-bibtex/citing/index.html&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;Citation Keys :: Better BibTeX for Zotero&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Generating citekeys for your items The BibTeX citations keys generated by the standard Zotero exporters are always generated at time of export, using an algorithm that usually generates unique keys. For serious LaTeX users, &amp;ldquo;usually&amp;rdquo; presents the follo&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;retorque.re&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;&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;gt; Better BibTeX &amp;gt; Regenerate BibTeX key 를 클릭해 citekey를 다시 설정해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논문을 클릭하면 우측 내요에 논문 관련 정보들이 뜨게 되는데 Citation Key에서 우리가 적용한 설정이 잘 반영이 되었는지 확인해줍니다.&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/cRju1e/dJMcagT37Ow/ui8nM7jwvvhDGKZobXKMkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRju1e/dJMcagT37Ow/ui8nM7jwvvhDGKZobXKMkk/img.png&quot; data-origin-width=&quot;1392&quot; data-origin-height=&quot;1254&quot; data-is-animation=&quot;false&quot; style=&quot;width: 65.1702%; margin-right: 10px;&quot; data-widthpercent=&quot;65.94&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRju1e/dJMcagT37Ow/ui8nM7jwvvhDGKZobXKMkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRju1e%2FdJMcagT37Ow%2Fui8nM7jwvvhDGKZobXKMkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1392&quot; height=&quot;1254&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mFNdb/dJMcaasNVGR/Ykm8CCKnmzwx0igR6pLiI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mFNdb/dJMcaasNVGR/Ykm8CCKnmzwx0igR6pLiI0/img.png&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;1130&quot; data-is-animation=&quot;false&quot; style=&quot;width: 33.667%;&quot; data-widthpercent=&quot;34.06&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mFNdb/dJMcaasNVGR/Ykm8CCKnmzwx0igR6pLiI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmFNdb%2FdJMcaasNVGR%2FYkm8CCKnmzwx0igR6pLiI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;648&quot; height=&quot;1130&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 이제 Template을 만들 차례&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;템플릿을 만들기 전에!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Zotero는 아래 8가지 색깔의 하이라이트를 형광펜과 밑줄 형태로 제공해요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;162&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MvF0s/dJMcab6hpFO/un7rk2kpyb6XOaP5EVyGyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MvF0s/dJMcab6hpFO/un7rk2kpyb6XOaP5EVyGyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MvF0s/dJMcab6hpFO/un7rk2kpyb6XOaP5EVyGyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMvF0s%2FdJMcab6hpFO%2Fun7rk2kpyb6XOaP5EVyGyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;418&quot; height=&quot;162&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;162&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;그리고 이전 포스팅에서 제가 언급한 논문을 읽을 때 생각해야 할, 얻어 가야 할 내용 5가지를 소개해 드렸죠?&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;이 논문의 RQ와 Contribution&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;&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;읽을 때 총 6가지의 색상을 사용합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 133px;&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;height: 19px;&quot;&gt;&lt;b&gt;색&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;b&gt;Zotero 색 이름&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;b&gt;용도&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;b&gt;무엇을 칠하나&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;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;height: 19px;&quot;&gt;  주황&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;Orange&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;b&gt;RQ / 문제의식&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;이 논문이 답하려는 질문, 연구 목적, 풀려는 문제&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;question&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;  파랑&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;Blue&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;b&gt;Method&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;대상&amp;middot;표본, 실험 설계, 측정 지표, 절차&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;info&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;  초록&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;Green&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;b&gt;Result&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;실제 수치, 발견, 통계 결과&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;success&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;  빨강&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;Red&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;b&gt;Limitation&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;저자가 밝힌 한계, 내가 발견한 약점&amp;middot;반론&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;⚪ 회색&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;Gray&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;b&gt;내 연구와의 연결&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;내 연구에 써먹을 지점, 인용 후보, 아이디어&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;quote&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;  노랑&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;Yellow&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;b&gt;개인적으로 중요&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;그 외 개인적으로 중요하다고 생각한 부분&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;attention&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;표를 보고 콜아웃이 뭐지? 라고 생각하시는 분들이 있으실텐데요,&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-origin-width=&quot;1070&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwRT1E/dJMb998qAC0/kLjaRqYKXPCwVpKrb4vRlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwRT1E/dJMb998qAC0/kLjaRqYKXPCwVpKrb4vRlk/img.png&quot; data-alt=&quot;이런 형식이 콜아웃!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwRT1E/dJMb998qAC0/kLjaRqYKXPCwVpKrb4vRlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwRT1E%2FdJMb998qAC0%2FkLjaRqYKXPCwVpKrb4vRlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;166&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;246&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;Obsidian에서도 해당 기능을 지원하는데요, 지원하는 아이콘과 색깔은 다음과 같아요.&lt;/p&gt;
&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://obsidian.md/help/callouts&quot;&gt;https://obsidian.md/help/callouts&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1786232916850&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;Callouts - Obsidian Help&quot; data-og-description=&quot;This page details how to use callouts to include additional content without breaking the flow of your notes.&quot; data-og-host=&quot;obsidian.md&quot; data-og-source-url=&quot;https://obsidian.md/help/callouts&quot; data-og-url=&quot;https://obsidian.md/help/callouts&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Xs5ZC/dJMb9jgMRCx/nlVimwYeAwRyNCVyfaIBJ1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://obsidian.md/help/callouts&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://obsidian.md/help/callouts&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Xs5ZC/dJMb9jgMRCx/nlVimwYeAwRyNCVyfaIBJ1/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;Callouts - Obsidian Help&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This page details how to use callouts to include additional content without breaking the flow of your notes.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;obsidian.md&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/9VkOi/dJMcaa7riTs/gXCo9RWlkLmhpMxuDFC8j0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9VkOi/dJMcaa7riTs/gXCo9RWlkLmhpMxuDFC8j0/img.png&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;1426&quot; data-is-animation=&quot;false&quot; style=&quot;width: 51.5455%; margin-right: 10px;&quot; data-widthpercent=&quot;52.15&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9VkOi/dJMcaa7riTs/gXCo9RWlkLmhpMxuDFC8j0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9VkOi%2FdJMcaa7riTs%2FgXCo9RWlkLmhpMxuDFC8j0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1206&quot; height=&quot;1426&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/250tS/dJMcadJHpvF/o0jNCSRU1FtTe4GkcFTjt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/250tS/dJMcadJHpvF/o0jNCSRU1FtTe4GkcFTjt1/img.png&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;1562&quot; data-is-animation=&quot;false&quot; style=&quot;width: 47.2917%;&quot; data-widthpercent=&quot;47.85&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/250tS/dJMcadJHpvF/o0jNCSRU1FtTe4GkcFTjt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F250tS%2FdJMcadJHpvF%2Fo0jNCSRU1FtTe4GkcFTjt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1212&quot; height=&quot;1562&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;저는 여기서 지원해 주는 색과 기호와 제가 Zotero에서 사용하는 색을 최대한 통일시켰어요.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 속성에 기본적인 논문 정보를 끌어왔고요, 이후에 제목, 학회, DOI링크를 한 번 더 표시해 주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;abstract 내용도 바로 확인할 수 있도록 배치해 주었어요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1490&quot; data-origin-height=&quot;1788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKHJCu/dJMcahlcmAj/lkvTd3O8YLFwoey7kN5lR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKHJCu/dJMcahlcmAj/lkvTd3O8YLFwoey7kN5lR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKHJCu/dJMcahlcmAj/lkvTd3O8YLFwoey7kN5lR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKHJCu%2FdJMcahlcmAj%2FlkvTd3O8YLFwoey7kN5lR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;840&quot; data-origin-width=&quot;1490&quot; data-origin-height=&quot;1788&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;다음은 우리가 열심히 하이라이트하고 comment단 내용들을 불러와야겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 항상 하이라이트한 문장 + 내 comment 순으로&amp;nbsp; 오도록 배치했어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;comment가 없다면 문장만 등장합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1708&quot; data-origin-height=&quot;1048&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwfNKa/dJMcahlcmSS/Z9CvkHCrSbA3daV7UEkff0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwfNKa/dJMcahlcmSS/Z9CvkHCrSbA3daV7UEkff0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwfNKa/dJMcahlcmSS/Z9CvkHCrSbA3daV7UEkff0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwfNKa%2FdJMcahlcmSS%2FZ9CvkHCrSbA3daV7UEkff0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1708&quot; height=&quot;1048&quot; data-origin-width=&quot;1708&quot; data-origin-height=&quot;1048&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;그리고 제가 언급했던 5가지 내용들을 스스로 정리할 공간이 필요해서 마지막엔 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;그래서 제 템플릿을 Zotero와 함께 사용하면&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Zotero만 사용해서 정독 + 필요한 부분 메모&lt;/li&gt;
&lt;li&gt;Obsidian으로 불러와서 중요내용 확인&lt;/li&gt;
&lt;li&gt;나만의 내용 정리&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;1370&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oG2SP/dJMcahL9GLf/FqULO5lp1zHSbc1XtWKNWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oG2SP/dJMcahL9GLf/FqULO5lp1zHSbc1XtWKNWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oG2SP/dJMcahL9GLf/FqULO5lp1zHSbc1XtWKNWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoG2SP%2FdJMcahL9GLf%2FFqULO5lp1zHSbc1XtWKNWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;648&quot; height=&quot;599&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;1370&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;/p&gt;
&lt;p 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/bGIrhc/dJMcabE9EKU/GNqaCYkI6WcsRABJXUCCX1/Zotero%20Template.md?attach=1&amp;amp;knm=tfile.md&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;Zotero Template.md&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.00MB&lt;/div&gt;
&lt;/div&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;p data-ke-size=&quot;size16&quot;&gt;이 템플릿은 제가 논문을 읽는 방식에 맞추어 제가 만들어낸 저의 창작물입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차가공을 하셔서 개인적으로 사용하시는 건 괜찮지만, 상업적인 사용은 금하며, 공유할 때는 꼭 출처를 밝혀주시면 감사하겠습니다 :)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 &lt;a href=&quot;https://github.com/community-archive/obsidian-zotero-integration/blob/main/docs/README.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/community-archive/obsidian-zotero-integration/blob/main/docs/README.md&lt;/a&gt; 를 참고해서 템플릿을 만들었어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완전히 다른 형식의 템플릿을 제작하시고 싶다면 위 링크를 클릭하셔서 zotero integration 플러그인 개발문서를 참조하시면 좋을 것 같습니다!&lt;/p&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;그럼 위 템플릿을 적용해서 Zotero에 있는 내용을 Obsidian으로 불러오는 방법을 설명드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 cmd + z로 명렁어 선택을 실행시켜요. (맥북기준)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1432&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dFH4Cd/dJMcaa0z7Cj/3pC0A2VwDRa8KsyBXEMV9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dFH4Cd/dJMcaa0z7Cj/3pC0A2VwDRa8KsyBXEMV9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dFH4Cd/dJMcaa0z7Cj/3pC0A2VwDRa8KsyBXEMV9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdFH4Cd%2FdJMcaa0z7Cj%2F3pC0A2VwDRa8KsyBXEMV9K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1432&quot; height=&quot;360&quot; data-origin-width=&quot;1432&quot; data-origin-height=&quot;360&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-origin-width=&quot;1636&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s9pEa/dJMcagT37W8/afCuXrSKcdySs7FboK6JQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s9pEa/dJMcagT37W8/afCuXrSKcdySs7FboK6JQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s9pEa/dJMcagT37W8/afCuXrSKcdySs7FboK6JQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs9pEa%2FdJMcagT37W8%2FafCuXrSKcdySs7FboK6JQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1636&quot; height=&quot;512&quot; data-origin-width=&quot;1636&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1632&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/diao8B/dJMcadJHptF/BzFwUOKnC8cgeZZk4TquY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/diao8B/dJMcadJHptF/BzFwUOKnC8cgeZZk4TquY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/diao8B/dJMcadJHptF/BzFwUOKnC8cgeZZk4TquY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdiao8B%2FdJMcadJHptF%2FBzFwUOKnC8cgeZZk4TquY0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1632&quot; height=&quot;374&quot; data-origin-width=&quot;1632&quot; data-origin-height=&quot;374&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2296&quot; data-origin-height=&quot;1990&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beCFwM/dJMcadXkiPq/00mDbkvNWZRPA96Ih9Km3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beCFwM/dJMcadXkiPq/00mDbkvNWZRPA96Ih9Km3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beCFwM/dJMcadXkiPq/00mDbkvNWZRPA96Ih9Km3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeCFwM%2FdJMcadXkiPq%2F00mDbkvNWZRPA96Ih9Km3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2296&quot; height=&quot;1990&quot; data-origin-width=&quot;2296&quot; data-origin-height=&quot;1990&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;&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;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;p style=&quot;text-align: center;&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;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTPgDr/dJMcafHFE2E/f1uoISNEf83yGNibh8XVx0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTPgDr/dJMcafHFE2E/f1uoISNEf83yGNibh8XVx0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTPgDr/dJMcafHFE2E/f1uoISNEf83yGNibh8XVx0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTPgDr%2FdJMcafHFE2E%2Ff1uoISNEf83yGNibh8XVx0%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;419&quot; height=&quot;296&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;랩실 주말 출근하고&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;야밤에 쓰는 포스팅이라&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;정신이 혼미하네요...&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이전 포스팅이 궁금하시다면,,,&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://easy1nhard2.tistory.com/35&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://easy1nhard2.tistory.com/35&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1786234708888&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;영국 방문연구원의 Zotero로 논문 읽는 방법!&quot; data-og-description=&quot; ️ 공학계열 논문 읽는법, Zotero 사용법 안녕하세요..?오랜만입니다.... 껄껄 저는 25년도 중반까지, 그리고 특히 24년에 개발자가 되겠다는 꿈을 안고,,최대한 부지런히 tech blog를 썼던 사람입니&quot; data-og-host=&quot;easy1nhard2.tistory.com&quot; data-og-source-url=&quot;https://easy1nhard2.tistory.com/35&quot; data-og-url=&quot;https://easy1nhard2.tistory.com/35&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/v9HOx/dJMb8QMrO1h/K4MXEK5bisB9IqolaNid80/img.png?width=800&amp;amp;height=933&amp;amp;face=0_0_800_933,https://scrap.kakaocdn.net/dn/bfWJ2N/dJMb8RR7wJ3/JDLwZWmO29HyDCqbl6CxO0/img.png?width=800&amp;amp;height=933&amp;amp;face=0_0_800_933,https://scrap.kakaocdn.net/dn/Mmk8T/dJMb8UafrI0/cIK6akNKDE3hR0T2tEXx61/img.png?width=1460&amp;amp;height=1776&amp;amp;face=0_0_1460_1776&quot;&gt;&lt;a href=&quot;https://easy1nhard2.tistory.com/35&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://easy1nhard2.tistory.com/35&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/v9HOx/dJMb8QMrO1h/K4MXEK5bisB9IqolaNid80/img.png?width=800&amp;amp;height=933&amp;amp;face=0_0_800_933,https://scrap.kakaocdn.net/dn/bfWJ2N/dJMb8RR7wJ3/JDLwZWmO29HyDCqbl6CxO0/img.png?width=800&amp;amp;height=933&amp;amp;face=0_0_800_933,https://scrap.kakaocdn.net/dn/Mmk8T/dJMb8UafrI0/cIK6akNKDE3hR0T2tEXx61/img.png?width=1460&amp;amp;height=1776&amp;amp;face=0_0_1460_1776');&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;영국 방문연구원의 Zotero로 논문 읽는 방법!&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt; ️ 공학계열 논문 읽는법, Zotero 사용법 안녕하세요..?오랜만입니다.... 껄껄 저는 25년도 중반까지, 그리고 특히 24년에 개발자가 되겠다는 꿈을 안고,,최대한 부지런히 tech blog를 썼던 사람입니&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;easy1nhard2.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;다들 보람찬 연구생활 하시길...&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>생산성</category>
      <category>Obsidian</category>
      <category>obsidian 사용법</category>
      <category>Obsidian 활용법</category>
      <category>Zotero</category>
      <category>Zotero 사용법</category>
      <category>Zotero내용 Obsidian에 불러오기</category>
      <category>공학논문 읽는 법</category>
      <category>논문 읽는 방법</category>
      <category>논문 정리</category>
      <author>orieasy1</author>
      <guid isPermaLink="true">https://easy1nhard2.tistory.com/36</guid>
      <comments>https://easy1nhard2.tistory.com/36#entry36comment</comments>
      <pubDate>Sun, 9 Aug 2026 09:24:09 +0900</pubDate>
    </item>
    <item>
      <title>영국 방문연구원의 Zotero로 논문 읽는 방법!</title>
      <link>https://easy1nhard2.tistory.com/35</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt; ️ 공학계열 논문 읽는법, Zotero 사용법&lt;/p&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-origin-width=&quot;500&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OxXra/dJMcahlaTbg/wHYJVoB7MhRwx9wJEvF2UK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OxXra/dJMcahlaTbg/wHYJVoB7MhRwx9wJEvF2UK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OxXra/dJMcahlaTbg/wHYJVoB7MhRwx9wJEvF2UK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOxXra%2FdJMcahlaTbg%2FwHYJVoB7MhRwx9wJEvF2UK%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;414&quot; height=&quot;331&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;400&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;오랜만입니다.... 껄껄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 25년도 중반까지, 그리고 특히 24년에 개발자가 되겠다는 꿈을 안고,,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대한 부지런히 tech blog를 썼던 사람입니다...&lt;/p&gt;
&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;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;210&quot; data-origin-height=&quot;210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLWlwX/dJMcaaGlTGL/r9ML2VGp0OzHfSr5Nyu5tK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLWlwX/dJMcaaGlTGL/r9ML2VGp0OzHfSr5Nyu5tK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLWlwX/dJMcaaGlTGL/r9ML2VGp0OzHfSr5Nyu5tK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLWlwX%2FdJMcaaGlTGL%2Fr9ML2VGp0OzHfSr5Nyu5tK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;210&quot; height=&quot;210&quot; data-origin-width=&quot;210&quot; data-origin-height=&quot;210&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;하지만 3학년이 너무 힘들었고... (시간적인 여유도 없을 뿐더러)&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 중간중간 개발 얘기도 있겠지만 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;논문 리뷰에 초점&lt;/span&gt;을 맞춰서 이 블로그를 운영해 볼까 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+ &lt;span style=&quot;background-color: #f6e199;&quot;&gt;노션, 옵시디언과 같은 생산성 어플리케이션&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그래서 오늘의 주제는 &quot;논문 읽는 법&quot;&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 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;&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;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;'&lt;/b&gt;&lt;b&gt;내가 왜 이 논문을 읽는지', '이 논문에서 무엇을 얻어갈 것인지'&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;목적이 분명할수록 기억에 오래 남고 여러 관점에서 논문을 읽으면서 내 것을 만들어 갈 수 있기 때문입니다.&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;저는 컴퓨터공학 논문 특히 HCI, Human-Computer Interaction 분야의 논문을 많이 찾아봅니다.&lt;/p&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;(Abstract을 읽고 바로 Methodology 파트로 넘어감)&lt;/p&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 읽을 논문을 어떻게 선정하나요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;첫번째, Google Scholar&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;보통 구글 Scholar에서 검색을 많이 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://scholar.google.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://scholar.google.com/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1786032418647&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;Google 학술 검색&quot; data-og-description=&quot;거인의 어깨에 올라서서 더 넓은 세상을 바라보라 - 아이작 뉴턴 죄송합니다. 자바스크립트를 사용하도록 설정하지 않으면 일부 기능이 작동하지 않을 수 있습니다. 최적의 상태로 사용하려면 &quot; data-og-host=&quot;scholar.google.com&quot; data-og-source-url=&quot;https://scholar.google.com/&quot; data-og-url=&quot;https://scholar.google.com/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://scholar.google.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://scholar.google.com/&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;Google 학술 검색&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;거인의 어깨에 올라서서 더 넓은 세상을 바라보라 - 아이작 뉴턴 죄송합니다. 자바스크립트를 사용하도록 설정하지 않으면 일부 기능이 작동하지 않을 수 있습니다. 최적의 상태로 사용하려면&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;scholar.google.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;Google Scholar에서 검색을 할 땐 키워드 검색이 중요한데, 저는 주로 키워드 선정에서는 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;예를 들어서 &quot;~주제에 대해 공부를 하고 싶어. Google Scholar에 검색할 키워드 좀 정리해줘.&quot; 혹은 &quot;~ 가 고민이어서 논문을 좀 찾아보려고 해. Google Scholar에 검색할 키워드 좀 정리해줘.&quot; 식으로 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;&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;그리고 선정하실 때 해당 학회, 컨퍼런스, 저널이 믿을 만한지, 해당 저자의 논문 활동이 최근까지 활발한지를 주로 체크해 보는 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마음에 드는 연구자나 교수님이 나타나면 해당 저자나 저자가 속해 있는 팀의 논문을 발행 연도나 주제별로 읽어 보기도 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;두번째, Reference 논문 타고 타고 보기&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;그리고 꼬리에 꼬리를 무는 방법도 추천합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 논문을 읽어 내려가면서 reference로 사이트된 논문을 읽어 보는 겁니다.&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/M0LEL/dJMcajwtC0p/M2WRzoSG2diRkm06PUwykk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M0LEL/dJMcajwtC0p/M2WRzoSG2diRkm06PUwykk/img.png&quot; data-origin-width=&quot;932&quot; data-origin-height=&quot;1012&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.222%; margin-right: 10px;&quot; data-widthpercent=&quot;52.84&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M0LEL/dJMcajwtC0p/M2WRzoSG2diRkm06PUwykk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FM0LEL%2FdJMcajwtC0p%2FM2WRzoSG2diRkm06PUwykk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;932&quot; height=&quot;1012&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YplFl/dJMcafVamLB/KqZisRZlhAWHhopcsZEk0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YplFl/dJMcafVamLB/KqZisRZlhAWHhopcsZEk0k/img.png&quot; data-origin-width=&quot;1460&quot; data-origin-height=&quot;1776&quot; data-is-animation=&quot;false&quot; style=&quot;width: 46.6152%;&quot; data-widthpercent=&quot;47.16&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YplFl/dJMcafVamLB/KqZisRZlhAWHhopcsZEk0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYplFl%2FdJMcafVamLB%2FKqZisRZlhAWHhopcsZEk0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1460&quot; height=&quot;1776&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;저기 3.3 Tasks and Procedure 파트에 위치한 adapted from the study procedure [51] 보이시나요?&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;그리고 51번 레퍼런스 논문으로 이동해서 그 논문도 함께 읽어 보는 것입니다.&lt;/p&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;Related Work 세션은 건너뛰어도 된다라는 말 종종 들어보셨을 꺼예요.&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;Related Work 세션에 사이트된 reference 논문을 읽다보면 해당 분야의 고전 논문부터 중요한 개념을 공부할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 해당년도 conference 홈페이지에 들어가서 paper들을 확인하는 방법이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 학회 + 년도 + program을 치면 발표 순서별로? 날짜별로? 논문들을 확인할 수 있어요.&lt;/p&gt;
&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;예를 들어 제가 올해 CHI conference에서 발표된 논문들을 보고 싶으면 CHI 2026 Programs 라고 구글에 검색해서 찾아봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1478&quot; data-origin-height=&quot;910&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Z5ECu/dJMcagGzpp2/bF4VpRVBpZ1dJQ2BeirOPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Z5ECu/dJMcagGzpp2/bF4VpRVBpZ1dJQ2BeirOPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Z5ECu/dJMcagGzpp2/bF4VpRVBpZ1dJQ2BeirOPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZ5ECu%2FdJMcagGzpp2%2FbF4VpRVBpZ1dJQ2BeirOPK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1478&quot; height=&quot;910&quot; data-origin-width=&quot;1478&quot; data-origin-height=&quot;910&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;학회 주최측의 digital library를 살펴보는 방법도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CHI는 ACM이 주최하고 ISMAR는 IEEE가 주최하는데요, 그려면 ACM Digital Library, IEEE Digital Library라고 구글에 검색해보는거죠.&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/bHsOZi/dJMcahSQoSO/n5XltKj35fl48Gji2KVw91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHsOZi/dJMcahSQoSO/n5XltKj35fl48Gji2KVw91/img.png&quot; data-origin-width=&quot;1446&quot; data-origin-height=&quot;1406&quot; data-is-animation=&quot;false&quot; style=&quot;width: 47.9301%; margin-right: 10px;&quot; data-widthpercent=&quot;48.49&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHsOZi/dJMcahSQoSO/n5XltKj35fl48Gji2KVw91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHsOZi%2FdJMcahSQoSO%2Fn5XltKj35fl48Gji2KVw91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1446&quot; height=&quot;1406&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/72ale/dJMb991HAhM/5MNASUqvSaGGNhsYHIbro0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/72ale/dJMb991HAhM/5MNASUqvSaGGNhsYHIbro0/img.png&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;1408&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;51.51&quot; style=&quot;width: 50.9071%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/72ale/dJMb991HAhM/5MNASUqvSaGGNhsYHIbro0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F72ale%2FdJMb991HAhM%2F5MNASUqvSaGGNhsYHIbro0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1538&quot; height=&quot;1408&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;해당 디지털 라이브러리에서 검색하면 해당 주최즉 저널, 컨퍼러스의 논문들만 볼 수 있습니다.&lt;/p&gt;
&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;&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. 읽는 방법 + 논문 읽는 앱 추천&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;어떤걸 생각하면서, 어떤 순서로 읽어야 하나요?&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;개인적으로 논문을 읽을 때 생각해야하는 것, 논문을 읽은 뒤 얻어가야하는 것은 크게 5가지라고 생각합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 논문의 RQ와 Contribution&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Research Question과 Contribution, 당연히 이 논문이 어떤 문제를 해결하려 했고 어떤 기여를 했는지를 살펴봐야겠죠.&lt;/p&gt;
&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 data-ke-size=&quot;size16&quot;&gt;아마 Discussion 혹은 Future work 세션에 저자들이 생각하는 논문의 한계점을 명시해 두었을 겁니다.&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;마지막으로 해당 논문과 내 연구와의 관계성입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p 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;p data-ke-size=&quot;size16&quot;&gt;저는 보통 abstract -&amp;gt; intro에서 RQ와 Contribution만 간단하게 체크 -&amp;gt; method -&amp;gt; result -&amp;gt; discussion &amp;amp; contribution 하는 편입니다.&lt;/p&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;방법론이 궁금해서 읽는다면 abstract만 읽고 해당 스터디의 method와 result만 읽고 넘어가기도 합니다.&lt;/p&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이 되는 논문이라면 Related Work까지 모두 꼼꼼하게 읽는 편입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 Related Work는 보통 제일 마지막에 읽는 편이에요.&lt;/p&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;size18&quot;&gt;논문을 읽을 때 추천하는 어플리케이션: Zotero&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 alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;146&quot; data-origin-height=&quot;146&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cL4fDL/dJMcahyDGuv/Mrkso8CkgxjL9XzCC7Atxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cL4fDL/dJMcahyDGuv/Mrkso8CkgxjL9XzCC7Atxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cL4fDL/dJMcahyDGuv/Mrkso8CkgxjL9XzCC7Atxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcL4fDL%2FdJMcahyDGuv%2FMrkso8CkgxjL9XzCC7Atxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;146&quot; height=&quot;146&quot; data-origin-width=&quot;146&quot; data-origin-height=&quot;146&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 Zotero입니다.&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;다운로드 링크 ⬇️&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.zotero.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.zotero.org/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1786038339979&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;Zotero | Your personal research assistant&quot; data-og-description=&quot;&quot; data-og-host=&quot;www.zotero.org&quot; data-og-source-url=&quot;https://www.zotero.org/&quot; data-og-url=&quot;https://www.zotero.org/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/6iCyi/dJMb8QMryyc/wLvnStwNK5gbsnV4oxl8hK/img.png?width=1170&amp;amp;height=706&amp;amp;face=0_0_1170_706&quot;&gt;&lt;a href=&quot;https://www.zotero.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.zotero.org/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/6iCyi/dJMb8QMryyc/wLvnStwNK5gbsnV4oxl8hK/img.png?width=1170&amp;amp;height=706&amp;amp;face=0_0_1170_706');&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;Zotero | Your personal research assistant&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.zotero.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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 Zotero를 좋아하는 이유는 프로젝트별로 논문을 구분해서 저장할 수 있고, 하이라이트와 Comment 기능 때문입니다.&lt;/p&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1716&quot; data-origin-height=&quot;2002&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBxt6P/dJMcad30agk/9iQN3T9KrBc0UXUYKtKBz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBxt6P/dJMcad30agk/9iQN3T9KrBc0UXUYKtKBz1/img.png&quot; data-alt=&quot;Zotero 사용 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBxt6P/dJMcad30agk/9iQN3T9KrBc0UXUYKtKBz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBxt6P%2FdJMcad30agk%2F9iQN3T9KrBc0UXUYKtKBz1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1716&quot; height=&quot;2002&quot; data-origin-width=&quot;1716&quot; data-origin-height=&quot;2002&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Zotero 사용 예시&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;사실 많은 분들이 논문을 읽는데 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;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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 지금은 문장별로 번역을 시킨 다음에 Zotero를 사용해서 문장 구조를 확인해가면 필요하거나 중요한 내용은 메모를 하는 방식으로 사용하고 있답니다.&lt;/p&gt;
&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;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;&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;Zotero는 Chorme 확장 프로그램과 함께 동작해요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3096&quot; data-origin-height=&quot;1550&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uwulW/dJMcaf8y4kd/87kcBq3V5y72bk8ld4Y901/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uwulW/dJMcaf8y4kd/87kcBq3V5y72bk8ld4Y901/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uwulW/dJMcaf8y4kd/87kcBq3V5y72bk8ld4Y901/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuwulW%2FdJMcaf8y4kd%2F87kcBq3V5y72bk8ld4Y901%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3096&quot; height=&quot;1550&quot; data-origin-width=&quot;3096&quot; data-origin-height=&quot;1550&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2256&quot; data-origin-height=&quot;1752&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBaAiR/dJMcafnltrQ/NG9hfnM5GLv27AgFtmdNt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBaAiR/dJMcafnltrQ/NG9hfnM5GLv27AgFtmdNt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBaAiR/dJMcafnltrQ/NG9hfnM5GLv27AgFtmdNt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBaAiR%2FdJMcafnltrQ%2FNG9hfnM5GLv27AgFtmdNt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2256&quot; height=&quot;1752&quot; data-origin-width=&quot;2256&quot; data-origin-height=&quot;1752&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;확장프로그램을 사용해서 논문 웹사이트에서 바로바로 자기가 원하는 Zotero 폴더로 논문을 저장할 수 있죠.&lt;/p&gt;
&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;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1186&quot; data-origin-height=&quot;724&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Oov7K/dJMcabE8llY/9osK9v5fnBMI8jFRy9TFH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Oov7K/dJMcabE8llY/9osK9v5fnBMI8jFRy9TFH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Oov7K/dJMcabE8llY/9osK9v5fnBMI8jFRy9TFH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOov7K%2FdJMcabE8llY%2F9osK9v5fnBMI8jFRy9TFH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1186&quot; height=&quot;724&quot; data-origin-width=&quot;1186&quot; data-origin-height=&quot;724&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;그래서 프로젝트끼리 논문을 관리할 수 있고, 나중에 논문 작성 시 Reference로 사이트할 논문을 찾기도 비교적 수월하답니다!&lt;/p&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;그리고 Zotmoov를 사용하실 때 Zotmoov라는 플러그인을 함께 사용하시는 걸 추천들려요!!&lt;/p&gt;
&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;Zotmoov를 사용하시면 지정한 폴더로 저장할 수 있어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Zotmoov 설치링크⬇️&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/wileyyugioh/zotmoov&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/wileyyugioh/zotmoov&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1786039223535&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 - wileyyugioh/zotmoov: Zotero plugin to automatically move attachments and link them&quot; data-og-description=&quot;Zotero plugin to automatically move attachments and link them - wileyyugioh/zotmoov&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/wileyyugioh/zotmoov&quot; data-og-url=&quot;https://github.com/wileyyugioh/zotmoov&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ilnl0/dJMb9jgMAYV/qGtOtYHLFASgbkDz3HFZW0/img.png?width=1824&amp;amp;height=1480&amp;amp;face=0_0_1824_1480&quot;&gt;&lt;a href=&quot;https://github.com/wileyyugioh/zotmoov&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/wileyyugioh/zotmoov&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ilnl0/dJMb9jgMAYV/qGtOtYHLFASgbkDz3HFZW0/img.png?width=1824&amp;amp;height=1480&amp;amp;face=0_0_1824_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;GitHub - wileyyugioh/zotmoov: Zotero plugin to automatically move attachments and link them&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Zotero plugin to automatically move attachments and link them - wileyyugioh/zotmoov&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;설정하는 방법도 간단해요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 링크로 들어가신 뒤, 아래 사진의 Download the latest release here을 클릭해서 들어가주세요!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1610&quot; data-origin-height=&quot;1688&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceDwQp/dJMb998pey5/TrvlNjWP924uOZnWzgxi5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceDwQp/dJMb998pey5/TrvlNjWP924uOZnWzgxi5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceDwQp/dJMb998pey5/TrvlNjWP924uOZnWzgxi5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceDwQp%2FdJMb998pey5%2FTrvlNjWP924uOZnWzgxi5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1610&quot; height=&quot;1688&quot; data-origin-width=&quot;1610&quot; data-origin-height=&quot;1688&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;그럼 아래 화면이 나타나는데요, xpi 확장자의 파일을 다운받아주세요!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2224&quot; data-origin-height=&quot;1240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rqp2l/dJMcadQswOu/aF4F0yNIuwBCw0jaUEhYdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rqp2l/dJMcadQswOu/aF4F0yNIuwBCw0jaUEhYdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rqp2l/dJMcadQswOu/aF4F0yNIuwBCw0jaUEhYdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frqp2l%2FdJMcadQswOu%2FaF4F0yNIuwBCw0jaUEhYdK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2224&quot; height=&quot;1240&quot; data-origin-width=&quot;2224&quot; data-origin-height=&quot;1240&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;그다음 Zotero &amp;gt; Tools &amp;gt; Plugins에 들어가신 뒤, Install Plugins Form File을 클릭해주세요.&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/bm8GGw/dJMcabkWXB9/fLR4K478b9dUsUNn9lFnXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm8GGw/dJMcabkWXB9/fLR4K478b9dUsUNn9lFnXK/img.png&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;960&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.5416%; margin-right: 10px;&quot; data-widthpercent=&quot;50.12&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm8GGw/dJMcabkWXB9/fLR4K478b9dUsUNn9lFnXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbm8GGw%2FdJMcabkWXB9%2FfLR4K478b9dUsUNn9lFnXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1400&quot; height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Yk7bt/dJMcadbPmKZ/ZLdGE6PkIzFXkiRbUHoVXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Yk7bt/dJMcadbPmKZ/ZLdGE6PkIzFXkiRbUHoVXk/img.png&quot; data-origin-width=&quot;1988&quot; data-origin-height=&quot;1370&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.2957%;&quot; data-widthpercent=&quot;49.88&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Yk7bt/dJMcadbPmKZ/ZLdGE6PkIzFXkiRbUHoVXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYk7bt%2FdJMcadbPmKZ%2FZLdGE6PkIzFXkiRbUHoVXk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1988&quot; height=&quot;1370&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;그런 다음 다운받은 xpi 확장자 플러그인 파일을 클릭하시면 아래 처럼 설치된 걸 보실 수 있습니다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1098&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dtgaQf/dJMcajwtDzp/t6zNLg8MZOkPOJmpkljvEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dtgaQf/dJMcajwtDzp/t6zNLg8MZOkPOJmpkljvEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dtgaQf/dJMcajwtDzp/t6zNLg8MZOkPOJmpkljvEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdtgaQf%2FdJMcajwtDzp%2Ft6zNLg8MZOkPOJmpkljvEK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;1098&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1098&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;그런 다음 해당 창을 닫고 Settings 창에 들어가시면 어디 디렉토리 밑으로 논문 파일들을 저장할지 설정하실 수 있어요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1604&quot; data-origin-height=&quot;1268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bujU2Z/dJMcaaTNnK8/Ku3Tk3tsbP1lxO26nVc2C1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bujU2Z/dJMcaaTNnK8/Ku3Tk3tsbP1lxO26nVc2C1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bujU2Z/dJMcaaTNnK8/Ku3Tk3tsbP1lxO26nVc2C1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbujU2Z%2FdJMcaaTNnK8%2FKu3Tk3tsbP1lxO26nVc2C1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1604&quot; height=&quot;1268&quot; data-origin-width=&quot;1604&quot; data-origin-height=&quot;1268&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논문 목록에서 우클릭 &amp;gt; ZotMoov: Move Selected to Directory를 사용해서 이동시킬 수 있습니다!!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1282&quot; data-origin-height=&quot;1108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdVPBp/dJMcadQswPd/S0LBYBiSiKV0UKf6kstkM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdVPBp/dJMcadQswPd/S0LBYBiSiKV0UKf6kstkM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdVPBp/dJMcadQswPd/S0LBYBiSiKV0UKf6kstkM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdVPBp%2FdJMcadQswPd%2FS0LBYBiSiKV0UKf6kstkM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1282&quot; height=&quot;1108&quot; data-origin-width=&quot;1282&quot; data-origin-height=&quot;1108&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;&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;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;p data-ke-size=&quot;size16&quot;&gt;여기까지가 기본적인 논문읽는 방법과 Zotero 사용법이었어요!&lt;/p&gt;
&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;Obsidian을 사용하면 완전 편리하게! 해당 내용을 Obisidian 노트로 가져올 수 있답니다!&lt;/p&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-origin-width=&quot;328&quot; data-origin-height=&quot;262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bogW6Z/dJMcahFlLUd/P5scwOfo4KaEsOh8Mxcsb1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bogW6Z/dJMcahFlLUd/P5scwOfo4KaEsOh8Mxcsb1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bogW6Z/dJMcahFlLUd/P5scwOfo4KaEsOh8Mxcsb1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbogW6Z%2FdJMcahFlLUd%2FP5scwOfo4KaEsOh8Mxcsb1%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;328&quot; height=&quot;262&quot; data-origin-width=&quot;328&quot; data-origin-height=&quot;262&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기록과 정리에 미친 저의 obsidian, 노션 활용법 포스팅을 앞으로도 꾸준히 들고 올테니 확인해주시면 감사하겠습니다 :)&lt;/p&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;</description>
      <category>생산성</category>
      <category>Zotero</category>
      <category>Zotero사용법</category>
      <category>공학논문</category>
      <category>공학논문읽는법</category>
      <category>논문</category>
      <category>논문읽는법</category>
      <category>대학원</category>
      <category>대학원생</category>
      <category>컴공논문</category>
      <category>학부연구생</category>
      <author>orieasy1</author>
      <guid isPermaLink="true">https://easy1nhard2.tistory.com/35</guid>
      <comments>https://easy1nhard2.tistory.com/35#entry35comment</comments>
      <pubDate>Fri, 7 Aug 2026 03:13:05 +0900</pubDate>
    </item>
    <item>
      <title>[LangChain] 7. 텍스트 분할 (Text Splitter)</title>
      <link>https://easy1nhard2.tistory.com/34</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 문서 분할이란?&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;문서분할(Text Spliter)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RAG의 2단계로, 로드된 문서를 LLM이 처리하기 좋은 작은 조각(청크) 으로 나누는 과정&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;크고 복잡한 문서를 LLM 이 받아들일 수 있는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;효율적인 작은 규모의 조각으로 나누는 작업&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;시스템이 정보를 보다 잘 활용할 수 있도록&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목적: &lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&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;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;핀포인트 정보 검색(정확성)&lt;/b&gt;: &lt;br /&gt;문서를 세분화함으로써&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;질문(Query) 에 연관성이 있는 정보&lt;/b&gt;만 가져오는데 도움이 됨.&lt;br /&gt;각각의 단위는 특정 주제나 내용에 초점을 맞추므로,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;관련성이 높은 정보를 제공함.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;리소스 최적화(효율성)&lt;/b&gt;: &lt;br /&gt;전체 문서를 LLM 으로 입력하게 되면 비용이 많이 발생할 뿐더러, 효율적인 답변을 많은 정보속에 발췌하여 답변하지 못하게 됨. 때로는 이러한 문제가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;할루시네이션&lt;/b&gt;으로 이어지게 됨 &amp;rarr; 답변에 필요한 정보만 발췌&lt;/li&gt;
&lt;/ol&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;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;문서 구조 파악&lt;/b&gt;: PDF 파일, 웹 페이지, 전자 책 등 다양한 형식의 문서에서 구조를 파악 (문서의 헤더, 푸터, 페이지 번호, 섹션 제목 등을 식별하는 과정을 포함)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단위 선정&lt;/b&gt;: 문서를 어떤 단위로 나눌지 결정 (ex. 페이지별, 섹션별, 또는 문단별일 수 있으며, 문서의 내용과 목적에 따라 다름)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단위 크기 선정(chunk size)&lt;/b&gt;: 문서를 몇 개의 토큰 단위로 나눌 것인지를 정함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;청크 오버랩(chunk overlap)&lt;/b&gt;: 분할된 끝 부분에서 맥락이 이어질 수 있도록 일부를 겹쳐서(overlap) 분할하는 것이 일반적&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. CharacterTextSplitter&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;기본적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&quot;\n\n&quot;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 기준으로 문자 단위로 텍스트를 분할&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #000000; text-align: start;&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;&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 id=&quot;code_1767515060077&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# data/appendix-keywords.txt 파일을 열어서 f라는 파일 객체를 생성합니다.
with open(&quot;./data/appendix-keywords.txt&quot;) as f:
    file = f.read()  # 파일의 내용을 읽어서 file 변수에 저장합니다.&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;CharacterTextSplitter 설정&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767515367045&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_text_splitters import CharacterTextSplitter

text_splitter = CharacterTextSplitter(
    # 텍스트를 분할할 때 사용할 구분자를 지정
    # separator=&quot; &quot;,
    # 분할된 텍스트 청크의 최대 크기를 지정
    chunk_size=250,
    # 분할된 텍스트 청크 간의 중복되는 문자 수를 지정
    chunk_overlap=50,
    # 텍스트의 길이를 계산하는 함수를 지정
    length_function=len,
    # 구분자가 정규식인지 여부를 지정
    is_separator_regex=False,
)&lt;/code&gt;&lt;/pre&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt; 매개변수 &lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt; 설정값 &lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;의미&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;separator&lt;/td&gt;
&lt;td&gt;기본값 \n\n&lt;/td&gt;
&lt;td&gt;문단 단위 분할&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;chunk_size&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;td&gt;청크 최대 문자 수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;chunk_overlap&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;인접 청크 간 중복 문자 수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;length_function&lt;/td&gt;
&lt;td&gt;len&lt;/td&gt;
&lt;td&gt;길이 계산 기준 = 문자 수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;is_separator_regex&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;td&gt;separator를 일반 문자열로 처리&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;&lt;b&gt;문서 분할&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;text_splitter&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;를 사용하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;file&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;텍스트를 문서 단위로 분할&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767515473301&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;texts = text_splitter.create_documents([file])
print(texts[0])  # 분할된 문서 중 첫 번째 문서를 출력합니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;541&quot; data-origin-height=&quot;124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGhNl6/dJMcahiMC1C/qxLTopdzq26jWs1DiGQtj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGhNl6/dJMcahiMC1C/qxLTopdzq26jWs1DiGQtj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGhNl6/dJMcahiMC1C/qxLTopdzq26jWs1DiGQtj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGhNl6%2FdJMcahiMC1C%2FqxLTopdzq26jWs1DiGQtj0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;541&quot; height=&quot;124&quot; data-origin-width=&quot;541&quot; data-origin-height=&quot;124&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;pre id=&quot;code_1767515611653&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;metadatas = [
    {&quot;document&quot;: 1},
    {&quot;document&quot;: 2},
]  # 문서에 대한 메타데이터 리스트를 정의합니다.
documents = text_splitter.create_documents(
    [
        file,
        file,
    ],  # 분할할 텍스트 데이터를 리스트로 전달합니다.
    metadatas=metadatas,  # 각 문서에 해당하는 메타데이터를 전달합니다.
)
print(documents[0])  # 분할된 문서 중 첫 번째 문서를 출력합니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/S84fj/dJMcafec5jz/SHKw0jzGCe0tKX6mbZbO3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/S84fj/dJMcafec5jz/SHKw0jzGCe0tKX6mbZbO3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/S84fj/dJMcafec5jz/SHKw0jzGCe0tKX6mbZbO3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FS84fj%2FdJMcafec5jz%2FSHKw0jzGCe0tKX6mbZbO3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;540&quot; height=&quot;124&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;124&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;pre id=&quot;code_1767515724373&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# text_splitter를 사용하여 file 텍스트를 분할하고, 분할된 텍스트의 첫 번째 요소를 반환
text_splitter.split_text(file)[0]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;123&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zKrTe/dJMcaiPt0No/SXzWV4fexCdN0C9WrQtJsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zKrTe/dJMcaiPt0No/SXzWV4fexCdN0C9WrQtJsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zKrTe/dJMcaiPt0No/SXzWV4fexCdN0C9WrQtJsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzKrTe%2FdJMcaiPt0No%2FSXzWV4fexCdN0C9WrQtJsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;540&quot; height=&quot;123&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;123&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;03. 재귀적 문자 텍스트 분할 (RecursiveCharacterTextSplitter)&lt;/h2&gt;
&lt;p data-end=&quot;395&quot; data-start=&quot;247&quot; data-ke-size=&quot;size16&quot;&gt;RecursiveCharacterTextSplitter는 &lt;b&gt;일반적인 텍스트 문서에 가장 권장되는 분할 방식&lt;/b&gt;&lt;br /&gt;이 분할기는 &lt;b&gt;여러 개의 문자 구분자 목록을 순차적으로 적용&lt;/b&gt;하여, 청크가 충분히 작아질 때까지 &lt;b&gt;재귀적으로 텍스트를 분할&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;467&quot; data-start=&quot;397&quot; data-ke-size=&quot;size16&quot;&gt;단순히 하나의 기준으로 자르는 것이 아니라, &lt;b&gt;의미 단위를 최대한 유지하면서&lt;/b&gt; 점진적으로 잘게 나누는 것이 핵심.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;텍스트가 분할되는 방식: 문자 목록([&quot;\n\n&quot;, &quot;\n&quot;, &quot; &quot;, &quot;&quot;]) 에 의해 분할됩니다.&lt;/li&gt;
&lt;li&gt;청크 크기가 측정되는 방식: 문자 수에 의해 측정됩니&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;467&quot; data-start=&quot;397&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;467&quot; data-start=&quot;397&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;467&quot; data-start=&quot;397&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기본 동작 원리&lt;/b&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 data-end=&quot;467&quot; data-start=&quot;397&quot;&gt;기본 문자 목록: [&quot;\n\n&quot;,&amp;nbsp;&quot;\n&quot;,&amp;nbsp;&quot;&amp;nbsp;&quot;,&amp;nbsp;&quot;&quot;]&lt;/li&gt;
&lt;li data-end=&quot;467&quot; data-start=&quot;397&quot;&gt;분할 시도 순서
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;573&quot; data-start=&quot;559&quot;&gt;단락 (\n\n)&lt;/li&gt;
&lt;li data-end=&quot;588&quot; data-start=&quot;576&quot;&gt;문장 (\n)&lt;/li&gt;
&lt;li data-end=&quot;602&quot; data-start=&quot;591&quot;&gt;단어 ( )&lt;/li&gt;
&lt;li data-end=&quot;624&quot; data-start=&quot;605&quot;&gt;문자 (&quot;&quot;, 최후 수단)&lt;/li&gt;
&lt;/ol&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;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_1767517876821&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# data/appendix-keywords.txt 파일을 열어서 f라는 파일 객체를 생성합니다.
with open(&quot;./data/appendix-keywords.txt&quot;) as f:
    file = f.read()  # 파일의 내용을 읽어서 file 변수에 저장합니다.&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;RecursiveCahrarcterTextSplitter 설정&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767517903350&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_text_splitters import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(
    # 분할된 텍스트 청크의 최대 크기를 지정
    chunk_size=250,
    # 분할된 텍스트 청크 간의 중복되는 문자 수를 지정
    chunk_overlap=50,
    # 텍스트의 길이를 계산하는 함수를 지정
    length_function=len,
    # 구분자가 정규식인지 여부를 지정
    is_separator_regex=False,
)&lt;/code&gt;&lt;/pre&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&gt;&lt;b&gt;매개변수&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;설정값&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;의미&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;separators&lt;/td&gt;
&lt;td&gt;기본값 [&quot;\n\n&quot;, &quot;\n&quot;, &quot; &quot;, &quot;&quot;]&lt;/td&gt;
&lt;td&gt;재귀적 분할 기준 문자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;chunk_size&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;td&gt;청크 최대 문자 수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;chunk_overlap&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;인접 청크 간 중복 문자 수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;length_function&lt;/td&gt;
&lt;td&gt;len&lt;/td&gt;
&lt;td&gt;길이 계산 기준 = 문자 수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;is_separator_regex&lt;/td&gt;
&lt;td&gt;False&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-end=&quot;1705&quot; data-start=&quot;1680&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1705&quot; data-start=&quot;1680&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문서 분할 (Document 객체 반환)&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1783&quot; data-start=&quot;1707&quot; data-ke-size=&quot;size16&quot;&gt;RecursiveCharacterTextSplitter를 사용하여 file 텍스트를 &lt;b&gt;문서(Document) 단위로 분할&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1783&quot; data-start=&quot;1707&quot; data-ke-size=&quot;size16&quot;&gt;분할된 문서는 texts 리스트에 저장됨&lt;/p&gt;
&lt;pre id=&quot;code_1767518132710&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;texts = text_splitter.create_documents([file])

print(texts[0])  # 첫 번째 문서 출력
print(&quot;===&quot; * 20)
print(texts[1])  # 두 번째 문서 출력&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;544&quot; data-origin-height=&quot;237&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WFt3T/dJMcaaRu8G7/PXgCOMLT0ubF8ubi1fQpNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WFt3T/dJMcaaRu8G7/PXgCOMLT0ubF8ubi1fQpNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WFt3T/dJMcaaRu8G7/PXgCOMLT0ubF8ubi1fQpNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWFt3T%2FdJMcaaRu8G7%2FPXgCOMLT0ubF8ubi1fQpNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;544&quot; height=&quot;237&quot; data-origin-width=&quot;544&quot; data-origin-height=&quot;237&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;pre id=&quot;code_1767518217309&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 텍스트를 분할하고 분할된 텍스트의 처음 2개 요소를 반환
text_splitter.split_text(file)[:2]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;535&quot; data-origin-height=&quot;189&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5MlBu/dJMcafSOr0g/xQ9AvvoVK1V7jwy5g2Ugw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5MlBu/dJMcafSOr0g/xQ9AvvoVK1V7jwy5g2Ugw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5MlBu/dJMcafSOr0g/xQ9AvvoVK1V7jwy5g2Ugw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5MlBu%2FdJMcafSOr0g%2FxQ9AvvoVK1V7jwy5g2Ugw1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;189&quot; data-origin-width=&quot;535&quot; data-origin-height=&quot;189&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;04. 토큰 텍스트 분할(TokenTextSplitter)&lt;/h2&gt;
&lt;p data-end=&quot;288&quot; data-start=&quot;187&quot; data-ke-size=&quot;size16&quot;&gt;대부분의 &lt;b&gt;언어 모델(LLM)은 입력 가능한 토큰 수에 제한&lt;/b&gt;이 있음.&lt;br /&gt;따라서 문서를 분할할 때 &lt;b&gt;문자 수가 아니라 토큰 수 기준으로 관리&lt;/b&gt;해야 하는 경우가 많음.&lt;/p&gt;
&lt;p data-end=&quot;288&quot; data-start=&quot;187&quot; data-ke-size=&quot;size16&quot;&gt;TokenTextSplitter는 텍스트를 &lt;b&gt;토큰 개수를 기준으로 청크(chunk)로 분할&lt;/b&gt;하는 데 사용되는 분할기&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;543&quot; data-start=&quot;388&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;463&quot; data-start=&quot;426&quot;&gt;문자 수 기준 분할은 실제 토큰 수를 초과할 위험 존재&lt;/li&gt;
&lt;li data-end=&quot;543&quot; data-start=&quot;464&quot;&gt;토큰 기준 분할은:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;543&quot; data-start=&quot;479&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;502&quot; data-start=&quot;479&quot;&gt;&lt;b&gt;모델 입력 제한을 안전하게 만족&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;543&quot; data-start=&quot;505&quot;&gt;특히 embedding, generation 단계에서 필수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 114px;&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;height: 19px;&quot;&gt;CharacterTextSplitter&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;문자&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;문자 수&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;가장 단순&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;RecursiveCharacterTextSplitter&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;문자(재귀)&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;문자 수&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;의미 보존 ⭕&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;TokenTextSplitter&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;토큰&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;토큰 수&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;LLM 안전 ⭕&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;tiktoken + Recursive&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;재귀 + 토큰&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;토큰 수&lt;/td&gt;
&lt;td style=&quot;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;height: 19px;&quot;&gt;spaCy / NLTK&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;문장&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;문자 수&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;NLP 전통 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;KoNLPy&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;형태소&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;문장&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;한국어 특화&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;tiktoken&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;tiktoken이란?&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;OpenAI에서 만든 빠른 BPE(Byte Pair Encoding) 토크나이저&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;GPT 계열 모델과 동일한 토큰 계산 방식 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;%pip install --upgrade --quiet langchain-text-splitters tiktoken&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&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;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;withopen(&quot;./data/appendix-keywords.txt&quot;)as f:
    file = f.read()&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;tiktoken 기반 분할 (CharacterTextSplitter 활용)&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;from langchain_text_splittersimport CharacterTextSplitter

text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
    chunk_size=300,
    chunk_overlap=0,
)

texts = text_splitter.split_text(file)&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&gt;&lt;b&gt;분할 자체는 CharacterTextSplitter 방식&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;청크 크기 계산에만 tiktoken 사용&lt;/b&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;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;&lt;b&gt;권장 대안&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;RecursiveCharacterTextSplitter.from_tiktoken_encoder&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&gt;토큰 기준 크기를 초과하면 &lt;b&gt;재귀적으로 재분할&lt;/b&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TokenTextSplitter&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TokenTextSplitter는 &lt;b&gt;처음부터 토큰 단위로 텍스트를 분할&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;from langchain_text_splittersimport TokenTextSplitter

text_splitter = TokenTextSplitter(
    chunk_size=200,
    chunk_overlap=0,
)

texts = text_splitter.split_text(file)

&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&gt;분할 기준: &lt;b&gt;토큰&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;청크 크기: &lt;b&gt;토큰 수 기준&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;LLM 입력 안정성 ⭕&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;h3 data-ke-size=&quot;size23&quot;&gt;기타 토크나이저 기반 분할기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;spaCy 기반 분할&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;spaCy tokenizer 사용&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;문장 단위 분할에 강점&lt;/li&gt;
&lt;li&gt;chunk size 측정은 &lt;b&gt;문자 수 기준&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;import warnings
from langchain_text_splitters import SpacyTextSplitter

# 경고 메시지를 무시합니다.
warnings.filterwarnings(&quot;ignore&quot;)

# SpacyTextSplitter를 생성합니다.
text_splitter = SpacyTextSplitter(
    chunk_size=200,  # 청크 크기를 200으로 설정합니다.
    chunk_overlap=50,  # 청크 간 중복을 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;&lt;b&gt;NLTK 기반 분할&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;Natural Language Toolkit (NLTK)은 Python 프로그래밍 언어로 작성된 영어 자연어 처리(NLP)를 위한 라이브러리와 프로그램 모음&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;b&gt;NLTK tokenizer 기반&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;비교적 단순한 문장 분할&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;from langchain_text_splitters import NLTKTextSplitter

text_splitter = NLTKTextSplitter(
    chunk_size=200,  # 청크 크기를 200으로 설정합니다.
    chunk_overlap=0,  # 청크 간 중복을 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;&lt;b&gt;SentenceTransformersTokenTextSplitter&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;sentence-transformer 모델 전용&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;모델의 &lt;b&gt;토큰 윈도우 크기에 맞게 분할&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1767520443961&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_text_splitters import SentenceTransformersTokenTextSplitter

# 문장 분할기를 생성하고 청크 간 중복을 0으로 설정합니다.
splitter = SentenceTransformersTokenTextSplitter(chunk_size=200, chunk_overlap=0)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;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;&lt;b&gt;KoNLPy (한국어)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한국어는 영어와 구조가 다르므로 &lt;b&gt;전용 토크나이저 필요&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;KoNLPy의 &lt;b&gt;Kkma 형태소 분석기&lt;/b&gt; 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;from langchain_text_splitters import KonlpyTextSplitter

# KonlpyTextSplitter를 사용하여 텍스트 분할기 객체를 생성합니다.
text_splitter = KonlpyTextSplitter()

texts = text_splitter.split_text(file)  # 한국어 문서를 문장 단위로 분할합니다.
print(texts[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;&lt;b&gt;Hugging Face Tokenizer&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;GPT2TokenizerFast 등 사용 가능&lt;/li&gt;
&lt;li&gt;Hugging Face 토크나이저 기준으로 &lt;b&gt;토큰 길이 계산&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;text_splitter = CharacterTextSplitter.from_huggingface_tokenizer(
    # 허깅페이스 토크나이저를 사용하여 CharacterTextSplitter 객체를 생성합니다.
    hf_tokenizer,
    chunk_size=300,
    chunk_overlap=50,
)
# state_of_the_union 텍스트를 분할하여 texts 변수에 저장합니다.
texts = text_splitter.split_text(file)&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;h2 data-ke-size=&quot;size26&quot;&gt;05. 시멘틱 청커 (SemanticChunker)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;SemanticChunker란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SemanticChunker는 텍스트를 &lt;b&gt;의미론적 유사성(semantic similarity)&lt;/b&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;LangChain의 &lt;b&gt;실험적(experimental) 기능&lt;/b&gt;이며, Greg Kamradt의 아이디어와 노트북을 기반으로 구현되었습니다.&lt;/p&gt;
&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;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;의미가 크게 바뀌는 지점에서 문서를 나눈다&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;텍스트를 &lt;b&gt;문장 단위로 분리&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;인접 문장 간 &lt;b&gt;임베딩 거리(차이)&lt;/b&gt; 계산&lt;/li&gt;
&lt;li&gt;의미 차이가 충분히 크면 &amp;rarr; &lt;b&gt;분할 (breakpoint)&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;&lt;b&gt;동작 방식 개요&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;텍스트를 문장 단위로 분할&lt;/li&gt;
&lt;li&gt;문장 임베딩 생성 (OpenAI Embeddings 등)&lt;/li&gt;
&lt;li&gt;인접 문장 간 임베딩 거리 계산&lt;/li&gt;
&lt;li&gt;임계값(threshold)을 초과하는 지점에서 분할&lt;/li&gt;
&lt;li&gt;의미적으로 유사한 문장들은 하나의 청크로 병합&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;파일 로딩&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;with open(&quot;./data/appendix-keywords.txt&quot;) as f:
    file = f.read()

&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;SemanticChunker 생성&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai.embeddings import OpenAIEmbeddings

text_splitter = SemanticChunker(OpenAIEmbeddings())

&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&gt;&lt;b&gt;임베딩 모델 필수&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;OpenAI Embeddings 외에도 다른 임베딩 모델 사용 가능&lt;/li&gt;
&lt;li&gt;텍스트 분할&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;chunks = text_splitter.split_text(file)
print(chunks[0])

&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&gt;반환 타입: List[str]&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문단/문자 기준이 아닌 의미 단위 기준 분할&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Document 객체로 변환&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;docs = text_splitter.create_documents([file])
print(docs[0].page_content)

&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&gt;반환 타입: &lt;b&gt;LangChain Document&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;RAG 파이프라인에 바로 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Breakpoint (분리 기준점)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SemanticChunker는 &lt;b&gt;문장을 &amp;ldquo;어디서 나눌지&amp;rdquo;&lt;/b&gt; 결정하는 방식이 핵심&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 &lt;b&gt;문장 간 임베딩 차이&lt;/b&gt;를 기준으로 판단&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;분할 기준점 방식 (Threshold Types)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Percentile (백분위수, 기본값)&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;text_splitter = SemanticChunker(
    OpenAIEmbeddings(),
    breakpoint_threshold_type=&quot;percentile&quot;,
    breakpoint_threshold_amount=70,
)

&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&gt;문장 간 거리 분포 계산&lt;/li&gt;
&lt;li&gt;상위 N% 이상 차이가 나는 지점에서 분할&lt;/li&gt;
&lt;li&gt;상대적으로 안정적이고 일반적인 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Standard Deviation (표준편차)&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;text_splitter = SemanticChunker(
    OpenAIEmbeddings(),
    breakpoint_threshold_type=&quot;standard_deviation&quot;,
    breakpoint_threshold_amount=1.25,
)

&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&gt;평균 대비 표준편차 이상 차이가 날 경우 분할&lt;/li&gt;
&lt;li&gt;강한 의미 변화만 분할&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Interquartile Range (사분위수 범위)&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;text_splitter = SemanticChunker(
    OpenAIEmbeddings(),
    breakpoint_threshold_type=&quot;interquartile&quot;,
    breakpoint_threshold_amount=0.5,
)

&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&gt;IQR 기반으로 이상치 수준의 의미 변화 감지&lt;/li&gt;
&lt;li&gt;percentile과 standard deviation의 중간 성격&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;06. 마크다운 헤더 텍스트 분할 (MarkdownHeaderTextSplitter&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;b&gt;헤더(#, ##, ### &amp;hellip;)&lt;/b&gt; 구조를 읽어서&lt;b&gt;헤더 단위(섹션 단위)&lt;/b&gt; 로 텍스트를 청크로 분할하는 splitter.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문서의 &lt;b&gt;구조/맥락을 유지한 채&lt;/b&gt; 임베딩&amp;middot;검색(RAG)에 유리한 청크를 만들 때 유용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;분할 기준 설정: headers_to_split_on&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;headers_to_split_on = [
  (&quot;#&quot;,&quot;Header 1&quot;),
  (&quot;##&quot;,&quot;Header 2&quot;),
  (&quot;###&quot;,&quot;Header 3&quot;),
]&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&gt;어떤 레벨의 헤더를 &amp;ldquo;경계&amp;rdquo;로 볼지 지정.&lt;/li&gt;
&lt;li&gt;두 번째 값(&quot;Header 1&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;결과 형태: split_text() &amp;rarr; Document 리스트&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# 마크다운 헤더를 기준으로 텍스트를 분할하는 MarkdownHeaderTextSplitter 객체를 생성
markdown_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
# markdown_document를 헤더를 기준으로 분할하여 md_header_splits에 저장
md_header_splits = markdown_splitter.split_text(markdown_document)&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&gt;반환: List[Document]&lt;/li&gt;
&lt;li&gt;각 Document는
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;page_content: 해당 헤더 아래 내용&lt;/li&gt;
&lt;li&gt;metadata: &lt;b&gt;상위 헤더 정보가 누적&lt;/b&gt;되어 들어감&lt;/li&gt;
&lt;li&gt;예) {'Header 1': 'Title', 'Header 2': '1. SubTitle', 'Header 3': ...}&lt;/li&gt;
&lt;/ul&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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;헤더를 본문에서 제거/유지 옵션: strip_headers&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본값: strip_headers=True &amp;rarr; &lt;b&gt;헤더 문자열은 page_content에서 제거&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정:&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;markdown_splitter = MarkdownHeaderTextSplitter(
    # 분할할 헤더를 지정합니다.
    headers_to_split_on=headers_to_split_on,
    # 헤더를 제거하지 않도록 설정합니다.
    strip_headers=False,
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 헤더도 함께 포함해서 저장 가능 (&amp;ldquo;청크만 봐도 제목이 보이게&amp;rdquo; 하고 싶을 때 유용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;b&gt;&amp;ldquo;헤더로 1차 분할 &amp;rarr; 다른 splitter로 2차 분할&amp;rdquo; 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;헤더 단위로 먼저 의미 있는 큰 덩어리를 만든 뒤, 그 안에서 토큰/문자 기준으로 더 잘게 나눌 수 있음.&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;chunk_size = 200  # 분할된 청크의 크기를 지정
chunk_overlap = 20  # 분할된 청크 간의 중복되는 문자 수를 지정

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=chunk_size, chunk_overlap=chunk_overlap
)&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&gt;장점: &lt;b&gt;구조 기반(헤더) 맥락 유지 + 크기 제어(chunk_size)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;결과:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작은 청크로 잘려도 &lt;b&gt;metadata에 헤더 정보가 계속 남음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;RAG에서 &amp;ldquo;어느 섹션에서 나온 내용인지&amp;rdquo; 추적 쉬움&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;185&quot; data-start=&quot;135&quot; data-ke-size=&quot;size26&quot;&gt;07. HTML 헤더 텍스트 분할 (HTMLHeaderTextSplitter)&lt;/h2&gt;
&lt;p data-end=&quot;377&quot; data-start=&quot;216&quot; data-ke-size=&quot;size16&quot;&gt;HTMLHeaderTextSplitter는 &lt;b&gt;HTML 문서의 구조(&amp;lt;h1&amp;gt;, &amp;lt;h2&amp;gt;, &amp;lt;h3&amp;gt; &amp;hellip;)&lt;/b&gt; 를 인식하여 헤더 단위로 텍스트를 분할하고, 각 청크에 &lt;b&gt;구조 기반 메타데이터&lt;/b&gt;를 부여하는 &lt;b&gt;구조 인식(structure-aware) 텍스트 분할기&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;436&quot; data-start=&quot;379&quot; data-ke-size=&quot;size16&quot;&gt;개념적으로는 &lt;b&gt;MarkdownHeaderTextSplitter의 HTML 버전&lt;/b&gt;이라고 보면 됨&lt;/p&gt;
&lt;p data-end=&quot;452&quot; data-start=&quot;443&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;452&quot; data-start=&quot;443&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심 목적&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;560&quot; data-start=&quot;453&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;477&quot; data-start=&quot;453&quot;&gt;HTML 문서의 &lt;b&gt;계층 구조를 보존&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;521&quot; data-start=&quot;478&quot;&gt;각 텍스트 청크에 &lt;b&gt;&amp;ldquo;어떤 헤더 아래에 속하는지&amp;rdquo;를 메타데이터로 유지&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;560&quot; data-start=&quot;522&quot;&gt;의미적으로 관련된 텍스트를 &lt;b&gt;대략적으로 하나의 그룹&lt;/b&gt;으로 묶음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;594&quot; data-start=&quot;567&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;594&quot; data-start=&quot;567&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HTML 문자열을 직접 사용하는 경우&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;608&quot; data-start=&quot;596&quot; data-ke-size=&quot;size16&quot;&gt;분할 기준 설정&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767525783200&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_text_splitters import HTMLHeaderTextSplitter

headers_to_split_on = [
    (&quot;h1&quot;, &quot;Header 1&quot;),  # 분할할 헤더 태그와 해당 헤더의 이름을 지정합니다.
    (&quot;h2&quot;, &quot;Header 2&quot;),
    (&quot;h3&quot;, &quot;Header 3&quot;),
]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;866&quot; data-start=&quot;783&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;812&quot; data-start=&quot;783&quot;&gt;어떤 HTML 헤더 태그를 기준으로 분할할지 지정&lt;/li&gt;
&lt;li data-end=&quot;866&quot; data-start=&quot;813&quot;&gt;&quot;Header 1&quot;, &quot;Header 2&quot; 등은 &lt;b&gt;metadata key&lt;/b&gt;로 사용됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;888&quot; data-start=&quot;873&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;888&quot; data-start=&quot;873&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HTML 문자열 분할&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767525862954&quot; class=&quot;ini&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# 지정된 헤더를 기준으로 HTML 텍스트를 분할하는 HTMLHeaderTextSplitter 객체를 생성
html_splitter = HTMLHeaderTextSplitter(headers_to_split_on=headers_to_split_on)

# HTML 문자열을 분할하여 결과를 html_header_splits 변수에 저장
html_header_splits = html_splitter.split_text(html_string)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;1160&quot; data-start=&quot;1158&quot; data-ke-size=&quot;size16&quot;&gt;예: &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;Some text about the first subtopic of Bar. {'Header 1': 'Foo', 'Header 2': 'Bar main section', 'Header 3': 'Bar subsection 1'}&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1333&quot; data-start=&quot;1301&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;rarr; HTML 계층 구조가 그대로 메타데이터에 반영됨&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2414&quot; data-start=&quot;2400&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2414&quot; data-start=&quot;2400&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2414&quot; data-start=&quot;2400&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;한계 (중요)&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2458&quot; data-start=&quot;2416&quot; data-ke-size=&quot;size16&quot;&gt;HTMLHeaderTextSplitter는 다음 가정을 기반으로 동작: &lt;b&gt;헤더는 항상 관련 텍스트보다 위(부모&amp;middot;형제 노드)에 있다&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2534&quot; data-start=&quot;2499&quot; data-ke-size=&quot;size16&quot;&gt;하지만 실제 웹 페이지에서는 이 가정이 깨지는 경우가 많음.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1092&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/erb2ui/dJMcajgyqxW/8JTRw4reLxAzVTSPzeH1Q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/erb2ui/dJMcajgyqxW/8JTRw4reLxAzVTSPzeH1Q1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/erb2ui/dJMcajgyqxW/8JTRw4reLxAzVTSPzeH1Q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ferb2ui%2FdJMcajgyqxW%2F8JTRw4reLxAzVTSPzeH1Q1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;371&quot; data-origin-width=&quot;1092&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;2534&quot; data-start=&quot;2499&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;08. 재귀적 JSON 분할 (RecursiveJsonSplitter)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RecursiveJsonSplitter는 &lt;b&gt;JSON 데이터를 구조를 유지한 채 재귀적으로 분할&lt;/b&gt;하는 텍스트 분할기입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSON 객체를 &lt;b&gt;깊이 우선 탐색(DFS)&lt;/b&gt; 하면서, 가능한 한 &lt;b&gt;중첩 구조를 보존&lt;/b&gt;한 상태로 작은 JSON 청크(chunk)를 생성합니다.&lt;/p&gt;
&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;API 스펙(OpenAPI), 설정 파일, 로그 등 &lt;b&gt;구조화된 JSON 문서&lt;/b&gt;를&lt;/li&gt;
&lt;li&gt;RAG / 임베딩에 사용할 수 있도록 &lt;b&gt;의미 단위(JSON 객체 단위)&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;&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;&lt;b&gt;텍스트 분할 기준&lt;/b&gt;: JSON 값(value) 단위&lt;/li&gt;
&lt;li&gt;&lt;b&gt;청크 크기 기준&lt;/b&gt;: 문자 수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중첩 객체&lt;/b&gt;: 가능한 한 유지&lt;/li&gt;
&lt;li&gt;&lt;b&gt;매우 긴 문자열 값&lt;/b&gt;: 분할하지 않음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;리스트(list)&lt;/b&gt;: 기본적으로 분할하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;청크 크기를 엄격히 제어해야 한다면 &lt;b&gt;RecursiveJsonSplitter &amp;rarr; RecursiveCharacterTextSplitter &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;&lt;b&gt;RecursiveJsonSplitter 기본 사용&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;from langchain_text_splittersimport RecursiveJsonSplitter

splitter = RecursiveJsonSplitter(max_chunk_size=300)

# JSON을 재귀적으로 분할
json_chunks = splitter.split_json(json_data=json_data)

&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&gt;반환: &lt;b&gt;JSON 형태의 작은 딕셔너리 조각들&lt;/b&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;b&gt;Document / Text 형태로 변환&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# JSON 데이터를 기반으로 문서를 생성합니다.
docs = splitter.create_documents(texts=[json_data])

# JSON 데이터를 기반으로 문자열 청크를 생성합니다.
texts = splitter.split_text(json_data=json_data)

# 첫 번째 문자열을 출력합니다.
print(docs[0].page_content)

print(&quot;===&quot; * 20)
# 분할된 문자열 청크를 출력합니다.
print(texts[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;&lt;b&gt;주의사항&lt;/b&gt;&lt;br /&gt;RecursiveJsonSplitter는&amp;nbsp;JSON&amp;nbsp;내&amp;nbsp;리스트(list)를&amp;nbsp;기본적으로&amp;nbsp;분할하지&amp;nbsp;않는다.&lt;br /&gt;이&amp;nbsp;때문에&amp;nbsp;리스트가&amp;nbsp;포함된&amp;nbsp;객체는&amp;nbsp;max_chunk_size를&amp;nbsp;초과하는&amp;nbsp;청크가&amp;nbsp;생성될&amp;nbsp;수&amp;nbsp;있다.&lt;br /&gt;&lt;br /&gt;필요한 경우 convert_lists=True 옵션을 사용하면, 리스트를&amp;nbsp;index:item&amp;nbsp;형태의&amp;nbsp;key-value&amp;nbsp;구조로&amp;nbsp;변환하여&amp;nbsp;더&amp;nbsp;잘게&amp;nbsp;분할할&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;</description>
      <category>AI</category>
      <author>orieasy1</author>
      <guid isPermaLink="true">https://easy1nhard2.tistory.com/34</guid>
      <comments>https://easy1nhard2.tistory.com/34#entry34comment</comments>
      <pubDate>Sun, 4 Jan 2026 20:40:17 +0900</pubDate>
    </item>
    <item>
      <title>[HCI] Survey 설문조사에 대하여</title>
      <link>https://easy1nhard2.tistory.com/33</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;488&quot; data-origin-height=&quot;488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TAEM3/dJMcafrn2iJ/5gFEvxdczCnczKHmZcv10K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TAEM3/dJMcafrn2iJ/5gFEvxdczCnczKHmZcv10K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TAEM3/dJMcafrn2iJ/5gFEvxdczCnczKHmZcv10K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTAEM3%2FdJMcafrn2iJ%2F5gFEvxdczCnczKHmZcv10K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;488&quot; height=&quot;488&quot; data-origin-width=&quot;488&quot; data-origin-height=&quot;488&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: #9d9d9d;&quot;&gt;아래 글은 Research Methods in Human-Computer Interaction(2nd Edition)을 읽고 정리한 글입니다.&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 data-ke-size=&quot;size16&quot;&gt;HCI(인간-컴퓨터 상호작용)에서는 설문조사(survey)를 많이 사용한다.&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;h2 data-ke-size=&quot;size26&quot;&gt;서론: 왜 설문조사는 여전히 중요한가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설문조사(Survey)는 사회과학과 공학 전반에서 가장 널리 사용되는 연구 방법 중 하나이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;우리가 어떤 집단의 &lt;b&gt;의견, 태도, 인식, 행동 패턴&lt;/b&gt;을 이해하고자 할 때 가장 먼저 떠올리는 방법이기도 하다.&lt;br /&gt;HCI(Human&amp;ndash;Computer Interaction) 연구에서도 설문은 사용자 경험, 기술 수용성, 인식 변화 등을 폭넓게 탐색하기 위한 기본 도구로 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Survey는 well-defined and well-written set of questions to which an individual is asked to answer로 정의할 수 있다.&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;이기도 하다. 그 이유는 &amp;ldquo;쉬워 보이지만, 잘못 설계되면 신뢰하기 어려운 데이터를 낳기 때문&amp;rdquo;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 설계된 설문은 방대한 집단으로부터 통계적으로 의미 있는 데이터를 수집할 수 있는 강력한 도구지만, &lt;b&gt;형식적이거나 검증되지 않은 설문&lt;/b&gt;은 오히려 연구의 신뢰성을 해친다.&lt;br /&gt;따라서 설문은 단순한 질문지(questionnaire)가 아니라, &lt;b&gt;명확한 연구 목적&amp;middot;표집 설계&amp;middot;응답자 기준&amp;middot;분석 계획&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;그래서 무엇보다 설문조사를 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;&quot;잘 설계하는 것&quot;&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;&lt;b&gt;설문은 대부분 &lt;b&gt;자기기입식(self-administered)&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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이런 특성 때문에 인터뷰나 참여관찰과 같은 질적 연구에 비해 데이터의 깊이는 얕지만, 대신 &lt;b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1260&quot; data-start=&quot;1119&quot; data-ke-size=&quot;size16&quot;&gt;요약하자면, 설문조사는 &amp;ldquo;가장 적합하기 때문이 아니라, 가장 쉽기 때문에 선택되는 경우가 많다.&amp;rdquo; 하지만 HCI 연구에서는 단순히 &amp;lsquo;쉬운 방법&amp;rsquo;이 아니라, &lt;b&gt;잘 통제되고 체계적으로 설계된 설문&lt;/b&gt;이 사용자 경험을 정량적으로 이해하는 데 매우 유용하다.&lt;/p&gt;
&lt;p data-end=&quot;1260&quot; data-start=&quot;1119&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1260&quot; data-start=&quot;1119&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1260&quot; data-start=&quot;1119&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;1260&quot; data-start=&quot;1119&quot; data-ke-size=&quot;size26&quot;&gt;설문조사의 장점과 한계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설문조사의 큰 장점 중 하나는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;비용 대비 효율이 높다는 것&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;온라인 도구(SurveyMonkey, Google Forms, Qualtrics 등)를 활용하면 짧은 시간 안에 수백 명 이상으로부터 데이터를 수집할 수 있다.&lt;br /&gt;또한 지리적으로 분산된 사용자들로부터 동시에 응답을 받을 수 있어, &lt;b&gt;광범위한 인구 집단의 스냅샷(snapshot)&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;설문은 또한 IRB(인간대상연구윤리위원회) 승인 절차에서도 비교적 &lt;b&gt;non-intrusive&lt;/b&gt;으로 간주되며, 개인 인터뷰보다 부담이 적다.&lt;br /&gt;이러한 이유로, HCI 연구에서 &lt;b&gt;사용자 인식&amp;middot;태도&amp;middot;의도&amp;middot;만족도&amp;middot;특성 비교&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;하지만 설문에는 명확한 한계가 있다.&lt;/p&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;lsquo;지난주에 이 앱을 몇 번 사용했습니까?&amp;rsquo;)은 회상 오류(recall bias)가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째, 흥미로운 패턴이 나타나더라도 &lt;b&gt;즉각적인 후속 질문(follow-up)&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-end=&quot;2025&quot; data-start=&quot;1879&quot; data-ke-size=&quot;size16&quot;&gt;따라서 설문조사는 깊은 정성적 이해를 제공하지는 못하지만, &lt;b&gt;정확한 표집 설계와 문항 구성만으로도 전체 사용자 집단의 경향을 예측할 수 있는 도구&lt;/b&gt;가 된다.&lt;/p&gt;
&lt;p data-end=&quot;2025&quot; data-start=&quot;1879&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2025&quot; data-start=&quot;1879&quot; data-ke-size=&quot;size16&quot;&gt;HCI 연구에서는 종종 실험이나 인터뷰 등 다른 방법과 결합해 &lt;b&gt;&amp;ldquo;보완적 수단&amp;rdquo;&lt;/b&gt; 으로 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;연구 대상과 설문 목표 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설문조사는 많은 사람들로부터 데이터를 수집할 수 있기 때문에, 연구자는 우선 &amp;ldquo;누구로부터 응답을 받을 것인가?&amp;rdquo;를 명확히 해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 &lt;b&gt;대상 집단(Target Population)&lt;/b&gt;, &lt;b&gt;대상 응답자(Targeted Respondents)&lt;/b&gt;, 그리고 &lt;b&gt;포함 기준(Inclusion Criteria)&lt;/b&gt; 이라는 세 가지 개념이 중요하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2414&quot; data-start=&quot;2257&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2323&quot; data-start=&quot;2257&quot;&gt;&lt;b&gt;대상 집단&lt;/b&gt;: 연구자가 관심을 갖는 전체 인구.&lt;br /&gt;예: &amp;ldquo;모바일 헬스 앱을 사용하는 20&amp;ndash;40대 직장인&amp;rdquo;&lt;/li&gt;
&lt;li data-end=&quot;2353&quot; data-start=&quot;2324&quot;&gt;&lt;b&gt;대상 응답자&lt;/b&gt;: 실제로 설문을 받은 사람들.&lt;/li&gt;
&lt;li data-end=&quot;2414&quot; data-start=&quot;2354&quot;&gt;&lt;b&gt;포함 기준&lt;/b&gt;: 설문에 참여할 자격 조건.&lt;br /&gt;예: &amp;ldquo;지난 한 달 내 앱 사용 경험이 있는 사람&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2574&quot; data-start=&quot;2416&quot; data-ke-size=&quot;size16&quot;&gt;또한 설문을 배포할 때 필요한 &lt;b&gt;모집단 프레임(population frame)&lt;/b&gt;&amp;mdash;즉, 이메일 목록이나 사용자 데이터베이스&amp;mdash;를 확보해야 한다.&lt;/p&gt;
&lt;p data-end=&quot;2574&quot; data-start=&quot;2416&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;HCI 연구에서는 이러한 명단이 불명확한 경우가 많기 때문에, 연구자는 종종 SNS, 커뮤니티, 혹은 컨퍼런스 네트워크 등을 활용한다.&lt;/p&gt;
&lt;p data-end=&quot;2574&quot; data-start=&quot;2416&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2700&quot; data-start=&quot;2576&quot; data-ke-size=&quot;size16&quot;&gt;만약 모집단이 명확히 정의되지 않았다면, 가능한 한 &lt;b&gt;응답자 내 다양한 하위 집단(subgroup)&lt;/b&gt; 이 포함되도록 해야 한다.&lt;br /&gt;예를 들어, &amp;ldquo;남녀, 연령대, 기술 숙련도&amp;rdquo;가 균형을 이루도록 표집을 설계하는 식이다..&lt;/p&gt;
&lt;p data-end=&quot;2700&quot; data-start=&quot;2576&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2700&quot; data-start=&quot;2576&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2700&quot; data-start=&quot;2576&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;2700&quot; data-start=&quot;2576&quot; data-ke-size=&quot;size26&quot;&gt;확률 표집 Probabilistic Sampling&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사회학에서 설문조사의 고전적인 목적은 전체 인구의 특성을 추정하는 것이다.&lt;br /&gt;이를 가장 정확하게 달성하는 방법은 인구조사(census)이지만, 현실적으로는 불가능에 가깝다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;그래서 등장한 것이 &lt;b&gt;확률 표집(probabilistic sampling)&lt;/b&gt; 이다.&lt;/p&gt;
&lt;p data-end=&quot;3012&quot; data-start=&quot;2895&quot; data-ke-size=&quot;size16&quot;&gt;확률 표집이란 모집단의 모든 구성원이 &lt;b&gt;0보다 큰 확률로, 그리고 알려진 확률로 선택될 수 있는 표집 방식&lt;/b&gt;을 말한다.&lt;/p&gt;
&lt;p data-end=&quot;3012&quot; data-start=&quot;2895&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;즉, 각 참여자가 선택될 가능성이 명확히 정의되어 있고, 표본은 무작위로 선정된다.&lt;/p&gt;
&lt;p data-end=&quot;3175&quot; data-start=&quot;3014&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 10,000명 중 500명을 무작위로 추출한다면, 이 500명은 전체 인구의 특성을 통계적으로 대변할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;3175&quot; data-start=&quot;3014&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이 과정에서 &lt;b&gt;포함 기준(inclusion criteria)&lt;/b&gt; 을 충족하고, &lt;b&gt;제외 기준(exclusion criteria)&lt;/b&gt; 을 위반하지 않아야 한다.&lt;/p&gt;
&lt;p data-end=&quot;3328&quot; data-start=&quot;3177&quot; data-ke-size=&quot;size16&quot;&gt;확률 표집은 &amp;ldquo;비용은 들지만, 일반화 가능성(generalizability)이 높은 방식&amp;rdquo;이다.&lt;br /&gt;HCI 연구에서 IBM Beehive 연구(Chen et al., 2009)는 좋은 사례로, 전체 사용자 중 500명을 무작위로 선택해 230명의 유효 응답을 얻었다.&lt;/p&gt;
&lt;p data-end=&quot;3328&quot; data-start=&quot;3177&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3536&quot; data-start=&quot;3330&quot; data-ke-size=&quot;size16&quot;&gt;확률 표집은 또한 &lt;b&gt;층화(Stratification)&lt;/b&gt; 기법을 사용해 대표성을 강화할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;3536&quot; data-start=&quot;3330&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3536&quot; data-start=&quot;3330&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 미국 우체국의 주소 변경 데이터베이스에서 최근 이사한 6,000명을 표본으로 삼고, 이 중&lt;br /&gt;1/3은 50마일 이내의 단거리 이사, 2/3은 장거리 이사로 나누는 식이다.&lt;br /&gt;이는 장거리 이동이 중심 주제였기 때문에 특정 그룹의 비율을 조정한 것이다.&lt;/p&gt;
&lt;p data-end=&quot;3687&quot; data-start=&quot;3538&quot; data-ke-size=&quot;size16&quot;&gt;응답 규모(Response Size)는 신뢰수준(confidence level)과 허용 오차(margin of error)에 따라 달라진다.&lt;/p&gt;
&lt;p data-end=&quot;3687&quot; data-start=&quot;3538&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;Sue &amp;amp; Ritter(2007)에 따르면, 95% 신뢰 수준에서 &amp;plusmn;5% 오차를 허용하려면 약 384명의 응답이 필요하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1126&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRf8NS/dJMcajm1xUC/F0OTPIaZyIDBk4UKRgC6q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRf8NS/dJMcajm1xUC/F0OTPIaZyIDBk4UKRgC6q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRf8NS/dJMcajm1xUC/F0OTPIaZyIDBk4UKRgC6q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRf8NS%2FdJMcajm1xUC%2FF0OTPIaZyIDBk4UKRgC6q0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;141&quot; data-origin-width=&quot;1126&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;h4 data-ke-size=&quot;size20&quot;&gt;확률 표집의 주요 오류 유형&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;4040&quot; data-start=&quot;3715&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;3812&quot; data-start=&quot;3715&quot;&gt;&lt;b&gt;표집 오류(Sampling Error)&lt;/b&gt;: 응답 수가 너무 적거나 표본이 충분히 대표하지 못할 때 발생한다.&lt;br /&gt;예: 1만 명에게 발송했지만 100명만 응답.&lt;/li&gt;
&lt;li data-end=&quot;3903&quot; data-start=&quot;3813&quot;&gt;&lt;b&gt;포괄 오류(Coverage Error)&lt;/b&gt;: 모집단의 일부가 조사 대상에서 제외될 때 발생.&lt;br /&gt;예: 이메일 주소가 없는 사람은 조사 기회가 없음.&lt;/li&gt;
&lt;li data-end=&quot;3955&quot; data-start=&quot;3904&quot;&gt;&lt;b&gt;측정 오류(Measurement Error)&lt;/b&gt;: 문항이 불명확하거나 편향된 경우.&lt;/li&gt;
&lt;li data-end=&quot;4040&quot; data-start=&quot;3956&quot;&gt;&lt;b&gt;비응답 오류(Nonresponse Error)&lt;/b&gt;: 실제 응답자와 모집단의 통계적 구성이 다를 때.&lt;br /&gt;예: 성별 비율이 모집단과 다름.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;4109&quot; data-start=&quot;4042&quot; data-ke-size=&quot;size16&quot;&gt;이러한 오류를 최소화하기 위해, 연구자는 &lt;b&gt;표집 설계 단계에서부터 오차 요인을 예측하고 통제 전략을 마련해야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4109&quot; data-start=&quot;4042&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4109&quot; data-start=&quot;4042&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4109&quot; data-start=&quot;4042&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;4109&quot; data-start=&quot;4042&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;비확률 표집 Non-Probabilistic Sampling&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 다룬 &lt;b&gt;확률 표집(probabilistic sampling)&lt;/b&gt; 은, 모집단의 모든 구성원이 &lt;b&gt;동일하고 알려진 확률로&lt;/b&gt; 선택된다는 점에서 통계적으로 가장 이상적인 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;하지만 현실의 HCI 연구에서는 이런 이상적인 상황이 거의 없다.&lt;/p&gt;
&lt;p data-end=&quot;563&quot; data-start=&quot;308&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 &amp;ldquo;AI 어시스턴트를 사용하는 대학생&amp;rdquo;이나 &amp;ldquo;스마트워치를 쓰는 고령층&amp;rdquo; 같은 모집단은 명확하게 정의되어 있지도 않고, 중앙 데이터베이스나 공식 명단이 있는 것도 아니다.&lt;/p&gt;
&lt;p data-end=&quot;563&quot; data-start=&quot;308&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;이럴 때 연구자는 &lt;b&gt;&amp;lsquo;무작위 추출(random)&amp;rsquo;이 불가능하다는 사실을 인정하고&lt;/b&gt;, 대신 &lt;b&gt;실제 참여 가능한 사람들로부터 의미 있는 데이터를 수집하는 방향&lt;/b&gt;을 선택&lt;/span&gt;한다.&lt;br /&gt;이게 바로 &lt;b&gt;비확률 표집(non-probabilistic sampling)&lt;/b&gt; 이다.&lt;/p&gt;
&lt;p data-end=&quot;563&quot; data-start=&quot;308&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;563&quot; data-start=&quot;308&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;563&quot; data-start=&quot;308&quot; data-ke-size=&quot;size20&quot;&gt;왜 HCI에서는 비확률 표집이 흔한가?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HCI(Human&amp;ndash;Computer Interaction) 연구의 목적은 단순히 모집단 전체의 평균을 추정하는 것이 아니라, &lt;b&gt;&amp;lsquo;사람이 기술을 어떻게 경험하고 사용하는가&amp;rsquo;를 이해하는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;즉, &amp;ldquo;대표성(representativeness)&amp;rdquo;보다는 &lt;b&gt;&amp;ldquo;맥락(context)&amp;rdquo;과 &amp;ldquo;경험의 다양성&amp;rdquo;&lt;/b&gt; 이 더 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;971&quot; data-start=&quot;782&quot; data-ke-size=&quot;size16&quot;&gt;이 때문에 HCI 연구에서는 &lt;b&gt;표본의 통계적 무작위성보다 현실적 접근성(accessibility)&lt;/b&gt; 을 우선시한다.&lt;/p&gt;
&lt;p data-end=&quot;971&quot; data-start=&quot;782&quot; data-ke-size=&quot;size16&quot;&gt;연구자는 실제로 시스템을 사용하는 사용자들을 중심으로 데이터를 수집하며, 이 과정에서 표집의 엄격한 통계적 기준보다는 &lt;b&gt;연구의 목적에 부합하는 실질적 타당성&lt;/b&gt;을 추구한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mE2xt/dJMcakfadEn/0QxK8cqt3ivxkezoUeZHoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mE2xt/dJMcakfadEn/0QxK8cqt3ivxkezoUeZHoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mE2xt/dJMcakfadEn/0QxK8cqt3ivxkezoUeZHoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmE2xt%2FdJMcakfadEn%2F0QxK8cqt3ivxkezoUeZHoK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;155&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;310&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;563&quot; data-start=&quot;308&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;563&quot; data-start=&quot;308&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;563&quot; data-start=&quot;308&quot; data-ke-size=&quot;size20&quot;&gt;비확률 표집의 주요 형태&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HCI 설문 연구에서 자주 사용되는 대표적인 비확률 표집 방법은 다음 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;1. 자발적 참여 패널 (Volunteer Panels)&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1218&quot; data-start=&quot;1082&quot; data-ke-size=&quot;size16&quot;&gt;연구 참여를 자발적으로 신청한 사람들을 모아두고, 필요할 때마다 연구에 참여시키는 방식이다.&lt;/p&gt;
&lt;p data-end=&quot;1218&quot; data-start=&quot;1082&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 한 대학의 UX 연구실이 &amp;ldquo;디지털 헬스 앱 사용자 패널&amp;rdquo;을 운영한다면, 이 패널을 활용해 다양한 실험이나 설문을 진행할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1313&quot; data-start=&quot;1220&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1264&quot; data-start=&quot;1220&quot;&gt;&lt;b&gt;장점&lt;/b&gt;: 연구 주제에 관심이 많고 성실히 응답하는 참여자 확보 가능&lt;/li&gt;
&lt;li data-end=&quot;1313&quot; data-start=&quot;1265&quot;&gt;&lt;b&gt;단점&lt;/b&gt;: 기술 친숙도나 관심 수준이 일반 사용자보다 높아 편향이 생길 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1345&quot; data-start=&quot;1315&quot; data-ke-size=&quot;size16&quot;&gt;즉, &amp;lsquo;품질은 높지만 일반화는 어렵다&amp;rsquo;는 특성이 있다.&lt;/p&gt;
&lt;p data-end=&quot;1345&quot; data-start=&quot;1315&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1345&quot; data-start=&quot;1315&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 자기 선택 설문 (Self-Selected Surveys)&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1502&quot; data-start=&quot;1394&quot; data-ke-size=&quot;size16&quot;&gt;사용자가 스스로 참여를 선택하는 방식이다.&lt;/p&gt;
&lt;p data-end=&quot;1502&quot; data-start=&quot;1394&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 웹사이트에 &amp;ldquo;AI 챗봇 사용 경험 설문에 참여해 주세요&amp;rdquo;라는 배너를 띄우거나, SNS에 설문 링크를 공개하는 경우가 여기에 해당한다.&lt;/p&gt;
&lt;p data-end=&quot;1502&quot; data-start=&quot;1394&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1663&quot; data-start=&quot;1504&quot; data-ke-size=&quot;size16&quot;&gt;이 방식은 &lt;b&gt;참여 장벽이 낮고 빠르게 데이터를 모을 수 있다&lt;/b&gt;는 장점이 있다.&lt;/p&gt;
&lt;p data-end=&quot;1663&quot; data-start=&quot;1504&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1663&quot; data-start=&quot;1504&quot; data-ke-size=&quot;size16&quot;&gt;하지만 반대로 &lt;b&gt;주제에 강한 관심을 가진 사람들만 참여하기 때문에 편향(bias)&lt;/b&gt;이 생길 수 있다.&lt;br /&gt;예를 들어 챗봇에 불만이 있는 사람만 설문에 참여한다면 결과가 부정적으로 쏠릴 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;1820&quot; data-start=&quot;1665&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1820&quot; data-start=&quot;1665&quot; data-ke-size=&quot;size16&quot;&gt;그럼에도 불구하고, 아직 연구되지 않은 주제나 새로운 사용자 현상을 탐색할 때는 &lt;b&gt;가장 자연스럽고 효과적인 시작점&lt;/b&gt;이 된다.&lt;br /&gt;조지아 공대(Georgia Tech)의 HCI 연구팀도 이 방식을 활용해 초기 사용자 행동 패턴을 관찰하는 연구를 여러 차례 수행했다.&lt;/p&gt;
&lt;p data-end=&quot;1820&quot; data-start=&quot;1665&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1820&quot; data-start=&quot;1665&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 눈덩이 표집 (Snowball Sampling)&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1951&quot; data-start=&quot;1863&quot; data-ke-size=&quot;size16&quot;&gt;이미 확보한 응답자가 다른 참여자를 소개하는 방식이다.&lt;br /&gt;처음 확보한 응답자가 친구나 동료에게 설문을 공유하면서 &amp;lsquo;눈덩이처럼&amp;rsquo; 표본이 커지는 구조다.&lt;/p&gt;
&lt;p data-end=&quot;1951&quot; data-start=&quot;1863&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2075&quot; data-start=&quot;1953&quot; data-ke-size=&quot;size16&quot;&gt;이 방식은 &lt;b&gt;접근하기 어려운 집단&lt;/b&gt;을 연구할 때 특히 효과적이다.&lt;br /&gt;예를 들어 시각장애인의 보조기기 사용 경험을 조사하려는 경우, 처음 몇 명의 참여자가 본인이 속한 커뮤니티에서 다른 사람을 연결해줄 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2161&quot; data-start=&quot;2077&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2111&quot; data-start=&quot;2077&quot;&gt;&lt;b&gt;장점&lt;/b&gt;: 신뢰 관계가 형성된 집단에서 빠르게 확산&lt;/li&gt;
&lt;li data-end=&quot;2161&quot; data-start=&quot;2112&quot;&gt;&lt;b&gt;단점&lt;/b&gt;: 사회적 네트워크가 유사한 사람들끼리 연결되므로 다양성이 부족할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;비확률 표집의 신뢰성 높이기&lt;/h4&gt;
&lt;p data-end=&quot;563&quot; data-start=&quot;308&quot; data-ke-size=&quot;size16&quot;&gt;비확률 표집에서는 &quot;통계적 일반화&quot;보다는 데이터의 타당성(validity) 확보가 중요하다.&lt;/p&gt;
&lt;p data-end=&quot;563&quot; data-start=&quot;308&quot; data-ke-size=&quot;size16&quot;&gt;연구자는 다음과 같은 방법으로 신뢰성을 높일 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;563&quot; data-start=&quot;308&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4516&quot; data-start=&quot;4422&quot;&gt;&lt;b&gt;인구통계학적 정보 수집(Demographic Data)&lt;/b&gt;&lt;br /&gt;연령, 성별, 직업, 교육 수준 등 기본 정보를 통해 응답 집단의 다양성을 평가할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;4633&quot; data-start=&quot;4517&quot;&gt;&lt;b&gt;과표집(Oversampling)&lt;/b&gt;&lt;br /&gt;모집단 규모를 정확히 모를 때는 가능한 한 많은 응답을 확보해야 한다.&lt;br /&gt;응답 수가 많을수록 특정 집단이 완전히 배제될 가능성이 줄어들기 때문이다.&lt;/li&gt;
&lt;li data-end=&quot;4741&quot; data-start=&quot;4634&quot;&gt;&lt;b&gt;사용 행위 기반 표집(Random Sampling of Usage)&lt;/b&gt;&lt;br /&gt;사용자 대신 &amp;lsquo;사용 행위&amp;rsquo;를 단위로 표집. 예: &amp;ldquo;웹페이지가 10번째 로드될 때마다 팝업 설문 표시&amp;rdquo;.&lt;/li&gt;
&lt;li data-end=&quot;4850&quot; data-start=&quot;4742&quot;&gt;&lt;b&gt;자기선택(Self-Selected) 설문&lt;/b&gt;&lt;br /&gt;모든 방문자에게 설문 참여를 개방하는 방식. 예: 조지아 공대의 웹 설문(1994&amp;ndash;1998)은 5,000명 이상의 응답을 확보했다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;설문 문항 개발&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설문 문항 개발은 연구 설계 중 가장 섬세한 단계다.&lt;br /&gt;응답자는 연구자의 도움 없이 스스로 설문을 읽고 작성해야 하므로, &lt;b&gt;모든 문항은 명확하고 중립적이며 이해하기 쉬워야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;5318&quot; data-start=&quot;5292&quot; data-ke-size=&quot;size16&quot;&gt;문항은 보통 세 가지 형식 중 하나로 구성된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;5663&quot; data-start=&quot;5320&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;5409&quot; data-start=&quot;5320&quot;&gt;&lt;b&gt;개방형(Open-ended)&lt;/b&gt;&lt;br /&gt;응답자가 자유롭게 의견을 기술.&lt;br /&gt;&amp;rarr; 현상 이해에는 유용하지만, 분석이 어렵고 응답이 모호할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;5590&quot; data-start=&quot;5410&quot;&gt;&lt;b&gt;폐쇄형(Closed-ended)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5590&quot; data-start=&quot;5440&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5511&quot; data-start=&quot;5440&quot;&gt;순서형(Ordered): Likert 척도(1~5, 1~9 등)를 사용.&lt;br /&gt;예: &amp;ldquo;매우 만족 ~ 매우 불만족&amp;rdquo;&lt;/li&gt;
&lt;li data-end=&quot;5590&quot; data-start=&quot;5515&quot;&gt;비순서형(Unordered): 논리적 순서가 없는 범주형 선택지.&lt;br /&gt;예: &amp;ldquo;성별&amp;rdquo;, &amp;ldquo;주 사용 디바이스&amp;rdquo;, &amp;ldquo;OS 종류&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;5663&quot; data-start=&quot;5591&quot;&gt;&lt;b&gt;복합형(Hybrid)&lt;/b&gt;&lt;br /&gt;폐쇄형 문항 끝에 &amp;ldquo;기타(Other): _______&amp;rdquo;을 추가해 부분적 개방성을 부여.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-end=&quot;5680&quot; data-start=&quot;5665&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-end=&quot;5680&quot; data-start=&quot;5665&quot; data-ke-size=&quot;size20&quot;&gt;피해야 할 문항 유형&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5952&quot; data-start=&quot;5681&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5769&quot; data-start=&quot;5681&quot;&gt;&lt;b&gt;이중질문(Double-barreled)&lt;/b&gt;: &amp;ldquo;이 앱은 빠르고 유용했습니까?&amp;rdquo; &amp;rarr; &amp;ldquo;빠르다고 느끼셨습니까?&amp;rdquo; / &amp;ldquo;유용했습니까?&amp;rdquo;로 분리해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;5823&quot; data-start=&quot;5770&quot;&gt;&lt;b&gt;부정표현(Negative wording)&lt;/b&gt;: &amp;ldquo;불편하지 않다고 생각하지 않습니까?&amp;rdquo;&lt;/li&gt;
&lt;li data-end=&quot;5878&quot; data-start=&quot;5824&quot;&gt;&lt;b&gt;편향된 단어(Biased wording)&lt;/b&gt;: &amp;ldquo;전문가들이 추천한 앱을 사용했습니까?&amp;rdquo;&lt;/li&gt;
&lt;li data-end=&quot;5952&quot; data-start=&quot;5879&quot;&gt;&lt;b&gt;감정적 단어(Hot-button words)&lt;/b&gt;: &amp;ldquo;불쾌한 경험이 있었나요?&amp;rdquo;보다는 &amp;ldquo;불편했던 점이 있었나요?&amp;rdquo;가 적절하다.&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HCI 분야에는 이미 수십 년간 사용되어 온 검증된 설문 도구들이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&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-end=&quot;6810&quot; data-start=&quot;6793&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 data-end=&quot;6810&quot; data-start=&quot;6793&quot;&gt;CSUQ (Computer System Usability Questionnaire)&lt;/li&gt;
&lt;li data-end=&quot;6810&quot; data-start=&quot;6793&quot;&gt;ICTQ (Interface Consistency Testing Questionnaire)&lt;/li&gt;
&lt;li data-end=&quot;6810&quot; data-start=&quot;6793&quot;&gt;PUTQ (Perdue Usability Testing Questionnaire)&lt;/li&gt;
&lt;li data-end=&quot;6810&quot; data-start=&quot;6793&quot;&gt;QUIS (Questionnaire for User Interaction Satisfaction)&lt;/li&gt;
&lt;li data-end=&quot;6810&quot; data-start=&quot;6793&quot;&gt;SUMI (Software Usability Measurement Inventory)&lt;/li&gt;
&lt;li data-end=&quot;6810&quot; data-start=&quot;6793&quot;&gt;WAMMI (Website Analysis and MeasureMent Inventory)&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;종이 설문과 온라인 설문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘날 대부분의 설문은 온라인으로 진행된다.&lt;br /&gt;웹 기반 설문은 개발이 빠르고 비용이 거의 들지 않으며, 데이터가 자동으로 저장되어 분석 속도도 빠르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;7632&quot; data-start=&quot;7475&quot; data-ke-size=&quot;size16&quot;&gt;그러나 모든 연구에 온라인 방식이 적합한 것은 아니다.&lt;br /&gt;인터넷 접근이 어려운 집단(예: 노년층, 저소득층, 특정 장애 집단)은 배제될 위험이 있다.&lt;br /&gt;따라서 연구자는 연구 목적과 대상의 접근성을 고려해 종이 설문, 이메일 설문, 웹 설문 중 가장 적절한 방식을 선택해야 한다.&lt;/p&gt;
&lt;p data-end=&quot;7776&quot; data-start=&quot;7634&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;7776&quot; data-start=&quot;7634&quot; data-ke-size=&quot;size16&quot;&gt;실제로는 &lt;b&gt;접근성(accessibility)&lt;/b&gt; 이 결정 요인이다.&lt;br /&gt;정기적인 오프라인 모임을 통해 대상자를 직접 만날 수 있다면 종이 설문이 적합하고, 이메일 주소 목록이 있다면 메일 설문을, 온라인 커뮤니티 기반이라면 웹 설문이 효율적이다.&lt;/p&gt;
&lt;p data-end=&quot;7937&quot; data-start=&quot;7778&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;7937&quot; data-start=&quot;7778&quot; data-ke-size=&quot;size16&quot;&gt;또한 두 방식을 병행하는 &lt;b&gt;혼합형 설문(Mixed-mode survey)&lt;/b&gt; 도 가능하다.&lt;br /&gt;이 경우 응답자의 선택권이 넓어지고 표본의 다양성이 커질 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;7937&quot; data-start=&quot;7778&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;7937&quot; data-start=&quot;7778&quot; data-ke-size=&quot;size16&quot;&gt;단, 서로 다른 포맷(예: 종이 vs 웹)은 시각적 구조 차이로 편향(bias)을 유발할 수 있으므로 주의해야 한다.&lt;/p&gt;
&lt;p data-end=&quot;8146&quot; data-start=&quot;7939&quot; data-ke-size=&quot;size16&quot;&gt;온라인 설문은 익명성이 보장될 때 &lt;b&gt;민감한 주제에서 더 솔직한 응답을 유도&lt;/b&gt;한다는 연구 결과도 있다(Sussman &amp;amp; Sproull, 1999).&lt;br /&gt;특히 웹 기반 자기기입식 설문은 면접 방식보다 응답자의 심리적 방어를 줄인다(Couper, 2005).&lt;/p&gt;
&lt;p data-end=&quot;8146&quot; data-start=&quot;7939&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;8146&quot; data-start=&quot;7939&quot; data-ke-size=&quot;size16&quot;&gt;다만, IRB 기준상 &lt;b&gt;온라인 참여 동의서(informed consent)&lt;/b&gt; 를 명시적으로 제시해야 한다.&lt;/p&gt;
&lt;p data-end=&quot;8146&quot; data-start=&quot;7939&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;8146&quot; data-start=&quot;7939&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;8146&quot; data-start=&quot;7939&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;8146&quot; data-start=&quot;7939&quot; data-ke-size=&quot;size26&quot;&gt;설문 배포 이후의 절차&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설문은 배포로 끝나지 않는다.&lt;br /&gt;오히려 진짜 품질은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;&amp;ldquo;배포 전후의 절차 관리&amp;rdquo;&lt;/b&gt;&lt;/span&gt;에서 결정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;설문 데이터의 신뢰성과 타당성은 &lt;b&gt;파일럿 테스트(pilot test)&lt;/b&gt;, &lt;b&gt;응답률 관리(response rate)&lt;/b&gt;, 그리고 &lt;b&gt;데이터 분석(data analysis)&lt;/b&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;Pilot Testing&lt;/h3&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;br /&gt;설문을 본격적으로 배포하기 전에, &lt;b&gt;소규모 집단을 대상으로 미리 테스트를 수행&lt;/b&gt;하여 문항의 명확성, 흐름, 기술적 오류를 점검한다.&lt;/p&gt;
&lt;p data-end=&quot;8851&quot; data-start=&quot;8791&quot; data-ke-size=&quot;size16&quot;&gt;가장 널리 사용되는 접근은 Dillman(2000)의 &lt;b&gt;3단계 사전검증(pretesting) 과정&lt;/b&gt;이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;9219&quot; data-start=&quot;8853&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;8965&quot; data-start=&quot;8853&quot;&gt;&lt;b&gt;전문가 검토(Expert Review)&lt;/b&gt;&lt;br /&gt;연구 주제와 관련 있는 동료나 전문가에게 설문 초안을 검토받는다.&lt;br /&gt;논리적 일관성, 문항의 의미 모호성, 편향적 표현 등을 점검한다.&lt;/li&gt;
&lt;li data-end=&quot;9086&quot; data-start=&quot;8967&quot;&gt;&lt;b&gt;사용자 피드백(User Feedback)&lt;/b&gt;&lt;br /&gt;실제 응답자가 될 가능성이 있는 사람 2~3명을 대상으로 인터뷰를 진행한다.&lt;br /&gt;설문을 작성하며 느낀 혼란, 흥미, 동기부여 수준 등을 탐색한다.&lt;/li&gt;
&lt;li data-end=&quot;9219&quot; data-start=&quot;9088&quot;&gt;&lt;b&gt;파일럿 조사(Pilot Study)&lt;/b&gt;&lt;br /&gt;최종 후보 설문을 소규모 집단(대략 5~10명)에게 실제 배포한다.&lt;br /&gt;수집된 응답을 바탕으로 응답 누락, 중복 선택, 기타 응답 비율 등을 확인하고 설문 도구를 수정한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;9393&quot; data-start=&quot;9221&quot; data-ke-size=&quot;size16&quot;&gt;이 단계에서 발견되는 오류는 대부분 단순하지만 치명적이다.&lt;br /&gt;예를 들어 &amp;ldquo;응답자가 특정 문항을 건너뛰었거나, 한 문항에 두 개의 답을 한 경우&amp;rdquo;, 혹은 &amp;ldquo;너무 많은 사람들이 &amp;lsquo;기타(Other)&amp;rsquo;를 선택한 경우&amp;rdquo; 등이 있다.&lt;/p&gt;
&lt;p data-end=&quot;9393&quot; data-start=&quot;9221&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이런 문제는 &lt;b&gt;설문 배포 전에 반드시 제거되어야 하는 구조적 결함&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;9393&quot; data-start=&quot;9221&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;9538&quot; data-start=&quot;9395&quot; data-ke-size=&quot;size16&quot;&gt;파일럿 규모는 전체 연구 크기에 따라 다르다.&lt;br /&gt;작은 연구(200&amp;ndash;300 응답 예상)는 5&amp;ndash;10명의 파일럿으로 충분하지만, 대규모 연구(수만 명 대상)는 더 많은 파일럿 응답자가 필요하다.&lt;/p&gt;
&lt;p data-end=&quot;9538&quot; data-start=&quot;9395&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;9538&quot; data-start=&quot;9395&quot; data-ke-size=&quot;size16&quot;&gt;단, 파일럿 참여자는 최종 분석에는 포함되지 않아야 한다.&lt;/p&gt;
&lt;p data-end=&quot;9538&quot; data-start=&quot;9395&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;9538&quot; data-start=&quot;9395&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;9538&quot; data-start=&quot;9395&quot; data-ke-size=&quot;size23&quot;&gt;Response Rate 관리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 설계된 설문이라도 &lt;b&gt;응답률이 낮으면 데이터 품질이 급격히 떨어진다.&lt;/b&gt;&lt;br /&gt;응답률은 단순히 숫자가 아니라, &lt;b&gt;표본의 대표성과 신뢰도를 보증하는 지표&lt;/b&gt;다.&lt;/p&gt;
&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;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;10269&quot; data-start=&quot;9690&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;9811&quot; data-start=&quot;9690&quot;&gt;&lt;b&gt;사전 안내문(Pre-contact letter)&lt;/b&gt;&lt;br /&gt;설문 발송 전에 &amp;ldquo;누가 연구를 수행하는지, 왜 중요한지, 얼마나 시간이 걸리는지&amp;rdquo;를 명확히 안내한다.&lt;br /&gt;신뢰성과 투명성을 확보하는 단계이다.&lt;/li&gt;
&lt;li data-end=&quot;9933&quot; data-start=&quot;9813&quot;&gt;&lt;b&gt;응답 편의성 향상&lt;/b&gt;&lt;br /&gt;종이 설문에는 **회신용 봉투(prepaid envelope)**를 동봉하고,&lt;br /&gt;온라인 설문은 클릭 한 번으로 접근 가능한 짧은 URL과 모바일 친화형 화면을 제공한다.&lt;/li&gt;
&lt;li data-end=&quot;10191&quot; data-start=&quot;9935&quot;&gt;&lt;b&gt;리마인더(Reminder)&lt;/b&gt;&lt;br /&gt;응답하지 않은 사람에게 1~2회 리마인더 메일을 보내는 것이 일반적이다.&lt;br /&gt;Dillman의 &lt;b&gt;5단계 연락 모델(5-step process)&lt;/b&gt; 은 응답률 향상에 특히 효과적이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;10191&quot; data-start=&quot;10070&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;10087&quot; data-start=&quot;10070&quot;&gt;(1) 사전 안내문 발송&lt;/li&gt;
&lt;li data-end=&quot;10104&quot; data-start=&quot;10091&quot;&gt;(2) 설문 발송&lt;/li&gt;
&lt;li data-end=&quot;10131&quot; data-start=&quot;10108&quot;&gt;(3) 감사 및 리마인더 카드 발송&lt;/li&gt;
&lt;li data-end=&quot;10156&quot; data-start=&quot;10135&quot;&gt;(4) 2~4주 후 설문 재발송&lt;/li&gt;
&lt;li data-end=&quot;10191&quot; data-start=&quot;10160&quot;&gt;(5) 마지막으로 다른 채널(전화&amp;middot;이메일 등)로 접촉&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;10269&quot; data-start=&quot;10193&quot;&gt;&lt;b&gt;인센티브 제공&lt;/b&gt;&lt;br /&gt;설문 참여에 대한 보상은 소규모라도 효과적이다. 예: 추첨 쿠폰, 소정의 기념품, 연구 참여 증명서.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;10367&quot; data-start=&quot;10271&quot; data-ke-size=&quot;size16&quot;&gt;응답률이 20% 미만이라면, 표본 대표성에 심각한 문제가 있을 수 있다.&lt;br /&gt;하지만 응답률이 40&amp;ndash;60% 수준이면, 비확률 표본에서도 일정 수준의 타당성을 확보할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;10367&quot; data-start=&quot;10271&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;10367&quot; data-start=&quot;10271&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;10367&quot; data-start=&quot;10271&quot; data-ke-size=&quot;size23&quot;&gt;데이터 정제 및 분석&lt;/h3&gt;
&lt;p data-end=&quot;10446&quot; data-start=&quot;10422&quot; data-ke-size=&quot;size16&quot;&gt;설문 데이터 분석은 크게 두 단계로 나뉜다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;10828&quot; data-start=&quot;10448&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;10664&quot; data-start=&quot;10448&quot;&gt;&lt;b&gt;정량 데이터 분석 (Quantitative Analysis)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;10664&quot; data-start=&quot;10494&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;10566&quot; data-start=&quot;10494&quot;&gt;기술통계(descriptive statistics): 빈도, 비율, 평균, 표준편차, 교차표(crosstabulation)&lt;/li&gt;
&lt;li data-end=&quot;10627&quot; data-start=&quot;10570&quot;&gt;추론통계(inferential statistics): 상관관계, 회귀분석, 집단 간 차이검정 등&lt;/li&gt;
&lt;li data-end=&quot;10664&quot; data-start=&quot;10631&quot;&gt;목적: 응답 패턴을 요약하고 가설을 통계적으로 검증한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;10828&quot; data-start=&quot;10666&quot;&gt;&lt;b&gt;정성 데이터 분석 (Qualitative Analysis)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;10828&quot; data-start=&quot;10711&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;10782&quot; data-start=&quot;10711&quot;&gt;개방형 문항(open-ended responses)은 &lt;b&gt;코딩(coding)&lt;/b&gt; 작업을 거쳐 주제(theme)로 묶는다.&lt;/li&gt;
&lt;li data-end=&quot;10828&quot; data-start=&quot;10786&quot;&gt;자연어 분석이나 키워드 빈도 분석을 통해 응답자 서술의 맥락을 이해한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;10856&quot; data-start=&quot;10830&quot; data-ke-size=&quot;size16&quot;&gt;이전에 수행해야 할 전처리 단계는 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;10993&quot; data-start=&quot;10858&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;10891&quot; data-start=&quot;10858&quot;&gt;중복 응답 제거(duplicate filtering)&lt;/li&gt;
&lt;li data-end=&quot;10927&quot; data-start=&quot;10892&quot;&gt;불완전 응답 제외(incomplete responses)&lt;/li&gt;
&lt;li data-end=&quot;10968&quot; data-start=&quot;10928&quot;&gt;포함 기준(inclusion criteria) 미충족 응답자 제외&lt;/li&gt;
&lt;li data-end=&quot;10993&quot; data-start=&quot;10969&quot;&gt;비정상 응답(패턴 반복, 극단치) 필터링&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;11028&quot; data-start=&quot;10995&quot; data-ke-size=&quot;size16&quot;&gt;이 과정을 거쳐야만 통계적 신뢰성과 질적 타당성이 확보된다.&lt;/p&gt;
&lt;p data-end=&quot;11028&quot; data-start=&quot;10995&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;11028&quot; data-start=&quot;10995&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;11028&quot; data-start=&quot;10995&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;11028&quot; data-start=&quot;10995&quot; data-ke-size=&quot;size26&quot;&gt;마무리 하며...&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설문조사는 단순히 &amp;ldquo;많은 사람에게 물어보는 것&amp;rdquo;이 아니다.&lt;br /&gt;HCI에서 설문은 사용자와 기술의 관계를 &lt;b&gt;정량적으로 모델링하는 연구 방법&lt;/b&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-end=&quot;11256&quot; data-start=&quot;11213&quot; data-ke-size=&quot;size16&quot;&gt;요약하자면, 설문은 다음과 같은 조건이 충족될 때 비로소 과학적 방법이 된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;11582&quot; data-start=&quot;11258&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;11328&quot; data-start=&quot;11258&quot;&gt;&lt;b&gt;명확한 연구 목적과 변수 정의&lt;/b&gt;&lt;br /&gt;&amp;ndash; &amp;ldquo;무엇을 묻는가?&amp;rdquo;가 아니라 &amp;ldquo;왜 이걸 묻는가?&amp;rdquo;를 우선 정의한다.&lt;/li&gt;
&lt;li data-end=&quot;11396&quot; data-start=&quot;11329&quot;&gt;&lt;b&gt;표집의 정당성 확보&lt;/b&gt;&lt;br /&gt;&amp;ndash; 모집단이 명확하지 않더라도 포함 기준과 응답자 특성을 투명하게 명시한다.&lt;/li&gt;
&lt;li data-end=&quot;11446&quot; data-start=&quot;11397&quot;&gt;&lt;b&gt;문항의 타당성&lt;/b&gt;&lt;br /&gt;&amp;ndash; 이중질문, 부정문, 편향어, 감정어를 피한다.&lt;/li&gt;
&lt;li data-end=&quot;11515&quot; data-start=&quot;11447&quot;&gt;&lt;b&gt;파일럿 검증 및 응답률 관리&lt;/b&gt;&lt;br /&gt;&amp;ndash; 설문을 발송하기 전에 반드시 시험하고, 응답 유도 전략을 세운다.&lt;/li&gt;
&lt;li data-end=&quot;11582&quot; data-start=&quot;11516&quot;&gt;&lt;b&gt;적절한 분석 기법의 선택&lt;/b&gt;&lt;br /&gt;&amp;ndash; 단순한 빈도 분석을 넘어, 변수 간 관계를 추론하고 통찰을 도출한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;11751&quot; data-start=&quot;11584&quot; data-ke-size=&quot;size16&quot;&gt;HCI 연구자는 설문조사를 다른 연구 방법과 &lt;b&gt;보완적(complementary)&lt;/b&gt; 으로 결합할 때 더 큰 효과를 얻을 수 있다.&lt;br /&gt;예를 들어 로그 데이터나 사용자 실험 결과를 설문 응답과 결합하면, &lt;b&gt;&amp;ldquo;행동(behavior)&amp;rdquo;과 &amp;ldquo;인식(perception)&amp;rdquo;의 간극&lt;/b&gt;을 분석할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;11751&quot; data-start=&quot;11584&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;11869&quot; data-start=&quot;11753&quot; data-ke-size=&quot;size16&quot;&gt;결국 설문은 HCI 연구에서 &lt;b&gt;사용자의 목소리를 데이터로 번역하는 첫 번째 도구&lt;/b&gt;다.&lt;br /&gt;그리고 이 도구의 힘은, 얼마나 많은 응답을 모았는가가 아니라, &lt;b&gt;얼마나 정교하게 설계했는가&lt;/b&gt;에 달려 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>HCI</category>
      <category>Human-Computer Interaction</category>
      <category>survey</category>
      <category>설문조사</category>
      <category>인간-컴퓨터 상호작용</category>
      <author>orieasy1</author>
      <guid isPermaLink="true">https://easy1nhard2.tistory.com/33</guid>
      <comments>https://easy1nhard2.tistory.com/33#entry33comment</comments>
      <pubDate>Sun, 9 Nov 2025 17:44:54 +0900</pubDate>
    </item>
    <item>
      <title>[Paper Review] AppAgent: Multimodal Agents as Smartphone Users</title>
      <link>https://easy1nhard2.tistory.com/32</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dWHI6C/dJMcaaQ7AZB/p4SHcHXXGpjvPKHe2Zd6S1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dWHI6C/dJMcaaQ7AZB/p4SHcHXXGpjvPKHe2Zd6S1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dWHI6C/dJMcaaQ7AZB/p4SHcHXXGpjvPKHe2Zd6S1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdWHI6C%2FdJMcaaQ7AZB%2Fp4SHcHXXGpjvPKHe2Zd6S1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;615&quot; height=&quot;573&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;573&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학기에 논문 세미나를 진행한 논문에 대한 리뷰를 작성해보고자 한다.&lt;/p&gt;
&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;시간이 지날수록 LLM의 역할이 점점 더 다양해지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM이 단순히 텍스트나 표, 이미지 등을 생성하는 도구를 넘어서 &lt;b&gt;행동(Act)를 수행하는 에이전트&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;그중에서도 CHI 2025에 게재된 &lt;b&gt;AppAgent: Multimodal Agents as Smartphone Users&lt;/b&gt;라는 논문이 이 흐름을 잘 보여주고 있지 않나라고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 논문에서는 기존 텍스트 기반 정보에만 의존했던 LLM Agent와 달리 이미지 처리 능력이 추가된 최신 LLM 모델을 바탕으로 사람의 행동을 모방하여 수행하는 LLM 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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dl.acm.org/doi/full/10.1145/3706598.3713600&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dl.acm.org/doi/full/10.1145/3706598.3713600&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 논문 LLM이 &quot;사람처럼 스마트폰을 조작할 수 있을까?&quot; 라는 질문에서 출발한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 해당 시스템을 실행시켜보면 정말 사람처럼 수행한다고 느껴진다.&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;논문에서도 어떤 스마트폰 앱이든 조작할 수 있는 에이전트를 구축하는 것이 주요 도전 과제라고 설명하며 시스템 백엔드 접근과 함수 호출을 통해 동작하는 기존 에이전트와는 다르게 AppAgent의 경우, GUI에서 터치와 스와프 같은 저수준 작업을 사용하여 앱을 제어함으로써 사람처럼 스마트폰 앱과 상호작용하도록 구현하였다고 언급한다.&lt;/p&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;시스템 백엔드 접근이 불필요하며 GUI 수준에서 작동하기 때문에 앱 인터페이스의 변경이나 업데이트와 상관없이 유연하게 작동할 수 있다는게 해당 시스템의 장점이라고 한다.&lt;/p&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;Exploration Phase 실행 및 느낀점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 위에서 언급한 목표를 달성하기 위해 논문에서 제시한 핵심 아이디어가 &quot;document-driven few shot learning&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;인간이 새로운 앱을 빠르게 배우는 방식에서 영감을 받은 아이디어로, 에이전트는 앱과 상호작용하며 그 결과를 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;에이전트는 스크린샷과 XML 정보를 받아, 화면에 어떤 버튼이 있고 어떤 요소가 클릭 가능한지를 스스로 파악한 뒤, 그 결과를 &lt;b&gt;JSON 기반 문서(documentation)&lt;/b&gt; 로 기록하면서 학습한다.&lt;br /&gt;이 문서는 이후 Deployment Phase에서 실제 명령을 수행할 때 일종의 &amp;ldquo;행동 지식 베이스&amp;rdquo;로 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이 논문을 읽을 수록 새로운 어플리케이션 UI 사용성 평가를 제외하곤 어떤 방향으로 해당 기술을 사용할 수 있을지 의문이 들었지만 시스템이 학습하는 Exploration Phase를 실행시켜보는 것은 상당히 재미있었다.&lt;/p&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Autonomous Exploration&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;에이전트가 스스로 UI를 탐색하며 상호작용. 각 행동의 결과를 문서로 기록&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Human Demonstration&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 모드 모두 목표(Task Description)를 기반으로 진행된다.&lt;br /&gt;예를 들어 이번 실험에서는 다음과 같은 명령을 주었다.&lt;/p&gt;
&lt;blockquote data-end=&quot;1014&quot; data-start=&quot;970&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1014&quot; data-start=&quot;972&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;execute YouTube and search dog video&quot;, &lt;br /&gt;&quot;Set an alarm for 12:30 PM every Friday and Sunday&quot;&lt;/b&gt;&lt;/p&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;h3 data-ke-size=&quot;size23&quot;&gt;흠.. XML파일을 기반으로 UI를 인식한다고?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 내가 이 시스템에 회의적이게 된 이유는 초반 시작할 때 해당 화면의 xml파일을 받아온다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AppAgent는 실시간 스크린샷과 함께, &lt;b&gt;UI 요소에 대한 세부 정보를 담은 XML 파일&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-origin-width=&quot;1014&quot; data-origin-height=&quot;1588&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4V7sE/dJMcai9spTY/VwuX1akc47JM8S028Fu2Yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4V7sE/dJMcai9spTY/VwuX1akc47JM8S028Fu2Yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4V7sE/dJMcai9spTY/VwuX1akc47JM8S028Fu2Yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4V7sE%2FdJMcai9spTY%2FVwuX1akc47JM8S028Fu2Yk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1014&quot; height=&quot;1588&quot; data-origin-width=&quot;1014&quot; data-origin-height=&quot;1588&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;위 사진은 AppAgent가 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Autonomous Exploration을 실행한 후에 생성된 파일들의 스크린샷인데 숫자는 turn 순서를 나타내고 before는 해당 턴 실행 전의 스크린샷, after는 해당 턴 실행 후의 스크린샷이다.&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;그리고 함께 xml 파일이 저장된 것을 볼 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 내부에는 각 UI 요소의 위치(bounds), 속성(clickable, text, class 등), 계층 구조가 포함되어 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1592&quot; data-origin-height=&quot;1062&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MFlDi/dJMcahipkfr/eXrzjzUPPTHkOFaiiaS1nK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MFlDi/dJMcahipkfr/eXrzjzUPPTHkOFaiiaS1nK/img.png&quot; data-alt=&quot;XML 파일 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MFlDi/dJMcahipkfr/eXrzjzUPPTHkOFaiiaS1nK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMFlDi%2FdJMcahipkfr%2FeXrzjzUPPTHkOFaiiaS1nK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1592&quot; height=&quot;1062&quot; data-origin-width=&quot;1592&quot; data-origin-height=&quot;1062&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;XML 파일 예시&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;br /&gt;&amp;lt;node class=&quot;android.widget.TextView&quot; text=&quot;YouTube&quot; clickable=&quot;true&quot; bounds=&quot;[811,1400][1016,1672]&quot; /&amp;gt; 이런 식으로 앱 내의 각 뷰(View)가 구체적으로 정의된다.&lt;/p&gt;
&lt;p data-end=&quot;1433&quot; data-start=&quot;1367&quot; data-ke-size=&quot;size16&quot;&gt;이를 통해 LLM은 &amp;ldquo;어떤 요소가 클릭 가능한지&amp;rdquo;, &amp;ldquo;이 좌표가 무엇을 의미하는지&amp;rdquo;를 시스템적으로 파악할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;1433&quot; data-start=&quot;1367&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1433&quot; data-start=&quot;1367&quot; data-ke-size=&quot;size16&quot;&gt;이것을 보고 내가 가졌던 의문은 &quot;UI 내부구조를 이미 알고 잇따면 사실상 LLM이 완전한 시각적 추론을 하는 것은 아닐 수도 있지 않을까?&quot;였다.&lt;/p&gt;
&lt;p data-end=&quot;1433&quot; data-start=&quot;1367&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1433&quot; data-start=&quot;1367&quot; data-ke-size=&quot;size16&quot;&gt;즉 논문에서 언급했듯이 사라이 눈으로 보고 판단하듯 시각적으로 행동하는 것이 아니라, 시스템이 이미 제공하는 UI정보에 의존해 조작하는 방식이기 때문에, &lt;b&gt;'GUI를 직접 이해한다'는 의미의 노벨티가 다소 약해 보였다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1433&quot; data-start=&quot;1367&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1433&quot; data-start=&quot;1367&quot; data-ke-size=&quot;size16&quot;&gt;게다가 현재 이 시스템은 아래 명령어로 XML 구조를 손쉽게 덤프해오고 있는데,&amp;nbsp; iOS에서는 이런 구조를 손쉽게 덤프하기 어려운 것으로 알고 있어, 현재 구조로는 &lt;b&gt;안드로이드 환경에 특화된 프레임워크&lt;/b&gt;라는 한계도 있어 보인다.&lt;/p&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1762096455202&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;adb shell uiautomator dump&lt;/code&gt;&lt;/pre&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;&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;저장된 png 파일 목록을 보면 labeled 라는 표시도 보일 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AppAgent는 스크린샷을 찍은 후 아래 사진처럼 UI에 라벨을 달아 표시하고 이를 LLM input으로 사용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1792&quot; data-origin-height=&quot;1990&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dkPA7b/dJMcacakCzL/U0605lSRUy6l7Nvtr9uvak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dkPA7b/dJMcacakCzL/U0605lSRUy6l7Nvtr9uvak/img.png&quot; data-alt=&quot;labeled 예시1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dkPA7b/dJMcacakCzL/U0605lSRUy6l7Nvtr9uvak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdkPA7b%2FdJMcacakCzL%2FU0605lSRUy6l7Nvtr9uvak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1792&quot; height=&quot;1990&quot; data-origin-width=&quot;1792&quot; data-origin-height=&quot;1990&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;labeled 예시1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1996&quot; data-origin-height=&quot;1886&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clDIW3/dJMcabCuDXN/L6zpMkZn1oGimxyel0dV9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clDIW3/dJMcabCuDXN/L6zpMkZn1oGimxyel0dV9K/img.png&quot; data-alt=&quot;labeled 예시2&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clDIW3/dJMcabCuDXN/L6zpMkZn1oGimxyel0dV9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclDIW3%2FdJMcabCuDXN%2FL6zpMkZn1oGimxyel0dV9K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1996&quot; height=&quot;1886&quot; data-origin-width=&quot;1996&quot; data-origin-height=&quot;1886&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;labeled 예시2&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;AppAgent는 스크린샷을 단순 저장하는 것이 아니라, 각 UI 요소에 번호(라벨)를 부여해 시각적으로 표시한다.&lt;/p&gt;
&lt;p data-end=&quot;1981&quot; data-start=&quot;1860&quot; data-ke-size=&quot;size16&quot;&gt;png 파일을 열어보면 UI의 클릭 가능한 요소마다 숫자가 붙어 있는 걸 볼 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;1981&quot; data-start=&quot;1860&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1981&quot; data-start=&quot;1860&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 YouTube 앱에서는 &amp;ldquo;홈(1)&amp;rdquo;, &amp;ldquo;검색창(2)&amp;rdquo;, &amp;ldquo;프로필(3)&amp;rdquo; 이런 식으로 표시된다.&lt;/p&gt;
&lt;p data-end=&quot;2145&quot; data-start=&quot;1983&quot; data-ke-size=&quot;size16&quot;&gt;이 라벨링된 이미지는 LLM의 입력으로 들어가며, 모델은 &amp;ldquo;tap(5)&amp;rdquo;, &amp;ldquo;text(2): dog video&amp;rdquo;와 같은 형식으로 행동을 추론한다.&lt;/p&gt;
&lt;p data-end=&quot;2145&quot; data-start=&quot;1983&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2145&quot; data-start=&quot;1983&quot; data-ke-size=&quot;size16&quot;&gt;이는 단순한 스크린샷이 아니라 &lt;b&gt;행동 가능한 상태 표현(actionable representation)&lt;/b&gt; 이라는 점에서 인상적이었다.&lt;/p&gt;
&lt;p data-end=&quot;2145&quot; data-start=&quot;1983&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2145&quot; data-start=&quot;1983&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2145&quot; data-start=&quot;1983&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2145&quot; data-start=&quot;1983&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그러나 앞서 언급한 XML파일을 기반으로 한 라벨링 문제 때문에 아래 사진처럼 모달창의 경우 라벨링이 되지 않는 문제가 발생하기도 했다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VS3q3/dJMcajUPxpT/jmB0mlNkDmrQTWT4IF0RQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VS3q3/dJMcajUPxpT/jmB0mlNkDmrQTWT4IF0RQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VS3q3/dJMcajUPxpT/jmB0mlNkDmrQTWT4IF0RQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVS3q3%2FdJMcajUPxpT%2FjmB0mlNkDmrQTWT4IF0RQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;1240&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1240&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;Explanation Phase 동작 과정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AppAgent는 이러한 input data를 바탕으로 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;지원하는 task 종류는 다음과 같다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;유형&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;앱 실행&lt;/td&gt;
&lt;td&gt;홈 화면에서 유튜브 앱 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;탭 동작 (tap)&lt;/td&gt;
&lt;td&gt;라벨된 UI 요소에 한정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;텍스트 입력 (text)&lt;/td&gt;
&lt;td&gt;검색창에 &quot;dog video&quot; 입력 등&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;스크롤 (swipe)&lt;/td&gt;
&lt;td&gt;1차 테스트에서 사용안함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;long press&lt;/td&gt;
&lt;td&gt;1차 테스트에서 사용안함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI 뒤로가기(Back)&lt;/td&gt;
&lt;td&gt;1차 테스트에서 사용안함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;프로세스 종료(Exit)&lt;/td&gt;
&lt;td&gt;1차 테스트에서 사용안함&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;Human Demonstration의 경우 아래처럼 인간과 상호작용하면서 어떻게 동작하는지를 학습하고 JSON을 담은 txt 파일을 생성해낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 실행한 terminal 기록 복사본이다.&lt;/p&gt;
&lt;pre id=&quot;code_1762097262728&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Choose one of the following actions you want to perform on the current screen:
tap, text, long press, swipe, stop

tap
Which element do you want to tap? Choose a numeric tag from 1 to 13:

5
Choose one of the following actions you want to perform on the current screen:
tap, text, long press, swipe, stop

tap 
Which element do you want to tap? Choose a numeric tag from 1 to 13:

5
Choose one of the following actions you want to perform on the current screen:
tap, text, long press, swipe, stop

text
Which element do you want to input the text string? Choose a numeric tag from 1 to 3:

2
Enter your input text below:

dog video
Choose one of the following actions you want to perform on the current screen:
tap, text, long press, swipe, stop

tap
Which element do you want to tap? Choose a numeric tag from 1 to 6:

5
Choose one of the following actions you want to perform on the current screen:
tap, text, long press, swipe, stop

stop
Demonstration phase completed. 5 steps were recorded.&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-origin-width=&quot;199&quot; data-origin-height=&quot;464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zq4TP/dJMcagKzn8x/cvKI3BqMu9FMUnfyKHahak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zq4TP/dJMcagKzn8x/cvKI3BqMu9FMUnfyKHahak/img.png&quot; data-alt=&quot;Human demonstration 결과물&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zq4TP/dJMcagKzn8x/cvKI3BqMu9FMUnfyKHahak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzq4TP%2FdJMcagKzn8x%2FcvKI3BqMu9FMUnfyKHahak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;199&quot; height=&quot;464&quot; data-origin-width=&quot;199&quot; data-origin-height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Human demonstration 결과물&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;Autonomous Exploration은 위 과정을 시스템이 LLM과 직접 상호작용하며 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 최종결과로 만들어진 text파일 복사본이다.&lt;/p&gt;
&lt;pre id=&quot;code_1762098490490&quot; class=&quot;smalltalk&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;{&quot;step&quot;: 1, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: None\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;1_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The screenshot shows a smartphone home screen with various app icons. The clock app is labeled with the number 9.\n\nThought: To set an alarm, I need to open the clock app.\n\nAction: tap(9)\n\nSummary: I tapped the clock app icon to open it and proceed with setting an alarm.&quot;}
{&quot;step&quot;: 2, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: I tapped the clock app icon to open it and proceed with setting an alarm.\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;2_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The alarm is set for 12:30 PM on Sunday, Wednesday, Thursday, and Saturday. The vibration option is enabled.\n\nThought: To set the alarm for Friday and Sunday, I need to deselect Wednesday and Thursday, and select Friday. Then, I need to disable the vibration.\n\nAction: tap(14)\n\nSummary: I tapped the clock app icon to open it and proceeded with setting an alarm. I then selected Friday for the alarm.&quot;}
{&quot;step&quot;: 3, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: I tapped the clock app icon to open it and proceeded with setting an alarm. I then selected Friday for the alarm.\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;3_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The alarm is set for 12:30 PM on Sunday, Wednesday, Thursday, Friday, and Saturday. The vibration option is enabled.\n\nThought: To complete the task, I need to disable the vibration for the alarm.\n\nAction: tap(18)\n\nSummary: I tapped the clock app icon to open it, proceeded with setting an alarm, selected Friday, and then disabled the vibration.&quot;}
{&quot;step&quot;: 4, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: I tapped the clock app icon to open it, proceeded with setting an alarm, selected Friday, and then disabled the vibration.\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;4_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The alarm is set for 12:30 PM on Sunday, Wednesday, Thursday, Friday, and Saturday. Vibration is disabled. The days of the week are selectable.\n\nThought: To complete the task, I need to deselect Wednesday and Thursday, leaving only Friday and Sunday selected.\n\nAction: tap(11)\n\nSummary: I tapped the clock app icon to open it, proceeded with setting an alarm, selected Friday, disabled the vibration, and deselected Wednesday.&quot;}
{&quot;step&quot;: 5, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: None\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;5_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The screen shows an alarm set for 12:30 PM on Sunday, Tuesday, Wednesday, Thursday, Friday, and Saturday. The vibration option is enabled.\n\nThought: To set the alarm for Friday and Sunday only, I need to disable the other days. I will start by disabling Tuesday.\n\nAction: tap(11)\n\nSummary: I tapped to disable the alarm on Tuesday, leaving it set for Sunday, Wednesday, Thursday, Friday, and Saturday.&quot;}
{&quot;step&quot;: 6, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: None\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;6_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The alarm is set for 12:30 PM on Sunday, Tuesday, Thursday, Friday, and Saturday. The vibration option is enabled.\n\nThought: To set the alarm for Friday and Sunday only, I need to deselect Tuesday, Thursday, and Saturday.\n\nAction: tap(10)\n\nSummary: I tapped to deselect Tuesday from the alarm schedule.&quot;}
{&quot;step&quot;: 7, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: I tapped to deselect Tuesday from the alarm schedule.\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;7_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The alarm is set for 12:30 PM on Sunday, Monday, Tuesday, Thursday, Friday, and Saturday. The vibration option is enabled.\n\nThought: To complete the task, I need to disable the vibration option.\n\nAction: tap(16)\n\nSummary: I tapped to deselect Tuesday from the alarm schedule and then disabled the vibration option.&quot;}
{&quot;step&quot;: 8, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: None\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;8_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The screen shows an alarm set for 12:30 PM on Sunday, Monday, Tuesday, Thursday, Friday, and Saturday. The vibration option is enabled.\n\nThought: To set the alarm for Friday and Sunday only, I need to deselect Monday, Tuesday, Thursday, and Saturday.\n\nAction: tap(10)\n\nSummary: I tapped to deselect Monday from the alarm schedule.&quot;}
{&quot;step&quot;: 9, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: I tapped to deselect Monday from the alarm schedule.\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;9_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The alarm is set for 12:30 PM on Sunday, Tuesday, Thursday, Friday, and Saturday. The vibration option is enabled.\n\nThought: To complete the task, I need to disable the vibration option.\n\nAction: tap(8)\n\nSummary: I tapped to deselect Monday from the alarm schedule and then disabled the vibration option.&quot;}
{&quot;step&quot;: 10, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: None\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;10_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The alarm is set for 12:30 PM on Sunday, Tuesday, Thursday, Friday, and Saturday. Vibration is enabled.\n\nThought: To set the alarm for Friday and Sunday only, I need to deselect Tuesday, Thursday, and Saturday. I'll start by deselecting Tuesday.\n\nAction: tap(9)\n\nSummary: I tapped to deselect Tuesday from the alarm schedule.&quot;}
{&quot;step&quot;: 11, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: None\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;11_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The alarm is set for 12:30 PM on Sunday, Monday, Tuesday, Thursday, Friday, and Saturday. The vibration option is enabled.\n\nThought: To set the alarm for Friday and Sunday only, I need to deselect Monday, Tuesday, Thursday, and Saturday. I will start by deselecting Monday.\n\nAction: tap(8)\n\nSummary: I observed that the alarm is set for multiple days, including Monday. I tapped to deselect Monday.&quot;}
{&quot;step&quot;: 12, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: I observed that the alarm is set for multiple days, including Monday. I tapped to deselect Monday.\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;12_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The alarm is set for multiple days: Monday, Tuesday, Thursday, Friday, and Saturday. The vibration option is enabled.\n\nThought: To complete the task, I need to deselect Tuesday and Thursday, and disable the vibration.\n\nAction: tap(9)\n\nSummary: I deselected Monday. Now, I have deselected Tuesday to set the alarm for Friday and Sunday only.&quot;}
{&quot;step&quot;: 13, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: I deselected Monday. Now, I have deselected Tuesday to set the alarm for Friday and Sunday only.\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;13_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The alarm is set for 12:30 PM on Monday, Tuesday, Friday, and Saturday. The vibration option is enabled.\n\nThought: To complete the task, I need to disable the vibration option.\n\nAction: tap(13)\n\nSummary: I deselected Monday and Tuesday to set the alarm for Friday and Sunday only. Now, I have disabled the vibration option.&quot;}
{&quot;step&quot;: 14, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: None\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;14_before_labeled.png&quot;, &quot;response&quot;: &quot;```plaintext\nObservation: The screen shows the \&quot;Alarm sound\&quot; settings with options to select different sounds. There is a back button labeled 1.\nThought: To set the alarm, I need to go back to the main alarm settings screen.\nAction: tap(1)\nSummary: I tapped the back button to return to the main alarm settings screen to continue setting the alarm.\n```&quot;}
{&quot;step&quot;: 15, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: I tapped the back button to return to the main alarm settings screen to continue setting the alarm.\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;15_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The alarm is set for 12:30 PM on Monday, Tuesday, Friday, and Saturday. The vibration option is enabled.\n\nThought: To complete the task, I need to disable the vibration option.\n\nAction: tap(12)\n\nSummary: I tapped the back button to return to the main alarm settings screen and then disabled the vibration option for the alarm.&quot;}
{&quot;step&quot;: 16, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: None\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;16_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The alarm is set for 12:30 PM on Monday, Tuesday, Friday, and Saturday. The vibration option is enabled.\n\nThought: To set the alarm for Friday and Sunday, I need to deselect Monday and Tuesday, and select Sunday. Then, I need to disable the vibration.\n\nAction: tap(8)\n\nSummary: I tapped to deselect Monday from the alarm settings.&quot;}
{&quot;step&quot;: 17, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: I tapped to deselect Monday from the alarm settings.\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;17_before_labeled.png&quot;, &quot;response&quot;: &quot;```plaintext\nObservation: The alarm is set for 12:30 PM on Sunday, Monday, Tuesday, Friday, and Saturday. The vibration option is enabled.\nThought: To complete the task, I need to disable the vibration option.\nAction: tap(6)\nSummary: I tapped to deselect Monday from the alarm settings and then disabled the vibration option.\n```&quot;}
{&quot;step&quot;: 18, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: None\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;18_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The screenshot shows a smartphone home screen with various app icons. The clock app is labeled with the number 9.\n\nThought: To set an alarm, I need to open the clock app.\n\nAction: tap(9)\n\nSummary: I tapped the clock app icon to open it and proceed with setting an alarm.&quot;}
{&quot;step&quot;: 19, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: I tapped the clock app icon to open it and proceed with setting an alarm.\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;19_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The screen shows the alarm section of a clock app. There are three alarms set: 8:30 AM, 9:00 AM, and 12:30 PM. The 12:30 PM alarm is active and set for Sunday, Monday, Tuesday, Friday, and Saturday. There is a toggle switch next to each alarm.\n\nThought: To set the 12:30 PM alarm for only Friday and Sunday, I need to edit the days it is set for.\n\nAction: tap(16)\n\nSummary: I tapped the clock app icon to open it and proceeded to tap the 12:30 PM alarm to edit its settings.&quot;}
{&quot;step&quot;: 20, &quot;prompt&quot;: &quot;You are an agent that is trained to complete certain tasks on a smartphone. You will be \ngiven a screenshot of a smartphone app. The interactive UI elements on the screenshot are labeled with numeric tags \nstarting from 1. \n\nYou can call the following functions to interact with those labeled elements to control the smartphone:\n\n1. tap(element: int)\nThis function is used to tap an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be tap(5), which taps the UI element labeled with the number 5.\n\n2. text(text_input: str)\nThis function is used to insert text input in an input field/box. text_input is the string you want to insert and must \nbe wrapped with double quotation marks. A simple use case can be text(\&quot;Hello, world!\&quot;), which inserts the string \n\&quot;Hello, world!\&quot; into the input area on the smartphone screen. This function is only callable when you see a keyboard \nshowing in the lower half of the screen.\n\n3. long_press(element: int)\nThis function is used to long press an UI element shown on the smartphone screen.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen.\nA simple use case can be long_press(5), which long presses the UI element labeled with the number 5.\n\n4. swipe(element: int, direction: str, dist: str)\nThis function is used to swipe an UI element shown on the smartphone screen, usually a scroll view or a slide bar.\n\&quot;element\&quot; is a numeric tag assigned to an UI element shown on the smartphone screen. \&quot;direction\&quot; is a string that \nrepresents one of the four directions: up, down, left, right. \&quot;direction\&quot; must be wrapped with double quotation \nmarks. \&quot;dist\&quot; determines the distance of the swipe and can be one of the three options: short, medium, long. You should \nchoose the appropriate distance option according to your need.\nA simple use case can be swipe(21, \&quot;up\&quot;, \&quot;medium\&quot;), which swipes up the UI element labeled with the number 21 for a \nmedium distance.\n\nThe task you need to complete is to set an alarm at 12:30 pm every Friday and Sunday, disable the vibration. Your past actions to proceed with this task are summarized as \nfollows: I tapped the clock app icon to open it and proceeded to tap the 12:30 PM alarm to edit its settings.\nNow, given the following labeled screenshot, you need to think and call the function needed to proceed with the task. \nYour output should include three parts in the given format:\nObservation: &amp;lt;Describe what you observe in the image&amp;gt;\nThought: &amp;lt;To complete the given task, what is the next step I should do&amp;gt;\nAction: &amp;lt;The function call with the correct parameters to proceed with the task. If you believe the task is completed or \nthere is nothing to be done, you should output FINISH. You cannot output anything else except a function call or FINISH \nin this field.&amp;gt;\nSummary: &amp;lt;Summarize your past actions along with your latest action in one or two sentences. Do not include the numeric \ntag in your summary&amp;gt;\nYou can only take one action at a time, so please directly call the function.&quot;, &quot;image&quot;: &quot;20_before_labeled.png&quot;, &quot;response&quot;: &quot;Observation: The alarm is set for 12:30 PM on Sunday, Monday, Tuesday, Friday, and Saturday. The vibration option is currently enabled.\n\nThought: To complete the task, I need to disable the vibration option.\n\nAction: tap(6)\n\nSummary: I tapped the clock app icon to open it, proceeded to tap the 12:30 PM alarm to edit its settings, and then disabled the vibration option.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;AppAgent의 프롬프트 설계&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;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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;715&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgoOWD/dJMcaiIn2oT/L4wkfkr2NoDOe5bhv6YT21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgoOWD/dJMcaiIn2oT/L4wkfkr2NoDOe5bhv6YT21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgoOWD/dJMcaiIn2oT/L4wkfkr2NoDOe5bhv6YT21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdgoOWD%2FdJMcaiIn2oT%2FL4wkfkr2NoDOe5bhv6YT21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;580&quot; height=&quot;715&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;715&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;figure data-ke-type=&quot;image&quot; data-ke-style=&quot;alignCenter&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프롬프트를 보면 주어진 스크린샷과 XML 라벨 정보를 바탕으로 Observation -&amp;gt; Thought -&amp;gt; Action -&amp;gt; Summary의 과정을 반복하는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 각 행동의 목적을 요약하는 Summary까지 생성하여 행동 맥락을 지속적으로 확인하는 것을 관찰할 수 있다.&lt;/p&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;두 번째 프롬프트는 앞서 수행한 행동이 실제로 task를 진전시켰는지 판단한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 장의 스크린샷(before/after)을 비교하여 다음 네 가지 중 하나를 결정한다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;BACK&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;잘못된 페이지로 이동함 &amp;rarr; 이전 화면으로 복귀&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;INEFFECTIVE&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;아무 변화 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;CONTINUE&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;변화는 있으나 목표와 무관&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;SUCCESS&lt;/b&gt;&lt;/td&gt;
&lt;td&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-origin-width=&quot;519&quot; data-origin-height=&quot;747&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bN0eor/dJMcaaQ7AC9/WJ2t2girp5dZbkCFO8osW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bN0eor/dJMcaaQ7AC9/WJ2t2girp5dZbkCFO8osW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bN0eor/dJMcaaQ7AC9/WJ2t2girp5dZbkCFO8osW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbN0eor%2FdJMcaaQ7AC9%2FWJ2t2girp5dZbkCFO8osW0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;519&quot; height=&quot;747&quot; data-origin-width=&quot;519&quot; data-origin-height=&quot;747&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 평가 결과는 다시 문서(JSON)로 기록되어 이후 few-shot learning의 레퍼런스로 사용된다.&lt;br /&gt;즉, AppAgent는 &amp;ldquo;관찰 &amp;rarr; 행동 &amp;rarr; 평가&amp;rdquo;의 완전한 순환 구조를 통해 스스로 탐색하고 개선하는 셈이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 우리는 AppAgent가 &lt;b&gt;Chain-of-Thought를 &amp;lsquo;행동 단위&amp;rsquo;로 확장한 시스템&lt;/b&gt;이라는 것을 알 수 있다.&lt;br /&gt;텍스트로 사고 과정을 설명하는 수준을 넘어, 그 사고 결과를 실제 터치&amp;middot;입력&amp;middot;스와이프 같은 물리적 행동으로 연결한다.&lt;/p&gt;
&lt;p data-end=&quot;1578&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1578&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size16&quot;&gt;물론 여전히 XML 기반 입력과 제한된 인터페이스 등 기술적 한계가 존재하지만, 이 구조는 &lt;b&gt;&amp;ldquo;스스로 생각하고, 실수하고, 수정하는&amp;rdquo; LLM기반 행동 Agent&lt;/b&gt;의 가능성을 명확히 보여준다&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1578&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1578&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1578&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;1578&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;정리하며..&lt;/span&gt;&lt;/h2&gt;
&lt;p data-end=&quot;1578&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;사실 딥러닝, 머신러닝 모델을 사용하는 것도 아니고 단순히 LLM API만 사용해서 이러한 시스템을 구현하였기 때문에 성능에 대한 기본적인 한계는 존재할 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1578&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1578&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;실제로 실행해보며 나도 이점을 느꼈다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1578&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1578&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;하지만 해당 시스템에서 사용한 프롬프트를 보고 전체적인 동작 코드를 뜯어보면서 사람처럼 배워서 동작을 수행하는 agent를 만들겠다는 인간 모방 에이전트를 LLM과 프롬프트만으로는 꽤 잘 구현하지 않았나 생각한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1578&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1578&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1578&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;기술적으로 업그레이드 된 AppAgentX에 대한 논문도 최근에 나왔으니 참고해보면 좋을 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1578&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;a href=&quot;https://appagentx.github.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://appagentx.github.io/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1762100084885&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;AppAgentX: Evolving GUI Agents as Proficient Smartphone Users&quot; data-og-description=&quot;AppAgentX: Evolving GUI Agents as Proficient Smartphone Users&quot; data-og-host=&quot;appagentx.github.io&quot; data-og-source-url=&quot;https://appagentx.github.io/&quot; data-og-url=&quot;https://appagentx.github.io/URL%20OF%20THE%20WEBSITE&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/mgGp7/hyZMufgvGi/VUqDcCnBFHWNojvPPZykx0/img.jpg?width=2067&amp;amp;height=1180&amp;amp;face=0_0_2067_1180,https://scrap.kakaocdn.net/dn/N70Hj/hyZLaJs5we/M6E2nyNUr4c30Kiw9b0H51/img.jpg?width=2067&amp;amp;height=1180&amp;amp;face=0_0_2067_1180,https://scrap.kakaocdn.net/dn/cMYu53/hyZMFHR6Jq/AUXeCKFUxrk3GAKAwYjXx1/img.jpg?width=1238&amp;amp;height=942&amp;amp;face=0_0_1238_942&quot;&gt;&lt;a href=&quot;https://appagentx.github.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://appagentx.github.io/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/mgGp7/hyZMufgvGi/VUqDcCnBFHWNojvPPZykx0/img.jpg?width=2067&amp;amp;height=1180&amp;amp;face=0_0_2067_1180,https://scrap.kakaocdn.net/dn/N70Hj/hyZLaJs5we/M6E2nyNUr4c30Kiw9b0H51/img.jpg?width=2067&amp;amp;height=1180&amp;amp;face=0_0_2067_1180,https://scrap.kakaocdn.net/dn/cMYu53/hyZMFHR6Jq/AUXeCKFUxrk3GAKAwYjXx1/img.jpg?width=1238&amp;amp;height=942&amp;amp;face=0_0_1238_942');&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;AppAgentX: Evolving GUI Agents as Proficient Smartphone Users&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;AppAgentX: Evolving GUI Agents as Proficient Smartphone Users&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;appagentx.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://arxiv.org/abs/2503.02268&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://arxiv.org/abs/2503.02268&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1762100095444&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;AppAgentX: Evolving GUI Agents as Proficient Smartphone Users&quot; data-og-description=&quot;Recent advancements in Large Language Models (LLMs) have led to the development of intelligent LLM-based agents capable of interacting with graphical user interfaces (GUIs). These agents demonstrate strong reasoning and adaptability, enabling them to perfo&quot; data-og-host=&quot;arxiv.org&quot; data-og-source-url=&quot;https://arxiv.org/abs/2503.02268&quot; data-og-url=&quot;https://arxiv.org/abs/2503.02268v3&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ccIdXL/hyZM9PaZxk/AWTSFfCR4XGarD2a6PJVq1/img.png?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/dEZvcD/hyZM3g6YB5/dV2Q8cCbNc9hJC0VhaPPB0/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/2503.02268&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://arxiv.org/abs/2503.02268&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ccIdXL/hyZM9PaZxk/AWTSFfCR4XGarD2a6PJVq1/img.png?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/dEZvcD/hyZM3g6YB5/dV2Q8cCbNc9hJC0VhaPPB0/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;AppAgentX: Evolving GUI Agents as Proficient Smartphone Users&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Recent advancements in Large Language Models (LLMs) have led to the development of intelligent LLM-based agents capable of interacting with graphical user interfaces (GUIs). These agents demonstrate strong reasoning and adaptability, enabling them to perfo&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;</description>
      <category>논문</category>
      <category>Agent</category>
      <category>llm</category>
      <category>PrompEngineering</category>
      <category>prompt</category>
      <author>orieasy1</author>
      <guid isPermaLink="true">https://easy1nhard2.tistory.com/32</guid>
      <comments>https://easy1nhard2.tistory.com/32#entry32comment</comments>
      <pubDate>Mon, 3 Nov 2025 01:16:05 +0900</pubDate>
    </item>
    <item>
      <title>[Kotlin] 기본 문법 1 - 변수 및 자료형, 조건문, Array</title>
      <link>https://easy1nhard2.tistory.com/31</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;* 3학년 2학기 모바일 프로그래밍 수업 기록&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;현재 Android 어플리케이션을 개발하기 위해 주로 사용되는 언어는 바로 Kotlin이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Android 모바일 어플리케이션 개발 기록을 기록하기 앞서 Kotlin 문법에 대해 간단히 설명해보고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(이 글은 기본적으로 Java를 알고 있다고 가정하고 정리한 글이다.)&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;자료형은 다른 프로그래밍 언어와 매우 비슷하다.&lt;/p&gt;
&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;Boolean 자료형은 true와 false 두 가지 자료형을 포함하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Charater은 Char타입으로 나타내는데 보통 ' '안에 작성한다.&lt;/p&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;\t&lt;/span&gt; (탭)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;\b&lt;/span&gt; (백스페이스)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;\n&lt;/span&gt; (줄바꿈)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;\r&lt;/span&gt; (캐리지 리턴)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;\'&lt;/span&gt; (작은따옴표)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;\&quot;&lt;/span&gt; (큰따옴표)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;\\&lt;/span&gt; (역슬래시)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;\$&lt;/span&gt; (달러 기호)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 다른 문자를 표현하려면 유니코드 이스케이프를 사용한다. (예: '\uFF00&amp;rsquo;)&lt;/p&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;다음은 String template이다.&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 id=&quot;code_1758109554749&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 변수 이름 직접 삽입
val i = 0
println(&quot;i =$i&quot;)  // 출력: i = 10

//{}안에 expression 삽입
val s = &quot;abc&quot;
println(&quot;$s length is ${s.length}&quot;)  // 출력: abc length is 3&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 Kotlin에서 변수를 선언할 때는 var 키워드를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var 키워드를 사용해 선언한 변수는 재할당이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 가지 Java와 다른 점은 타입 자동 추출이 가능하다는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1758109958126&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var x = 5 // Int로 타입이 자동으로 추출
x += 1

//자료형을 정의하면서 변수를 선언할 수 도 있다.
var y: Int&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;반면 상수는 val 키워드를 사용하여 선언한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽기 전용이며 var과 달리 재할당이 불가능하다는 것이 특징이다.&lt;/p&gt;
&lt;pre id=&quot;code_1758110140104&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val a: Int = 1    // 즉시 할당, 타입을 명시해서 선언할 수 있다.
val b = 2    // Int 타입이 자동으로 추론됨
val c: Int   // 초기값이 없으면 타입을 반드시 명시해야 함
c = 3   // 처음 한 번만 할당 가능, 두번째 할당은 불가능&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 조건문&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;if 문&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if문의 기본구조는 다른 언어와 유사하다.&lt;/p&gt;
&lt;pre id=&quot;code_1758110466959&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 기본 구조
if (조건) {
    // 조건이 true일 때 실행
}

// if ~ else
if (a &amp;gt; b) {
    max = a
} else {
    max = b
}&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;한 가지 다른 점은 kotlin에서 if는 값을 반환할 수 있는 표현식이기 때문에 변수에 바로 넣어서 사용할 수 있다는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1758110562826&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val max = if (a &amp;gt; b) a else b&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;위 식에서 표현되어있는 조건에 따라 그 결과 값이 max에 할당되게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java와 C언어의 삼항 연산자 (a &amp;gt; b ? a : 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;아래 코드 처럼 여러 줄로 블럭을 작성하는 것 또한 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1758112477914&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val max = if (a &amp;gt; b) {
    println(&quot;Choose a&quot;)
    a   // 마지막 줄이 반환됨
} else {
    println(&quot;Choose b&quot;)
    b
}&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;h4 data-ke-size=&quot;size20&quot;&gt;2. when 문&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kotlin에만 존대하는 조건문이 있는데 그것이 바로 when문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 언어에도 비슷한 문법(switch-case 등)은 존재하지만 when이라는 이름과 형태는 Kotlin의 고유 형태이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;when문이 switch-case보다 더 강력하고 유연하다는 것이 특징이다.&lt;/p&gt;
&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_1758116109086&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 기본구조
when(parameter) {
	condition -&amp;gt; action1
    condition -&amp;gt; action2
    
    else -&amp;gt; { //Note the block
    	action3
    }
}

// 예시
val grade = &quot;A+&quot;

when(grade){
	&quot;A+&quot; -&amp;gt; Log.d(&quot;ITM&quot;, &quot;Oh.. great..!&quot;)
    &quot;B+&quot; -&amp;gt; Log.d(&quot;ITM&quot;, &quot;Hey?&quot;)
    else -&amp;gt; {
    	 Log.d(&quot;ITM&quot;, &quot;I don't know who you are&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;또 여러 조건을 ,로 묶어서 한 줄에 처리하는 것도 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1758116216671&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 기본 구조
when (parameter) {
	condition1, condition2 -&amp;gt; action1
    else -&amp;gt; {// Note the block
    	action2
    }
}

// 예시
when (grade) {
    &quot;A+&quot;, &quot;B+&quot;, &quot;C+&quot; -&amp;gt; Log.d(&quot;ITM&quot;, &quot;Oh.. great..!!&quot;)
    &quot;A&quot;, &quot;B&quot;, &quot;C&quot;    -&amp;gt; Log.d(&quot;ITM&quot;, &quot;Hey?&quot;)
    else -&amp;gt; Log.d(&quot;ITM&quot;, &quot;I don't know who you are.&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;범위(Range)와 조건을 when문에서 활용할 수 있는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;in 혹은 !in을 사용해 값이 특정 범위에 속하는지 검사가 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1758202240794&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val score = 89

when (score) {
	in 90..100 -&amp;gt; Log.d(&quot;ITM&quot;, &quot;A+&quot;)
    else -&amp;gt; Log.d(&quot;ITM&quot;, &quot;resit!&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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;또 parameter가 없는 when문은 if-else if 체인의 대체로 사용가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1758202613842&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val score = 49

when {
	score &amp;gt; 90 -&amp;gt; Log.d(&quot;ITM&quot;, &quot;A+&quot;)
    score in 50..89 -&amp;gt; Log.d (&quot;ITM&quot;, &quot;A0&quot;)
    else -&amp;gt; Log.d(&quot;ITM&quot;, &quot;resit!!&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;&amp;nbsp;is 키워드를 사용하면 타입 체크도 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1758202916478&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val x: Any = 20.5

when (x) {
	is Int -&amp;gt; Log.d(&quot;It's Int type&quot;)
    is String -&amp;gt; Log.d(&quot;It's String type&quot;)
    else -&amp;gt; Log.d(&quot;What is this?&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;when문이 Java의 조건문과 비교했을 때 특별한 점은 단순한 제어문이 아니라 표현식으로도 사용할 수 있다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 값을 반환하여 변수에 할당할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1758203958023&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val myScore = 80
val myGrade = when(myScore) {
	in 90..100  -&amp;gt; &quot;A+&quot;
    else -&amp;gt; &quot;F&quot;
}

Log.d(&quot;ITM, &quot;My score is $myScore, so my grade is $myGrade&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Array 배열&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열은 기본적으로 고정 길이 데이터를 저장하는 자료구조로 한 번 크기를 정하면 변경할 수 없는 것이 특징이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 언어와 마찬가지로 인덱스(0부터 시작)으로 접근한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기화 방법은 크게 2가지로 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 Array()을 사용하여 크기를 지정하여 생성하는 경우가 있고, 두 번째로 arrayOf()를 사용하여 직접 값을 넣어 생성하는 경우가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1760139568668&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Array() 생성자: 크기, 초기화 함수
val squares = Array(5) { i -&amp;gt; i * i}
// 결과: [ 0, 1, 4, 9, 16]

//arrayOf(): 요소 직접 지정
val fruits = arrayOf(&quot;apple&quot;, &quot;banana&quot;, &quot;cherry&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kotlin은 성능을 위해 각 기본형에 맞는 배열 타입을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열 종류에는 ByteArray, ShortArray, IntArray, LongArray, CharArray, FloatArray, DoubleArray, BooleanArray가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1760144821931&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val x: IntArray = intArrayOf(1,2,3)
var y = arrayOf(&quot;one&quot;, two&quot;,&quot;three&quot;)

val arr = IntArray(5)
// 결과: [0, 0, 0, 0, 0]

var arr2 = IntArray(5) { 42 }
// 결과: [42, 42, 42, 42, 42]

var arr3 = IntArray(5) { it + 1 }
// 결과: [1, 2, 3, 4, 5]

var arr4 = Array(5){i -&amp;gt; i * i}
// 결과: [0, 1, 4, 9, 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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;get(), set() 또는 [ ] 연산자를 사용하여 값에 접근할 수 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;동작&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;문법&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;조회&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;arr[index]&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;특정 위치의 값 읽기&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;조회2&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;arr.get(index)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;get() 함수 사용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;변경&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;arr[index] = value&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;인덱스로 값 변경&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;변경2&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;arr.set(index, value)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;set() 함수 사용&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자주 쓰는 유틸리티 함수는 다음과 같다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 104px;&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: 35.5814%; height: 19px;&quot;&gt;&lt;b&gt;함수&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 64.4186%; 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: 35.5814%; height: 17px;&quot;&gt;size&lt;/td&gt;
&lt;td style=&quot;width: 64.4186%; height: 17px;&quot;&gt;배열의 크기 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 35.5814%; height: 17px;&quot;&gt;first() / last()&lt;/td&gt;
&lt;td style=&quot;width: 64.4186%; height: 17px;&quot;&gt;배열의 첫/마지막 요소 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 35.5814%; height: 17px;&quot;&gt;sort()&lt;/td&gt;
&lt;td style=&quot;width: 64.4186%; height: 17px;&quot;&gt;오름차순 정렬 (원본 변경됨)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 35.5814%; height: 17px;&quot;&gt;sortedArray()&lt;/td&gt;
&lt;td style=&quot;width: 64.4186%; height: 17px;&quot;&gt;정렬된 새 배열 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 35.5814%; height: 17px;&quot;&gt;sortedArrayDescending()&lt;/td&gt;
&lt;td style=&quot;width: 64.4186%; height: 17px;&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;pre id=&quot;code_1760606660975&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val x: IntArray = intArrayOf(1, 2, 3) 
val y = arrayOf(&quot;one&quot;, &quot;two&quot;, &quot;three&quot;)
val arr = IntArray(5) 
val arr2 = IntArray(5) { 42 } 
var arr3 = IntArray(5) { it+1 }
var arr4 = Array(5){i-&amp;gt; i*i}

Log.d(&quot;ITM&quot;,&quot;x.size: ${x.size}&quot;)
Log.d(&quot;ITM&quot;,&quot;arr.size: ${arr.size}&quot;)

Log.d(&quot;ITM&quot;,Arrays.toString(x))
Log.d(&quot;ITM&quot;,Arrays.toString(y))
Log.d(&quot;ITM&quot;,Arrays.toString(arr))
Log.d(&quot;ITM&quot;,Arrays.toString(arr2))
Log.d(&quot;ITM&quot;,Arrays.toString(arr3))
Log.d(&quot;ITM&quot;,Arrays.toString(arr4))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1760606776165&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val arr: IntArray = IntArray(10){it+1}
val first = arr[0]
val first2 = arr.first()
val first3 = arr.get(0)
val last = arr.last()

Log.d(&quot;ITM&quot;, &quot;${Arrays.toString(arr)}&quot;)
Log.d(&quot;ITM&quot;, &quot;first: $first $first2 $first3 last: $last&quot;)

arr[0] = 100
arr.set(1,200)

Log.d(&quot;ITM&quot;, &quot;${Arrays.toString(arr)}&quot;)
arr.sort() // in-place sorting
val arr2 = arr.sortedArrayDescending() // return a new sorted array (desc.)

Log.d(&quot;ITM&quot;, &quot;${Arrays.toString(arr)}&quot;)
Log.d(&quot;ITM&quot;, &quot;${Arrays.toString(arr2)}&quot;)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발/Web&amp;amp;App</category>
      <category>Android</category>
      <category>Kotlin</category>
      <category>안드로이드</category>
      <category>코틀린</category>
      <category>코틀린문법</category>
      <author>orieasy1</author>
      <guid isPermaLink="true">https://easy1nhard2.tistory.com/31</guid>
      <comments>https://easy1nhard2.tistory.com/31#entry31comment</comments>
      <pubDate>Sun, 12 Oct 2025 23:37:56 +0900</pubDate>
    </item>
    <item>
      <title>Chrome 확장 프로그램과 Node.js 서버 간 WebSocket 통신 구축 방법</title>
      <link>https://easy1nhard2.tistory.com/30</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;지난 여름, 연구실에서 사용자 적응형 다크 모드 프로그램과 관련해서 연구를 진행했었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;s&gt;엎어졌지만...&lt;/s&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; 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;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그 말인 즉슨 &lt;b&gt;HTTP 요청 - 응답 구조만으로는 한계가 있음&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;1. HTTP의 한계와 WebSocket의 사용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;전통적인 웹통신 구조인 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;HTTP 요청-응답 모델은 항상 &lt;b&gt;&quot;클라이언트가 요청 &amp;rarr; 서버가 응답&quot;&lt;/b&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;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이 방식은 일반적인 웹사이트나 API 요청에는 충분하지만 제가 구상했던 사용자 적응형 다크 모드 시스템 처럼 &lt;b&gt;서버가 클라이언트의 상태를 제어해야하는 구조에는 적합하지 않았습니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; 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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;HTTP 기반 구조라면 서버는 클라이언트가 요청을 보내기 전까지는 아무것도 할 수 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;서버가 먼저 행동을 지시해야하는데 &lt;b&gt;HTTP의 경우 서버가 먼저 행동을 '지시'할 수 있는 방법이 없는 것&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이런 문제를 해결하기 위해 사용할 수 있는 것이 바로 양방향 통신인 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;WebSocket&lt;/b&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;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;WebSocket이란?&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;WebSocket은 클라이언트와 서버가 항상 연결된 상태로 실시간 양방향 통신을 주고 받을 수 잇는 프로토콜입니다.&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;한 번의 handshake 이후에는 서버가 언제든 클라이언트로 메세지를 보낼 수 있고, 클라이언트 역시 별도의 요청 없이 데이터를 즉시 서버에 보낼 수 있습니다.&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;즉 WebSocket을 사용하면, 요청에만 반응하는 웹의 기존 패러다임에서 벗어나 &lt;b&gt;지속적이고 상호적인 연결을 구축&lt;/b&gt;할 수 있습니다.&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;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;HTTP&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;WebSocket&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;연결 구조&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;요청 후 응답으로 종료&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;한 번 연결 후 지속 유지&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;통신 방향&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;단방향 (client &amp;rarr; server)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;양방향 (client &amp;harr; server)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;사용 예시&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;일반 API, 데이터 요청&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;채팅, 알림, 실시간 제어&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;전송 프로토콜&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;HTTP/HTTPS&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ws:// 또는 wss://&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;&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;그래서 저는 이 WebSocket 통신을 이용하여 서버가 클라이언트에게 &quot;폰트 크기를 조정해라, &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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2.&amp;nbsp; 시스템 설명 및 구현&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;&quot;&gt;2.1&amp;nbsp; 전체 시스템 구상&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;다시 한 번 설명하자면, (음.. 여기서 주제 관련 자세한 이야기는 할 수 없지만...) 구상한 시스템 아키텍처 상 서버가 클라이언트를 제어하는 구조여야 했고, 이를 위해서는 WebSocket 통신을 도입하는 방향으로 진행을 해야했습니다.&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 data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Chrome Extension으로 해당 시스템을 만들어야 했고 Chrome Extension은 대부분 TypeScript로 이루어져있습니다.&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;그래서 JavaScript를 사용하는 Backend Framework인 &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;Node.js로 서버를 구축&lt;/b&gt;하고 Chrome Extension의 &lt;b&gt;background.ts를 클라이언트&lt;/b&gt;로 설정해 서버에서 직접 확정 프로그램 UI를 제어하는 구조&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;&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;그 과정에서 CSP, popup 제약 등 여러 시행착오를 겪었지만, 결국 background 기반 WebSocket 통신이 가장 안정적이라는 결론에 도달 했습니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2.2&amp;nbsp; 왜 background.ts?&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;왜 background에서 WebSocket 통신으 다루는 것이 안정적인지에 대한 이야기를 해보겠습니다.&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;Chroem 확장 프로그램은 크게 3가지 주요 실행 단위&lt;/b&gt;로 구성됩니다.&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;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 15.5814%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 61.5116%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;설명&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;실행 특성&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 15.5814%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;popup&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 61.5116%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;사용자가 확장 아이콘을 클릭했을 때 뜨는 UI 화면&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;일시적 (UI 닫히면 종료)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 15.5814%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;content script&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 61.5116%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;웹페이지에 삽입되어 DOM을 조작하는 스크립트&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;페이지 단위로 로드/종료&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 15.5814%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;background&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 61.5116%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;확장 프로그램 전체의 백엔드 로직을 담당하는 스크립트 (Service Worker 형태)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 22.7907%;&quot;&gt;&amp;nbsp;&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;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이 중 background는 말 그대로 확장 프로그램의 두뇌 역할을 합니다.&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;popup이 사라져도, 탭이 닫혀도&lt;b&gt; background는 살아남아 확장 전체의 상태를 관리하고 서버와의 연결을 유지&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;&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;WebSocket의 핵심은 &lt;b&gt;&quot;한 번 연결되면 계속 살아있는 상태로 데이터를 주고받는 것&quot;&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;하지만 popup이나 content script는 수명이 짧기 때문에 WebSocket 연결을 여기에 두면 다음과 같은 문제가 발생합니다.&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;popup을 닫으면 연결이 바로 끊김&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;페이지가 새로고침되면 연결이 초기화됨&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;또 추가적으로 Chrome Extension은 보안상 Content Security Policy(CSP)가 매우 엄격합니다.&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;그래서 Chrome Extension에서&amp;nbsp;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;WebSocket 연결은 항상 실행중인&lt;/span&gt; background에서 관리하고, 필요할 때 popup이나 content script와 메시지를 주고받는 구조가 제일 안정적인 것&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;&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;2.3&amp;nbsp; 기본 시스템 구조 설계 및 구현&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&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759643519090&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[ Chrome Extension ]
     └─► background.ts
              └─ WebSocket 연결
              └─ 서버에 메시지 전송 / 수신 처리

[ Node.js Backend Server ]
     └─ WebSocket 서버 (ws://localhost:3001)
              └─ 메시지 수신 &amp;rarr; 처리 &amp;rarr; 응답 전송&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;/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;벡엔드 폴더로 접속하여 아래 명령어를 실행해 필요한 기본 패키지를 설치했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759644186979&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install
npm install ws
npm install express&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;그리고 지금은 기본적인 부분만 구축했기 때문에 index.js 파일에서 WebSocket 통신을 관리하도록 기본 코드를 작성해놓앗습니다.&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;추후에는 node index.js 명령어로 서버를 실행할 수 있고 서버가 성공적으로 실행되면 대기중인 WebSocket 서버도 활성화됩니다.&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;/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;아래 코드는 단순히 연결된 클라이언트의 메세지를 받아 같은 내용을 echo&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;index.js&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759644417135&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const WebSocket = require('ws');

// WebSocket 전용 포트
const PORT = 3001;

// 서버 생성
const wss = new WebSocket.Server({ port: PORT });

wss.on('connection', (ws) =&amp;gt; {
  console.log('✅ 클라이언트 WebSocket 연결됨');

  ws.on('message', (message) =&amp;gt; {
    console.log('  클라이언트 메시지:', message.toString());

    // 응답 전송
    ws.send(`서버 응답: ${message}`);
  });

  ws.on('close', () =&amp;gt; {
    console.log('❌ 클라이언트 연결 종료');
  });
});

console.log(`  WebSocket 서버 실행 중 (ws://localhost:${PORT})`);&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;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;클라이언트 측 구현 (background.ts)&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;아래 코드는 Chrome Extension의 &lt;b&gt;background.ts&lt;/b&gt; 파일에서 WebSocket 클라이언트로 동작하도록 구현한 부분입니다.&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;저희는 다크 모드 관련 확장 프로그램인 DarkReader의 3.5.4 버전에서 수정을 실행했습니다.&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;아래 코드는 해당 확장 프로그램의 background.ts 파일에 추가한 내용입니다.&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;a href=&quot;https://github.com/darkreader/darkreader&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/darkreader/darkreader&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1759644764326&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 - darkreader/darkreader: Dark Reader Chrome and Firefox extension&quot; data-og-description=&quot;Dark Reader Chrome and Firefox extension. Contribute to darkreader/darkreader development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/darkreader/darkreader&quot; data-og-url=&quot;https://github.com/darkreader/darkreader&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/n1fIp/hyZKt9n5YL/Y3kEKKszKtKEmy6tnDrLQ1/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640,https://scrap.kakaocdn.net/dn/c86OkT/hyZKmPZbAl/kyatiiEhDaNLqEbFbNws6k/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640&quot;&gt;&lt;a href=&quot;https://github.com/darkreader/darkreader&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/darkreader/darkreader&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/n1fIp/hyZKt9n5YL/Y3kEKKszKtKEmy6tnDrLQ1/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640,https://scrap.kakaocdn.net/dn/c86OkT/hyZKmPZbAl/kyatiiEhDaNLqEbFbNws6k/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640');&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 - darkreader/darkreader: Dark Reader Chrome and Firefox extension&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Dark Reader Chrome and Firefox extension. Contribute to darkreader/darkreader 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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;popup에서 직접 서버에 연결을 시도하면 CSP(Content Security Policy) 제약으로 차단되기 때문에, 항상 실행되는 background service worker가 &lt;b&gt;서버와의 지속적인 연결을 담당하도록 설계&lt;/b&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_1759644685231&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// WebSocket 변수
let socket: any = null;

// WebSocket 연결 함수
function connectWebSocket() {
    socket = new WebSocket('ws://localhost:3001');

    socket.onopen = () =&amp;gt; {
        console.log('[bg] WebSocket 연결됨');
        if (socket &amp;amp;&amp;amp; socket.readyState === 1) {
            socket.send('[bg] 확장에서 서버 연결됨');
        }
    };

    socket.onmessage = (event) =&amp;gt; {
        console.log('[bg] 서버 응답:', event.data);
        chrome.runtime.sendMessage({ from: 'server', data: event.data });
    };

    socket.onclose = () =&amp;gt; {
        console.warn('[bg] 연결 끊김 &amp;rarr; 재연결 예정');
        setTimeout(connectWebSocket, 3000);
    };

    socket.onerror = (err) =&amp;gt; {
        console.error('[bg] WebSocket 오류:', err);
        if (socket) socket.close();
    };
}

// popup에서 보내는 메시지 수신 &amp;rarr; 서버로 전달
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) =&amp;gt; {
    if (msg.from === 'popup' &amp;amp;&amp;amp; socket &amp;amp;&amp;amp; socket.readyState === 1) {
        console.log('[bg] popup &amp;rarr; 서버:', msg.data);
        socket.send(msg.data);
    }
});

// 확장 프로그램 초기화 시 WebSocket 연결 실행
loadConfigs(() =&amp;gt; {
    extension = new DarkReader.Extension(new DarkReader.FilterCssGenerator());
    onExtensionLoaded.invoke(extension);

    // WebSocket 연결 시작
    connectWebSocket();
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;3. 작동 확인&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;darkreader 3.5.4는 mainfest v2로 구버전입니다.&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;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;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&amp;nbsp; 빌드 폴더 생성&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&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;아래 명령어를 실행하면 자동으로 build&amp;nbsp;폴더가 생성됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759645061584&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm run release&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;빌드 과정에서 필요한 패키지가 없다는 에러가 뜬다면 npm이 안내하는 대로 &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;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;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&amp;nbsp; Chrome 확장 프로그램 등록&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;크롬 주소창에 chrome://extensions 를 입력해 확장 프로그램 관리 페이지로 이동합니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1668&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crerJp/btsQ2UBBhnj/q82bPLFhcdp5CAeagpz9O1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crerJp/btsQ2UBBhnj/q82bPLFhcdp5CAeagpz9O1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crerJp/btsQ2UBBhnj/q82bPLFhcdp5CAeagpz9O1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrerJp%2FbtsQ2UBBhnj%2Fq82bPLFhcdp5CAeagpz9O1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1668&quot; height=&quot;242&quot; data-origin-width=&quot;1668&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;&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;3.1 단계에서 생성된 build.zip을 압축 해제합니다.&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;확장 프로그램 관리 페이지에서 &quot;압축해제된 확장 프로그램 로드&quot; 버튼을 클릭하고 방금 압축 해제한 buil 폴더를 선택해 등록합니다.&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;아래 사진에 Dark Reader 3.5.4가 등록된 것 보이시죠?&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;등록이 완료되면 확장 프로그램이 크롬에 추가되고, 확장 아이콘을 통해 popup 화면을 열 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2ZTIP/btsQ2eArewM/IXhAiv72DvAeKMDgEdjrr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2ZTIP/btsQ2eArewM/IXhAiv72DvAeKMDgEdjrr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2ZTIP/btsQ2eArewM/IXhAiv72DvAeKMDgEdjrr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2ZTIP%2FbtsQ2eArewM%2FIXhAiv72DvAeKMDgEdjrr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;644&quot; data-origin-width=&quot;1280&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;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 백엔드 서버 실행 및 연결 확인&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;이제 WebSocket 서버를 실행해보겠습니다.&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;VS Code 터미널에서 backend 폴더로 이동한 뒤 아래 명령어를 입력합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759645374815&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;node index.js&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;pre id=&quot;code_1759645414964&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  WebSocket 서버 실행 중 (ws://localhost:설정한 포트 번호)
✅ 클라이언트 WebSocket 연결됨&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그리고 크롬 확장 프로그램 관리 페이지에서 아래 사진 속 뷰 검사 페이지(background/background.html)에 접속합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q3OcY/btsQ2RY9B5Q/wUHVvXPT84KAOk2rGXvgDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q3OcY/btsQ2RY9B5Q/wUHVvXPT84KAOk2rGXvgDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q3OcY/btsQ2RY9B5Q/wUHVvXPT84KAOk2rGXvgDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq3OcY%2FbtsQ2RY9B5Q%2FwUHVvXPT84KAOk2rGXvgDk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;277&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;478&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;/p&gt;
&lt;pre id=&quot;code_1759645538598&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[bg] WebSocket 연결됨  
[bg] 서버 응답: [bg] 확장에서 서버 연결됨&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1088&quot; data-origin-height=&quot;381&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9i8Wk/btsQ3ooTih4/e0A2mkDFB34EkWgb1cWQg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9i8Wk/btsQ3ooTih4/e0A2mkDFB34EkWgb1cWQg1/img.png&quot; data-alt=&quot;WebSocket 통신 연결 성공 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9i8Wk/btsQ3ooTih4/e0A2mkDFB34EkWgb1cWQg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9i8Wk%2FbtsQ3ooTih4%2Fe0A2mkDFB34EkWgb1cWQg1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1088&quot; height=&quot;381&quot; data-origin-width=&quot;1088&quot; data-origin-height=&quot;381&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;WebSocket 통신 연결 성공 화면&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;&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;4. 추가 화면 수정 로직 구현&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;앞서 작성한 코드에서 좀 더 수정하여 5초마다 랜덤한 다크모드 설정을 서버가 전송하고 확장 프로그램이 이를 받아 동적으로 적용하는 기능을 구현했습니다.&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;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1759645990315&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// index.js
const WebSocket = require('ws');

// WebSocket 전용 포트
const PORT = 3001;

// 서버 생성
const wss = new WebSocket.Server({ port: PORT });

wss.on('connection', (ws) =&amp;gt; {
  console.log('✅ 클라이언트 WebSocket 연결됨');

  ws.on('message', (message) =&amp;gt; {
    console.log('  클라이언트 메시지:', message.toString());

    // 응답 전송
    ws.send(`서버 응답: ${message}`);
  });

  // 5초마다 임의의 JSON 데이터 전송
  const intervalId = setInterval(() =&amp;gt; {
    const data = {
      type: 'UPDATE_FILTER',
      payload: {
        mode: 1, // 다크모드
        brightness: Math.floor(Math.random() * 100) + 50,
        contrast: Math.floor(Math.random() * 100) + 50,
        grayscale: Math.floor(Math.random() * 100), // 0~99
        sepia: Math.floor(Math.random() * 100),     // 0~99
        useFont: Math.random() &amp;gt; 0.5,               // true/false 랜덤
        fontFamily: &quot;Open Sans&quot;,                     // 예시 폰트
        textStroke: Math.floor(Math.random() * 3),   // 0~2
        invertListed: false,
        siteList: []
      }
    };
    console.log('서버가 전송하는 JSON:', data);
    ws.send(JSON.stringify(data));
  }, 5000);

  ws.on('close', () =&amp;gt; {
    console.log('❌ 클라이언트 연결 종료');
    clearInterval(intervalId);
  });
});

console.log(`  WebSocket 서버 실행 중 (ws://localhost:${PORT})`);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1759646050699&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// background.ts
// WebSocket 변수
    let socket: any = null;

    // WebSocket 연결 함수
    function connectWebSocket() {
        socket = new WebSocket('ws://localhost:3001');

        socket.onopen = () =&amp;gt; {
            console.log('[bg] WebSocket 연결됨');
            if (socket &amp;amp;&amp;amp; socket.readyState === 1) {
                socket.send('[bg] 확장에서 서버 연결됨');
            }
        };

        socket.onmessage = (event) =&amp;gt; {
            try {
                const data = JSON.parse(event.data);
                if (data.type === 'UPDATE_FILTER') {
                    console.log('[bg] 서버에서 받은 UPDATE_FILTER payload:', data.payload);
                    // config를 동적으로 갱신 (Object.assign 대신 for...in 사용)
                    for (var key in data.payload) {
                        if (data.payload.hasOwnProperty(key) &amp;amp;&amp;amp; extension.config.hasOwnProperty(key)) {
                            extension.config[key] = data.payload[key];
                        }
                    }
                    // 모든 탭에 스타일 적용
                    chrome.tabs.query({}, (tabs) =&amp;gt; {
                        tabs.forEach(tab =&amp;gt; {
                            if (tab.id &amp;amp;&amp;amp; tab.url) {
                                extension[&quot;addStyleToTab&quot;](tab); // protected이지만 강제 접근
                            }
                        });
                    });
                }
            } catch (e) {
                console.log('[bg] 서버 응답:', event.data);
            }
        };

        socket.onclose = () =&amp;gt; {
            console.warn('[bg] 연결 끊김 &amp;rarr; 재연결 예정');
            setTimeout(connectWebSocket, 3000);
        };

        socket.onerror = (err) =&amp;gt; {
            console.error('[bg] WebSocket 오류:', err);
            if (socket) socket.close();
        };
    }

    // popup에서 보내는 메시지 수신 &amp;rarr; 서버로 전달
    chrome.runtime.onMessage.addListener((msg, sender, sendResponse) =&amp;gt; {
        if (msg.from === 'popup' &amp;amp;&amp;amp; socket &amp;amp;&amp;amp; socket.readyState === 1) {
            console.log('[bg] popup &amp;rarr; 서버:', msg.data);
            socket.send(msg.data);
        }
    });

    loadConfigs(() =&amp;gt; {
        extension = new DarkReader.Extension(new DarkReader.FilterCssGenerator());
        onExtensionLoaded.invoke(extension);

        //websocket 연결
        connectWebSocket();
    });&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;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;/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;브라우저 콘솔을 통해 전송된 JSON 데이터와 적용 결과를 모두 확인할 수 있었으며, 설정 값이 5초 간격으로 정상적으로 변경되고 반영되는 것을 확인했습니다.&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/lKIzl/btsQ3ZoFKik/qCoNQJZJPY8pgxx1vgIrw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lKIzl/btsQ3ZoFKik/qCoNQJZJPY8pgxx1vgIrw0/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;658&quot; data-is-animation=&quot;false&quot; style=&quot;width: 75.0625%; margin-right: 10px;&quot; data-widthpercent=&quot;75.95&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lKIzl/btsQ3ZoFKik/qCoNQJZJPY8pgxx1vgIrw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlKIzl%2FbtsQ3ZoFKik%2FqCoNQJZJPY8pgxx1vgIrw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;658&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CHNXc/btsQ2R5ZKmo/qxLjKLGbo9z6vDjyig4tMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CHNXc/btsQ2R5ZKmo/qxLjKLGbo9z6vDjyig4tMk/img.png&quot; data-origin-width=&quot;504&quot; data-origin-height=&quot;818&quot; data-is-animation=&quot;false&quot; style=&quot;width: 23.7747%;&quot; data-widthpercent=&quot;24.05&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CHNXc/btsQ2R5ZKmo/qxLjKLGbo9z6vDjyig4tMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCHNXc%2FbtsQ2R5ZKmo%2FqxLjKLGbo9z6vDjyig4tMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;504&quot; height=&quot;818&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>개발/Web&amp;amp;App</category>
      <category>Chromeextension</category>
      <category>WebSocket</category>
      <category>양방향 통신</category>
      <category>웹소켓 통신</category>
      <category>크롬</category>
      <category>크롬익스텐션</category>
      <category>크롬확장프로그램</category>
      <author>orieasy1</author>
      <guid isPermaLink="true">https://easy1nhard2.tistory.com/30</guid>
      <comments>https://easy1nhard2.tistory.com/30#entry30comment</comments>
      <pubDate>Sun, 5 Oct 2025 15:40:13 +0900</pubDate>
    </item>
    <item>
      <title>[LangChain] 1. LangChain 시작하기: OpenAI API부터 Runnable까지</title>
      <link>https://easy1nhard2.tistory.com/29</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;※ Teddy님의 랭체인 노트 책을 바탕으로 진행하는 스터디 기록입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;해당 쳅터: LangChain 노트 Ch01&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;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;1. 기본 환경 설정 및 OpenAI API키 발급&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;우선 아래 링크 내용을 바탕으로 기본 환경 설정을 진행했고 OpeanAI 웹사이트에 접속하여 OpenAI API키 발급까지 진행했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://teddynote.com/10-RAG%EB%B9%84%EB%B2%95%EB%85%B8%ED%8A%B8/%ED%99%98%EA%B2%BD%20%EC%84%A4%EC%A0%95%20(Mac)/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://teddynote.com/10-RAG%EB%B9%84%EB%B2%95%EB%85%B8%ED%8A%B8/%ED%99%98%EA%B2%BD%20%EC%84%A4%EC%A0%95%20(Mac)/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1759525108537&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;환경 설정 (Mac)&quot; data-og-description=&quot;환경 설정 (Mac) 터미널 열기 spotlight 검색에서 &amp;quot;terminal&amp;quot; 검색 후 열기 Homebrew 설치 Homebrew 설치 명령어 1. 아래의 명령어를 실행하여 Homebrew 설치 /bin/bash -c &amp;quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/&quot; data-og-host=&quot;teddynote.com&quot; data-og-source-url=&quot;https://teddynote.com/10-RAG%EB%B9%84%EB%B2%95%EB%85%B8%ED%8A%B8/%ED%99%98%EA%B2%BD%20%EC%84%A4%EC%A0%95%20(Mac)/&quot; data-og-url=&quot;https://teddynote.com/10-RAG%EB%B9%84%EB%B2%95%EB%85%B8%ED%8A%B8/%ED%99%98%EA%B2%BD%20%EC%84%A4%EC%A0%95%20(Mac)/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bAiJcJ/hyZKqdmCvl/QQ4kcb4RG9cV9OlbabZEy0/img.png?width=2718&amp;amp;height=1476&amp;amp;face=0_0_2718_1476,https://scrap.kakaocdn.net/dn/c5uNsS/hyZKy3xwxf/t1edUw5BKbzZUDNzR0ix50/img.png?width=2708&amp;amp;height=1180&amp;amp;face=0_0_2708_1180,https://scrap.kakaocdn.net/dn/SumHb/hyZKisJDIT/uq7er9mbeoJXLN338QTq80/img.png?width=1744&amp;amp;height=672&amp;amp;face=0_0_1744_672&quot;&gt;&lt;a href=&quot;https://teddynote.com/10-RAG%EB%B9%84%EB%B2%95%EB%85%B8%ED%8A%B8/%ED%99%98%EA%B2%BD%20%EC%84%A4%EC%A0%95%20(Mac)/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://teddynote.com/10-RAG%EB%B9%84%EB%B2%95%EB%85%B8%ED%8A%B8/%ED%99%98%EA%B2%BD%20%EC%84%A4%EC%A0%95%20(Mac)/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bAiJcJ/hyZKqdmCvl/QQ4kcb4RG9cV9OlbabZEy0/img.png?width=2718&amp;amp;height=1476&amp;amp;face=0_0_2718_1476,https://scrap.kakaocdn.net/dn/c5uNsS/hyZKy3xwxf/t1edUw5BKbzZUDNzR0ix50/img.png?width=2708&amp;amp;height=1180&amp;amp;face=0_0_2708_1180,https://scrap.kakaocdn.net/dn/SumHb/hyZKisJDIT/uq7er9mbeoJXLN338QTq80/img.png?width=1744&amp;amp;height=672&amp;amp;face=0_0_1744_672');&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;환경 설정 (Mac)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;환경 설정 (Mac) 터미널 열기 spotlight 검색에서 &quot;terminal&quot; 검색 후 열기 Homebrew 설치 Homebrew 설치 명령어 1. 아래의 명령어를 실행하여 Homebrew 설치 /bin/bash -c &quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;teddynote.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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2. LangSmith 추적 설정&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;LangSmith는 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;LLM 기반 애플리케이션을 개발하고 운영할 때 관찰성(obsevability), 평가(evaluation), 디버깅(debug), 모니터링(monitoring), 프롬프트 엔지니어링을 지합니다.&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 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;추적은 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;추적 기능은 다음과 같은 문제를 추적하는데 도움을 줍니다.&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;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;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;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;3. 체인이 예상보다 느린 이유&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;4. 에이전트가 각 단계에서 사용한 토큰 수&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;LangSmith를 사용하면 프로젝트 단위로 추적할 수 있고 각각의 실행에 대한 세부 단계별 추적도 가능하기 때문에 매우 편리합니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2.1 LangSmith 추적 기본 설정&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;a href=&quot;https://smith.langchain.com/&quot;&gt;https://smith.langchain.com/&lt;/a&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;이후 좌측 하단의 톱니바퀴를 눌러 설정으로 들어간 뒤&amp;nbsp; '+API Key' 버튼을 눌러 새로운 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;항상 새로운 api key를 생성하면 안전한 곳에 저장해두어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4fGPY/btsQ3gK5kSQ/D1Jo18eC7trgUWrLd64IPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4fGPY/btsQ3gK5kSQ/D1Jo18eC7trgUWrLd64IPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4fGPY/btsQ3gK5kSQ/D1Jo18eC7trgUWrLd64IPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4fGPY%2FbtsQ3gK5kSQ%2FD1Jo18eC7trgUWrLd64IPK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1224&quot; height=&quot;700&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;700&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;그리고 .env 파일을 만들어서 생성한 키들을 작성해줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;758&quot; data-origin-height=&quot;160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ck0h4u/btsQ1qOIcFf/ejNTr2LGwFccCHuiGTyvg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ck0h4u/btsQ1qOIcFf/ejNTr2LGwFccCHuiGTyvg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ck0h4u/btsQ1qOIcFf/ejNTr2LGwFccCHuiGTyvg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fck0h4u%2FbtsQ1qOIcFf%2FejNTr2LGwFccCHuiGTyvg1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;160&quot; data-origin-width=&quot;758&quot; data-origin-height=&quot;160&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: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;.env 파일은 추후에 깃허브에 공유되지 않도록 꼭 .gitignore 파일을 만들어서 적어줍니다.&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; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2.2 추적 활성화 하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; 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;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;먼저 .env에 설정한 내용을 다음 코드를 불러옵니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759559517123&quot; class=&quot;stylus&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;from dotenv import load_dotenv

load_dotenv()&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;저의 경우에는 처음 이렇게 돌렸을 때 아래 사진처럼 ModuleNotFoundError가 떴습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CYH0d/btsQ4jtwRmh/JSCKLRjk2kZEltHA0SKC30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CYH0d/btsQ4jtwRmh/JSCKLRjk2kZEltHA0SKC30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CYH0d/btsQ4jtwRmh/JSCKLRjk2kZEltHA0SKC30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCYH0d%2FbtsQ4jtwRmh%2FJSCKLRjk2kZEltHA0SKC30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1096&quot; height=&quot;642&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;642&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;python-dotenv 모듈이 설치되어있지 않아 발생하는 에러로 아래 명령어를 입력해 모듈을 설치하면 해결할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759559609749&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install python-dotenv&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;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;우선은 책을 따라서 langchain-teddynote 패키지를 사용할 것이므로 &lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;아래 명령어를 터미널 창에서 실행해주었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759560366259&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install langchain-teddynote&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;1678&quot; data-origin-height=&quot;850&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJeEi8/btsQ1q2nh1Q/Lue6oxR8wbkKnhQhNkm1kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJeEi8/btsQ1q2nh1Q/Lue6oxR8wbkKnhQhNkm1kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJeEi8/btsQ1q2nh1Q/Lue6oxR8wbkKnhQhNkm1kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJeEi8%2FbtsQ1q2nh1Q%2FLue6oxR8wbkKnhQhNkm1kk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1678&quot; height=&quot;850&quot; data-origin-width=&quot;1678&quot; data-origin-height=&quot;850&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: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;.env 파일에 LangSmith 키를 설정해둔 상태로 아래 코드를 입력해서 실행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759561016671&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_teddynote import logging

# &quot; &quot;안에는 프로젝트 이름을 입력
logging.langsmith(&quot;CH01-Basic&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;1074&quot; data-origin-height=&quot;488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZqohT/btsQ2sSJJv5/ts3mw317Ck0JBfQmKqcXdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZqohT/btsQ2sSJJv5/ts3mw317Ck0JBfQmKqcXdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZqohT/btsQ2sSJJv5/ts3mw317Ck0JBfQmKqcXdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZqohT%2FbtsQ2sSJJv5%2Fts3mw317Ck0JBfQmKqcXdK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1074&quot; height=&quot;488&quot; data-origin-width=&quot;1074&quot; data-origin-height=&quot;488&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;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;추적을 원하지 않을 때는 다음과 같이 추적을 끌 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759561243169&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_teddynote import logging

# set_enable=False 로 지정하면 추적을 하지 않습니다.
logging.langsmith(&quot;랭체인 튜토리얼 프로젝트&quot;, set_enable=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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;3. OpenAI 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;LangChain의 핵심은 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;&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;ChatOpenAI 클래스는 OpenAI의 ChatAPI를 파이썬 객체로 감싸서, 복잡한 HTTP 요청 없이도 모델을 호출하고 응답을 다룰 수 있게 해줍니다.&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 기본 LLM 호출 - .invoke()&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;invoke()는 가장 단순한 실행 방식인데요, &lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;하나의 프롬프트를 입력하면 LLM이 한 번에 전체 답변을 반환합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759587489148&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(
    temperature=0.1,  # 창의성 (0.0 ~ 2.0)
    model_name=&quot;gpt-4.1-nano&quot;,  # 모델명
)

# 질의내용
question = &quot;대한민국의 수도는 어디인가요?&quot;

# 질의
print(f&quot;[답변]: {llm.invoke(question)}&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;color: #333333; text-align: start; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;[답변]: content='대한민국의 수도는 서울입니다.'&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;&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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이처럼 .invoke()는 단일 입력을 &lt;/span&gt;&lt;b&gt;동기식(synchronous)&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;즉, 모델이 응답을 모두 생성할 때까지 기다린 후 결과를 반환합니다.&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;LangChain은 이때 모델의 응답을 단순한 문자열이 아니라 AIMessage 객체로 감쌉니다.&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;토큰 사용량, 모델명, 실행 ID&lt;/b&gt; 같은 추가적인 메타데이터가 함께 담겨 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759587602294&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 질의내용
question = &quot;대한민국의 수도는 어디인가요?&quot;

# 질의
response = llm.invoke(question)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1759587648242&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;response&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; text-align: start; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;AIMessage(content='대한민국의 수도는 서울입니다.', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 8, 'prompt_tokens': 16, 'total_tokens': 24, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4.1-nano-2025-04-14', 'system_fingerprint': 'fp_7c233bf9d1', 'id': 'chatcmpl-CMxNoDvrYIsaDJr1mcSvs8FnfjtpI', 'service_tier': 'default', 'finish_reason': 'stop', 'logprobs': None}, id='run--ec12ab19-da5e-491f-9265-077114f22fd8-0', usage_metadata={'input_tokens': 16, 'output_tokens': 8, 'total_tokens': 24, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})&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_1759587663361&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;response.content&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start; 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_1759587705542&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;response.response_metadata&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;{'token_usage': {'completion_tokens': 8, &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt; 'prompt_tokens': 16, &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt; 'total_tokens': 24, &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt; 'completion_tokens_details': {'accepted_prediction_tokens': 0, &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt; 'audio_tokens': 0, &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt; 'reasoning_tokens': 0, &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt; 'rejected_prediction_tokens': 0}, &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt; 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt; 'model_name': 'gpt-4.1-nano-2025-04-14', &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt; 'system_fingerprint': 'fp_7c233bf9d1', &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt; 'id': 'chatcmpl-CMxNoDvrYIsaDJr1mcSvs8FnfjtpI', &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt; 'service_tier': 'default', &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt; 'finish_reason': 'stop', &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt; 'logprobs': None}&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;&quot;&gt;3.2 스트리밍 출력 - .stream()&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;다음은 stream() 메서드를 활용해 &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;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;대화형 챗봇이나 UI에서 &amp;ldquo;한 글자씩 출력되는&amp;rdquo; 효과를 구현할 때 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759588337333&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 스트림 방식으로 질의
# answer 에 스트리밍 답변의 결과를 받습니다.
answer = llm.stream(&quot;대한민국의 아름다운 관광지 10곳과 주소를 알려주세요!&quot;)

# 스트리밍 방식으로 각 토큰을 출력합니다. (실시간 출력)
for token in answer:
    print(token.content, end=&quot;&quot;, flush=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;span style=&quot;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-origin-width=&quot;872&quot; data-origin-height=&quot;1056&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yozh6/btsQ2SRh6Um/Lk6hHIyu0600GBBn3IUOt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yozh6/btsQ2SRh6Um/Lk6hHIyu0600GBBn3IUOt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yozh6/btsQ2SRh6Um/Lk6hHIyu0600GBBn3IUOt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fyozh6%2FbtsQ2SRh6Um%2FLk6hHIyu0600GBBn3IUOt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;606&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;1056&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;LangChain 내부적으로는 OpenAI의 &lt;b&gt;Server-Sent Events (SSE)&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;모델이 토큰을 생성할 때마다 즉시 전달받습니다.&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;따라서 stream()은 &amp;ldquo;대화형 UX를 구현할 때 반드시 알아야 할 핵심 함수&amp;rdquo;입니다.&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;3.3 멀티 모달 모델 - MultiModal()&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;멀티모달(Multi-Modal)은 텍스트뿐 아니라 &lt;b&gt;이미지나 음성, 비디오 등 &lt;/b&gt;여러 형태의 데이터를 통합적으로 이해하고 처리하는 기술을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #24292f; text-align: start;&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;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이미지: 사진, 그래픽, 그림 등 시각적 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;오디오: 음성, 음악, 소리 효과 등의 청각적 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;비디오: 동영상 클립, 실시간 스트리밍 등 시각적 및 청각적 정보의 결합&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;&quot;&gt;LangChain에서는 MultiModal 객체를 통해 이미지를 입력으로 받아 LLM이 이를 해석하도록 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759588627665&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_teddynote.models import MultiModal
from langchain_teddynote.messages import stream_response

# 객체 생성
llm = ChatOpenAI(
    temperature=0.1,  # 창의성 (0.0 ~ 2.0)
    model_name=&quot;gpt-4.1-nano&quot;,  # 모델명
)

# 멀티모달 객체 생성
multimodal_llm = MultiModal(llm)

# 샘플 이미지 주소(웹사이트로 부터 바로 인식)
IMAGE_URL = &quot;https://t3.ftcdn.net/jpg/03/77/33/96/360_F_377339633_Rtv9I77sSmSNcev8bEcnVxTHrXB4nRJ5.jpg&quot;

# 이미지 파일로 부터 질의
answer = multimodal_llm.stream(IMAGE_URL)
# 스트리밍 방식으로 각 토큰을 출력합니다. (실시간 출력)
stream_response(answer)&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-origin-width=&quot;2520&quot; data-origin-height=&quot;1534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqYw6a/btsQ37mxoN2/Ids0Zujh7mvbdgLSWEawIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqYw6a/btsQ37mxoN2/Ids0Zujh7mvbdgLSWEawIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqYw6a/btsQ37mxoN2/Ids0Zujh7mvbdgLSWEawIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqYw6a%2FbtsQ37mxoN2%2FIds0Zujh7mvbdgLSWEawIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2520&quot; height=&quot;1534&quot; data-origin-width=&quot;2520&quot; data-origin-height=&quot;1534&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;&amp;nbsp;&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;&quot;&gt;4. LCEL (LangChain Expression Language) 기본 개념&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;LangChain Expression Language, 줄여서 &lt;b&gt;LCEL&lt;/b&gt;은 기존의 체인(LLMChain) 구조를 더 직관적이고 선언적으로 표현할 수 있도록 만든 문법입니다.&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;&amp;ldquo;LLM 파이프라인을 코드가 아니라 수식처럼 표현&amp;rdquo; &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;&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;기존에는 체인을 만들려면 긴 코드가 필요했지만 LCEL에서는 훨씬 간단하게 아래 한 줄로 표현할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759652050661&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chain = prompt | llm | parser&lt;/code&gt;&lt;/pre&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;이 구조는 &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;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;덕분에 체인을 작성할 때 &amp;ldquo;데이터의 흐름&amp;rdquo;이 한눈에 들어오죠.&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;&amp;nbsp;&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;4.1 LCEL의 기본 구조&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;LCEL은 크게 3가지 구성 요소로 이루어져있습니다.&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;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.0698%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;구성요소&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.4651%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;역할&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.3488%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;예시 클래스&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.0698%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Prompt&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.4651%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;입력을 문자열 템플릿으로 변환&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.3488%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ChatPromptTemplate&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.0698%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;LLM&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.4651%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;실제 모델 호출&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.3488%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ChatOpenAI&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.0698%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Parser&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.4651%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;모델의 출력을 사람이 보기 좋은 형태로 변환&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.3488%;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;StrOutputParser&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;이 세 가지를 | 로 연결하면 &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;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&amp;nbsp;&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;4.2 LCEL 예시 코드&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1759652320897&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_teddynote.messages import stream_response
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser

template = &quot;&quot;&quot;
당신은 영어를 가르치는 10년차 영어 선생님입니다. 주어진 상황에 맞는 영어 회화를 작성해 주세요.
양식은 [FORMAT]을 참고하여 작성해 주세요.

#상황:
{question}

#FORMAT:
- 영어 회화:
- 한글 해석:
&quot;&quot;&quot;

# 프롬프트 템플릿을 이용하여 프롬프트를 생성합니다.
prompt = PromptTemplate.from_template(template)

# ChatOpenAI 챗모델을 초기화합니다.
model = ChatOpenAI(model_name=&quot;gpt-4.1-nano&quot;)

# 문자열 출력 파서를 초기화합니다.
output_parser = StrOutputParser()

# 체인을 구성합니다.
chain = prompt | model | output_parser

# 완성된 Chain을 실행하여 답변을 얻습니다.
answer = chain.stream({&quot;question&quot;: &quot;저는 식당에 가서 음식을 주문하고 싶어요&quot;})
stream_response(answer)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;5. LCEL Advanced&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;기본 LCEL(prompt | llm | parser)은 하나의 선형 체인만 구성하지만, LangChain은 LCEL을 &lt;b&gt;Runnable 구조&lt;/b&gt;로 확장하여 &amp;ldquo;여러 체인을 병렬로 실행하거나, 순차적으로 연결&amp;rdquo;할 수 있게 합니다.&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;Runnable은 &amp;ldquo;실행 가능한 모든 노드&amp;rdquo;를 의미합니다.&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;즉, PromptTemplate, ChatOpenAI, StrOutputParser, 심지어 RunnableSequence까지 모두 Runnable로 취급됩니다.&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;Runnable은 표준화된 실행 인터페이스를 제공합니다.&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 170px;&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;height: 19px;&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;/td&gt;
&lt;td style=&quot;height: 19px;&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;/td&gt;
&lt;td style=&quot;height: 19px;&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;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;invoke()&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;동기&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;입력 1건을 실행하고 최종 결과 반환&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;stream()&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;동기&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;토큰/청크 단위로 실시간 출력&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;batch()&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;동기&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;여러 입력을 병렬로 실행&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ainvoke()&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;비동기&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;입력 1건을 비동기로 실행&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;astream()&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;비동기&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;토큰 단위 비동기 스트리밍&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;abatch()&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;비동기&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;여러 입력을 비동기로 실행&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;astream_log()&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;비동기&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&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;&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;해당 메서드를 쓰는 상황은 아래와 같이 정리할 수 있습니다.&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;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&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;/td&gt;
&lt;td&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;/td&gt;
&lt;td&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;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;단일 입력을 빠르게 처리&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;invoke()&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;가장 단순한 실행&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;대화형 실시간 출력&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;stream() 또는 astream()&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;스트리밍 토큰 출력&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;여러 입력을 한꺼번에 처리&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;batch() 또는 abatch()&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;대량 처리용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;서버 환경의 비동기 파이프라인&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ainvoke() / abatch()&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;asyncio 기반&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;디버깅, 로그 추적&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;astream_log()&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;중간 이벤트 추적&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;여러 체인을 병렬 실행&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;RunnableMap&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;병렬 분기 처리&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;단계별 순차 실행&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;RunnableSequence&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&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;&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;&amp;nbsp;&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;&amp;nbsp;5.1 기본 체인 - invoke / stream/ batch&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;stream: 실시간 토큰 단위 응답&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;invoke: 일반 동기 호출&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;batch: 여러 입력을 병렬 실행&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1759654869685&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
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser

# 모델 및 체인 구성
model = ChatOpenAI()
prompt = PromptTemplate.from_template(&quot;{topic} 에 대하여 3문장으로 설명해줘.&quot;)
chain = prompt | model | StrOutputParser()

# 1️⃣ 실시간 스트리밍 실행
for token in chain.stream({&quot;topic&quot;: &quot;멀티모달&quot;}):
    print(token, end=&quot;&quot;, flush=True)

# 2️⃣ 단일 입력 실행
chain.invoke({&quot;topic&quot;: &quot;ChatGPT&quot;})

# 3️⃣ 여러 입력 일괄 실행
chain.batch(
    [
        {&quot;topic&quot;: &quot;ChatGPT&quot;},
        {&quot;topic&quot;: &quot;Instagram&quot;},
        {&quot;topic&quot;: &quot;머신러닝&quot;},
    ],
    config={&quot;max_concurrency&quot;: 3},
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;5.2 비동기 체인 - astream / ainvoke/ abatch&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;비동기(asyncio) 기반으로 동작하며 await 키워드가 필수입니다.&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;astream은 실제서비스에서 가장 많이 활용되며 abatch로 대량 요청을 동시에 처리할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759654988200&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 비동기 stream
async for token in chain.astream({&quot;topic&quot;: &quot;YouTube&quot;}):
    print(token, end=&quot;&quot;, flush=True)

# 비동기 단일 실행
my_process = chain.ainvoke({&quot;topic&quot;: &quot;NVDA&quot;})
await my_process

# 비동기 일괄 실행
await chain.abatch(
    [{&quot;topic&quot;: &quot;YouTube&quot;}, {&quot;topic&quot;: &quot;Instagram&quot;}, {&quot;topic&quot;: &quot;Facebook&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;&amp;nbsp;&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;5.3 병렬 실행 체인 - RunnableParallel&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;LCEL의 &amp;ldquo;병렬 실행&amp;rdquo; 확장 개념을 보여주는 코드로 여러 체인을 동시에 실행하는 구조를 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759655070069&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_core.runnables import RunnableParallel

# 수도를 묻는 체인
chain1 = (
    PromptTemplate.from_template(&quot;{country} 의 수도는 어디야?&quot;)
    | model
    | StrOutputParser()
)

# 면적을 묻는 체인
chain2 = (
    PromptTemplate.from_template(&quot;{country} 의 면적은 얼마야?&quot;)
    | model
    | StrOutputParser()
)

# 병렬 실행 체인 구성
combined = RunnableParallel(capital=chain1, area=chain2)

# 병렬 실행
combined.invoke({&quot;country&quot;: &quot;대한민국&quot;})

# 병렬 일괄 실행
combined.batch([{&quot;country&quot;: &quot;대한민국&quot;}, {&quot;country&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;&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;6. Runnable&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.1 Runnable이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LCEL의 모든 구성요소는 Runnable 프로토콜을 기반으로 작동합니다.&lt;/p&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, Model, Parser는 모두 Runnable로 취급되며, 공통된 실행 인터페이스(&lt;span&gt;invoke&lt;/span&gt;, &lt;span&gt;stream&lt;/span&gt;, &lt;span&gt;batch&lt;/span&gt; 등)를 공유합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말해 &lt;b&gt;&amp;ldquo;입력을 받아 실행하고 결과를 반환할 수 있는 모든 객체&quot;&lt;/b&gt;는 Runnable이라 할 수 있습니다.&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;6.2 RunnablePassthrough - 입력 그대로 통과 시키기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RunnablePassthrough&lt;/span&gt;&lt;span&gt;는 말 그대로 &lt;/span&gt;&lt;b&gt;입력값을 가공하지 않고 그대로 다음 단계로 전달&lt;/b&gt;&lt;span&gt;하는 Runnable입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM 호출 없이 입력 데이터를 확인하거나, 중간 단계 디버깅용으로 자주 사용됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759655821980&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI

# prompt 와 llm 을 생성합니다.
prompt = PromptTemplate.from_template(&quot;{num} 의 10배는?&quot;)
llm = ChatOpenAI(temperature=0)

# 체인 구성
chain = prompt | llm

# 체인 실행
chain.invoke({&quot;num&quot;: 5})
chain.invoke(5)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1759655835545&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_core.runnables import RunnablePassthrough

# RunnablePassthrough은 입력 그대로 반환
RunnablePassthrough().invoke({&quot;num&quot;: 10})

# chain 내부에 삽입
runnable_chain = {&quot;num&quot;: RunnablePassthrough()} | prompt | ChatOpenAI()
runnable_chain.invoke(10)&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;h3 data-ke-size=&quot;size23&quot;&gt;6.3 RunnableParallel - 병렬 실행 체인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RunnableParallel&lt;/span&gt;은 여러 Runnable을 &lt;span&gt;&lt;b&gt;동시에 실행&lt;/b&gt;&lt;/span&gt;하는 구조입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력값을 각 Runnable에 동일하게 전달한 뒤, 결과를 병렬로 받아와 딕셔너리 형태로 반환됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759656021928&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI

# 두 개의 체인을 정의합니다.
chain1 = (
    {&quot;country&quot;: RunnablePassthrough()}
    | PromptTemplate.from_template(&quot;{country} 의 수도는?&quot;)
    | ChatOpenAI()
)
chain2 = (
    {&quot;country&quot;: RunnablePassthrough()}
    | PromptTemplate.from_template(&quot;{country} 의 면적은?&quot;)
    | ChatOpenAI()
)

# RunnableParallel로 병렬 실행 구성
combined_chain = RunnableParallel(capital=chain1, area=chain2)

# 병렬 실행
combined_chain.invoke(&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.4 RunnableLambda - 사용자 정의 함수형 체인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RunnableLambda&lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;b&gt;파이썬 함수를 Runnable로 감싸는 유틸리티&lt;/b&gt;&lt;span&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 정의 함수를 통해 입력 전처리 또는 동적 데이터 삽입이 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759656072545&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.runnables import RunnableLambda, RunnablePassthrough
from datetime import datetime

# 오늘 날짜를 반환하는 함수
def get_today(_):
    return datetime.today().strftime(&quot;%b-%d&quot;)

# 프롬프트 및 모델 구성
prompt = PromptTemplate.from_template(
    &quot;{today} 가 생일인 유명인 {n} 명을 나열하세요. 생년월일을 표기해 주세요.&quot;
)
llm = ChatOpenAI(temperature=0, model_name=&quot;gpt-4.1-mini&quot;)

# 체인 구성
chain = (
    {&quot;today&quot;: RunnableLambda(get_today), &quot;n&quot;: RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser()
)

# 실행
print(chain.invoke(3))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&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&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://wikidocs.net/book/14314&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://wikidocs.net/book/14314&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1759525037449&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;&amp;lt;랭체인LangChain 노트&amp;gt; - LangChain 한국어 튜토리얼 &quot; data-og-description=&quot;**추천**은 공유할 수 있는 무료 전자책을 집필하는데 정말 큰 힘이 됩니다. **&amp;quot;추천&amp;quot;** 한 번씩만 부탁 드리겠습니다  ✅ **랭체인 한국어 튜토리얼 강의** &amp;hellip;&quot; data-og-host=&quot;wikidocs.net&quot; data-og-source-url=&quot;https://wikidocs.net/book/14314&quot; data-og-url=&quot;https://wikidocs.net/book/14314&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bK850W/hyZKBFZmAd/JzbDpBoXKKCAwRqXxoPwUk/img.png?width=255&amp;amp;height=332&amp;amp;face=0_0_255_332,https://scrap.kakaocdn.net/dn/crjN3m/hyZKxKh4qQ/nw3oCASji1vZzOKWmm30hk/img.png?width=255&amp;amp;height=332&amp;amp;face=0_0_255_332,https://scrap.kakaocdn.net/dn/ZcdUh/hyZKdZh263/h83A1pJOpmcqGGnLPVCB31/img.png?width=307&amp;amp;height=400&amp;amp;face=0_0_307_400&quot;&gt;&lt;a href=&quot;https://wikidocs.net/book/14314&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://wikidocs.net/book/14314&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bK850W/hyZKBFZmAd/JzbDpBoXKKCAwRqXxoPwUk/img.png?width=255&amp;amp;height=332&amp;amp;face=0_0_255_332,https://scrap.kakaocdn.net/dn/crjN3m/hyZKxKh4qQ/nw3oCASji1vZzOKWmm30hk/img.png?width=255&amp;amp;height=332&amp;amp;face=0_0_255_332,https://scrap.kakaocdn.net/dn/ZcdUh/hyZKdZh263/h83A1pJOpmcqGGnLPVCB31/img.png?width=307&amp;amp;height=400&amp;amp;face=0_0_307_400');&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;&amp;lt;랭체인LangChain 노트&amp;gt; - LangChain 한국어 튜토리얼 &lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;**추천**은 공유할 수 있는 무료 전자책을 집필하는데 정말 큰 힘이 됩니다. **&quot;추천&quot;** 한 번씩만 부탁 드리겠습니다  ✅ **랭체인 한국어 튜토리얼 강의** &amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;wikidocs.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://github.com/teddylee777/langchain-kr&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/teddylee777/langchain-kr&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1759525057320&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 - teddylee777/langchain-kr: LangChain 공식 Document, Cookbook, 그 밖의 실용 예제를 바탕으로 작성한 한&quot; data-og-description=&quot;LangChain 공식 Document, Cookbook, 그 밖의 실용 예제를 바탕으로 작성한 한국어 튜토리얼입니다. 본 튜토리얼을 통해 LangChain을 더 쉽고 효과적으로 사용하는 방법을 배울 수 있습니다. - teddylee777/langch&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/teddylee777/langchain-kr&quot; data-og-url=&quot;https://github.com/teddylee777/langchain-kr&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bPUXVD/hyZKBsqUx1/PbNsXs9kNugtoOhzORWWE0/img.png?width=1200&amp;amp;height=600&amp;amp;face=978_135_1045_208,https://scrap.kakaocdn.net/dn/cCJUHA/hyZKrXEU80/wkGUNt4IMkYzmd1knCUDVk/img.png?width=1200&amp;amp;height=600&amp;amp;face=978_135_1045_208&quot;&gt;&lt;a href=&quot;https://github.com/teddylee777/langchain-kr&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/teddylee777/langchain-kr&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bPUXVD/hyZKBsqUx1/PbNsXs9kNugtoOhzORWWE0/img.png?width=1200&amp;amp;height=600&amp;amp;face=978_135_1045_208,https://scrap.kakaocdn.net/dn/cCJUHA/hyZKrXEU80/wkGUNt4IMkYzmd1knCUDVk/img.png?width=1200&amp;amp;height=600&amp;amp;face=978_135_1045_208');&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 - teddylee777/langchain-kr: LangChain 공식 Document, Cookbook, 그 밖의 실용 예제를 바탕으로 작성한 한&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;LangChain 공식 Document, Cookbook, 그 밖의 실용 예제를 바탕으로 작성한 한국어 튜토리얼입니다. 본 튜토리얼을 통해 LangChain을 더 쉽고 효과적으로 사용하는 방법을 배울 수 있습니다. - teddylee777/langch&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>AI</category>
      <author>orieasy1</author>
      <guid isPermaLink="true">https://easy1nhard2.tistory.com/29</guid>
      <comments>https://easy1nhard2.tistory.com/29#entry29comment</comments>
      <pubDate>Sat, 4 Oct 2025 23:41:57 +0900</pubDate>
    </item>
    <item>
      <title>[Unity] 구글폼 연동해서 데이터를 구글 스프레드시트에 저장하는 방법</title>
      <link>https://easy1nhard2.tistory.com/28</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;저는 현재 MR 환경에서 사용자 연구를 진행하고 있는데요, 실험을 진행하면서 데이터를 저장해야했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 그냥 기기 내에 csv 파일을 저장하는 방향으로 생각했는데 실시간으로 체크해야할 필요성을 느껴서 구글폼과 구글폼에 연동되어있는 스프레드시트로 데이터를 기록하는 방법으로 구현을 진행하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 오늘은 구글폼과 스프레드 시트를 이용하여 편하게 Unity 내에서 데이터를 기록하는 방법에 대해 이야기 해보고자 합니다.&lt;/p&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;1. TaskManager&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 저는 기능 전반을 관리하는 TaskManager C# 파일이 있었습니다. (전체적인 프로그램 진행 관리)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 파일에서 LogCurrentTask()라는 메소드를 사용하여 전반적인 데이터 관리 로직을 구현하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 한 task가 끝날 때마다 해당 메소드를 호출하여 데이터를 csv 파일에 추가하는 방식으로 진행을 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글폼으로 진행하기로 마음을 먹은 뒤에는 GoogleSpreadSheetsManager 이라는 클래스를 새로 만들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 메인 TaskManager에서 GoogleSpreadSheetsManager에 데이터를 보내주는 로직을 LogCurrentTask() 메소드 안에 작성해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1759069059104&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void LogCurrentTask(bool success)
    {
        if (_phase == TaskPhase.Practice) return;

        float manipulationTime = (_manipStartTime &amp;gt; 0f) ? (Time.time - _manipStartTime) : 0f;
        float firstGrabToSuccess = (_firstGrabTime &amp;gt; 0f &amp;amp;&amp;amp; _successTime &amp;gt; 0f) 
                               ? (_successTime - _firstGrabTime) 
                               : 0f;

        var saver = GetComponent&amp;lt;GoogleFormSaver&amp;gt;();
        if (saver)
        {
            StartCoroutine(saver.PostData(
                participantID,
                _taskIndex + 1,
                manipulationTime,
                _targetEuler.x, _targetEuler.y, _targetEuler.z,
                _finalEuler.x, _finalEuler.y, _finalEuler.z,
                _targetQ.x, _targetQ.y, _targetQ.z, _targetQ.w,
                _finalQ.x, _finalQ.y, _finalQ.z, _finalQ.w,
                _angleDiff,
                _cumObjTotal,
                _cumRightTotal,
                _firstGrabTime,
                _successTime,
                firstGrabToSuccess
            ));
        }
        else
        {
            Debug.LogError(&quot;[TaskManager] GoogleFormSaver not found!&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. GoogleSpreadSheetsManager&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 구글폼과 우리 프로그램을 연결해줄 GoogleSpreadSheetsManager을 만들 차례입니다.&lt;/p&gt;
&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;그후 F12를 누르셔서 elements 창에 들어갑니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;formResponse를 검색해서 나타나는 url을 복사해주세요!&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/cY38CB/btsQTT9Lfgx/BxmV0EkjRtPgbksDy0KEhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cY38CB/btsQTT9Lfgx/BxmV0EkjRtPgbksDy0KEhK/img.png&quot; data-origin-width=&quot;955&quot; data-origin-height=&quot;840&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 48.8623%; margin-right: 10px;&quot; data-widthpercent=&quot;49.44&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cY38CB/btsQTT9Lfgx/BxmV0EkjRtPgbksDy0KEhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcY38CB%2FbtsQTT9Lfgx%2FBxmV0EkjRtPgbksDy0KEhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;955&quot; height=&quot;840&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caNfcr/btsQSaSeYI0/bZuxr6HmK4ut8gVKFo1kzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caNfcr/btsQSaSeYI0/bZuxr6HmK4ut8gVKFo1kzk/img.png&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;516&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.9749%;&quot; data-widthpercent=&quot;50.56&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caNfcr/btsQSaSeYI0/bZuxr6HmK4ut8gVKFo1kzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaNfcr%2FbtsQSaSeYI0%2FbZuxr6HmK4ut8gVKFo1kzk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;516&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;pre id=&quot;code_1759070102798&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class GoogleFormSaver : MonoBehaviour
{
    private string BASE_URL = &quot;링크&quot;;

    public IEnumerator PostData(
        string participantID, int taskIndex, float completionTime,
        // 목표 Euler
        float targetX, float targetY, float targetZ,
        // 최종 Euler
        float finalX, float finalY, float finalZ,
        // 목표 Quaternion
        float targetQx, float targetQy, float targetQz, float targetQw,
        // 최종 Quaternion
        float finalQx, float finalQy, float finalQz, float finalQw,
        // Quaternion.Angle 기반 최종 오차
        float angleDiff,
        // 누적 회전량
        float cumObjTotal,
        float cumRightTotal,
        // 추가 항목
        float firstGrabTime,
        float successTime,
        float firstGrabToSuccess
    )
    {
        WWWForm form = new WWWForm();

        // 기본 정보
        form.AddField(&quot;entry.1813064294&quot;, participantID);               // 1
        form.AddField(&quot;entry.2037882169&quot;, taskIndex.ToString());        // 2
        form.AddField(&quot;entry.800267908&quot;, completionTime.ToString());    // 3

        // 목표 Euler
        form.AddField(&quot;entry.1055469485&quot;, targetX.ToString());          // 4
        form.AddField(&quot;entry.507956897&quot;, targetY.ToString());           // 5
        form.AddField(&quot;entry.1031840251&quot;, targetZ.ToString());          // 6

        // 최종 Euler
        form.AddField(&quot;entry.1220958015&quot;, finalX.ToString());           // 7
        form.AddField(&quot;entry.1290950597&quot;, finalY.ToString());           // 8
        form.AddField(&quot;entry.912135107&quot;, finalZ.ToString());            // 9

        // 목표 Quaternion
        form.AddField(&quot;entry.1476745007&quot;, targetQx.ToString());         // 10
        form.AddField(&quot;entry.1084862304&quot;, targetQy.ToString());         // 11
        form.AddField(&quot;entry.1065111899&quot;, targetQz.ToString());         // 12
        form.AddField(&quot;entry.905889161&quot;, targetQw.ToString());          // 13

        // 최종 Quaternion
        form.AddField(&quot;entry.585115881&quot;, finalQx.ToString());           // 14
        form.AddField(&quot;entry.960417364&quot;, finalQy.ToString());           // 15
        form.AddField(&quot;entry.1742970737&quot;, finalQz.ToString());          // 16
        form.AddField(&quot;entry.968201013&quot;, finalQw.ToString());           // 17

        // 전체 오차
        form.AddField(&quot;entry.779680696&quot;, angleDiff.ToString());         // 18

        // 누적 회전량
        form.AddField(&quot;entry.1576350621&quot;, cumObjTotal.ToString());      // 19
        form.AddField(&quot;entry.415742032&quot;, cumRightTotal.ToString());     // 20

        // 추가 필드
        form.AddField(&quot;entry.1318261917&quot;, firstGrabTime.ToString());    // 21
        form.AddField(&quot;entry.1960975797&quot;, successTime.ToString());      // 22
        form.AddField(&quot;entry.1242245653&quot;, firstGrabToSuccess.ToString());// 23

        using (UnityWebRequest www = UnityWebRequest.Post(BASE_URL, form))
        {
            yield return www.SendWebRequest();

            if (www.result != UnityWebRequest.Result.Success)
                Debug.LogError(&quot;Google Form POST Error: &quot; + www.error);
            else
                Debug.Log(&quot;Google Form POST Success!&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;그리고 위 entry.숫자 부분 보이시나요?&lt;/p&gt;
&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;F12를 눌러 다시 개발자툴창에 접속하고 이번에는 Network에 접속해주세요. 그리고 임으로 만든 폼을 제출합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;572&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DKEeT/btsQR6WybZT/Mq5nhdNRghgO5f6khZiEi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DKEeT/btsQR6WybZT/Mq5nhdNRghgO5f6khZiEi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DKEeT/btsQR6WybZT/Mq5nhdNRghgO5f6khZiEi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDKEeT%2FbtsQR6WybZT%2FMq5nhdNRghgO5f6khZiEi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;572&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;572&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;그럼 이렇게 뜨게 되는데요. 여기서 formResponse를 클릭해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Payload 를 클릭하면 Form Data를 볼 수 있습니다. 해당 entry들을 코드 안에 작성해주면 완성입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;759&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCXwzh/btsQSwAJY9h/jPik6OBSKCo0bhBuIzD9q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCXwzh/btsQSwAJY9h/jPik6OBSKCo0bhBuIzD9q1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCXwzh/btsQSwAJY9h/jPik6OBSKCo0bhBuIzD9q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCXwzh%2FbtsQSwAJY9h%2FjPik6OBSKCo0bhBuIzD9q1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;759&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;759&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;그후 유니티 Scene에서 TaskManager가 연결되어있는 오브젝트에 구글폼 컴포넌트를 추가하는 것 잊지말아주세요!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;746&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJMpeE/btsQRARvATy/VFbU2vDRisJyg9ng49VGzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJMpeE/btsQRARvATy/VFbU2vDRisJyg9ng49VGzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJMpeE/btsQRARvATy/VFbU2vDRisJyg9ng49VGzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJMpeE%2FbtsQRARvATy%2FVFbU2vDRisJyg9ng49VGzk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;602&quot; height=&quot;746&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;746&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;944&quot; data-origin-height=&quot;695&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfrIQ6/btsQTwfDbwU/YnRs8kZrFaeCZONzRlLzik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfrIQ6/btsQTwfDbwU/YnRs8kZrFaeCZONzRlLzik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfrIQ6/btsQTwfDbwU/YnRs8kZrFaeCZONzRlLzik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfrIQ6%2FbtsQTwfDbwU%2FYnRs8kZrFaeCZONzRlLzik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;944&quot; height=&quot;695&quot; data-origin-width=&quot;944&quot; data-origin-height=&quot;695&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSV를 활용하는 것도 좋지만 구글폼을 사용할 경우 실시간으로 업데이트 되는 것을 확인할 수 있어서 굉장히 편했습니다!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유니티를 이용해 데이터 수집을 할 때 참고해서 진행하시면 좋을 것 같습니다!&lt;/p&gt;</description>
      <category>개발/VR&amp;amp;XR</category>
      <category>Unity</category>
      <category>구글폼</category>
      <category>데이터수집</category>
      <category>실시간데이터수집</category>
      <category>유니티</category>
      <category>유니티구글폼연결</category>
      <category>유니티데이터수집</category>
      <author>orieasy1</author>
      <guid isPermaLink="true">https://easy1nhard2.tistory.com/28</guid>
      <comments>https://easy1nhard2.tistory.com/28#entry28comment</comments>
      <pubDate>Sun, 28 Sep 2025 23:51:58 +0900</pubDate>
    </item>
    <item>
      <title>Unity로 Meta Quest3 MR(Passthrough) 빌드하기</title>
      <link>https://easy1nhard2.tistory.com/27</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 연구실에서 Passthrough 관련 연구를 진행하고 있어서 user study를 진행할 프로그램을 만들고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 오늘은 Meta Ques 3을 기준으로 Unity로 MR 프로그램을 빌드하는 법을 소개하려고 한다.&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. Unity 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 다운로드 받은 Unity Editor에 Android Build Support과 관련된 모듈을 다운받아 줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;957&quot; data-origin-height=&quot;190&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BU0lz/btsQGZpRHDZ/4vcUUaOZ1kBkD91kGFCu9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BU0lz/btsQGZpRHDZ/4vcUUaOZ1kBkD91kGFCu9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BU0lz/btsQGZpRHDZ/4vcUUaOZ1kBkD91kGFCu9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBU0lz%2FbtsQGZpRHDZ%2F4vcUUaOZ1kBkD91kGFCu9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;957&quot; height=&quot;190&quot; data-origin-width=&quot;957&quot; data-origin-height=&quot;190&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;그리고 Edit &amp;gt; Project Setting &amp;gt; XR Plugin Management를 접속하여 해당 plugin management도 다운 받아줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bx1wST/btsQGegM7mP/DH7UaELo7OZV34iMPcKPN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bx1wST/btsQGegM7mP/DH7UaELo7OZV34iMPcKPN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bx1wST/btsQGegM7mP/DH7UaELo7OZV34iMPcKPN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbx1wST%2FbtsQGegM7mP%2FDH7UaELo7OZV34iMPcKPN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;747&quot; height=&quot;540&quot; data-origin-width=&quot;747&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;&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;그리고 OpenXR에 체크 표시를 해줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;753&quot; data-origin-height=&quot;541&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3NWus/btsQHB21HUh/KN2iUZ76pGFp5jOJ4QCbI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3NWus/btsQHB21HUh/KN2iUZ76pGFp5jOJ4QCbI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3NWus/btsQHB21HUh/KN2iUZ76pGFp5jOJ4QCbI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3NWus%2FbtsQHB21HUh%2FKN2iUZ76pGFp5jOJ4QCbI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;541&quot; data-origin-width=&quot;753&quot; data-origin-height=&quot;541&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;그러면 아래 사진과 같이 fix 해야할 것들이 많다고 뜰 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두 Fix All 처리를 해주면 된다.&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/t93LB/btsQHjuQQsh/62ARMZV7kXRAlzKOIEul40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t93LB/btsQHjuQQsh/62ARMZV7kXRAlzKOIEul40/img.png&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;538&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.3726%; margin-right: 10px;&quot; data-widthpercent=&quot;49.95&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t93LB/btsQHjuQQsh/62ARMZV7kXRAlzKOIEul40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft93LB%2FbtsQHjuQQsh%2F62ARMZV7kXRAlzKOIEul40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;747&quot; height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lA2tq/btsQIOOhrWE/8B31TuZElpBL8wXnFjv1B0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lA2tq/btsQIOOhrWE/8B31TuZElpBL8wXnFjv1B0/img.png&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;537&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4646%;&quot; data-widthpercent=&quot;50.05&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lA2tq/btsQIOOhrWE/8B31TuZElpBL8wXnFjv1B0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlA2tq%2FbtsQIOOhrWE%2F8B31TuZElpBL8wXnFjv1B0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;747&quot; height=&quot;537&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;이제 Meta Quest build platform을 설정해줄 차례이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;File &amp;gt; Build Profiles로 접속한 뒤 Android에서 Switch Platform을 클릭하여 Platform을 전환 시켜준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;610&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bA3ofp/btsQI0HKozn/Mnfv0sK8mW1ImOkK2Gp3Ek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bA3ofp/btsQI0HKozn/Mnfv0sK8mW1ImOkK2Gp3Ek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bA3ofp/btsQI0HKozn/Mnfv0sK8mW1ImOkK2Gp3Ek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbA3ofp%2FbtsQI0HKozn%2FMnfv0sK8mW1ImOkK2Gp3Ek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;610&quot; data-origin-width=&quot;728&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 나는 Meta XR Interaction SDK를 다운받아서 사용하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://assetstore.unity.com/packages/tools/integration/meta-xr-interaction-sdk-265014&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://assetstore.unity.com/packages/tools/integration/meta-xr-interaction-sdk-265014&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1758284447292&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;Meta XR Interaction ​SDK | 기능 통합 | Unity Asset Store&quot; data-og-description=&quot;Use the Meta XR Interaction ​SDK from Meta on your next project. Find this integration tool &amp;amp; more on the Unity Asset Store.&quot; data-og-host=&quot;assetstore.unity.com&quot; data-og-source-url=&quot;https://assetstore.unity.com/packages/tools/integration/meta-xr-interaction-sdk-265014&quot; data-og-url=&quot;https://assetstore.unity.com/packages/tools/integration/meta-xr-interaction-sdk-265014&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/AhfcX/hyZI2qZ8op/mDPttL2vek6epu6UE8IEAk/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bp8j53/hyZJlQQVC3/dmWClKFN7oSqhgRBgdq32K/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bcmrF4/hyZJhhnl4e/wDprnI9QtVVosFFJJrB8vK/img.jpg?width=1950&amp;amp;height=1300&amp;amp;face=0_0_1950_1300&quot;&gt;&lt;a href=&quot;https://assetstore.unity.com/packages/tools/integration/meta-xr-interaction-sdk-265014&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://assetstore.unity.com/packages/tools/integration/meta-xr-interaction-sdk-265014&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/AhfcX/hyZI2qZ8op/mDPttL2vek6epu6UE8IEAk/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bp8j53/hyZJlQQVC3/dmWClKFN7oSqhgRBgdq32K/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bcmrF4/hyZJhhnl4e/wDprnI9QtVVosFFJJrB8vK/img.jpg?width=1950&amp;amp;height=1300&amp;amp;face=0_0_1950_1300');&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;Meta XR Interaction ​SDK | 기능 통합 | Unity Asset Store&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Use the Meta XR Interaction ​SDK from Meta on your next project. Find this integration tool &amp;amp; more on the Unity Asset Store.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;assetstore.unity.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;또 우측 상단에 위치한 Meta XR Tools에 들어가서 주기적으로 Fix all 처리를 해주어야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;505&quot; data-origin-height=&quot;57&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfVL3u/btsQH1G8BwF/m2kP37qRGgZHm1wihkwsck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfVL3u/btsQH1G8BwF/m2kP37qRGgZHm1wihkwsck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfVL3u/btsQH1G8BwF/m2kP37qRGgZHm1wihkwsck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfVL3u%2FbtsQH1G8BwF%2Fm2kP37qRGgZHm1wihkwsck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;57&quot; data-origin-width=&quot;505&quot; data-origin-height=&quot;57&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;h3 data-ke-size=&quot;size23&quot;&gt;2. 빌드 시 체크포인트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MR 콘텐츠를 제작 후 빌드할 예정이라면 체크해야할 부분이 몇 가지 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;example scenes 각 Scene의 OVRCameraRig에서 OVRManager &amp;gt; passthrough 옵션이 켜졌는지 확인해야한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;458&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0nRKO/btsQHjVTWk3/strG6q5Z0byROBcJne89wk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0nRKO/btsQHjVTWk3/strG6q5Z0byROBcJne89wk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0nRKO/btsQHjVTWk3/strG6q5Z0byROBcJne89wk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0nRKO%2FbtsQHjVTWk3%2FstrG6q5Z0byROBcJne89wk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;508&quot; height=&quot;458&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;458&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;사진에서처럼 .Supported로 표시되어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째, OVRCameraRig에 OVRPassthroughLayer 추가해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Inspector 하단의 Add Component를 클릭한 뒤 서치하여 추가하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;231&quot; data-origin-height=&quot;308&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CGbyn/btsQGElT61d/SVjcogqR35WQ7oO43AOnA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CGbyn/btsQGElT61d/SVjcogqR35WQ7oO43AOnA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CGbyn/btsQGElT61d/SVjcogqR35WQ7oO43AOnA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCGbyn%2FbtsQGElT61d%2FSVjcogqR35WQ7oO43AOnA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;231&quot; height=&quot;308&quot; data-origin-width=&quot;231&quot; data-origin-height=&quot;308&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;그리고 Placement 조건을 Underlay로 선택한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbcP5C/btsQH0VL3wU/ChU360xSFOiBpOxXFgwFlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbcP5C/btsQH0VL3wU/ChU360xSFOiBpOxXFgwFlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbcP5C/btsQH0VL3wU/ChU360xSFOiBpOxXFgwFlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbcP5C%2FbtsQH0VL3wU%2FChU360xSFOiBpOxXFgwFlK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;536&quot; height=&quot;356&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;356&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;br /&gt;마지막은 Skybox를 제거하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Window &amp;gt; Rendering &amp;gt; Lighting &amp;gt; Environment로 이동하여 Skybox Material에서의 SkyboxGradient를 삭제해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사진처럼 None이 뜨면 삭제가 된 것이다.&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/bkVz7m/btsQIYwnDe2/3VZ39skGieNLuzd1O9kcv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkVz7m/btsQIYwnDe2/3VZ39skGieNLuzd1O9kcv0/img.png&quot; data-origin-width=&quot;390&quot; data-origin-height=&quot;612&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4648%; margin-right: 10px;&quot; data-widthpercent=&quot;50.05&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkVz7m/btsQIYwnDe2/3VZ39skGieNLuzd1O9kcv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkVz7m%2FbtsQIYwnDe2%2F3VZ39skGieNLuzd1O9kcv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;390&quot; height=&quot;612&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SDnCl/btsQHUOO6td/26GVgaK7kKN2gFPf4B9bD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SDnCl/btsQHUOO6td/26GVgaK7kKN2gFPf4B9bD0/img.png&quot; data-origin-width=&quot;388&quot; data-origin-height=&quot;610&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.3724%;&quot; data-widthpercent=&quot;49.95&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SDnCl/btsQHUOO6td/26GVgaK7kKN2gFPf4B9bD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSDnCl%2FbtsQHUOO6td%2F26GVgaK7kKN2gFPf4B9bD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;388&quot; height=&quot;610&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Meta Quest 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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우산 아래 링크로 접속하여 adb를 다운받아야 한다. (설치가 안되어있는 경우)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.android.com/tools/releases/platform-tools?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.android.com/tools/releases/platform-tools?hl=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1758286359245&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;SDK 플랫폼 도구 출시 노트 &amp;nbsp;|&amp;nbsp; Android Studio &amp;nbsp;|&amp;nbsp; Android Developers&quot; data-og-description=&quot;Android SDK 플랫폼 도구는 Android SDK의 구성요소입니다.&quot; data-og-host=&quot;developer.android.com&quot; data-og-source-url=&quot;https://developer.android.com/tools/releases/platform-tools?hl=ko&quot; data-og-url=&quot;https://developer.android.com/tools/releases/platform-tools?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/csLgtJ/hyZJn8ZuY1/d4lFJ9OvUKWcUt5BEzGQqk/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676&quot;&gt;&lt;a href=&quot;https://developer.android.com/tools/releases/platform-tools?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.android.com/tools/releases/platform-tools?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/csLgtJ/hyZJn8ZuY1/d4lFJ9OvUKWcUt5BEzGQqk/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676');&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;SDK 플랫폼 도구 출시 노트 &amp;nbsp;|&amp;nbsp; Android Studio &amp;nbsp;|&amp;nbsp; Android Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Android SDK 플랫폼 도구는 Android SDK의 구성요소입니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.android.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;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/bkw8M6/btsQGfmsxoQ/hh0lDSGV47MklhoP8Ik1U1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkw8M6/btsQGfmsxoQ/hh0lDSGV47MklhoP8Ik1U1/img.png&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;533&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.9258%; margin-right: 10px;&quot; data-widthpercent=&quot;46.47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkw8M6/btsQGfmsxoQ/hh0lDSGV47MklhoP8Ik1U1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbkw8M6%2FbtsQGfmsxoQ%2Fhh0lDSGV47MklhoP8Ik1U1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;533&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byqWqS/btsQHDT5LEr/A8sKrARPMO96ZxmaeJSbFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byqWqS/btsQHDT5LEr/A8sKrARPMO96ZxmaeJSbFk/img.png&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;586&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.9114%;&quot; data-widthpercent=&quot;53.53&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byqWqS/btsQHDT5LEr/A8sKrARPMO96ZxmaeJSbFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyqWqS%2FbtsQHDT5LEr%2FA8sKrARPMO96ZxmaeJSbFk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;608&quot; height=&quot;586&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;시스템 변수 목록에서 Path을 선택하여 아까 확인한 platform-tools 경로(다운로드 받은 파일 압축을 푼 위치)를 입력해주면 된다.&lt;/p&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;이후 cmd창을 열어 잘 설정되었는지 확인해주자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;114&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/phlor/btsQIOtYWwG/HB0tJwh48GpX4VtZmplySk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/phlor/btsQIOtYWwG/HB0tJwh48GpX4VtZmplySk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/phlor/btsQIOtYWwG/HB0tJwh48GpX4VtZmplySk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fphlor%2FbtsQIOtYWwG%2FHB0tJwh48GpX4VtZmplySk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;496&quot; height=&quot;114&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;114&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;첫 번째처럼 unauthorized라고 뜬다면 헤드셋 안에서 USB 디버깅 허용 팝업을 확인하고 허용을 눌러야 한다.&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;blob&quot; data-origin-width=&quot;298&quot; data-origin-height=&quot;100&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdY1Hv/btsQIR5i6PF/oEUdjvSdQLL1UmdBPf91eK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdY1Hv/btsQIR5i6PF/oEUdjvSdQLL1UmdBPf91eK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdY1Hv/btsQIR5i6PF/oEUdjvSdQLL1UmdBPf91eK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdY1Hv%2FbtsQIR5i6PF%2FoEUdjvSdQLL1UmdBPf91eK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;298&quot; height=&quot;100&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;298&quot; data-origin-height=&quot;100&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;279&quot; data-origin-height=&quot;89&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BWMVd/btsQI5oIcgR/RpsahEsZ9KXG5kADWaxd50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BWMVd/btsQI5oIcgR/RpsahEsZ9KXG5kADWaxd50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BWMVd/btsQI5oIcgR/RpsahEsZ9KXG5kADWaxd50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBWMVd%2FbtsQI5oIcgR%2FRpsahEsZ9KXG5kADWaxd50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;279&quot; height=&quot;89&quot; data-origin-width=&quot;279&quot; data-origin-height=&quot;89&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;이후 Meta Quest 기기 를 연결한 상태로 build and run을 실행하며 passthrough 프로그램을 즐길 수 있다.&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/VR&amp;amp;XR</category>
      <category>MetaQuest3</category>
      <category>Mixed_Reality</category>
      <category>MR</category>
      <category>passthrough</category>
      <category>Unity</category>
      <category>빌드</category>
      <category>유니티</category>
      <author>orieasy1</author>
      <guid isPermaLink="true">https://easy1nhard2.tistory.com/27</guid>
      <comments>https://easy1nhard2.tistory.com/27#entry27comment</comments>
      <pubDate>Fri, 19 Sep 2025 22:59:57 +0900</pubDate>
    </item>
  </channel>
</rss>