Plan-and-Solve 기반 AI 답변 인터페이스. 사용자 질문을 검색 각도로 분해해 정보를 모으고, 답변 본문에 인용·이미지·시각 자료를 인라인으로 삽입합니다.
전형적인 챗봇 답변은 출처가 모호한 문장 덩어리, 검색엔진은 파란 링크 10개의 나열 입니다. 사용자가 정작 원하는 것은 그 사이 — 출처가 박힌 답변, 비교·수치·구조가 한눈에 보이는 시각화, 답변 흐름과 함께 등장하는 관련 이미지 입니다.
Pivot 은 답변을 두 단계로 나눠 처리합니다:
- Plan — 사용자 쿼리를 1~3개의 보완적 검색 각도로 분해, 각 각도마다 Brave 로 웹·이미지를 병렬 수집
- Solve — 수집된 컨텍스트로 LLM 이 답변. 본문에 출처 인용(
[N]), 이미지(media://img-N), 차트 스펙(\``chart`) 을 인라인으로 emit
하나의 입력창. 쿼리 제출.
쿼리가 동음이의어·약어 등으로 모호하면 LLM 이 분기 옵션 제시. 사용자가 의도 확정 후 Plan 단계 진입.
- LLM 이 쿼리를 1~3 각도로 분해 (의도 단일이면 1개)
- 각 각도마다 Brave web_search + image_search 동시 실행
- 결과 페이지·이미지 dedupe 후 LLM 컨텍스트로 정리
- 진행률은 SSE 로 실시간 표시 —
검색 중 (2/3)형태
컨텍스트가 모두 갖춰진 뒤 LLM 이 답변 토큰을 스트림. 답변에 자동으로 포함되는 요소:
- 인용
[N]— 검색 결과 번호 - 표 — 비교·수치·항목이 다수일 때 GFM 표
- 이미지 —
→ 프론트가 수집된 이미지를 lookup 해 본문에 인라인 - 차트 —
\``chart {json}```` 코드펜스 (현재는 코드블록으로 표시, 추후 시각화 렌더러 도입 예정)
답변 끝에 검색 결과 출처 목록(클릭하면 원본 페이지) 노출.
| 레이어 | 기술 |
|---|---|
| 백엔드 | FastAPI + asyncio + SSE 스트리밍 |
| 검색 | Brave Search API (web + image, 병렬) |
| LLM | Google Gemini (clarify / plan / solve) |
| 프론트엔드 | React 18 + Vite 5 + React Router 7, vanilla CSS |
| 마크다운 | react-markdown + remark-gfm (GFM 표 + custom img/code components) |
| 배포 | Vercel (FastAPI → Vercel Functions, SPA rewrite) |
- Plan-and-Solve 분리 — 정보 수집과 답변 생성을 명확히 분리. 수집이 완전히 끝난 뒤 LLM 답변 시작 (이미지 ID hallucination 방지)
- 스트리밍 우선 — Plan/검색/Solve 모든 단계가 SSE 이벤트로 진행 상황 송출
- 컨텍스트 주입 RAG — Gemini grounding 도구 사용하지 않음. 우리가 수집한 결과를 컨텍스트로 주입해 통제권 확보
- 인라인 미디어 — 답변 본문에 이미지가
media://마크다운으로 박혀, 프론트가 컨텍스트 한 곳에서 lookup - 보수적 분기 — clarify 는 정말 모호할 때만, plan 은 정말 다면적일 때만 쿼리를 분해. 단순 쿼리는 1개로 줄여 비용 절감
- 멀티턴 컨텍스트 보존 — 완료된 대화 턴을 snapshot 으로 history 에 보관, 다음 요청 LLM 에 전달
| 영역 | 조정 방법 |
|---|---|
| Refined query 상한 | app/core/plan.py::MAX_REFINED |
| 검색 결과 수 | app/core/plan.py::WEB_PER_QUERY, IMAGES_PER_QUERY |
| LLM 모델 교체 | 각 모듈 상단 *_MODEL 상수 |
| clarify 임계값 | app/core/clarify.py::CONFIDENCE_THRESHOLD |
| Solve 시스템 프롬프트 | app/core/solve.py::_SOLVE_SYSTEM |
로드맵: 차트 fence 렌더링 (recharts), [N] 인용 자동 링크화, 이미지 선택적 노출 룰, 페이지 본문 추출(top-K trafilatura).
# .env 설정
echo "GEMINI_API_KEY=..." > .env
echo "BRAVE_API_KEY=..." >> .env
# 백엔드 (port 8000)
PYTHONPATH=. uvicorn app.main:app --reload
# 프론트엔드 (port 3000)
cd frontend && npm install && npm run dev자세한 개발자 가이드는 CLAUDE.md 참조.