Google Gemini 2.5 + LangGraph로 구축하는 AI 연구 에이전트 - 풀스택 가이드
Google에서 공식 발표한 Gemini Fullstack LangGraph Quickstart 프로젝트는 Gemini 2.5 모델과 LangGraph를 활용하여 고도화된 AI 연구 에이전트를 구축하는 완전한 풀스택 솔루션입니다. 11.6k 스타를 받으며 큰 관심을 받고 있는 이 프로젝트는 단순한 질의응답을 넘어 반복적 검색과 지식 격차 분석을 통해 종합적인 연구 결과를 제공하는 혁신적인 접근법을 제시합니다.
프로젝트 개요
핵심 목적
이 프로젝트의 핵심 목적은 사용자의 자연어 질문을 입력받아, Gemini 모델이 스스로 검색 키워드를 생성하고 Google Search API로 자료를 수집·검증·정리하여 인용이 붙은 최종 답변을 반환하는 “풀스택 연구 에이전트” 예시를 제공하는 것입니다.
주요 특징
- 💬 React(Vite) + Tailwind + shadcn/ui로 작성된 SPA 프론트엔드
- 🧠 LangGraph 상태 머신형 에이전트 - 각 노드가 질문 생성, 웹 검색, 지식 갭 분석, 반복 여부 결정, 응답 합성 기능을 담당
- 🔍 Google Gemini 2.5 모델을 활용한 동적 검색 쿼리 생성
- 🌐 Google Search API 통합을 통한 실시간 웹 연구
- 🤔 반사적 추론(Reflective Reasoning)으로 지식 격차 식별 및 검색 개선
- 📄 인용 포함 답변 생성으로 신뢰할 수 있는 정보 제공
- 🔄 실시간 스트리밍 - 서버-센트 이벤트(SSE) 및 실시간 UI 업데이트 지원
- 🐳 Docker + docker-compose로 손쉬운 배포, Redis(pub-sub)·PostgreSQL(상태·메모리 영속) 의존
아키텍처 구성
Frontend (React + Vite)
↓ HTTP API
Backend (LangGraph + FastAPI)
↓ LLM Calls
Google Gemini 2.5
↓ Web Search
Google Search API
↓ Data Storage
Redis + PostgreSQL
프로젝트 구조 및 빌드 플로
폴더 구조 개요
디렉터리 | 주요 내용 | 비고 |
---|---|---|
frontend/ | src/App.tsx 에 API 엔드포인트 설정, shadcn UI 컴포넌트로 채팅 창 구성 |
Vite dev 서버(npm run dev ) |
backend/ | src/agent/graph.py : LangGraph 워크플로 정의src/api/main.py : FastAPI(or LangGraph dev 서버) 엔드포인트 |
langgraph dev 실행 시 시각적 스튜디오 자동 오픈 |
루트 | Dockerfile, docker-compose.yml, Makefile(make dev 로 프런트·백 동시 기동) |
ENV: GEMINI_API_KEY , LANGSMITH_API_KEY |
로컬 실행 절차
# 1. 사전 요구사항: Python 3.8+, Node.js 설치
python --version # 3.8+
node --version # v18+
# 2. API 키 설정
cd backend
cp .env.example .env
# .env 파일에 GEMINI_API_KEY="your_actual_gemini_api_key" 추가
# 3. 개발 서버 실행
cd ..
make dev
# 4. 브라우저에서 http://localhost:5173/app 접속하여 실시간 스트리밍 확인
에이전트 워크플로우 심화 분석
프로젝트의 핵심은 backend/src/agent/graph.py
에 정의된 LangGraph 에이전트입니다. 이 에이전트는 다음과 같은 정교한 연구 프로세스를 수행합니다:
LangGraph 워크플로 다이어그램
┌─> GenerateQueries ─┐
│ │ (반복 최대 N회)
│ WebSearch │
│ │ │
│ Reflect & Gap? ──┘— 예/아니오 분기
│
└─> SynthesizeAnswer (citations)
LangGraph 선택 이유: 에이전트의 각 단계를 그래프 노드로 명시해 흐름·상태·반복 조건을 투명하게 관리할 수 있고, LangSmith + LangGraph Studio로 디버깅·모니터링이 용이하기 때문입니다.
1. 초기 쿼리 생성 (Generate Initial Queries)
# 의사 코드 예시
def generate_initial_queries(user_input: str) -> List[str]:
"""
사용자 입력을 바탕으로 다각적 검색 쿼리 생성
"""
prompt = f"""
사용자 질문: {user_input}
이 질문에 대한 포괄적인 답변을 위해 필요한
다양한 관점의 검색 쿼리 3-5개를 생성하세요.
"""
response = gemini_model.generate(prompt)
return parse_queries(response)
2. 웹 연구 단계 (Web Research)
각 생성된 쿼리에 대해 Google Search API를 통한 실시간 정보 수집:
def web_research(queries: List[str]) -> Dict[str, List[SearchResult]]:
"""
각 쿼리별로 웹 검색 수행 및 결과 수집
"""
results = {}
for query in queries:
search_results = google_search_api.search(
query=query,
num_results=10,
include_snippets=True
)
results[query] = search_results
return results
3. 반사적 분석 (Reflection & Knowledge Gap Analysis)
수집된 정보의 충분성을 평가하고 지식 격차를 식별:
def analyze_knowledge_gaps(
original_question: str,
search_results: Dict
) -> KnowledgeAnalysis:
"""
검색 결과를 분석하여 지식 격차 식별
"""
analysis_prompt = f"""
원본 질문: {original_question}
수집된 정보: {format_search_results(search_results)}
다음을 분석하세요:
1. 질문에 대한 완전한 답변이 가능한가?
2. 부족한 정보나 지식 격차는 무엇인가?
3. 추가 검색이 필요한 특정 영역은?
"""
return gemini_model.analyze(analysis_prompt)
4. 반복적 개선 (Iterative Refinement)
지식 격차가 발견되면 추가 검색 쿼리를 생성하여 연구를 심화합니다. 부족 시 새 검색어 생성 후 루프를 반복하며, 최대 반복 횟수(default 3) 초과 시 강제 종료됩니다:
def iterative_research_loop(max_iterations: int = 3):
"""
최대 반복 횟수까지 연구를 지속적으로 개선
"""
for iteration in range(max_iterations):
gaps = analyze_knowledge_gaps(question, current_results)
if gaps.is_sufficient:
break
followup_queries = generate_followup_queries(gaps)
additional_results = web_research(followup_queries)
current_results.update(additional_results)
return current_results
5. 최종 답변 합성 (Finalize Answer)
모든 수집된 정보를 종합하여 인용과 함께 일관된 답변을 생성합니다. 최종 근거가 되는 문단을 인용 형태로 묶어 답변 본문을 생성합니다:
def synthesize_final_answer(
question: str,
all_results: Dict
) -> StructuredAnswer:
"""
연구 결과를 종합하여 인용 포함 최종 답변 생성
"""
synthesis_prompt = f"""
질문: {question}
연구 자료: {format_all_results(all_results)}
다음 형식으로 종합적인 답변을 작성하세요:
1. 핵심 답변 (2-3 문단)
2. 상세 설명
3. 인용 출처 목록 (URL과 관련 문단)
4. 추가 고려사항
각 주장에 대해 [1], [2] 형식으로 인용 번호를 표시하세요.
"""
return gemini_model.synthesize(synthesis_prompt)
인프라 및 배포 전략
개발 환경 vs 프로덕션 환경
환경 | 구성 | 특징 |
---|---|---|
개발용 | LangGraph dev 서버(포트 2024) + Vite dev 서버(5173) | FastAPI + SSE 제공, 핫리로드 지원 |
프로덕션 | Dockerfile에서 프론트엔드 빌드 후 백엔드에서 정적 파일 서빙 | docker-compose로 Redis·Postgres 함께 기동 |
개발 환경 구성
1. 사전 요구사항
# Node.js 및 Python 환경 확인
node --version # v18+
python --version # 3.8+
2. API 키 설정
# backend/.env 파일 생성
cd backend
cp .env.example .env
# .env 파일에 다음 추가
GEMINI_API_KEY="your_actual_gemini_api_key"
GOOGLE_SEARCH_API_KEY="your_google_search_api_key" # 선택사항
3. 의존성 설치 및 실행
# 백엔드 설정
cd backend
pip install .
# 프론트엔드 설정
cd ../frontend
npm install
# 개발 서버 실행 (루트 디렉토리에서)
make dev
프로덕션 배포
프로덕션 환경에서는 Redis와 PostgreSQL이 필요합니다:
# docker-compose.yml 예시
version: '3.8'
services:
app:
build: .
ports:
- "8123:8000"
environment:
- GEMINI_API_KEY=${GEMINI_API_KEY}
- LANGSMITH_API_KEY=${LANGSMITH_API_KEY}
depends_on:
- redis
- postgres
redis:
image: redis:7-alpine
ports:
- "6379:6379"
postgres:
image: postgres:15-alpine
environment:
- POSTGRES_DB=langgraph
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
ports:
- "5432:5432"
# Docker 빌드 및 실행
docker build -t gemini-fullstack-langgraph -f Dockerfile .
GEMINI_API_KEY=<your_key> LANGSMITH_API_KEY=<your_key> docker-compose up
확장성 고려사항
- 수평 확장: LangGraph 자체는 수평 확장 가능하지만 Redis pub-sub 채널 명 충돌에 주의
- 데이터베이스 최적화: Postgres 커넥션 풀을
pool_size=20
수준으로 조정(대량 동시 사용자 대비) - 캐싱 전략: Google Search API 호출 비용 절감을 위한 Redis TTL 캐시 구현 권장
커스터마이징 가이드
주요 커스터마이징 포인트
요구사항 | 적용 위치 | 참고 |
---|---|---|
다른 LLM 사용(OpenAI, Claude 등) | graph.py 에서 GeminiChat → ChatOpenAI 교체 |
기존 멀티-프로바이더 포크 예시 (nodew fork) |
검색 API 교체(Bing, Brave) | tools/web_search.py 모듈 추가 |
SerpAPI, ScrapingBee 등 대안 |
장기 메모리(벡터저장소) | LangGraph memory node 또는 Postgres + pgvector |
Chroma, Pinecone 통합 |
인증/사용자 관리 | FastAPI 라우터 확장 후 JWT 적용 | NextAuth.js, Auth0 연동 |
LLM 교체 예시
# Gemini에서 OpenAI로 교체
from langchain_openai import ChatOpenAI
# 기존 코드
# llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash")
# 새로운 코드
llm = ChatOpenAI(
model="gpt-4o",
api_key=os.getenv("OPENAI_API_KEY"),
temperature=0.1
)
검색 API 확장
# tools/web_search.py에 추가
class MultiSearchTool:
def __init__(self):
self.google_search = GoogleSearchAPIWrapper()
self.bing_search = BingSearchAPIWrapper()
self.brave_search = BraveSearchWrapper()
async def search_all(self, query: str) -> Dict[str, List[SearchResult]]:
"""여러 검색 엔진 결과를 병렬로 수집"""
tasks = [
self.google_search.run(query),
self.bing_search.run(query),
self.brave_search.run(query)
]
results = await asyncio.gather(*tasks)
return {
"google": results[0],
"bing": results[1],
"brave": results[2]
}
한계 및 개선 방향
현재 한계점
- 비용 최적화: Google Search API 호출이 루프마다 발생하여 비용 증가
- 반복 제한: 최대 3회 반복으로 복잡한 분석 문제에는 부족할 수 있음
- 인용 정확도: 현재는 URL 레벨 메타데이터만 표시
- 단일 모달: 텍스트 기반 검색에 국한
개선 아이디어
1. 비용 최적화
# Redis 캐싱 전략
@cache_search_results(expiry_hours=24)
async def cached_web_search(query: str):
"""검색 결과 캐싱으로 API 호출 최적화"""
return await google_search_api.search(query)
# SerpAPI free tier 활용
class HybridSearchStrategy:
def __init__(self):
self.free_quota = 100 # 일일 무료 할당량
self.paid_api = GoogleSearchAPI()
self.free_api = SerpAPI()
async def search(self, query: str):
if self.free_quota > 0:
self.free_quota -= 1
return await self.free_api.search(query)
else:
return await self.paid_api.search(query)
2. 인용 정확도 개선
# HTML 파싱 후 문장 단위 하이라이트
class EnhancedCitationTool:
def extract_relevant_passages(self, url: str, query: str) -> List[str]:
"""웹페이지에서 관련 문단 추출"""
html_content = self.fetch_html(url)
passages = self.parse_paragraphs(html_content)
# 의미적 유사도 기반 문단 선별
relevant_passages = self.semantic_filter(passages, query)
return relevant_passages
def generate_precise_citation(self, passage: str, url: str) -> str:
"""정확한 인용 형식 생성"""
return f'"{passage}" - {url}'
3. 멀티모달 확장
# Gemini 2.5 Vision 활용
class MultimodalResearchAgent(BaseAgent):
def analyze_visual_content(self, image_urls: List[str]) -> Dict:
"""Gemini Vision을 활용한 이미지 분석"""
visual_insights = {}
for url in image_urls:
analysis = self.vision_model.analyze_image(
image_url=url,
prompt="이 이미지에서 연구 질문과 관련된 정보를 추출하세요."
)
visual_insights[url] = analysis
return visual_insights
경쟁 프로젝트 비교
주요 대안 솔루션 비교
항목 | Gemini Fullstack LG | LangGraph Agent Toolkit | LangChain 기본 AgentExecutor |
---|---|---|---|
LLM | Gemini 2.5 (기본) | 다중(옵션) | 다중 |
흐름 정의 | 그래프형(LangGraph) | 그래프형 | 스택형(step loop) |
프론트엔드 | React(Vite) 포함 | 없음(백엔드 중심) | 없음 |
실시간 스트림 | Redis pub-sub → SSE | WebSocket/Redis | 없음 기본 |
배포 예시 | Docker-compose, Redis, PG | FastAPI/Streamlit 예시 | 별도 제공 X |
시각적 디버깅 | LangGraph Studio | LangGraph Studio | 없음 |
학습 곡선 | 중간 | 높음 | 낮음 |
선택 기준
- 풀스택 개발: Gemini Fullstack LG 선택
- 최대 유연성: LangGraph Agent Toolkit 선택
- 빠른 프로토타이핑: LangChain 기본 AgentExecutor 선택
고급 활용 사례
1. 도메인 특화 연구 에이전트
class DomainSpecificAgent(BaseAgent):
"""
특정 도메인(의료, 법률, 기술 등)에 특화된 연구 에이전트
"""
def __init__(self, domain: str):
self.domain = domain
self.specialized_sources = get_domain_sources(domain)
super().__init__()
def generate_domain_queries(self, question: str) -> List[str]:
"""도메인 특화 검색 쿼리 생성"""
domain_context = f"In the context of {self.domain}:"
return super().generate_queries(domain_context + question)
def validate_sources(self, sources: List[str]) -> List[str]:
"""도메인 관련성 기준으로 소스 필터링"""
return [s for s in sources if self.is_domain_relevant(s)]
2. 멀티모달 연구 확장
class MultimodalResearchAgent(BaseAgent):
"""
텍스트, 이미지, 동영상 등 다양한 미디어를 활용한 연구
"""
def analyze_visual_content(self, image_urls: List[str]) -> Dict:
"""Gemini Vision을 활용한 이미지 분석"""
visual_insights = {}
for url in image_urls:
analysis = gemini_vision.analyze_image(
image_url=url,
prompt="이 이미지에서 연구 질문과 관련된 정보를 추출하세요."
)
visual_insights[url] = analysis
return visual_insights
def synthesize_multimodal_answer(self, text_data: Dict, visual_data: Dict):
"""텍스트와 시각적 정보를 종합한 답변 생성"""
pass
3. 실시간 협업 연구
class CollaborativeResearchAgent:
"""
여러 사용자가 동시에 연구를 진행할 수 있는 협업 에이전트
"""
def __init__(self):
self.shared_knowledge_base = SharedKnowledgeBase()
self.collaboration_handler = CollaborationHandler()
async def collaborative_search(
self,
user_id: str,
question: str,
session_id: str
):
"""다중 사용자 협업 검색"""
# 기존 세션 정보 활용
existing_research = await self.get_session_research(session_id)
# 새로운 관점 추가
new_queries = self.generate_complementary_queries(
question, existing_research
)
# 실시간 업데이트
await self.broadcast_updates(session_id, new_queries)
성능 최적화 및 모니터링
LangSmith 통합
from langsmith import Client
langsmith_client = Client()
def trace_agent_execution(func):
"""에이전트 실행 과정을 LangSmith로 추적"""
@wraps(func)
async def wrapper(*args, **kwargs):
with langsmith_client.trace(
name=func.__name__,
inputs={"args": args, "kwargs": kwargs}
) as trace:
result = await func(*args, **kwargs)
trace.outputs = {"result": result}
return result
return wrapper
@trace_agent_execution
async def research_workflow(question: str):
"""전체 연구 워크플로우 추적"""
pass
캐싱 전략
import redis
from functools import wraps
redis_client = redis.Redis(host='localhost', port=6379, db=0)
def cache_search_results(expiry_hours: int = 24):
"""검색 결과 캐싱으로 API 호출 최적화"""
def decorator(func):
@wraps(func)
async def wrapper(query: str, *args, **kwargs):
cache_key = f"search:{hash(query)}"
# 캐시에서 먼저 확인
cached_result = redis_client.get(cache_key)
if cached_result:
return json.loads(cached_result)
# 캐시 미스 시 실제 검색 수행
result = await func(query, *args, **kwargs)
# 결과 캐싱
redis_client.setex(
cache_key,
expiry_hours * 3600,
json.dumps(result)
)
return result
return wrapper
return decorator
기술 스택 상세 분석
프론트엔드
- React 18 + Vite: 최신 개발 도구체인으로 빠른 개발 경험
- Tailwind CSS: 유틸리티 우선 CSS 프레임워크
- Shadcn UI: 재사용 가능한 고품질 컴포넌트
- TypeScript: 타입 안전성 보장
백엔드
- LangGraph: 복잡한 에이전트 워크플로우 관리
- FastAPI: 고성능 비동기 웹 프레임워크
- Google Gemini 2.5: 최신 멀티모달 LLM
- Redis: 실시간 스트리밍 및 캐싱
- PostgreSQL: 에이전트 상태 및 대화 기록 저장
실전 활용 시나리오
1. 학술 연구 지원
academic_agent = AcademicResearchAgent(
domains=["computer_science", "artificial_intelligence"],
paper_sources=["arxiv", "acm", "ieee"],
citation_style="APA"
)
result = await academic_agent.research(
"Transformer 아키텍처의 최신 발전과 한계점은?"
)
2. 비즈니스 인텔리전스
business_agent = BusinessIntelligenceAgent(
market_sources=["bloomberg", "reuters", "sec_filings"],
analysis_depth="comprehensive"
)
market_analysis = await business_agent.research(
"2025년 AI 칩셋 시장 전망과 주요 플레이어 분석"
)
3. 기술 문서화
tech_doc_agent = TechnicalDocumentationAgent(
code_repositories=["github", "gitlab"],
documentation_sources=["stackoverflow", "official_docs"]
)
documentation = await tech_doc_agent.research(
"React Server Components 구현 모범 사례"
)
결론 및 향후 전망
Google Gemini Fullstack LangGraph Quickstart는 “검색 · 반성 · 응답 합성” 과정을 LangGraph로 모델링해, 연구형 에이전트를 풀스택으로 구현하려는 개발자에게 훌륭한 템플릿을 제공합니다.
핵심 가치
- 완전한 풀스택 솔루션: React UI·Graph 백엔드·인프라 배포까지 한 번에 제공
- 실전 기능 확장 기반: 검색 도구 추가, LLM 교체, 장기 메모리 확장 등의 실험에 최적
- 시각적 디버깅: LangGraph Studio를 통한 투명한 에이전트 플로우 모니터링
- 확장 가능한 아키텍처: Redis 스트리밍과 PostgreSQL 기반의 대규모 시스템 대응
프로젝트의 의의
반복적 검색과 지식 격차 분석을 통한 고도화된 연구 프로세스는 기존 RAG 시스템의 한계를 극복하고, 보다 신뢰할 수 있고 포괄적인 AI 어시스턴트 구축의 가능성을 보여줍니다. 특히 인용 기반 답변 생성과 반사적 추론은 정보의 신뢰성과 투명성을 크게 향상시킵니다.
활용 권장 사항
사용 사례 | 추천 정도 | 비고 |
---|---|---|
연구 에이전트 프로토타입 | ⭐⭐⭐⭐⭐ | 완벽한 출발점 |
교육용 LangGraph 학습 | ⭐⭐⭐⭐⭐ | 시각적 디버깅 포함 |
프로덕션 기반 확장 | ⭐⭐⭐⭐ | 커스터마이징 필요 |
엔터프라이즈 배포 | ⭐⭐⭐ | 보안·스케일링 고려 필요 |
11.6k 스타와 활발한 커뮤니티 참여는 이 프로젝트의 실용성과 확장성을 입증하며, Google의 공식 지원으로 지속적인 업데이트와 개선이 기대됩니다. 대규모 에이전트 시스템을 구축하려는 팀에게 중요한 레퍼런스가 될 것이며, AI 에이전트 개발에 관심이 있다면 반드시 참고해야 할 필수 리소스입니다.