<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>김신건의 로그 - 위키 / ai</title><description>&apos;ai&apos; 카테고리 위키 페이지 최신 업데이트</description><link>https://shinkeonkim.com/</link><language>ko-KR</language><item><title>[LLM Eval] HELM: Holistic Evaluation of Language Models</title><link>https://shinkeonkim.com/wiki/ai/helm-llm-benchmark/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/ai/helm-llm-benchmark/</guid><pubDate>Mon, 29 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;HELM (Holistic Evaluation of Language Models)&lt;/strong&gt; 는 Stanford CRFM (Center for Research on Foundation Models) 이 2022년 발표한 LLM 종합 평가 프레임워크입니다. 기존 벤치마크가 정확도 단일 지표에 편중되는 문제를 지적하며, &lt;strong&gt;여러 시나리오 × 여러 메트릭의 행렬&lt;/strong&gt; 로 모델을 평가하는 것을 특징으로 합니다.&lt;/p&gt;
&lt;p&gt;원 논문 제목이 곧 방법론입니다. Holistic (전체적): 정확도만이 아니라 공정성, 편향, 견고성, 효율성까지 함께 보겠다는 선언.&lt;/p&gt;
&lt;h2 id=&quot;왜-등장했는가&quot;&gt;왜 등장했는가&lt;/h2&gt;
&lt;p&gt;2022 년 시점 LLM 평가의 문제:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;단일 태스크 평가&lt;/strong&gt; (MMLU, HellaSwag 등) 는 특정 능력만 봄&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;정확도 지표만 리포트&lt;/strong&gt; (calibration, robustness, bias 등은 무시)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;모델 비교가 임의적&lt;/strong&gt; (논문마다 다른 태스크 조합, 다른 세팅)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;재현성 부족&lt;/strong&gt; (프롬프트, 파라미터, few-shot 개수가 논문마다 다름)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;HELM 은 이를 &lt;strong&gt;표준화된 시나리오 세트 + 표준화된 메트릭 세트 + 표준화된 프롬프트/실행 방식&lt;/strong&gt; 으로 해결하려 했습니다.&lt;/p&gt;
&lt;h2 id=&quot;7-가지-핵심-메트릭-축&quot;&gt;7 가지 핵심 메트릭 축&lt;/h2&gt;
&lt;p&gt;원 논문의 7 축입니다. 각 시나리오에 대해 이 7 가지를 모두 측정하려 시도합니다.&lt;/p&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;축&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;의미&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;예시&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Accuracy&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;정답 맞추는 능력&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;정확도, F1, exact match&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Calibration&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;확신도 vs 실제 정확도 일치&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;ECE (Expected Calibration Error)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Robustness&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;입력 변형에도 안정적인가&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Typo, paraphrase, adversarial 변형 아래 성능&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Fairness&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;인구통계 집단별 성능 균등한가&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;이름/방언에 따른 성능 편차&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Bias&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;스테레오타입 재생산 여부&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;성별/인종 등에 대한 연관성 통계&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Toxicity&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;유해 텍스트 생성 여부&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Perspective API 등으로 측정&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Efficiency&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;추론 비용, 학습 비용&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;초당 토큰, 학습에 든 FLOPs&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;이 7 가지는 &lt;strong&gt;완전한 목록이 아니라 출발점&lt;/strong&gt; 이라고 논문 스스로 명시했습니다. 이후 버전에서 확장되었습니다.&lt;/p&gt;
&lt;h2 id=&quot;시나리오-scenario&quot;&gt;시나리오 (Scenario)&lt;/h2&gt;
&lt;p&gt;HELM 이 커버하는 태스크 유형입니다. 각 시나리오는 데이터셋 + 태스크 정의 + 평가 방식으로 구성됩니다. 초기 버전 42 개 시나리오를 대략 6 개 카테고리로 나눌 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Question Answering&lt;/strong&gt;: NaturalQuestions, NarrativeQA, TruthfulQA, QuAC 등&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Information Retrieval&lt;/strong&gt;: MS MARCO 등&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Summarization&lt;/strong&gt;: CNN/DailyMail, XSum&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sentiment Analysis / Classification&lt;/strong&gt;: IMDB, RAFT&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Toxicity Detection&lt;/strong&gt;: CivilComments&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reasoning&lt;/strong&gt;: MMLU, GSM8K, MATH, BBQ (bias)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이후 버전에서 코드 (HumanEval, MBPP), 롱-컨텍스트 (LongBench 계열), 멀티모달 등이 추가되었습니다.&lt;/p&gt;
&lt;h2 id=&quot;helm-variants-2023&quot;&gt;HELM Variants (2023~)&lt;/h2&gt;
&lt;p&gt;원 HELM (이하 &lt;strong&gt;HELM Classic&lt;/strong&gt;) 은 모든 시나리오 × 모든 메트릭을 시도했기 때문에 &lt;strong&gt;매우 비쌉니다&lt;/strong&gt; (수천~수만 달러 규모의 API 비용). 이를 축소한 파생 버전들이 나왔습니다.&lt;/p&gt;
&lt;h3 id=&quot;helm-lite-2023-말&quot;&gt;HELM Lite (2023 말~)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;실전에서 자주 쓰이는 시나리오만 &lt;strong&gt;10 개 내외&lt;/strong&gt; 로 축소&lt;/li&gt;
&lt;li&gt;MMLU (multiple-choice), GSM8K, MATH, NaturalQuestions, WMT, LegalBench 등&lt;/li&gt;
&lt;li&gt;하루~며칠 단위로 리더보드 업데이트&lt;/li&gt;
&lt;li&gt;빠른 반복 평가에 적합&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://crfm.stanford.edu/helm/lite/&quot;&gt;https://crfm.stanford.edu/helm/lite/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;helm-instruct&quot;&gt;HELM Instruct&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;지시 따르기 (instruction following)&lt;/strong&gt; 평가에 초점&lt;/li&gt;
&lt;li&gt;Open-ended generation 을 사람 또는 LLM-as-judge 로 평가&lt;/li&gt;
&lt;li&gt;MT-Bench, AlpacaEval 등과 유사한 접근&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://crfm.stanford.edu/helm/instruct/&quot;&gt;https://crfm.stanford.edu/helm/instruct/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;helm-safety&quot;&gt;HELM Safety&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;안전성 (harmful content, jailbreak 저항성) 중심&lt;/li&gt;
&lt;li&gt;유해 요청에 대한 거부, jailbreak 프롬프트 아래 견고성 등&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;도메인-특화-helm&quot;&gt;도메인 특화 HELM&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MedHELM&lt;/strong&gt;: 의료 도메인 (2024)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LegalBench&lt;/strong&gt; 통합&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AIR-Bench&lt;/strong&gt;: 리스크 카테고리별&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;리더보드는 &lt;a href=&quot;https://crfm.stanford.edu/helm/&quot;&gt;https://crfm.stanford.edu/helm/&lt;/a&gt; 최상단에서 여러 트랙을 선택할 수 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;시나리오--메트릭-매트릭스&quot;&gt;시나리오 × 메트릭 매트릭스&lt;/h2&gt;
&lt;p&gt;핵심 아이디어를 도식으로 표현하면:&lt;/p&gt;





































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;MMLU&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;HellaSwag&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;TruthfulQA&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;HumanEval&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;…&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Accuracy&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;pass@1&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;…&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Calibration&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;-&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;…&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Robustness&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓ (typo)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;…&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Fairness&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓ (이름 치환)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;-&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;-&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;-&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;…&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Bias&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;-&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;-&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓ (BBQ)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;-&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;…&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Toxicity&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;-&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;-&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;-&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;-&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;…&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Efficiency&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;tok/s, FLOPs&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;…&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;…&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;…&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;…&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;모든 셀이 다 채워지진 않습니다 (해당 메트릭이 그 시나리오에 적용 불가한 경우 존재). HELM 은 &lt;strong&gt;어떤 셀이 비어 있는지도 명시적으로 보여주어&lt;/strong&gt; 평가의 불완전성을 드러냅니다.&lt;/p&gt;
&lt;h2 id=&quot;리더보드-2026-기준&quot;&gt;리더보드 (2026 기준)&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://crfm.stanford.edu/helm/lite/&quot;&gt;https://crfm.stanford.edu/helm/lite/&lt;/a&gt; 최신 리더보드에서 확인 가능합니다. 상위권에는 GPT-5, Claude Opus 4, Gemini 2.5 계열 등이 위치하며, 오픈 웨이트 (Llama, Qwen, DeepSeek) 도 근접해 있습니다. 정확한 순위는 시점마다 바뀌므로 링크 참조가 정답입니다.&lt;/p&gt;
&lt;h2 id=&quot;실행-방법-helm-run&quot;&gt;실행 방법 (helm-run)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;pip&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; crfm-helm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 실행할 conf 파일 정의&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; run-specs.conf&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  {description: &quot;mmlu:subject=philosophy,model=openai/gpt-4o&quot;, priority: 1},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  {description: &quot;narrativeqa:model=openai/gpt-4o&quot;, priority: 1},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 실행&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;helm-run&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  --conf-paths&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; run-specs.conf&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  --suite&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; my-eval&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  --max-eval-instances&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  --num-threads&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 결과 요약 통합&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;helm-summarize&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --suite&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; my-eval&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 웹 UI 로 결과 확인&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;helm-server&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --suite&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; my-eval&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# http://localhost:8000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;지원 모델 provider: &lt;strong&gt;OpenAI, Anthropic, Google, Meta, Microsoft, Cohere, HuggingFace Hub, vLLM, Together, DeepSeek, Mistral&lt;/strong&gt; 등. 자체 서빙 모델도 &lt;code&gt;LocalModel&lt;/code&gt; 로 붙일 수 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;다른-벤치마크와-비교&quot;&gt;다른 벤치마크와 비교&lt;/h2&gt;



























































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;벤치마크&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;초점&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;장점&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;단점&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;HELM&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Holistic (다면적)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;여러 축 동시 측정, 표준화&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;실행 비용 큼&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;MMLU / MMLU-Pro&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;지식 QA&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;간단, 널리 인용됨&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;단일 정답 편중, 오염 우려&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;BIG-Bench&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;다양성 극대화&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;200+ 태스크&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;태스크 품질 편차 큼&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Chatbot Arena&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;사람 선호도&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;실사용자 판단, 편향 적음&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;태스크 세분화 없음, 오랜 축적 필요&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;AlpacaEval&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Instruction following&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;LLM-as-judge 로 빠름&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Judge 편향&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;MT-Bench&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;대화 품질&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;짧고 실용적&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;소규모 (80 문항)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;LM Eval Harness&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;프레임워크&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;EleutherAI, 매우 널리 쓰임&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;표준 축이 아니라 도구&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;AGIEval&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;인간 시험 (SAT, LSAT)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;실제 인간 기준&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;지역/언어 편중&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;HELM 은 벤치마크 그 자체이자 프레임워크&lt;/strong&gt;입니다. 다른 벤치마크의 결과를 HELM 구조 안에서 재실행할 수 있게 통합해 왔습니다.&lt;/p&gt;
&lt;h2 id=&quot;한계와-비판&quot;&gt;한계와 비판&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;오염 (contamination)&lt;/strong&gt;: MMLU 등 공개 벤치마크가 학습 데이터에 유출되어 점수가 부풀려질 수 있습니다. HELM 자체는 이를 감지하지 못합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;비용&lt;/strong&gt;: 원 HELM Classic 은 GPT-4 급 모델을 완전 실행하려면 수만 달러가 필요합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;7 축의 임의성&lt;/strong&gt;: 안전성/agentic 능력/멀티모달은 원 논문에 없었고 이후 추가되었지만 여전히 커버리지 논쟁.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;단일 시드 실행&lt;/strong&gt;: 확률적 생성이므로 결과가 흔들리며, 여러 시드로 여러 번 실행하는 것이 이상적이지만 비용 문제로 어려움.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;자동 평가의 한계&lt;/strong&gt;: LLM-as-judge 는 편향 (자기 편애, 길이 선호) 이 알려져 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;관련 [[transfer-learning|Transfer Learning]] 은 HELM 이 평가하는 파운데이션 모델의 근본 기법입니다&lt;/li&gt;
&lt;li&gt;관련 [[classification-metrics|분류 모델 지표]] 는 accuracy 축 세부 지표&lt;/li&gt;
&lt;li&gt;관련 [[sagemaker-model-monitor|SageMaker Model Monitor]] 는 프로덕션 모니터링, HELM 은 모델 선정 단계&lt;/li&gt;
&lt;li&gt;리더보드: &lt;a href=&quot;https://crfm.stanford.edu/helm/&quot;&gt;https://crfm.stanford.edu/helm/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Paper: &lt;a href=&quot;https://arxiv.org/abs/2211.09110&quot;&gt;Liang et al. 2022, HELM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href=&quot;https://github.com/stanford-crfm/helm&quot;&gt;https://github.com/stanford-crfm/helm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;관련 커뮤니티: &lt;a href=&quot;https://huggingface.co/spaces/HuggingFaceH4/open_llm_leaderboard&quot;&gt;Open LLM Leaderboard&lt;/a&gt;, &lt;a href=&quot;https://github.com/EleutherAI/lm-evaluation-harness&quot;&gt;LM Eval Harness&lt;/a&gt;, &lt;a href=&quot;https://chat.lmsys.org/&quot;&gt;Chatbot Arena&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>ai</category><category>llm</category><category>evaluation</category><category>benchmark</category><author>koa (김신건)</author></item><item><title>Function Calling / Tool Use: LLM 도구 사용</title><link>https://shinkeonkim.com/wiki/ai/function-calling/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/ai/function-calling/</guid><pubDate>Mon, 29 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Function Calling&lt;/strong&gt; (또는 &lt;strong&gt;Tool Use&lt;/strong&gt;) 은 LLM 이 정의된 함수/도구를 &lt;strong&gt;호출 인자를 생성&lt;/strong&gt; 하는 기능. JSON schema 로 함수 시그니처를 알려주면, LLM 이 사용자 질의에 맞는 함수와 인자를 JSON 으로 반환.&lt;/p&gt;
&lt;p&gt;OpenAI (2023), Anthropic Claude, Google Gemini, 오픈소스 (Llama 3.1+) 모두 지원.&lt;/p&gt;
&lt;h2 id=&quot;예시&quot;&gt;예시&lt;/h2&gt;
&lt;h3 id=&quot;함수-스펙-정의&quot;&gt;함수 스펙 정의&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;function&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;function&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        &quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;get_weather&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        &quot;description&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Get current weather for a city&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        &quot;parameters&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;object&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            &quot;properties&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;                &quot;city&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;                &quot;unit&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;enum&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;C&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;F&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;C&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            &quot;required&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;city&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;대화&quot;&gt;대화&lt;/h3&gt;
&lt;p&gt;사용자: “서울 날씨 알려줘”&lt;/p&gt;
&lt;p&gt;LLM 응답:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;tool_calls&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        &quot;function&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;get_weather&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        &quot;arguments&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;city&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Seoul&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;C&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;실행-후-결과-재주입&quot;&gt;실행 후 결과 재주입&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;tool result: {&quot;temp&quot;: 22, &quot;condition&quot;: &quot;sunny&quot;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;LLM 이 최종 답변 생성: “서울은 현재 22°C 로 맑습니다.”&lt;/p&gt;
&lt;h2 id=&quot;agent-프레임워크&quot;&gt;Agent 프레임워크&lt;/h2&gt;
&lt;p&gt;Function calling 을 반복적으로 활용:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ReAct&lt;/strong&gt;: Reasoning + Acting 사이클&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LangChain&lt;/strong&gt;, &lt;strong&gt;LlamaIndex&lt;/strong&gt;: 도구 오케스트레이션&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCP (Model Context Protocol)&lt;/strong&gt;: Anthropic 의 표준 (2024)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;함정&quot;&gt;함정&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;오호출&lt;/strong&gt;: LLM 이 없는 함수를 호출하려 함. 스키마 검증 필수.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;인자 hallucination&lt;/strong&gt;: 필수 필드 누락, enum 아닌 값 반환&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;무한 루프&lt;/strong&gt;: 도구 결과가 계속 다음 도구 호출 트리거&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;토큰 낭비&lt;/strong&gt;: 도구 스펙 자체가 큰 컨텍스트 소비&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;관련 [[llm-rag|LLM RAG]]&lt;/li&gt;
&lt;li&gt;관련 [[helm-llm-benchmark|HELM]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>ai</category><category>llm</category><category>function-calling</category><category>agent</category><author>koa (김신건)</author></item><item><title>LLM RAG: Retrieval-Augmented Generation</title><link>https://shinkeonkim.com/wiki/ai/llm-rag/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/ai/llm-rag/</guid><pubDate>Mon, 29 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;RAG (Retrieval-Augmented Generation)&lt;/strong&gt; 는 LLM 생성 전에 &lt;strong&gt;외부 지식 베이스에서 관련 문서를 검색&lt;/strong&gt; 하여 프롬프트에 삽입하는 패턴. 최신 정보, 도메인 지식, 사설 데이터 접근 필요할 때 사용.&lt;/p&gt;
&lt;h2 id=&quot;왜-필요한가&quot;&gt;왜 필요한가&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;최신 정보&lt;/strong&gt;: LLM 학습 컷오프 이후 지식&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;도메인 데이터&lt;/strong&gt;: 회사 내부 문서, 개인 지식&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;hallucination 감소&lt;/strong&gt;: “출처” 를 명시&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;비용 절감&lt;/strong&gt;: 파인튜닝 대신&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;파이프라인&quot;&gt;파이프라인&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  질의 → embed → vector search → 상위 K 문서 → prompt 조합 → LLM → 답변&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;핵심-구성-요소&quot;&gt;핵심 구성 요소&lt;/h2&gt;
&lt;h3 id=&quot;1-문서-chunk-화&quot;&gt;1. 문서 chunk 화&lt;/h3&gt;
&lt;p&gt;문서를 청크 (500&lt;del&gt;1000 토큰) 로 분할. 겹치는 슬라이딩 윈도우 (100&lt;/del&gt;200 토큰) 로 문맥 유지.&lt;/p&gt;
&lt;h3 id=&quot;2-embedding&quot;&gt;2. Embedding&lt;/h3&gt;
&lt;p&gt;각 청크를 벡터로 변환. &lt;code&gt;text-embedding-3-small&lt;/code&gt;, &lt;code&gt;bge-large-en&lt;/code&gt;, &lt;code&gt;nomic-embed&lt;/code&gt; 등.&lt;/p&gt;
&lt;h3 id=&quot;3-vector-store&quot;&gt;3. Vector Store&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;[[redis-vector-search|Redis Vector Search]]&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pinecone&lt;/strong&gt;, &lt;strong&gt;Weaviate&lt;/strong&gt;, &lt;strong&gt;Qdrant&lt;/strong&gt;, &lt;strong&gt;Milvus&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;pgvector&lt;/strong&gt; (PostgreSQL 확장)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;4-retrieval&quot;&gt;4. Retrieval&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dense&lt;/strong&gt;: cosine similarity, HNSW 인덱스&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sparse (BM25)&lt;/strong&gt;: 정확 매칭&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hybrid&lt;/strong&gt;: 두 점수 결합&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reranker&lt;/strong&gt;: cross-encoder 로 상위 K 재순위&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;5-prompt-composition&quot;&gt;5. Prompt Composition&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Context:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[문서 1 요약]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[문서 2 요약]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Question: {질의}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Answer based on the context above.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;최적화-기법&quot;&gt;최적화 기법&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HyDE&lt;/strong&gt;: 가상 답변 embedding 으로 검색&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-query rewriting&lt;/strong&gt;: 질의 확장&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contextual compression&lt;/strong&gt;: chunk 내 관련 부분만 추출&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Query routing&lt;/strong&gt;: 질의 종류별 다른 인덱스&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;평가-지표&quot;&gt;평가 지표&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Retrieval&lt;/strong&gt;: recall@k, MRR&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generation&lt;/strong&gt;: faithfulness (사실성), answer relevance&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ragas 프레임워크&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;관련 [[redis-vector-search|Redis Vector Search]]&lt;/li&gt;
&lt;li&gt;관련 [[function-calling|Function Calling]]&lt;/li&gt;
&lt;li&gt;관련 [[helm-llm-benchmark|HELM]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>ai</category><category>llm</category><category>rag</category><category>retrieval</category><author>koa (김신건)</author></item><item><title>[Voice AI] Agent 패턴: Supervisor, Handoff, ReAct, HITL</title><link>https://shinkeonkim.com/wiki/ai/agent-patterns/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/ai/agent-patterns/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;복잡한 음성 에이전트 = &lt;em&gt;여러 sub-agent + 조정 패턴&lt;/em&gt;. 단일 LLM 으로 처리하기 어려운 흐름.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
각 sub-agent 내부는 &lt;em&gt;VAD → STT → LLM → TTS 순차 파이프라인&lt;/em&gt; 위에서 동작. 본 페이지의 패턴은 &lt;em&gt;상위 조정 (orchestration)&lt;/em&gt; 레이어.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;4가지-핵심-패턴&quot;&gt;4가지 핵심 패턴&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q[Agent Patterns]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt; S[Supervisor]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt; H[Handoff]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt; R[ReAct]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt; HITL[Human-in-the-Loop]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;1-supervisor&quot;&gt;1. Supervisor&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User --&gt; Sup[Supervisor Agent]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Sup --&gt; Choose{어느 sub-agent?}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Choose --&gt;|결제 문의| Pay[Payment Agent]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Choose --&gt;|환불| Ref[Refund Agent]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Choose --&gt;|기술 지원| Tech[Tech Agent]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Pay --&gt; Sup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Ref --&gt; Sup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Tech --&gt; Sup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Sup --&gt; User&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SupervisorAgent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;&quot;&quot;질의 → 적절 sub-agent 라우팅&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    sub_agents &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;payment&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: PaymentAgent(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;refund&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: RefundAgent(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;tech_support&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: TechAgent(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; handle&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self, user_input: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        # LLM 으로 의도 분류&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        intent &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;._classify_intent(user_input)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        agent &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.sub_agents[intent]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; agent.handle(user_input)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; _classify_intent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self, text: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; llm.structured_output(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;            schema&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;IntentSchema,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;            messages&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[{&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;role&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: text}],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result.intent&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;작은 분류 모델 (gpt-4o-mini, Haiku) 가 &lt;em&gt;intent classifier&lt;/em&gt;, &lt;em&gt;세부 agent 가 더 큰 모델&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;2-handoff&quot;&gt;2. Handoff&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User-&gt;&gt;Booking: 예약 문의&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Booking-&gt;&gt;Booking: 예약 처리&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Note over Booking: 결제 단계&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Booking-&gt;&gt;Payment: HANDOFF (context 전달)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Payment-&gt;&gt;User: &quot;결제 진행하겠습니다&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User-&gt;&gt;Payment: 카드 정보&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Payment-&gt;&gt;Payment: 결제 처리&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Payment--&gt;&gt;Booking: HANDOFF BACK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Booking-&gt;&gt;User: &quot;예약 + 결제 완료&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;OpenAI Swarm 의 &lt;em&gt;handoff&lt;/em&gt; 패턴:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; swarm &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Swarm, Agent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;booking_agent &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Agent(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Booking&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    instructions&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;식당 예약을 도와줍니다.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    functions&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[lookup_restaurant, check_availability, transfer_to_payment],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;payment_agent &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Agent(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Payment&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    instructions&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;결제를 처리합니다.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    functions&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[charge_card, transfer_to_booking],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; transfer_to_payment&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; payment_agent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; transfer_to_booking&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; booking_agent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;client &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Swarm()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;response &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; client.run(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;agent&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;booking_agent, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;messages&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;messages)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Function return 으로 agent 교체&lt;/em&gt;. 깔끔.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;3-react-reason--act&quot;&gt;3. ReAct (Reason + Act)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Thought: 사용자가 &quot;내일 오후 회의 잡아줘&quot; 라고 했다.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Action: search_calendar(date=&quot;내일&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Observation: 14:00-15:00 비어있음&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Thought: 14시에 잡으면 되겠다. 참석자는 누구?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Action: ask_user(&quot;참석자는 누구신가요?&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Observation: &quot;민수씨와 영희씨요&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Thought: 그들의 가용성 확인 필요&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Action: check_availability([&quot;민수&quot;, &quot;영희&quot;], &quot;내일 14:00&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Observation: 모두 OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Thought: 회의 생성&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Action: create_meeting(...)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Observation: 회의 생성됨, ID=m_42&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Thought: 사용자에게 알림&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Action: respond(&quot;내일 오후 2시에 민수씨, 영희씨와 회의 잡았습니다.&quot;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; react_loop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(user_input, max_steps&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    messages &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [{&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;role&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: user_input}]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; step &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(max_steps):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        response &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; llm.chat(messages, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;tools&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tools)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; response.finish_reason &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;stop&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; response.content   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 최종 답변&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; response.tool_calls:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tc &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; response.tool_calls:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; execute_tool(tc)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                messages.append({&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;role&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;tool&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;tool_call_id&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: tc.id, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: result})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    raise&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ReActLoopExceededError()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;음성에서는 &lt;em&gt;너무 많은 step&lt;/em&gt; = 지연 폭증. &lt;em&gt;max_steps 3-5&lt;/em&gt; 권장.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;4-human-in-the-loop-hitl&quot;&gt;4. Human-in-the-Loop (HITL)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User-&gt;&gt;Agent: &quot;1억 송금&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Agent-&gt;&gt;HITL: critical action approval request&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    HITL-&gt;&gt;Human[운영자]: 알림 (&quot;승인 필요&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Human--&gt;&gt;HITL: approve / reject&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    HITL--&gt;&gt;Agent: result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Agent-&gt;&gt;User: &quot;송금 완료&quot; 또는 &quot;보안 확인 필요&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;@agent.tool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; transfer_money&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(amount: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, to: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; amount &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 10_000_000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        approval &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; request_human_approval(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;            action&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;송금 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amount&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;원 → &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;to&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;            timeout&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;30&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; approval:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;송금이 보류되었습니다. 보안팀 확인 후 처리됩니다.&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; bank_api.transfer(amount, to)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amount&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;원이 송금되었습니다.&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;고위험 작업&lt;/em&gt; (금액 큰 송금, 데이터 삭제, 외부 noti) 에 인간 승인.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;패턴-조합&quot;&gt;패턴 조합&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User --&gt; Sup[Supervisor]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Sup --&gt;|일반| Single[Single Agent + ReAct]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Sup --&gt;|복잡 → 전문| Hand[Handoff Chain]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Hand --&gt; Risk{고위험?}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Risk --&gt;|예| HITL[HITL Approval]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    HITL --&gt; Exec[실행]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;langgraph-예시-다중-agent--state-machine&quot;&gt;LangGraph 예시 (다중 agent + state machine)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; langgraph.graph &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; StateGraph, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;END&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; State&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;TypedDict&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    user_input: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    intent: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    result: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; classify&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(state):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    state[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;intent&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; classify_intent(state[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;user_input&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; state&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; payment&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(state):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    state[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;result&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; handle_payment(state[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;user_input&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; state&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; refund&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(state):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    state[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;result&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; handle_refund(state[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;user_input&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; state&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;graph &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; StateGraph(State)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;graph.add_node(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;classify&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, classify)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;graph.add_node(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;payment&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, payment)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;graph.add_node(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;refund&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, refund)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;graph.set_entry_point(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;classify&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;graph.add_conditional_edges(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;classify&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    lambda&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; s: s[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;intent&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;payment&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;payment&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;refund&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;refund&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;other&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;END&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;graph.add_edge(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;payment&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;END&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;graph.add_edge(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;refund&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;END&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;app &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; graph.compile()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;흔한-함정&quot;&gt;흔한 함정&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;모든 query 에 ReAct&lt;/strong&gt; = 단순 FAQ 도 3-step. 의도 분류 후 &lt;em&gt;복잡한 것만&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handoff 후 &lt;em&gt;context 손실&lt;/em&gt;&lt;/strong&gt; = 사용자가 같은 정보 반복. handoff 시 &lt;em&gt;summary&lt;/em&gt; 전달.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;너무 많은 sub-agent&lt;/strong&gt; = supervisor 가 &lt;em&gt;분류 어려움&lt;/em&gt;. 5-7개 이내.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HITL 없이 critical action&lt;/strong&gt; = 사고. 임계 정의 + 자동 승인 vs 인간.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[voice-agent-architecture]]&lt;/li&gt;
&lt;li&gt;[[voice-first-prompt]]&lt;/li&gt;
&lt;li&gt;[[function-calling]] (만일 별도 wiki 있다면)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>agent</category><category>multi-agent</category><category>supervisor</category><category>handoff</category><category>react</category><category>hitl</category><author>koa (김신건)</author></item><item><title>[Voice AI] LLM Serving: vLLM, PagedAttention, continuous batching</title><link>https://shinkeonkim.com/wiki/ai/llm-serving-vllm/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/ai/llm-serving-vllm/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;LLM Serving&lt;/strong&gt; = 자체 호스팅 LLM 을 &lt;em&gt;낮은 TTFT + 높은 throughput&lt;/em&gt; 으로 제공. 음성 에이전트의 &lt;em&gt;LLM 단계 지연&lt;/em&gt; 결정.&lt;/p&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;도구&lt;/th&gt;&lt;th&gt;특징&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;vLLM&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;PagedAttention&lt;/em&gt;, 표준. 한국에서도 압도적&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TGI&lt;/strong&gt; (Hugging Face)&lt;/td&gt;&lt;td&gt;안정, 옛 표준&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;SGLang&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;structured output 강함, 2024+&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;LMDeploy&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;InternLM, 중국&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TensorRT-LLM&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;NVIDIA 전용, 최고 성능&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;pagedattention&quot;&gt;PagedAttention&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q1[Request 1&amp;#x3C;br/&gt;&apos;안녕&apos;] --&gt; KV1[KV cache]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q2[Request 2&amp;#x3C;br/&gt;&apos;오늘 날씨&apos;] --&gt; KV2[KV cache]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    KV1 --&gt; Page[&quot;Memory Pages (16 tokens 단위)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    KV2 --&gt; Page&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Page --&gt; GPU[GPU memory]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;기존 (LLaMA, TGI 옛)&lt;/th&gt;&lt;th&gt;PagedAttention (vLLM)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;요청 시작 시 &lt;em&gt;최대 길이 만큼 KV cache 예약&lt;/em&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;Page 단위 동적 할당&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;짧은 응답도 &lt;em&gt;2K-32K 토큰 메모리&lt;/em&gt;&lt;/td&gt;&lt;td&gt;실제 사용 만큼만&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GPU 메모리 &lt;em&gt;심한 단편화&lt;/em&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;&amp;#x3C; 4% 낭비&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Throughput 낮음&lt;/td&gt;&lt;td&gt;&lt;em&gt;2-4x 향상&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;운영체제의 &lt;em&gt;Virtual Memory + paging&lt;/em&gt; 의 &lt;em&gt;LLM inference 적용&lt;/em&gt;. 모든 modern serving 의 기본.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;continuous-batching&quot;&gt;Continuous Batching&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Static[&quot;Static batching:&amp;#x3C;br/&gt;요청 8개 모일 때까지 대기&amp;#x3C;br/&gt;한 batch 끝날 때까지 다음 안 받음&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Cont[&quot;Continuous batching:&amp;#x3C;br/&gt;매 step 마다 batch 재구성&amp;#x3C;br/&gt;새 요청 즉시 합류, 완료된 거 즉시 빠짐&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Static --&gt; Slow[GPU idle 많음, latency 높음]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Cont --&gt; Fast[GPU 100% 활용, latency 낮음]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;step 단위 dynamic batching&lt;/em&gt; = vLLM, TGI 등의 &lt;em&gt;2026 표준&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;ttft-time-to-first-token-vs-tps&quot;&gt;TTFT (Time-to-First-Token) vs TPS&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Req[Request 도착] --&gt;|&quot;prefill (전체 prompt 처리)&quot;| F1[First token]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    F1 --&gt;|&quot;decode (1 토큰씩)&quot;| T2[Token 2]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    T2 --&gt;|decode| T3[Token 3]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Note[&quot;TTFT = prefill 시간&amp;#x3C;br/&gt;TPS = decode 속도&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;지표&lt;/th&gt;&lt;th&gt;의미&lt;/th&gt;&lt;th&gt;목표&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TTFT&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;첫 토큰까지&lt;/td&gt;&lt;td&gt;&lt;em&gt;&amp;#x3C; 200ms&lt;/em&gt; (음성)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TPS&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;초당 토큰&lt;/td&gt;&lt;td&gt;&gt; 50 tok/s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Throughput&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;동시 요청 처리&lt;/td&gt;&lt;td&gt;GPU 효율&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;음성 에이전트 = &lt;em&gt;TTFT 가 결정적&lt;/em&gt;. sentence aggregator 가 &lt;em&gt;첫 문장 받으면 TTS 시작&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;sse-스트리밍-server-sent-events&quot;&gt;SSE 스트리밍 (Server-Sent Events)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;http&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;GET&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; /v1/chat/completions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;Accept&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; text/event-stream&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; {&quot;choices&quot;: [{&quot;delta&quot;: {&quot;content&quot;: &quot;안&quot;}}]}\n\n&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; {&quot;choices&quot;: [{&quot;delta&quot;: {&quot;content&quot;: &quot;녕&quot;}}]}\n\n&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; {&quot;choices&quot;: [{&quot;delta&quot;: {&quot;content&quot;: &quot;하세요&quot;}}]}\n\n&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; [DONE]\n\n&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; openai &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; AsyncOpenAI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;client &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; AsyncOpenAI(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;base_url&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;http://localhost:8000/v1&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;stream &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; client.chat.completions.create(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    model&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;llama-3.1-8b-instruct&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    messages&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;messages,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    stream&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chunk &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stream:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    delta &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chunk.choices[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].delta.content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; delta:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        sentence_aggregator.feed(delta)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;자세한 SSE 는 [[SSE]] 의 일반.&lt;/p&gt;
&lt;h2 id=&quot;vllm-시작&quot;&gt;vLLM 시작&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;pip&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; vllm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# OpenAI 호환 server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;python&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; vllm.entrypoints.openai.api_server&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    --model&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; meta-llama/Llama-3.1-8B-Instruct&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    --max-model-len&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 8192&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    --gpu-memory-utilization&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0.9&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    --enable-chunked-prefill&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    --enable-prefix-caching&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    --port&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 8000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;옵션&lt;/th&gt;&lt;th&gt;의미&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;--max-model-len&lt;/code&gt;&lt;/td&gt;&lt;td&gt;최대 context&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;--gpu-memory-utilization&lt;/code&gt;&lt;/td&gt;&lt;td&gt;GPU 메모리 사용률 (0.9 권장)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;--enable-chunked-prefill&lt;/code&gt;&lt;/td&gt;&lt;td&gt;긴 prompt 를 청크로 분할 (latency 균형)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;--enable-prefix-caching&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;같은 prefix 의 KV cache 재사용&lt;/em&gt; (system prompt!)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;--tensor-parallel-size N&lt;/code&gt;&lt;/td&gt;&lt;td&gt;N GPU 분산&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;--pipeline-parallel-size N&lt;/code&gt;&lt;/td&gt;&lt;td&gt;pipeline 분산&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;prefix-caching-system-prompt-재사용&quot;&gt;Prefix Caching (system prompt 재사용)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Req1[&quot;Req 1: SYS+&apos;안녕&apos;&quot;] --&gt; Cache[&quot;Prefix Cache (SYS)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Req2[&quot;Req 2: SYS+&apos;오늘&apos;&quot;] --&gt; Cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Req3[&quot;Req 3: SYS+&apos;주문&apos;&quot;] --&gt; Cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Note[&quot;같은 system prompt 의 KV cache 재사용&amp;#x3C;br/&gt;→ TTFT 60-90% 단축&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;모든 요청이 &lt;em&gt;같은 긴 system prompt&lt;/em&gt; 면 &lt;em&gt;prefix caching&lt;/em&gt; 으로 &lt;em&gt;prefill 시간 거의 0&lt;/em&gt;. 음성 에이전트의 &lt;em&gt;고정 페르소나 prompt&lt;/em&gt; 와 완벽 매칭.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;quantization&quot;&gt;Quantization&lt;/h2&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;종류&lt;/th&gt;&lt;th&gt;메모리&lt;/th&gt;&lt;th&gt;정확도&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;FP16&lt;/td&gt;&lt;td&gt;100%&lt;/td&gt;&lt;td&gt;기준&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FP8 (H100+)&lt;/td&gt;&lt;td&gt;50%&lt;/td&gt;&lt;td&gt;~99%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;INT8 (smoothquant)&lt;/td&gt;&lt;td&gt;50%&lt;/td&gt;&lt;td&gt;~98%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;INT4 (AWQ, GPTQ)&lt;/td&gt;&lt;td&gt;25%&lt;/td&gt;&lt;td&gt;~95%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;INT4 + KV cache FP8&lt;/td&gt;&lt;td&gt;작음&lt;/td&gt;&lt;td&gt;~93%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# AWQ 4-bit 모델&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;python&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; vllm.entrypoints.openai.api_server&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    --model&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; TheBloke/Llama-3.1-8B-Instruct-AWQ&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    --quantization&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; awq&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;자세한 quantization 은 [[quantization]] 참고.&lt;/p&gt;
&lt;h2 id=&quot;모델-크기-vs-음성-적합성&quot;&gt;모델 크기 vs 음성 적합성&lt;/h2&gt;





















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;모델&lt;/th&gt;&lt;th&gt;한국어&lt;/th&gt;&lt;th&gt;TTFT (8B GPU)&lt;/th&gt;&lt;th&gt;적합&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Llama-3.1 8B Instruct&lt;/td&gt;&lt;td&gt;보통&lt;/td&gt;&lt;td&gt;150ms&lt;/td&gt;&lt;td&gt;일반&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Llama-3.1 70B AWQ&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;400ms&lt;/td&gt;&lt;td&gt;복잡 task&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Qwen2.5 7B Instruct&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;130ms&lt;/td&gt;&lt;td&gt;한국어 강함&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;EXAONE 3 7.8B&lt;/td&gt;&lt;td&gt;&lt;em&gt;최우수 (한국어)&lt;/em&gt;&lt;/td&gt;&lt;td&gt;150ms&lt;/td&gt;&lt;td&gt;한국어 voice agent&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Phi-3.5 mini (3.8B)&lt;/td&gt;&lt;td&gt;보통&lt;/td&gt;&lt;td&gt;60ms&lt;/td&gt;&lt;td&gt;edge, latency critical&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GPT-4o-mini (API)&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;200ms (API)&lt;/td&gt;&lt;td&gt;일반&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Gemini Flash 2.0 (API)&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;250ms (API)&lt;/td&gt;&lt;td&gt;일반&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;흔한-함정&quot;&gt;흔한 함정&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;prefix caching 없이 큰 system prompt&lt;/strong&gt; = 매 요청 prefill 1초+. 활성화 필수.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;streaming 안 함&lt;/strong&gt; = 응답 끝나길 기다림. &lt;em&gt;항상 stream=True&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPU memory util 너무 높음 (0.95+)&lt;/strong&gt; = OOM 위험. 0.85-0.9.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;연속 batching 없는 옛 서빙&lt;/strong&gt; = throughput 1/5. vLLM 으로.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[voice-agent-architecture]]&lt;/li&gt;
&lt;li&gt;[[tts-streaming-ssml]] (LLM 토큰 → SSE → TTS)&lt;/li&gt;
&lt;li&gt;[[quantization]]&lt;/li&gt;
&lt;li&gt;[[SSE]]&lt;/li&gt;
&lt;li&gt;[[latency-percentiles]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>llm-serving</category><category>vllm</category><category>paged-attention</category><category>kv-cache</category><category>ttft</category><author>koa (김신건)</author></item><item><title>[Voice AI] Pipecat vs LiveKit Agents: 프레임워크 비교</title><link>https://shinkeonkim.com/wiki/ai/pipecat-livekit/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/ai/pipecat-livekit/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;2026 시점 &lt;em&gt;voice agent 프레임워크&lt;/em&gt; 4가지 선택지:&lt;/p&gt;






















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Pipecat&lt;/th&gt;&lt;th&gt;LiveKit Agents&lt;/th&gt;&lt;th&gt;Vapi / Retell&lt;/th&gt;&lt;th&gt;자체 구축&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;카테고리&lt;/td&gt;&lt;td&gt;OSS framework&lt;/td&gt;&lt;td&gt;OSS SFU + framework&lt;/td&gt;&lt;td&gt;Managed&lt;/td&gt;&lt;td&gt;직접&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;운영&lt;/td&gt;&lt;td&gt;self-host&lt;/td&gt;&lt;td&gt;self-host 또는 LiveKit Cloud&lt;/td&gt;&lt;td&gt;호스팅&lt;/td&gt;&lt;td&gt;self&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;학습 곡선&lt;/td&gt;&lt;td&gt;중간&lt;/td&gt;&lt;td&gt;중간&lt;/td&gt;&lt;td&gt;&lt;em&gt;낮음&lt;/em&gt;&lt;/td&gt;&lt;td&gt;높음&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;비용&lt;/td&gt;&lt;td&gt;인프라만&lt;/td&gt;&lt;td&gt;인프라만 (LK Cloud 옵션)&lt;/td&gt;&lt;td&gt;비쌈 ($0.13-0.30/min)&lt;/td&gt;&lt;td&gt;인프라&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;유연성&lt;/td&gt;&lt;td&gt;&lt;em&gt;높음&lt;/em&gt;&lt;/td&gt;&lt;td&gt;높음&lt;/td&gt;&lt;td&gt;&lt;em&gt;낮음&lt;/em&gt; (블랙박스)&lt;/td&gt;&lt;td&gt;&lt;em&gt;최고&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;시간&lt;/td&gt;&lt;td&gt;1-2주&lt;/td&gt;&lt;td&gt;1-2주&lt;/td&gt;&lt;td&gt;1-2일&lt;/td&gt;&lt;td&gt;1-3개월&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;pipecat&quot;&gt;Pipecat&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Frame[Frame] --&gt; P1[&quot;Input Processor (mic)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    P1 --&gt; P2[VAD Processor]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    P2 --&gt; P3[STT Processor]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    P3 --&gt; P4[LLM Processor]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    P4 --&gt; P5[Aggregator]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    P5 --&gt; P6[TTS Processor]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    P6 --&gt; P7[&quot;Output Processor (speaker)&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Frame 이 processor 파이프라인을 흐름&lt;/em&gt;. Linux pipe 의 기능적 추상. 컴포넌트 &lt;em&gt;한 줄 교체&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pipecat.pipeline.pipeline &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Pipeline&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pipecat.services.deepgram &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; DeepgramSTTService&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pipecat.services.openai &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; OpenAILLMService&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pipecat.services.cartesia &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; CartesiaTTSService&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pipecat.transports.services.daily &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; DailyTransport&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pipecat.vad.silero &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; SileroVADAnalyzer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;transport &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; DailyTransport(room_url, token, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Bot&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, DailyParams(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    audio_in_enabled&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    audio_out_enabled&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    vad_analyzer&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;SileroVADAnalyzer(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pipeline &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Pipeline([&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    transport.input(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    DeepgramSTTService(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;api_key&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    OpenAILLMService(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;api_key&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;model&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;gpt-4o-mini&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    CartesiaTTSService(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;api_key&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;voice_id&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    transport.output(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;runner &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; PipelineRunner()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; runner.run(PipelineTask(pipeline))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;pipecat-의-frame-종류&quot;&gt;Pipecat 의 Frame 종류&lt;/h3&gt;









































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Frame&lt;/th&gt;&lt;th&gt;의미&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;AudioRawFrame&lt;/code&gt;&lt;/td&gt;&lt;td&gt;오디오 청크&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;TextFrame&lt;/code&gt;&lt;/td&gt;&lt;td&gt;텍스트&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;TranscriptionFrame&lt;/code&gt;&lt;/td&gt;&lt;td&gt;전사&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;LLMResponseStartFrame&lt;/code&gt; / &lt;code&gt;EndFrame&lt;/code&gt;&lt;/td&gt;&lt;td&gt;LLM 응답 경계&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;TTSStartFrame&lt;/code&gt; / &lt;code&gt;EndFrame&lt;/code&gt;&lt;/td&gt;&lt;td&gt;TTS 시작/종료&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;UserStartedSpeakingFrame&lt;/code&gt;&lt;/td&gt;&lt;td&gt;사용자 발화 시작&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;UserStoppedSpeakingFrame&lt;/code&gt;&lt;/td&gt;&lt;td&gt;종료&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;InterruptionFrame&lt;/code&gt;&lt;/td&gt;&lt;td&gt;끼어들기&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Frame 종류 추가 = 새 processor 추가&lt;/em&gt;. 확장이 깔끔.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;livekit-agents&quot;&gt;LiveKit Agents&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User1[&quot;사용자 1&quot;] --&gt;|WebRTC| SFU[LiveKit SFU]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User2[&quot;사용자 2&quot;] --&gt;|WebRTC| SFU&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    SFU --&gt;|Room API| Agent[&quot;Voice Agent&amp;#x3C;br/&gt;(headless participant)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Agent --&gt; STT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Agent --&gt; LLM&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Agent --&gt; TTS&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;LiveKit SFU&lt;/em&gt; 가 &lt;em&gt;WebRTC + room&lt;/em&gt; 인프라. &lt;em&gt;Agent 가 room 에 headless participant 로 합류&lt;/em&gt; → 다중 사용자 회의 / 룸 기반 voice agent 자연스러움.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; livekit.agents &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; VoiceAssistant, AutoSubscribe, JobContext, WorkerOptions, cli&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; livekit.agents.llm &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ChatContext&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; livekit.plugins &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; openai, silero, deepgram, cartesia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; entrypoint&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ctx: JobContext):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ctx.connect(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;auto_subscribe&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;AutoSubscribe.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;AUDIO_ONLY&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    initial_ctx &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ChatContext().append(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;        role&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;system&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;        text&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;당신은 친절한 한국어 음성 어시스턴트입니다. 짧게 답하세요.&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    assistant &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; VoiceAssistant(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;        vad&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;silero.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;VAD&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.load(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;        stt&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;deepgram.STT(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;language&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ko&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;        llm&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;openai.LLM(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;model&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;gpt-4o-mini&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;        tts&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cartesia.TTS(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;voice&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;language&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ko&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;        chat_ctx&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;initial_ctx,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;        min_endpointing_delay&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;        allow_interruptions&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    assistant.start(ctx.room)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; assistant.aclose()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;pipecat-vs-livekit-agents-결정&quot;&gt;Pipecat vs LiveKit Agents 결정&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q1{시나리오}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q1 --&gt;|1:1 콜봇, 전화| Pipecat&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q1 --&gt;|다중 사용자 방, WebRTC 우선| LK[LiveKit Agents]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q1 --&gt;|화상 회의 + AI 참여자| LK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q1 --&gt;|복잡한 frame 변환| Pipecat&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q1 --&gt;|이미 LiveKit SFU 운영| LK&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Pipecat&lt;/th&gt;&lt;th&gt;LiveKit Agents&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Transport&lt;/td&gt;&lt;td&gt;Daily, Twilio, Plivo, FastAPI 등 다양&lt;/td&gt;&lt;td&gt;LiveKit SFU 중심&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;추상 단위&lt;/td&gt;&lt;td&gt;Frame + Processor&lt;/td&gt;&lt;td&gt;Function 기반&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;회의 / 룸&lt;/td&gt;&lt;td&gt;단순&lt;/td&gt;&lt;td&gt;&lt;em&gt;강력&lt;/em&gt; (Multi-participant)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Python&lt;/td&gt;&lt;td&gt;&lt;em&gt;우선&lt;/em&gt;&lt;/td&gt;&lt;td&gt;Python + Node + Go&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;학습&lt;/td&gt;&lt;td&gt;약간 가파름&lt;/td&gt;&lt;td&gt;친절한 docs&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;managed-vapi-retell&quot;&gt;Managed (Vapi, Retell)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    You[당신] --&gt;|시스템 프롬프트만| Vapi[Vapi / Retell]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Vapi --&gt;|호스팅 파이프라인| Tel[Twilio 전화]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Vapi --&gt;|기본 STT/LLM/TTS| Pipeline&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;




















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;장점&lt;/th&gt;&lt;th&gt;단점&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Vapi&lt;/td&gt;&lt;td&gt;5분 만에 PoC&lt;/td&gt;&lt;td&gt;&lt;em&gt;블랙박스&lt;/em&gt;, $0.13-0.30/min&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Retell&lt;/td&gt;&lt;td&gt;빠른 시작, 음성 좋음&lt;/td&gt;&lt;td&gt;동일, &lt;em&gt;latency 가시성 낮음&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;build-vs-buy-기준-hamming-ai-가이드&quot;&gt;Build vs Buy 기준 (Hamming AI 가이드)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q{기준}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|&quot;월 &amp;#x3C; 10K 분&quot;| Buy[Vapi / Retell]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|&quot;월 10-50K 분&quot;| Mid[&quot;Pipecat / LiveKit (자체)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|&quot;월 &gt; 50K 분&quot;| Build[자체 + 깊은 최적화]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|&quot;엄격한 컴플라이언스 (HIPAA, FINRA)&quot;| Build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|&quot;500ms 미만 지연 필수&quot;| Build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|&quot;기존 system 깊은 통합&quot;| Build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Build --&gt; Save[&quot;최대 80% 비용 절감 가능&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
&lt;em&gt;PoC = Vapi/Retell&lt;/em&gt;. &lt;em&gt;확장 시 → Pipecat/LiveKit 마이그레이션&lt;/em&gt; 흐름이 일반.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;복원력-설계&quot;&gt;복원력 설계&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q[복원력 요소]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt; Fail[Independent failure points: STT, LLM, TTS]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt; Strat[전략]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Strat --&gt; Retry[Retry + backoff]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Strat --&gt; Fallback[&quot;Fallback (다른 vendor)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Strat --&gt; Graceful[&quot;Graceful: #quot;잠시 후 다시#quot;&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Strat --&gt; Health[&quot;Health check + circuit breaker&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;각 단계 독립 실패 → 우아하게 처리. 자세한 건 [[retry-with-backoff]] / [[circuit-breaker]].&lt;/p&gt;
&lt;h2 id=&quot;흔한-함정&quot;&gt;흔한 함정&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Managed 만 사용&lt;/strong&gt; = 비용 폭증 + 가시성 0. 1000분+ 면 self-host.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pipecat 의 Frame 무시&lt;/strong&gt; = 직접 콜백으로 짜다가 &lt;em&gt;경합 / 순서 문제&lt;/em&gt;. Frame 모델 활용.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LiveKit 의 transcription frame&lt;/strong&gt; = STT 결과가 &lt;em&gt;partial vs final&lt;/em&gt; 분리 안 보임. 명시 처리.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;자체 구축 시 turn detection&lt;/strong&gt; = VAD 만으로 한계. 시맨틱 모델 필요. Pipecat / LK 가 내장한 이유.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[voice-agent-architecture]]&lt;/li&gt;
&lt;li&gt;[[vad-silero]]&lt;/li&gt;
&lt;li&gt;[[turn-detection-barge-in]]&lt;/li&gt;
&lt;li&gt;[[webrtc]]&lt;/li&gt;
&lt;li&gt;[[circuit-breaker]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>pipecat</category><category>livekit</category><category>voice-framework</category><category>agent</category><category>sfu</category><author>koa (김신건)</author></item><item><title>[Voice AI] Voice RAG: 지연 병목 + 예측적 프리페치</title><link>https://shinkeonkim.com/wiki/ai/voice-rag/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/ai/voice-rag/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Voice RAG&lt;/strong&gt; = 음성 에이전트에 &lt;em&gt;RAG (Retrieval-Augmented Generation)&lt;/em&gt; 결합. &lt;em&gt;벡터 DB 조회&lt;/em&gt; 가 &lt;em&gt;지연 누적&lt;/em&gt; 의 큰 원인이 되므로 &lt;em&gt;예측적 프리페치&lt;/em&gt; 같은 패턴 필수.&lt;/p&gt;
&lt;h2 id=&quot;기본-흐름&quot;&gt;기본 흐름&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User-&gt;&gt;STT: 발화&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    STT-&gt;&gt;RAG: 질문 텍스트&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    RAG-&gt;&gt;Embed: 임베딩&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Embed-&gt;&gt;VectorDB: kNN search&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VectorDB--&gt;&gt;RAG: top-K chunks&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    RAG-&gt;&gt;LLM: prompt + chunks&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    LLM--&gt;&gt;TTS: 응답 토큰&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    TTS--&gt;&gt;User: 음성&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;각 단계가 직렬&lt;/em&gt;. RAG 추가 &lt;em&gt;200-1000ms&lt;/em&gt; → 종단 지연 &lt;em&gt;2초+&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;지연-분해&quot;&gt;지연 분해&lt;/h2&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;단계&lt;/th&gt;&lt;th&gt;일반&lt;/th&gt;&lt;th&gt;최적&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Embedding&lt;/td&gt;&lt;td&gt;50-200ms&lt;/td&gt;&lt;td&gt;30ms (로컬 small 모델)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Vector DB query&lt;/td&gt;&lt;td&gt;30-200ms&lt;/td&gt;&lt;td&gt;10ms (Redis vector, ES kNN)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Re-ranking&lt;/td&gt;&lt;td&gt;100-500ms&lt;/td&gt;&lt;td&gt;50ms (cross-encoder small)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LLM prompt assembly&lt;/td&gt;&lt;td&gt;5-20ms&lt;/td&gt;&lt;td&gt;5ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;RAG overhead&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;200-1000ms&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;&amp;#x3C; 100ms&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;예측적-프리페치-speculative-retrieval&quot;&gt;예측적 프리페치 (Speculative Retrieval)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Partial[Partial transcript] --&gt; Predict[가능 의도 예측]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Predict --&gt; Pre[&quot;미리 fetch (병렬)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Final[Final transcript] --&gt; Match{예측 매칭?}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Match --&gt;|예| UsePre[프리페치 결과 사용]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Match --&gt;|아니오| Re[다시 fetch]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SpeculativeRAG&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; __init__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.prefetched: Dict[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Future] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; on_partial&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self, partial: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;&quot;&quot;partial 받자마자 예측 fetch 시작&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(partial.split()) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;   # 너무 짧으면 skip&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        # 이미 fetch 중인 것이 있고 유사하면 재사용&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; any&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;._similar(partial, k) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; k &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.prefetched):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        # 미리 fetch (병렬)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        fut &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; asyncio.create_task(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;._retrieve(partial))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.prefetched[partial] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; fut&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; on_final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self, final: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) -&gt; List[Chunk]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;&quot;&quot;final 시 prefetched 결과 활용 또는 새로 fetch&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        # 가장 유사한 prefetched 찾기&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        best &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; max&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.prefetched.keys(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;                   key&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=lambda&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; k: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;._similarity(k, final),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;                   default&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;None&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; best &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;._similarity(best, final) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0.85&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.prefetched[best]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;._retrieve(final)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;partial 받자마자 &lt;em&gt;추측 fetch&lt;/em&gt;&lt;/em&gt; → final 시 &lt;em&gt;대부분 즉시 사용 가능&lt;/em&gt;. RAG overhead → 0 에 가깝게.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;캐시-계층&quot;&gt;캐시 계층&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q[Query] --&gt; L1[&quot;L1: in-memory recent (LRU)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    L1 -.miss.-&gt; L2[L2: Redis semantic cache]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    L2 -.miss.-&gt; L3[L3: Vector DB]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    L3 --&gt; Pop[populate L2 + L1]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;semantic-cache&quot;&gt;Semantic Cache&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SemanticCache&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;&quot;&quot;비슷한 질문의 결과 재사용&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; __init__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self, similarity_threshold&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.92&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.cache &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {}   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# embedding → result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.threshold &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; similarity_threshold&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self, query: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        emb &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; embed(query)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; cached_emb, result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.cache.items():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            sim &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; cosine_similarity(emb, cached_emb)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sim &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.threshold:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; None&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;자세한 건 [[Redis Vector Search]] 의 semantic cache.&lt;/p&gt;
&lt;h2 id=&quot;rag-인덱스-선택-음성-환경&quot;&gt;RAG 인덱스 선택 (음성 환경)&lt;/h2&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Pinecone&lt;/th&gt;&lt;th&gt;Redis Vector&lt;/th&gt;&lt;th&gt;ES kNN&lt;/th&gt;&lt;th&gt;Qdrant&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Latency (kNN)&lt;/td&gt;&lt;td&gt;30-100ms&lt;/td&gt;&lt;td&gt;5-20ms&lt;/td&gt;&lt;td&gt;20-50ms&lt;/td&gt;&lt;td&gt;10-30ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;운영&lt;/td&gt;&lt;td&gt;managed&lt;/td&gt;&lt;td&gt;익숙&lt;/td&gt;&lt;td&gt;익숙&lt;/td&gt;&lt;td&gt;중간&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Hybrid (BM25 + vector)&lt;/td&gt;&lt;td&gt;X&lt;/td&gt;&lt;td&gt;별도&lt;/td&gt;&lt;td&gt;&lt;em&gt;우수 (RRF)&lt;/em&gt;&lt;/td&gt;&lt;td&gt;가능&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;음성 에이전트 + 한국어 hybrid search = &lt;em&gt;ElasticSearch kNN + nori&lt;/em&gt; 가 강력.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;청크-전략-음성-친화&quot;&gt;청크 전략 (음성 친화)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 일반 RAG: 큰 청크 (500-1000 tokens)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 음성 RAG: *짧은 청크* (100-300 tokens) → LLM 응답 짧게 유도&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; chunk_for_voice&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(doc: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) -&gt; list[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;&quot;&quot;문장 단위 + 의미 단위 분할&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    sentences &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nltk.sent_tokenize(doc, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;language&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;korean&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    chunks &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    cur &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; s &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sentences:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(cur) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(s) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 300&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            chunks.append(cur)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            cur &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            cur &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; cur:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        chunks.append(cur)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chunks&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;re-ranking-의-trade-off&quot;&gt;Re-ranking 의 trade-off&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VS[Vector Search top 50] --&gt; Re[Re-ranker]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Re --&gt; Top5[top 5]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Re --&gt; Cost[+100-500ms]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;정확도 ↑ vs 지연 ↑&lt;/em&gt;. 음성 에이전트는 &lt;em&gt;작은 cross-encoder&lt;/em&gt; (Cohere rerank-v3 light, BAAI bge-reranker-base) 권장.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;흔한-함정&quot;&gt;흔한 함정&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;RAG 매 turn 동기 fetch&lt;/strong&gt; = 매 응답 200-1000ms 증가. &lt;em&gt;예측적 프리페치&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;거대 청크&lt;/strong&gt; = LLM 응답이 길어짐. 짧은 청크.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-encoder rerank 무조건&lt;/strong&gt; = 500ms+ 부담. &lt;em&gt;trade-off&lt;/em&gt; 결정.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;결과 그대로 prompt&lt;/strong&gt; = 토큰 폭증. 요약 또는 selection.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[voice-agent-architecture]]&lt;/li&gt;
&lt;li&gt;[[voice-first-prompt]]&lt;/li&gt;
&lt;li&gt;[[elasticsearch-vector-search]]&lt;/li&gt;
&lt;li&gt;[[Redis Vector Search]]&lt;/li&gt;
&lt;li&gt;[[latency-percentiles]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>voice-rag</category><category>rag</category><category>vector-db</category><category>latency</category><category>prefetch</category><author>koa (김신건)</author></item><item><title>[Voice AI] 음성 에이전트 아키텍처: Cascading / Streaming / S2S + Latency Budget</title><link>https://shinkeonkim.com/wiki/ai/voice-agent-architecture/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/ai/voice-agent-architecture/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;실시간 음성 AI 의 &lt;em&gt;3가지 패턴&lt;/em&gt;. 각자 &lt;em&gt;지연 vs 유연성 vs 비용&lt;/em&gt; 트레이드오프.&lt;/p&gt;
&lt;h2 id=&quot;3-패턴-비교&quot;&gt;3 패턴 비교&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    subgraph Cascading[&quot;1. Cascading (순차)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        C1[STT] --&gt; C2[LLM] --&gt; C3[TTS]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        Note1[&quot;2-4초 지연 (직렬)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    subgraph Streaming[&quot;2. Streaming (병행)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        S1[STT chunks] -.partial.-&gt; S2[LLM streaming]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        S2 -.tokens.-&gt; S3[TTS streaming]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        Note2[&quot;&amp;#x3C; 1초 지연 (병행)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    subgraph S2S[&quot;3. Speech-to-Speech&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        D1[Audio In] --&gt; D2[Multimodal Model]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        D2 --&gt; D3[Audio Out]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        Note3[&quot;&amp;#x3C; 300ms (직접 처리)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;



























































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Cascading&lt;/th&gt;&lt;th&gt;Streaming&lt;/th&gt;&lt;th&gt;S2S&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;종단 지연&lt;/td&gt;&lt;td&gt;&lt;em&gt;2-4초&lt;/em&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;&amp;#x3C; 1초&lt;/em&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;&amp;#x3C; 300ms&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;구현 난이도&lt;/td&gt;&lt;td&gt;쉬움&lt;/td&gt;&lt;td&gt;중간&lt;/td&gt;&lt;td&gt;어려움 (제약)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;유연성&lt;/td&gt;&lt;td&gt;&lt;em&gt;최고&lt;/em&gt; (각 단계 교체)&lt;/td&gt;&lt;td&gt;높음&lt;/td&gt;&lt;td&gt;&lt;em&gt;낮음&lt;/em&gt; (벤더 lock)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;비용&lt;/td&gt;&lt;td&gt;낮음&lt;/td&gt;&lt;td&gt;중간&lt;/td&gt;&lt;td&gt;&lt;em&gt;높음&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Function calling&lt;/td&gt;&lt;td&gt;OK&lt;/td&gt;&lt;td&gt;OK&lt;/td&gt;&lt;td&gt;&lt;em&gt;제한&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;톤/감정 보존&lt;/td&gt;&lt;td&gt;X&lt;/td&gt;&lt;td&gt;X&lt;/td&gt;&lt;td&gt;&lt;em&gt;예&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;한국어&lt;/td&gt;&lt;td&gt;모델 마다&lt;/td&gt;&lt;td&gt;모델 마다&lt;/td&gt;&lt;td&gt;일부 (Realtime API 한국어)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;사용&lt;/td&gt;&lt;td&gt;MVP / 일반&lt;/td&gt;&lt;td&gt;&lt;em&gt;프로덕션 표준&lt;/em&gt;&lt;/td&gt;&lt;td&gt;고급 UX&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;1-cascading-순차&quot;&gt;1. Cascading (순차)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User-&gt;&gt;STT: 발화 (3초)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Note over STT: 발화 종료 대기 + 전사 (500ms)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    STT-&gt;&gt;LLM: 전체 텍스트&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Note over LLM: 응답 생성 (1500ms)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    LLM-&gt;&gt;TTS: 전체 응답&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Note over TTS: 음성 합성 (800ms)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    TTS-&gt;&gt;User: 음성 시작&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Note over User,TTS: 총: ~3초 지연&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; cascaded_pipeline&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(audio_url):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    transcript &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stt.transcribe(audio_url)   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 발화 끝나길 기다림&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    response &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; llm.chat(transcript)           &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 전체 응답&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    audio &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tts.synthesize(response)          &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 전체 합성&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; audio&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;MVP 에는 OK&lt;/em&gt;. 프로덕션은 &lt;em&gt;streaming&lt;/em&gt; 으로 진화.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;2-streaming-현재-표준&quot;&gt;2. Streaming (현재 표준)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User-&gt;&gt;STT: 발화 (3초)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    par&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        STT--&gt;&gt;LLM: partial &quot;안녕&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        STT--&gt;&gt;LLM: partial &quot;안녕하세요&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        STT--&gt;&gt;LLM: FINAL &quot;안녕하세요, 오늘 회의&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        LLM--&gt;&gt;TTS: 토큰 &quot;오늘은&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        LLM--&gt;&gt;TTS: 토큰 &quot;수요일입니다&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        TTS--&gt;&gt;User: 오디오 청크 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        TTS--&gt;&gt;User: 오디오 청크 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Note over User: 음성 종료 후 &amp;#x3C; 1초 응답&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; streaming_pipeline&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(audio_stream):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; transcript_chunk &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stt.stream(audio_stream):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; transcript_chunk.is_final:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; token &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; llm.stream(transcript_chunk.text):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                sentence &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; aggregator.feed(token)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sentence:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                    async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; audio_chunk &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tts.stream(sentence):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                        yield&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; audio_chunk&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
&lt;em&gt;모든 단계 스트리밍 + sentence aggregator&lt;/em&gt;. 2026 시점 &lt;em&gt;프로덕션 음성 AI 의 표준&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;3-speech-to-speech-s2s&quot;&gt;3. Speech-to-Speech (S2S)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User-&gt;&gt;Realtime: 오디오 stream (WebRTC / WS)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Note over Realtime: GPT-4o / Gemini Live&amp;#x3C;br/&gt;(직접 오디오 처리)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Realtime--&gt;&gt;User: 오디오 stream (&amp;#x3C; 300ms)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;모델&lt;/th&gt;&lt;th&gt;출시&lt;/th&gt;&lt;th&gt;한국어&lt;/th&gt;&lt;th&gt;특징&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;OpenAI Realtime API (GPT-4o)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;2024-10&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;WebRTC / WS, function calling 부분&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Gemini Live (gemini-live-2.5)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;2024-12&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;Google AI Studio&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Moshi (Kyutai)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;OSS&lt;/td&gt;&lt;td&gt;영어&lt;/td&gt;&lt;td&gt;full-duplex, 자체 호스팅&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;[!CAUTION]
S2S 의 &lt;em&gt;function calling 제약&lt;/em&gt; = enterprise 시스템 연동 어려움. &lt;em&gt;function 이 필수면 cascading + streaming&lt;/em&gt; 채택. [arXiv 참조].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;latency-budget-지연-예산&quot;&gt;Latency Budget (지연 예산)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Mic[&quot;마이크 (사용자 발화 끝)&quot;] --&gt;|VAD endpointing 200-500ms| STT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    STT --&gt;|&quot;STT (100-500ms)&quot;| LLM&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    LLM --&gt;|&quot;LLM TTFT (200-2000ms)&quot;| TTS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    TTS --&gt;|&quot;TTS TTFA (200-800ms)&quot;| Speaker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Speaker --&gt;|&amp;#x3C;= 1000ms| User&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;


















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;단계&lt;/th&gt;&lt;th&gt;일반&lt;/th&gt;&lt;th&gt;최적&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Network (Mic → Server)&lt;/td&gt;&lt;td&gt;30-100ms&lt;/td&gt;&lt;td&gt;20ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VAD endpointing&lt;/td&gt;&lt;td&gt;500ms&lt;/td&gt;&lt;td&gt;200ms (시맨틱)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;STT (final)&lt;/td&gt;&lt;td&gt;200-500ms&lt;/td&gt;&lt;td&gt;100ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LLM TTFT (Time-to-First-Token)&lt;/td&gt;&lt;td&gt;500-2000ms&lt;/td&gt;&lt;td&gt;200ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Sentence aggregation&lt;/td&gt;&lt;td&gt;50-200ms&lt;/td&gt;&lt;td&gt;0 (streaming)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;TTS TTFB&lt;/td&gt;&lt;td&gt;200-800ms&lt;/td&gt;&lt;td&gt;90ms (Cartesia)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Network (Server → Speaker)&lt;/td&gt;&lt;td&gt;30-100ms&lt;/td&gt;&lt;td&gt;20ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;총&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;2-4초&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;&amp;#x3C; 700ms&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
&lt;em&gt;800ms 가 “로봇 같지 않게 느껴지는” 임계&lt;/em&gt;. 사람 평균 응답 300-500ms. &lt;em&gt;모든 단계 동시 최적화&lt;/em&gt; 필요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;단계별-최적화&quot;&gt;단계별 최적화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Opt[지연 줄이기]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Opt --&gt; S1[STT: 시맨틱 endpointing, partial 안 기다림]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Opt --&gt; S2[LLM: 작은 모델, TTFT 최우선, KV-cache]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Opt --&gt; S3[TTS: streaming + Cartesia급 모델]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Opt --&gt; Net[Network: WebRTC &amp;#x3C; WebSocket &amp;#x3C; HTTP]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Opt --&gt; Hop[Hop 축소: 같은 region, edge]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;결정-트리&quot;&gt;결정 트리&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q1{지연 요구}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q1 --&gt;|&amp;#x3C; 300ms 필수| S2S_check{Function calling 필수?}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q1 --&gt;|&amp;#x3C; 1초 OK| Stream[Streaming pipeline]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q1 --&gt;|2-3초 OK + MVP| Cascade[Cascading]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    S2S_check --&gt;|아니오| S2S[S2S 모델]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    S2S_check --&gt;|예| Stream&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;한국-시장-권장&quot;&gt;한국 시장 권장&lt;/h2&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;시나리오&lt;/th&gt;&lt;th&gt;권장&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;콜봇 (상담)&lt;/td&gt;&lt;td&gt;Streaming: CLOVA STT + GPT-4o-mini + CLOVA Voice&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;고급 음성 AI&lt;/td&gt;&lt;td&gt;Streaming: Deepgram + GPT-4o + Cartesia&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;비용 절감&lt;/td&gt;&lt;td&gt;Cascading: Whisper + GPT-3.5 + Edge TTS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;톤/감정 critical&lt;/td&gt;&lt;td&gt;S2S: GPT-4o Realtime&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;흔한-함정&quot;&gt;흔한 함정&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;STT/LLM/TTS 각자 다른 region&lt;/strong&gt; = network hop 누적 → 500ms+. 같은 region.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;batch 모델로 시작했다가 latency 못 맞춤&lt;/strong&gt; = 처음부터 streaming 모델.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LLM 응답 끝나길 기다리고 TTS 시작&lt;/strong&gt; = TTS 의 streaming 의미 없음.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VAD 없이 STT&lt;/strong&gt; = STT 가 &lt;em&gt;전사 못 끝남&lt;/em&gt;. 발화 종료 감지 필수.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[stt-streaming]]&lt;/li&gt;
&lt;li&gt;[[tts-streaming-ssml]]&lt;/li&gt;
&lt;li&gt;[[speech-to-speech-realtime]]&lt;/li&gt;
&lt;li&gt;[[vad-silero]]&lt;/li&gt;
&lt;li&gt;[[turn-detection-barge-in]]&lt;/li&gt;
&lt;li&gt;[[latency-percentiles]]&lt;/li&gt;
&lt;li&gt;[[pipecat-livekit]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>voice-agent</category><category>architecture</category><category>latency</category><category>streaming</category><category>cascading</category><category>s2s</category><author>koa (김신건)</author></item><item><title>[Voice AI] 음성 우선 프롬프트 + Function Calling + Structured Output</title><link>https://shinkeonkim.com/wiki/ai/voice-first-prompt/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/ai/voice-first-prompt/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;음성-우선-프롬프트-설계&quot;&gt;음성 우선 프롬프트 설계&lt;/h2&gt;
&lt;p&gt;음성 답변 = &lt;em&gt;귀로 듣는다&lt;/em&gt;. 텍스트 답변과 &lt;em&gt;완전 다르게&lt;/em&gt; 짜야 한다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Text[&quot;텍스트 답변 (긴 답변 OK)&quot;] --&gt; A1[&quot;**bold**, # 헤딩, 표&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Voice[&quot;음성 답변 (짧고 자연스럽게)&quot;] --&gt; A2[&quot;1-2 문장, 의문문으로 turn 넘김&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    A1 --&gt; Diff&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    A2 --&gt; Diff&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Diff{둘은 완전 다름}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;음성-프롬프트의-핵심-원칙&quot;&gt;음성 프롬프트의 핵심 원칙&lt;/h2&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;원칙&lt;/th&gt;&lt;th&gt;의미&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;짧게&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;한 답변 1-2 문장. 50-80 글자&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;자연스럽게&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;”$5 = ‘오 달러’” (숫자 정규화 사전 정의)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;마크다운 금지&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;**&lt;/code&gt;, &lt;code&gt;#&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt; 등 모두 &lt;em&gt;음성에 안 들어감&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;listicle 분해&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;”1, 2, 3…” 대신 &lt;em&gt;대화로 분배&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;turn 넘기기&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;질문으로 끝내거나 “도와드릴까요?”&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;에스컬레이션&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;”사람 상담원 연결해드릴까요?” 명시&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;SYSTEM_PROMPT&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;당신은 친절한 한국어 콜센터 상담원입니다.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;응답 규칙:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;- 한 응답은 *1-2 문장* 으로 짧게&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;- 자연스러운 구어체 사용 (&quot;입니다&quot; 보다 &quot;이에요&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;- 숫자는 풀어쓰기 (예: &quot;100만 원&quot; 보다 &quot;백만 원&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;- 마크다운, 영어 약어, 코드 사용 금지&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;- 모르는 정보면 &quot;확인이 어렵네요. 사람 상담원 연결해드릴까요?&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;- 답변 끝에 *질문* 으로 turn 을 사용자에게 넘김&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;페르소나:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;- 침착하고 공감하는 톤&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;- 고객을 &quot;고객님&quot; 으로 호칭&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;- 절대 &quot;AI&quot; 라고 본인을 칭하지 말 것&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;function--tool-calling&quot;&gt;Function / Tool Calling&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    autonumber&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User-&gt;&gt;Agent: &quot;내 주문 상태 확인해줘&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Agent-&gt;&gt;LLM: prompt + tool definitions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    LLM--&gt;&gt;Agent: function_call: get_order_status(user_id=42)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Agent-&gt;&gt;API: GET /orders?user=42&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    API--&gt;&gt;Agent: { status: &quot;shipped&quot;, eta: &quot;내일&quot; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Agent-&gt;&gt;LLM: tool_result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    LLM--&gt;&gt;Agent: &quot;고객님 주문은 배송 중이며, 내일 도착 예정이에요.&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Agent-&gt;&gt;TTS: 음성 합성&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    TTS-&gt;&gt;User: 음성 응답&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;openai-function-calling&quot;&gt;OpenAI Function Calling&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tools &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;function&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;function&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            &quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;get_order_status&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            &quot;description&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;사용자의 주문 상태를 조회합니다&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            &quot;parameters&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;object&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                &quot;properties&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                    &quot;user_id&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;integer&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;사용자 ID&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                    &quot;order_id&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;주문 ID (선택)&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                &quot;required&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;user_id&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;function&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;function&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            &quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;transfer_to_human&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            &quot;description&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;사람 상담원에게 연결합니다&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            &quot;parameters&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;object&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                &quot;properties&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                    &quot;reason&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                    &quot;priority&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;enum&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;low&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;high&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                &quot;required&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;reason&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;response &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; client.chat.completions.create(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    model&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;gpt-4o-mini&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    messages&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;messages,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    tools&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tools,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    tool_choice&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;auto&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    stream&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;병렬-function-calling&quot;&gt;병렬 Function Calling&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 같은 응답에서 여러 함수 동시 호출 가능&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  &quot;tool_calls&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    { &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;call_1&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;function&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: { &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;get_weather&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;arguments&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; } },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    { &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;call_2&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;function&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: { &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;get_traffic&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;arguments&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; } }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 병렬 실행&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;results &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; asyncio.gather(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    get_weather(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    get_traffic(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;직렬&lt;/em&gt; 보다 &lt;em&gt;수배 빠름&lt;/em&gt;. 독립 호출이면 활용.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;결과를-대화에-자연스럽게&quot;&gt;결과를 대화에 자연스럽게&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;@function_tool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; get_order_status&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(user_id: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;dict&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    order &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; db.get_order(user_id)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;status&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: order.status,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;eta&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: order.eta,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        # 함수 결과는 *데이터* 만. *음성 문장* 은 LLM 이 합성&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 잘못된 예: 함수가 문장 반환&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;@function_tool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; get_order_status_bad&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(user_id: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    order &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; db.get_order(user_id)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;주문 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;order.id&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; 는 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;order.status&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; 상태이며 ETA &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;order.eta&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; 입니다.&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # ← TTS 가 &quot;ETA&quot; 를 영어로 발음하거나 어색&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;structured-output&quot;&gt;Structured Output&lt;/h2&gt;
&lt;p&gt;LLM 응답을 &lt;em&gt;JSON schema 강제&lt;/em&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; IntentExtraction&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;BaseModel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    intent: Literal[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;order_status&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;refund&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;complaint&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;transfer&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;other&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    user_id: Optional[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    order_id: Optional[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    urgency: Literal[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;low&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;normal&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;high&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;response &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; client.chat.completions.parse(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    model&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;gpt-4o-mini&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    messages&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[{&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;role&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: user_text}],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    response_format&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;IntentExtraction,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;intent &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; response.choices[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].message.parsed&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# intent.intent == &quot;order_status&quot;  ← 타입 안전&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;슬롯-채우기-slot-filling&quot;&gt;슬롯 채우기 (Slot Filling)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 사용자가 부분 정보만 주면 → 부족한 슬롯 묻기&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; BookingRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;BaseModel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    restaurant: Optional[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    date: Optional[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    party_size: Optional[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    is_complete: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; False&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 첫 발화: &quot;내일 5명 예약하고싶어&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# extracted: { date: &quot;내일&quot;, party_size: 5, restaurant: None, is_complete: false }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# LLM 이 부족한 정보 *질문*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; extracted.restaurant:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    response &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;어느 식당으로 예약 도와드릴까요?&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;페르소나-일관성&quot;&gt;페르소나 일관성&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;PERSONA&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;이름: 민지&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;성격: 친절, 차분, 약간 유머&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;역할: 카페 음성 주문 도우미&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;말투: 격식 있는 존댓말 (&quot;이에요&quot;, &quot;괜찮으세요?&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;금지: 비속어, 정치/종교, 의료 조언&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;SYSTEM&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{PERSONA}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;응답 규칙:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;- 항상 페르소나 일관성 유지&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;- 메뉴 외 질문은 정중히 거절 + 본업으로 유도&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;흔한-함정&quot;&gt;흔한 함정&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;시스템 프롬프트가 &lt;em&gt;길고 마크다운&lt;/em&gt;&lt;/strong&gt; = TTS 가 안 읽지만, &lt;em&gt;LLM 의 응답이 마크다운 따라함&lt;/em&gt;. 출력 형식 명시.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;숫자 발음&lt;/strong&gt; = “1500000원” → “일오영영영영영원”. &lt;em&gt;별도 정규화&lt;/em&gt; 또는 SSML.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;function 결과로 &lt;em&gt;긴 텍스트 반환&lt;/em&gt;&lt;/strong&gt; = LLM 이 그대로 &lt;em&gt;읽음&lt;/em&gt;. 데이터만.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;tool calling 중 &lt;em&gt;interruption 허용&lt;/em&gt;&lt;/strong&gt; = DB write 중간에 끊김. &lt;code&gt;disallow_interruptions&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[voice-agent-architecture]]&lt;/li&gt;
&lt;li&gt;[[voice-rag]]&lt;/li&gt;
&lt;li&gt;[[agent-patterns]]&lt;/li&gt;
&lt;li&gt;[[turn-detection-barge-in]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>prompt</category><category>function-calling</category><category>structured-output</category><category>voice-llm</category><author>koa (김신건)</author></item></channel></rss>