*출처 : 요즘 AI 에이전트 개발 (박승규 지음)

# 작성 : 250922
# 멀티 에이전트 :
# 단일 에이전트에서는 도구와 구조화된 출력을 동시에 사용할 수 없다.
# -> 외부 API를 호출하는 도구를 사용하면서 동시에 결과를 특정 JSON 형식으로 강제할 수 없다.
# 서로 다른 역할을 가진 여러 에이전트를 조합하여 단일 에이전트의 한계를 극복하는 방법
# 첫번째 에이전트 : 도구(tool)를 활용하여 외부 데이터를 수집
# 두번째 에이전트 : 첫번째 에이전트가 수집한 데이터를 받아 output_schema를 사용하여 원하는 JSON 구조로 변환
# 오케스트레이터 에이전트 : 전체 프로세스를 관리하며, 각 에이전트 간의 데이터 전달과 실행 순서를 조정
from google.adk.agents import Agent
import httpx
from pydantic import BaseModel, Field
from typing import List, Dict, Any, Optional
# BookRecommendation는 BookList의 서브 스키마(하위 모델, nested model)라고 볼 수 있다. (250922)
# recommendations 필드가 BookRecommendation 객체들의 리스트임 → 즉, BookList는 BookRecommendation을 포함하고 있음
class BookRecommendation(BaseModel):
title: str = Field(description="책 제목")
author: str = Field(description="저자")
genre: str = Field(description="장르")
reason: str = Field(description="추천 이유")
rationg: float = Field(description="평점 (1-5)")
class BookList(BaseModel):
recommendations: List[BookRecommendation] # BookRecommendation 스키마가 BookList에 포함되는 구조 (250922)
total_count: int
# Tool - 1 : 최신 IT 도서 정보를 가져오는 함수 = "도구"
def get_book_search(search_keyword: Optional[str] = None) -> Dict[str, Any]:
"""최신 IT 도서 정보를 가져옵니다. 키워드가 없으면 신간 도서 목록을 가져옵니다."""
if search_keyword:
result = httpx.get(f"https://api.itbook.store/1.0/search/{search_keyword}")
else:
result = httpx.get("https://api.itbook.store/1.0/new")
return result.json()
# 검색된 결과를 JSON 형태 그대로 반환 -> 이미 정해져 있는 JSON 형태 그대로 반환된다. -> 내가 원하는(별로로 정의한) 형태로 반환하기를 원한다.
# Tool - 2 : 도서 정보를 검색하는 에이전트 = "에이전트" - tool (함수)를 호출하고 결과를 절절하게 출력
book_data_agent = Agent(
name = "book_data_finder",
model = "gemini-2.0-flash",
description = "최신 도서 정보를 조회하는 에이전트",
instruction="""사용자의 관심에 맞는 최신 도서 정보를 조회하세요.
get_book_search 도구를 사용하여 현재 인기있는 도서들을 조회하고,
사용자의 선호도에 맞는 도서들을 선별하세요.""",
tools = [get_book_search], # 도구 추가
)
# Tool - 3 : 구조화된 출력을 생성하는 에이전트 - Tool #2의 결과를 재가공
structured_output_agent = Agent(
name = "structured_output_generator",
model = "gemini-2.0-flash",
description = "도서 추천을 구조화된 형식으로 변환하는 에이전트",
instruction = """받은 도서 정보를 BookList 스키마에 맞게 정리하세요.
각 도서에 대해 추천 이유를 작성하고,
전체 추천 도서 수를 total_count에 포함시키세요.""",
output_schema = BookList, # 출력 스키마 지정
)
# Root Agent : 오케스트레이션
root_agent = Agent(
name = "book_recommendatio_orchestratior",
model = "gemini-2.0-flash",
description = "도서 추천 프로세스를 조정하는 메인 에이전트",
instruction = """
사용자의 도서 추천 요청을 처리하는 오케스트레이터입니다.
처리 순서:
1. 먼저 book_data_finder 에이전트를 사용하의 사용자의 관심사에 맞는 최신 도서 정보를 조회합니다.
2. 수집된 정보를 structured_output_generator 에이전트에게 전달하여 BookList 형식으로
구조화된 추천 목록을 생성합니다.
3. 최종 결과를 사용자에게 전달합니다.
각 에이전트의 역할:
- book_data_finder: IT도서 베스트 셀러 정보 조회
- structured_output_generator: 구조화된 BookList 형식으로 출력 생성
""",
sub_agents = [book_data_agent, structured_output_agent], # 하위 에이전트들 등록
)