
Perplexity 스타일의 Q&A 에이전트를 개인 개발 앱에 통합 — 6단계로 나눈 설계의 노하우
요약
Perplexity 스타일의 Q&A 에이전트를 개인 프로젝트에 통합하기 위한 6단계 설계 노하우를 공유합니다. 세이프티 체크부터 답변 생성까지의 전체 워크플로우와 실시간 스트리밍 구현 방식을 다룹니다.
핵심 포인트
- 6단계 공정(Safety, Context, Planning, Search, Review, Generation) 설계
- 가벼운 LLM을 활용한 사전 세이프티 체크 및 정책 차단 상태 분리
- Redis Streams와 SSE를 이용한 실시간 진행 상황 및 답변 스트리밍
- 검색 필요 여부를 판단하는 플래닝 단계의 중요성
서론
외부 웹 검색과 애플리케이션 내에서 사전에 AI로 분석한 독자적인 내부 기사를 결합하여, 출처가 포함된 답변을 반환하는 — 그런 "Perplexity 스타일의 Q&A 에이전트"를, 개인 개발 중인 해외 테크 뉴스 수집·분석 앱 『Vector』에 통합했습니다.
첨단 기술을 활용한 뛰어난 프로덕트 경험에 개인 개발로 어디까지 다가갈 수 있는가에 대한 시도와 설계의 노하우, 그리고 구현을 통해 드러난 현시점의 과제를 공유하고자 합니다.
소스 코드도 공개하고 있으니, 조금이라도 참고가 된다면 기쁘겠습니다.
GitHub 리포지토리: https://github.com/yook11/Vector -
실제 서비스 사이트: https://vectorbrief.online
(※ 실제 동작을 확인하실 수 있으나, 사용자 등록 및 이용은 초대제로 운영됩니다)
전체상
에이전트의 인터페이스는 대화 형식의 UI입니다.
사용자의 질문은 백그라운드의 Worker에서 비동기적으로 처리되며, 그 진행 상황(실행 중인 공정이나 검색 쿼리) 및 생성 중인 답변 텍스트는 Redis Streams (운영 환경: ElastiCache Valkey) + SSE의 조합으로 브라우저에 실시간 스트리밍됩니다.
전체 처리 플로우는 다음과 같은 6가지 공정으로 진행됩니다.
Safety Check (세이프티 체크)
사용자의 입력이 정책을 위반하지 않았는지, 위험한 내용을 포함하고 있지 않은지를 가볍게 체크하는 계층입니다. -
Context Gathering (컨텍스트 정리)
사용자의 요구에 정확히 답하기 위해, "지금 무엇을 요구받고 있는가"라는 대화의 컨텍스트 (Context)를 정리합니다. -
Planning (플래닝)
질문에 대해 어떻게 접근할지를 결정합니다. 먼저 "직접 답변할 수 있는지, 검색이 필요한지"를 판단하고, 검색이 필요한 경우에는 구체적인 검색 플랜을 세웁니다. -
Search (에비던스 수집)
Planning에서 세운 검색 플랜에 따라 외부 검색과 내부 검색을 실행하여, 답변의 근거가 되는 정보를 수집합니다. -
Evidence Review (에비던스 리뷰)
수집한 정보 중에서 플랜에 대해 유효한 정보(근거)를 선별합니다. -
답변 생성
Evidence Review에서 선별된 근거를 사용하여 최종적인 출처 포함 답변을 생성합니다.
Planning에서 "검색 불필요"라고 판단된 경우에는 검색을 수행하지 않고 그대로 질문에 답변합니다.
공정별 노하우
1. Safety Check (세이프티 체크)
첫 번째 공정에서는 사용자의 질문이 안전 정책상 처리해도 되는 것인지를 판정합니다.
에이전트 아키텍처에 대해 조사하던 중, "무거운 본체 처리에 들어가기 전에 가벼운 모델로 사전 체크를 거친다"라는 프랙티스 (Practice)를 알게 되어 제 앱에도 도입해 보았습니다. 실제 판정은 가벼운 LLM 콜 (Call)로 수행합니다.
여기서 고안한 점은 판정 그 자체보다 "차단 상태의 처리"입니다.
시스템 에러에 의한 실패 (failed) 와는 명확히 구분하여, "정책에 의한 차단 (policy_blocked) "이라는 전용 종료 상태를 마련했습니다.
에러 상태와 분리함으로써 다음과 같은 장점이 있습니다.
운영 측면: 시스템 에러가 아니므로 불필요한 재시도(Retry) 처리나 버그 조사 대상에서 제외할 수 있음 -
UI/UX 측면: 단순한 "에러가 발생했습니다"가 아니라, "정책에 의해 처리되지 않았습니다"라고 사용자에게 적절한 피드백을 줄 수 있음
참고로 구체적인 차단 이유는 사용자에게 반환하지 않습니다.
사용자에게는 고정된 문구만을 표시하고, 상세한 이유는 내부 로그와 메트릭스 (Metrics)에만 남기는 설계로 하고 있습니다.
2. Context Gathering (컨텍스트 정리)
이 부분은 구현 단계에서 저에게 큰 맹점이었던 부분입니다.
평소 코딩 에이전트 등을 사용하고 있으면 과거의 대화 내용을 자동으로 고려하여 답변해 줍니다.
하지만 직접 LLM을 호출하는 로직을 구현해 보니, "지금까지의 대화 이력은 매번 이쪽에서 전달하지 않는 한 모델 측에는 남지 않는다"라는 당연한 사양을 새삼 깨닫게 되었고, 이 공정을 마련하기로 했습니다.
그렇다고 해서 과거의 대화 이력을 그대로 후속 공정(플래닝이나 답변 생성)에 전달할 수는 없습니다. 대화가 이어질수록 텍스트가 길어져 필요 이상으로 컨텍스트 윈도우 (Context Window, 토큰 수)를 압박하기 때문입니다.
그래서 "후속 공정에 과거 대화에서 어떤 정보가 필요한가"를 정밀하게 검토하여, 필요한 정보만을 추출하여 전달하는 설계로 만들었습니다.
구체적으로는, 가장 최근의 대화 이력을 바탕으로 다음과 같은 요소를 추출 및 정리합니다.
추상적인 질문의 구체화 (컨텍스트 보완)
예를 들어 "그거, 더 자세히"와 같이 지시어를 포함한 추상적인 질문이 들어올 경우, 그대로 후속 공정에 전달하면 "그거"가 무엇인지 알 수 없습니다. 따라서 과거 이력을 바탕으로 "NVIDIA의 실적에 대해 더 자세히"와 같이, 단독으로도 의미가 통하는 구체적인 질문문으로 변환합니다. -
답변이 충족해야 할 조건
사용자의 요구에 대해 충족해야 할 조건을 정리하여, 답변이 의도에서 벗어나지 않도록 초점을 좁힙니다. -
답변 완료 내용의 정리
과거 턴(Turn)에서 이미 설명한 내용 중 이번 질문과 관련된 부분을 정리하여, AI가 동일한 답변을 반복하는 것을 방지하기 위해 후속 공정으로 인계합니다. -
스레드 전체의 목적
"투자 판단을 위해 조사하고 싶다"와 같이, 스레드 전체에서 공통되는 목적을 정리합니다.
후속 공정에서 이 목적을 고려하여 처리 방침을 결정함으로써, 단발적인 질문문만 보는 것보다 사용자의 의도에 부합하는 답변이 가능해집니다.
기타 고안 사항: 이력은 요약하지 않음 · 실패 시 축퇴 (Fallback)
이 공정에 입력하는 과거의 대화 이력 자체는 "요약"하지 않습니다.
요약 자체의 품질 문제(할루시네이션 (Hallucination) 등)를 가져올 리스크가 있기 때문에, 최근 6개의 메시지를 각각 2,000자 상한으로 전달하고 있습니다.
또한, 이 컨텍스트 정리 단계에서 실패할 경우에는 사용자의 질문 원문을 그대로 사용하여 다음 공정으로 진행하도록 하고 있습니다.
보조적인 공정의 에러로 인해 처리 전체가 실패하지 않도록 하기 위한 설계입니다.
3. Planning (플래닝)
이 공정에는 크게 나누어 "애초에 검색이 필요한지 여부의 판단"과 "검색할 경우의 계획 책정"이라는 두 가지 역할을 부여했습니다.
검색 필요 여부의 판단 (비용과 시간 절약)
인사나 앱 사용법 등 외부의 사실 확인이 불필요한 질문에 대해서는 검색을 수행하지 않고, 그대로 "직접 답변" 공정으로 스킵시킵니다.
이를 통해 불필요한 LLM 콜 (LLM Call)을 줄여 비용을 절약하고, 응답 속도도 높이고 있습니다.
검색을 수행할지 여부에 대한 판단은, 조금이라도 망설여질 경우에는 "검색을 실행한다" 쪽으로 기울어지도록 지시하고 있습니다.
검색이 필요한 정보를 놓치면 오답으로 이어지기 때문에, 안전한 방향으로 설정하여 답변의 품질(정확성)을 우선시하는 설계로 만들었습니다. -
리서치 목표와 내부 검색 쿼리 책정
검색이 필요한 경우에는 이전 공정에서 정리한 컨텍스트를 바탕으로 리서치 계획을 세웁니다.
"어떤 정보를 수집할 필요가 있는가"라는 리서치 목표 (전체 방침)와, 앱 내부에 있는 분석 완료된 기사를 찾기 위한 내부 검색용 쿼리를 결정합니다.
구현상의 고안 사항과 가드레일 (Guardrail)
외부 검색의 구체적인 쿼리는 결정하지 않음
여기서 결정하는 것은 어디까지나 "리서치 목표"까지입니다. 외부 웹 검색에서 실제로 어떤 쿼리를 사용할지는 후속 외부 검색 공정에 맡깁니다.
"목적에 맞는 정보를 정확하게 히트시키기 위한 쿼리를 선택하는 것"은 플래닝과는 또 다른 책임이라고 생각하여 역할을 분리했습니다. -
검색 수의 상한 (가드레일)
검색 처리의 가드레일로서 상한 수를 설정하고 있습니다. "조사의 축은 최대 3개", "내부 기사 검색 문구는 합계 3건까지"라고 프롬프트로 제약을 걸고 있습니다.
유사한 검색이 늘어나는 것을 방지함과 동시에, 1회의 run이 발생시키는 API 콜과 동시 실행량을 예측 가능한 범위 내로 유지하기 위해서입니다. -
출력의 모순 체크
LLM의 출력은 아무래도 편차가 생기기 때문에, 프로그램 측에서 정합성 체크 (Validation)를 넣고 있습니다. "검색이 불필요하다고 했는데 조사 태스크가 생성됨", "검색한다고 했는데 검색 문구가 비어 있음"과 같은 불일치를 걸러내거나, 상한을 초과한 검색 문구를 잘라내는 등 후속 처리가 안전하게 동작하도록 정돈합니다. -
기간 지정의 정규화
"최근의", "지난주의"와 같은 시간 표현도 이 공정에서 시스템이 다루기 쉬운 형태 (오늘, 지난주, 특정 월 등)로 변환 및 정규화하여 후속 공정으로 전달하도록 하고 있습니다. -
내부 검색과 외부 검색에서 쿼리 생성의 취급을 나눈 이유
외부 검색의 쿼리 책정은 후속 공정에 맡긴 반면, 내부 검색의 쿼리는 이 플래닝 (Planning) 공정의 출력을 그대로 사용하고 있습니다. 그 이유는 앱 내부의 기사 검색에는 벡터 검색 (Vector Search)을 채택하고 있기 때문입니다. 리서치 골 (Research Goal)에 기반한 '의미적으로 가까운 것'을 찾는 특성상, 플래너 (Planner)가 출력한 쿼리를 그대로 사용해도 현재로서는 문제없이 기능하고 있으며, 불필요한 LLM 호출을 줄여 비용을 절약할 수 있다는 장점도 있습니다.
향후 운용 과정에서 내부 검색의 정밀도에 과제가 발생할 경우에는, 이 부분 또한 쿼리 생성 공정을 분리하는 것을 검토할 예정입니다.
4. Evidence Collection (에비던스 수집)
이전 공정에서 세운 계획을 바탕으로, 답변의 재료(근거)를 실제로 수집하는 공정입니다.
조사 태스크마다, 애플리케이션 내부에서 사전에 AI 분석을 수행한 기사를 검색하는 '내부 검색'과 웹상을 검색하는 '외부 검색'을 병렬로 실행합니다.
내부 검색: AI 분석 완료된 기사 취득과 벡터 캐시 (Vector Cache)
플래닝 (Planning) 공정에서 작성된 일본어 검색 쿼리를 벡터 (Vector)로 변환하고, pgvector를 사용하여 의미적으로 가까운 기사를 가져옵니다.
여기서 고안한 점은 **벡터 변환 결과의 캐시 (Cache)**입니다.
텍스트의 벡터화 (Embedding)에도 API 호출이 발생하기 때문에, 동일한 검색문을 매번 변환하면 비용과 레이턴시 (Latency)가 늘어납니다.
따라서 한 번 생성한 벡터는 DB에 저장(캐시)하고, 동일한 검색문이 있으면 재사용하는 구조로 만들었습니다.
캐시 키는 검색문의 평문을 그대로 남기는 것이 아니라, SHA-256으로 해싱한 것을 사용합니다.
나아가 키에는 '사용한 임베딩 (Embedding) 모델명 · 태스크 종류 · 차원 수'를 조합한 식별자를 포함하고 있습니다.
이를 통해 향후 모델이나 차원 수를 변경했을 때, 조건이 다른 오래된 벡터를 잘못 재사용하는 것을 방지하도록 설계했습니다.
외부 검색: 영어 쿼리로의 변환과 크롤링 (Crawling) 생략
외부 검색은 실제로 검색에 사용할 쿼리를 작성하는 것부터 시작됩니다.
플래너 (Planner)로부터 받은 '리서치 골 (Research Goal, 무엇을 확인하고 싶은가)'을 바탕으로, LLM을 사용하여 웹 검색에서 히트하기 쉬운 영어 검색 쿼리 (1~3건)를 생성합니다.
플래닝 (Planning) 공정에서 외부 검색의 쿼리 작성을 분리한 이유는 바로 여기에 있습니다. '일본어 조사 목적으로부터 검색에 최적화된 영어 쿼리를 구성한다'는 서로 다른 책임을 부여하기 위해서입니다.
생성된 쿼리를 사용하여 검색 API (Tavily)를 호출하고, 기사 후보를 가져옵니다.
여기서의 고안점은 웹 페이지의 본문을 직접 가져오지 않는다는 것입니다.
API가 반환하는 제목, URL, 스니펫 (Snippet), 날짜만을 후보로 취급하며, 각 페이지의 크롤링 (Crawling)은 수행하지 않습니다. 이는 전체 레이턴시 (Latency)를 억제하는 것과, 임의의 URL을 페치 (Fetch)하는 기구를 앱 측에 두지 않는 것(보안상의 리스크를 줄임)을 우선시했기 때문입니다.
한쪽이 실패해도 멈추지 않음 (Fallback)
내부 검색과 외부 검색은 한쪽이 실패하더라도 처리를 정지하지 않고, 성공한 쪽의 결과만으로 후속 처리를 계속합니다.
한쪽의 정보원만으로도 충분히 답변을 작성할 수 있는 케이스가 많기 때문에, 도중에 처리를 중단시키지 않고 '답변을 완수하는 것'을 최우선으로 한 설계입니다.
5. Evidence Review (에비던스 리뷰)
수집한 후보를 그대로 답변 생성에 넘기는 것이 아니라, 플래너 (Planner)가 설정한 '리서치 골 (Research Goal)'에 대해 유효한 근거인지를 평가·선별하는 공정입니다.
단순히 근거를 고르는 것뿐만 아니라, 할루시네이션 (Hallucination)을 방지하기 위한 고안이나 향후의 확장성을 고려한 설계를 도입하고 있습니다.
유효한 근거의 선별과 '부족 정보'의 추출
수집한 정보 중에서 리서치 골 (Research Goal)에 부합하는 것만을 골라내는 동시에, '이번 검색으로 취득할 수 없었던 정보'도 정리합니다.
이 정보는 다음과 같이 활용됩니다.
이번 답변 생성: 조사에서 확인하지 못한 정보를 고려한 답변을 출력하도록 함. -
다음 플래닝 (Planning): 이번에 조사하지 못한 요소를 베이스로 다음 플랜을 세워, 사용자의 요구를 충족하는 리서치로 연결함. -
컨텍스트 (Context) 정리: 미해결되었으나 지속적으로 유효한 요구사항은 '충족해야 할 조건'으로서 기억시킴.
향후의 재검색 (Loop 구조)을 내다본 책임 분리
에비던스 수집과 리뷰 공정을 명시적으로 나눈 것은 책임을 분리하기 위해서입니다.
이렇게 공정을 독립시켜 둠으로써, "수집된 근거가 불충분하다"고 판단될 경우 수집 공정으로 돌아가 재검색을 수행하는 루프 (Loop) 구조를 향후에 쉽게 통합할 수 있도록 했습니다.
URL을 보여주지 않는 구조적 할루시네이션 (Hallucination) 대책
이 공정에서의 가장 큰 핵심은 LLM에게 URL을 직접 보여주지 않는다는 점입니다.
LLM에는 URL 자체를 전달하지 않고, 앱 측에서 부여한 인덱스 번호로 교체하여 관리합니다.
출처 지정도 해당 번호로 수행하게 하며, LLM으로부터 반환된 번호를 앱 측에서 원래의 URL로 복원하여 연결하는 메커니즘입니다.
프롬프트 (Prompt) 지시와 더불어 이러한 구성을 채택함으로써, 존재하지 않는 URL이 생성되는 할루시네이션 (Hallucination) 발생을 억제하고 있습니다.
6. 답변 생성
이전 공정에서 엄선된 근거를 바탕으로, 최종적인 답변을 마크다운 (Markdown) 형식으로 생성합니다.
- 출처의 인라인 인용 (Inline Citation)
근거에 기반한 주장 직후에는 [[1]]과 같은 형식으로 인라인 인용을 붙이도록 합니다.
프롬프트 (Prompt) 지시와 더불어, "존재하지 않는 번호를 인용하고 있지는 않은가", "필요한 인용이 누락되지 않았는가"를 검증하고, 규칙을 어겼을 경우 내부적으로 재시도(Retry) 및 수정을 수행하게 합니다.
스트리밍 (SSE) 표시 시의 노하우
생성 중인 답변 텍스트는 SSE를 통해 브라우저로 순차적으로 스트리밍되는데, 여기서 송신 측 (백엔드)에 약간의 기교를 넣었습니다.
스트리밍 중에는 아무래도 [[ 이나 [[1 과 같이 중간에 끊긴 문자가 흘러나오는 순간이 발생하는데, 이것들이 화면에서 깜빡거리지 않도록 마커 부분을 일시적으로 마스킹(Masking)하거나 제거합니다.
최종적으로 저장되는 텍스트에는 마커가 남도록 설계되어 있으며, 답변이 확정되는 타이밍에 출처 링크 (호버나 클릭이 가능한 UI)로 변환됩니다.
대화를 넘나드는 또 다른 컨텍스트: 과거 검색 기록
제2공정인 "Context Gathering (컨텍스트 정리)"가 담당하는 것은 어디까지나 "이번 질문에서 사용자가 무엇을 원하는가"라는 사용자 측 의도의 추출입니다.
하지만 대화를 성립시키기 위해서는 이와 별개로 "과거 턴에서 시스템 측이 무엇을 검색해 왔는가"라는 이력도 관리할 필요가 있었습니다.
그래서 외부 검색을 실행한 처리의 마지막에는 다음 액션에 활용하기 위해 다음과 같은 기록을 남기도록 합니다.
- 플래너 (Planner)가 세운 리서치 목표
- 실제로 외부 검색에 사용한 쿼리 (Query)
- 그 검색을 통해 무엇을 얻었는가 (에비던스 리뷰에서 채택된 근거)
- 어떤 정보가 부족했는가
동일한 스레드 내에서 대화가 이어질 경우, 이 직전 3회분의 검색 기록이 플래너 (Planner)의 입력값에 추가됩니다.
이것이 없으면 유사한 검색을 반복하거나, 지난번에 확인하지 못한 점을 다른 접근 방식으로 해결할 수 없게 됩니다.
LLM을 사용하지 않는 기교와 향후 전망
이 기록을 남기는 처리에는 LLM을 호출하지 않습니다. 각 공정이 이미 출력하고 있는 결과물들을 재구성할 뿐입니다.
"어떤 기록이 이번 질문과 관련이 있는가"를 선택하는 필터링도 수행하지 않고, 직전 3건을 그대로 플래너 (Planner)에게 전달하며, 관련성 여부의 판단도 맡깁니다.
다만, 향후 앱을 운용하는 과정에서 플래너 (Planner)의 판단 정밀도가 떨어지는 등의 과제가 발생할 경우에는, 이 "검색 기록의 정리 및 선별" 계층에도 LLM을 도입하는 것을 검토하고 있습니다.
검색이 실패했을 때의 처리
에러 등으로 실패한 검색은 실행하지 않은 것과 같으므로 기록하지 않습니다.
반대로 "검색 자체는 성공했지만, 유용한 정보를 찾지 못했다"는 경우에는 빈 채택 리스트로서 기록합니다.
지난번에는 이 쿼리로 유용한 후보를 얻지 못했다는 시그널을 플래너 (Planner)에게 보내기 위해서입니다.
참고로 과거의 기록은 어디까지나 "중복 회피"나 "쿼리 개선"을 위한 참고 정보이며, 현재 답변의 직접적인 근거로 재사용하지 않도록 프롬프트 (Prompt)로 지시하고 있습니다.
공정 전체를 뒷받침하는 공통 메커니즘
지금까지는 에이전트의 각 공정에 대해 작성했지만, 플로우 (Flow) 전체를 외부에서 지원하는 인프라나 제어 메커니즘에 대해서도 몇 가지 소개해 두겠습니다.
답변 스트림의 청크화 (Coalesce)
LLM이 생성하는 답변 텍스트를 토큰 (Token) 단위로 그대로 SSE에 흘려보내면, 통신이 너무 잘게 쪼개져 백엔드와 브라우저 렌더링 모두에 부하가 걸립니다.
전송하기 전에 텍스트 조각(delta)을 모으는 버퍼링 메커니즘(coalesce / 합류)을 도입했습니다. 구체적으로는 "0.25초 간격" 또는 "512자에 도달한 시점"을 상한으로 하여 청크(Chunk)화하고, 이를 모아서 전송함으로써 균형을 맞추고 있습니다.
일일 쿼터 (Daily Quota) 관리
이 에이전트 기능에는 "사용자 1명당 하루 10회까지"라는 이용 상한(Quota)을 설정했습니다.
쿼터가 소비되는 타이밍은 실제로 처리가 실행되었을 때가 아니라, 요청을 수락하고 run을 생성한 시점입니다.
여기서 주의해야 할 점은 레이스 컨디션 (Race Condition)입니다. 앱 측에서 SELECT를 통해 횟수를 확인한 후 UPDATE를 하는 방식으로 구현하면, 요청이 연타되었을 때 상한을 초과해버릴 가능성이 있습니다.
따라서 쿼터 소비는 run 생성과 동일한 트랜잭션 (Transaction) 내에 포함시키고, 다음과 같은 "조건부 UPSERT" 방식으로 수행하도록 했습니다. 상한 체크를 앱 측의 로직이 아닌 SQL 구조 자체에서 보장하는 형태입니다.
ON CONFLICT (user_id, usage_date) DO UPDATE
SET used_count = agent_user_daily_quotas.used_count + 1
WHERE agent_user_daily_quotas.used_count < 10
...
참고로, 현재 소비된 쿼터를 반환하는 경우는 큐(Queue)에 들어간 채 실행되지 않고 종료된 run뿐입니다.
이를 뒤집어 생각하면, 처리 시작 후에 시스템 측의 사정으로 실패할 경우, 사용자는 답변을 받지 못한 채 쿼터만 소비하게 됩니다.
현재는 초대제로 운영되는 애플리케이션이기 때문에 이 사양을 허용하고 있지만, 비즈니스적 가치를 제공하는 것을 전제로 한다면 "시스템 에러 등으로 사용자의 요청을 충족시키지 못했을 경우"에 소비분을 반환하는 메커니즘이 필요하다고 느꼈습니다.
마치며
여기까지 읽어주셔서 감사합니다.
이번에 에이전트를 직접 제작해보며 가장 큰 맹점이었던 것은 컨텍스트 관리 (Context Management)의 중요성과 그 어려움이었습니다.
어떤 정보를 추출하여 정리해야 하는지, 또한 단기 기억과 장기 기억을 어떻게 다루고 통합해 나갈지에 대해서는 앞으로 더욱 깊이 있게 학습해 나가고 싶습니다.
또 하나, 직접 만들어 보았기에 뼈저리게 느낀 점은 "본가"와의 압도적인 차이입니다. 특히 응답 속도는 도저히 상대가 되지 않는다고 느꼈습니다.
백그라운드에서 여러 번의 모델 호출과 검색 처리가 돌아가고 있을 텐데도, 사용자에게 "기다리고 있다"는 느낌을 주지 않는 그 속도감은 솔직히 믿기지 않을 정도입니다.
비슷한 메커니즘을 직접 구축해 봄으로써, 저 응답 속도를 구현하는 것이 얼마나 경이로운 기술인지 깨달았습니다.
후편에서는 스케일 업 (Scale-up) 되었을 때 실행 모델을 어떻게 변경해야 하는지에 대해 고찰했습니다. 괜찮으시다면 확인해 주세요.
피드백 등을 주신다면 정말 기쁘겠습니다!
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기