<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Claude API on monkshark.dev</title><link>https://monkshark.github.io/tags/claude-api/</link><description>Recent content in Claude API on monkshark.dev</description><generator>Hugo -- gohugo.io</generator><language>ko</language><lastBuildDate>Tue, 23 Jun 2026 12:00:00 +0900</lastBuildDate><atom:link href="https://monkshark.github.io/tags/claude-api/index.xml" rel="self" type="application/rss+xml"/><item><title>#3 - 요약을 온디바이스로, 네 엔진을 한 입구로</title><link>https://monkshark.github.io/p/pr-lens-summary/</link><pubDate>Tue, 23 Jun 2026 12:00:00 +0900</pubDate><guid>https://monkshark.github.io/p/pr-lens-summary/</guid><description>&lt;p&gt;마지막으로 얹은 건 PR 요약이다. 어려운 건 요약 자체가 아니라, &amp;ldquo;공짜로, 키 없이, diff 를 밖으로 안 보내고&amp;quot;와 &amp;ldquo;필요하면 최고 품질로&amp;quot;를 한 버튼 뒤에 같이 두는 일이었다.&lt;/p&gt;
&lt;h2 id="기본은-온디바이스-클라우드는-옵트인"&gt;&lt;a href="#%ea%b8%b0%eb%b3%b8%ec%9d%80-%ec%98%a8%eb%94%94%eb%b0%94%ec%9d%b4%ec%8a%a4-%ed%81%b4%eb%9d%bc%ec%9a%b0%eb%93%9c%eb%8a%94-%ec%98%b5%ed%8a%b8%ec%9d%b8" class="header-anchor"&gt;&lt;/a&gt;기본은 온디바이스, 클라우드는 옵트인
&lt;/h2&gt;&lt;p&gt;PR 을 AI 로 요약하려면 보통 diff 를 외부 모델로 보낸다. 코드 리뷰 도구가 매번 변경 내용을 남의 서버로 흘리는 건 기본값으로 두기엔 부담스러웠다. 그래서 기본 엔진을 브라우저 안에서 도는 모델로 잡았다.&lt;/p&gt;
&lt;p&gt;엔진은 넷이다. Chrome 내장 모델(Gemini Nano)은 키도 비용도 없이 기기 안에서 돌고, WebLLM 은 WebGPU 로 브라우저 안에서 도는데 첫 사용 때 가중치를 한 번 받아 캐시한 뒤로는 오프라인으로도 된다. 더 안정적인 클라우드가 필요하면 무료 키의 Gemini, 최고 품질이 필요하면 자기 키의 Claude 를 옵트인으로 고른다. 기본은 아무것도 안 나가고, 무언가 나가는 선택은 사용자가 직접 켠다.&lt;/p&gt;
&lt;h2 id="네-엔진을-한-모양으로"&gt;&lt;a href="#%eb%84%a4-%ec%97%94%ec%a7%84%ec%9d%84-%ed%95%9c-%eb%aa%a8%ec%96%91%ec%9c%bc%eb%a1%9c" class="header-anchor"&gt;&lt;/a&gt;네 엔진을 한 모양으로
&lt;/h2&gt;&lt;p&gt;엔진마다 호출법이 딴판이다. 내장 모델은 세션을 만들어 스트림을 reader 로 읽고, WebLLM 은 OpenAI 풍 &lt;code&gt;chat.completions&lt;/code&gt; 스트림, Gemini 는 날 SSE 를 직접 파싱, Claude 는 공식 SDK 의 &lt;code&gt;messages.stream&lt;/code&gt; 을 쓴다. 이걸 호출부에 그대로 노출하면 UI 가 엔진 수만큼 갈라진다.&lt;/p&gt;
&lt;p&gt;그래서 전부 같은 모양으로 감쌌다. system·user 프롬프트를 받아, 토큰이 올 때마다 &lt;code&gt;onChunk&lt;/code&gt; 로 흘려보내는 함수. 안쪽이 SSE 든 SDK 든, 바깥에서 보면 똑같이 &amp;ldquo;조각이 스트리밍된다&amp;quot;가 된다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;promptStreaming&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getReader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(;;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;onChunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="입력은-diff-출력은-한국어-고정"&gt;&lt;a href="#%ec%9e%85%eb%a0%a5%ec%9d%80-diff-%ec%b6%9c%eb%a0%a5%ec%9d%80-%ed%95%9c%ea%b5%ad%ec%96%b4-%ea%b3%a0%ec%a0%95" class="header-anchor"&gt;&lt;/a&gt;입력은 diff, 출력은 한국어 고정
&lt;/h2&gt;&lt;p&gt;요약할 재료는 GitHub REST API 에서 가져온다. PR 메타와 변경 파일을 페이지네이션으로 긁고(비공개 저장소나 rate limit 은 PAT 로 푼다), 너무 길면 정해둔 길이에서 자른 뒤 &amp;ldquo;이후 생략&amp;rdquo; 을 표시한다.&lt;/p&gt;
&lt;p&gt;프롬프트는 출력 형식을 못박는다. UI 언어가 영어든 한국어든 요약 본문은 한국어로 고정하고, &amp;ldquo;한 줄 요약 / 핵심 변경점 / 리뷰 포인트&amp;rdquo; 세 섹션의 마크다운으로만 답하게 한다. 작은 온디바이스 모델일수록 형식을 흔들기 쉬워서, 자유도를 줄이는 쪽이 결과가 안정적이었다. 한 번 생성한 요약은 PR 별로 저장해, 다시 들어오면 곧바로 보여준다.&lt;/p&gt;
&lt;h2 id="돌아보면"&gt;&lt;a href="#%eb%8f%8c%ec%95%84%eb%b3%b4%eb%a9%b4" class="header-anchor"&gt;&lt;/a&gt;돌아보면
&lt;/h2&gt;&lt;p&gt;3부의 핵심은 모델이 아니라 입구였다. 성능과 프라이버시가 다른 네 엔진을 같은 한 줄 인터페이스 뒤에 세우고, 그 입구의 기본값을 &amp;ldquo;기기 안, 무료, 아무것도 안 나감&amp;quot;으로 둔 것. 더 좋은 걸 원하면 키를 꽂아 옵트인하면 되고, 아무것도 안 하면 가장 안전한 쪽이 작동한다. 도구가 사용자 대신 내리는 기본 선택이 가장 정직해야 한다는 게, 이 프로젝트 내내 지킨 원칙이었다.&lt;/p&gt;</description></item></channel></rss>