13. Session/Memory/Artifact [2] - 세션 스테이트(session.state)를 활용한 핵심정보 선별적 관리(단기 기억)
앞서 살펴본 session.events(대화 기록 전체를 뒤져서 찾는 방식)와는 다르게, Google ADK의 session.state라는 명시적인 상태 저장소(Key-Value 딕셔너리 형태)를 활용해 단기 기억을 관리하는 예제입니다.
이 코드의 상세한 해설과 함께, 함수들을 tools 리스트에 등록하기만 하면 LLM이 이해할 수 있는 스키마(Schema)가 자동으로 생성되는 마법 같은 원리에 대해서도 아주 친절하게 설명해 드리겠습니다.
1. 코드 라인별 상세 해설
① 가상 날씨 데이터 준비 (WEATHER_DB)
WEATHER_DB = {
"서울": {"today": "맑음, 22도", "tomorrow": "비, 18도"},
"대전": {"today": "흐림, 20도", "tomorrow": "맑음, 23도"},
"부산": {"today": "바람, 19도", "tomorrow": "흐림, 20도"},
}
- 서울, 대전, 부산의 오늘 및 내일 날씨 정보를 담고 있는 단순한 파이썬 딕셔너리(데이터베이스 역할)입니다.
② 오늘 날씨 조회 및 상태 저장 함수 (get_today_weather)
def get_today_weather(city:str, tool_context=None)->str:
"""주어진 도시의 '오늘' 날씨를 조회하고, 해당 도시를 state에 저장합니다.
Args:
city:(str)날씨를 조회할 도시 이름
tool_context:실행 컨텍스트(state 접근용)
"""
# [1] 사용자가 언급한 도시를 세션 State에 'last_city'라는 키로 저장합니다.
tool_context.state["last_city"]=city
# 날씨 조회로직
info = WEATHER_DB.get(city)
if info:
return f"{city}의 오늘 날씨는 {info['today']}입니다."
else:
return f"죄송합니다. {city}의 날씨 정보가 없어요..."
- tool_context.state["last_city"] = city: 사용자가 *"서울 오늘 날씨 어때?"*라고 물었을 때, 도구가 실행되면서 언급된 도시(서울)를 세션 상태 저장소(tool_context.state)의 last_city라는 키에 영리하게 저장합니다.
- 이렇게 저장해 두면, 다음에 사용자가 도시 이름 없이 질문해도 이 값을 꺼내 쓸 수 있습니다. 이것이 바로 session.state를 이용한 단기 기억 메커니즘입니다.
③ 내일 날씨 조회 및 상태 활용 함수 (get_tomorrow_weather)
def get_tomorrow_weather(city:Optional[str], tool_context=None) ->str:
"""주어진 도시의 '내일'날씨를 조회합니다.
도시가 주어지지 않으면 state에 저장된 마지막 도시를 사용합니다.
Args:
city:(Optional[str]) 도시이름. 사용자가 생략하면 None이 될수 있음.
tool_context:실행 컨텍스트.
"""
target_city=city
# [2] 만약 사용자가 도시를 말하지 않았다면(None), State에서 꺼내옵니다.
if not target_city:
target_city = tool_context.state.get("last_city")
# [3] State에도 없다면, 사용자에게 되물어야 합니다.
if not target_city:
return "어느 도시의 날씨를 알고 싶은가요?"
# [4] 사용자가 새로운 도시를 명시했다면, State를 업데이트합니다.
if city:
tool_context.state["last_city"] = city
# 날씨 조회로직
info = WEATHER_DB.get(target_city)
if info:
return f"{target_city}의 내일 날씨는 {info['tomorrow']}입니다."
else:
return f"죄송합니다. {target_city}의 내일 날씨 정보가 없어요..."
- city: Optional[str]: 사용자가 도시 이름을 생략할 수 있으므로, city 파라미터가 None이 될 수 있음을 명시(Optional)합니다.
- 기억 불러오기 ([2]): if not target_city: (즉, 사용자가 "내일은?"이라고만 물어서 도시가 입력되지 않은 경우) 세션 저장소에 기억해 둔 last_city를 꺼내옵니다.
- 이중 안전망 ([3]): 이전 대화 기억(last_city)마저 없다면, 에이전트가 에러를 내는 대신 *"어느 도시의 날씨를 알고 싶은가요?"*라고 사용자에게 정중히 되묻습니다.
- 상태 갱신 ([4]): 만약 사용자가 "그럼 부산은?"처럼 새로운 도시를 명시해서 질문했다면, last_city 값을 새로운 도시(부산)로 곧바로 덮어씌워 갱신합니다.

2. tools 리스트 등록 시 '자동 스키마 생성'의 원리
코드 맨 아래에서 함수들을 에이전트에 이렇게 등록했습니다:
weather_agent = Agent(
...,
tools=[get_today_weather, get_tomorrow_weather],
)
LLM은 파이썬 코드를 직접 실행할 수 없습니다!
LLM(Gemini)은 텍스트를 이해하고 생성하는 언어 모델일 뿐, 우리가 작성한 def get_today_weather(...) 같은 파이썬 함수 코드를 직접 읽고 실행할 수 없습니다. 대신 LLM은 "아, 이런 함수들이 존재하고, 이런 인자(Parameter)를 요구하는구나"라는 것을 규격화된 JSON 스키마(Tool Declaration) 형태로 전달받아야만 합니다.
Google ADK와 Python Inspection의 마법
Google ADK는 파이썬의 인스펙션(Inspection)과 타입 힌트(Type Hints), 독스트링(Docstring) 메타데이터를 분석하여, 개발자가 별도의 JSON 스키마를 작성할 필요 없이 자동으로 스키마를 생성해 줍니다.
구체적으로 다음과 같은 요소들을 추출해 스키마를 만듭니다:
- 함수 이름: 도구의 고유 식별자 (get_today_weather)
- 독스트링 (Docstring): 함수의 설명(주어진 도시의 '오늘' 날씨를 조회하고...)을 읽어, LLM에게 "이 도구는 어떤 상황에서 어떤 목적으로 호출해야 하는지" 알려주는 설명서(Description)로 변환합니다.
- 파라미터 및 타입 힌트 (city: str):
- city라는 파라미터가 필수(str)인지, 혹은 생략 가능한(Optional[str]) 것인지를 분석합니다.
- 이를 바탕으로 LLM에게 *"이 도구를 호출하려면 반드시 city라는 문자열 값을 JSON 형태로 담아서 보내야 해"*라는 규칙을 알려줍니다.
요약하자면
우리가 파이썬 함수에 타입 힌트와 친절한 설명(Docstring)을 정성스럽게 작성해 두고 tools=[...]에 넣어주기만 하면, ADK가 이를 번역하여 Gemini 모델에게 "너는 지금부터 이런 도구들을 쓸 수 있어!"라고 완벽한 명세서를 쥐어주는 것입니다. 이 덕분에 에이전트는 사용자의 질문 의도를 파악하고 알맞은 도구를 정확한 인자와 함께 호출할 수 있게 됩니다.