[Tech Log] 단순 챗봇을 넘어 'AI 에이전트'로: 멘탈케어 서비스 '마음봄' 아키텍처 설계기

2025. 12. 2. 10:02AI 개발

 

들어가며 단순히 사용자의 질문에 답변만 하는 챗봇은 이제 낡았습니다. 사용자의 의도를 파악하고, 스스로 기억을 뒤져 정보를 찾고, 고민 끝에 답변을 내놓는 'AI 에이전트(AI Agent)'가 필요한 시점입니다. 이번 포스팅에서는 갱년기 여성들을 위한 심리 케어 서비스 '마음봄(Maeumbom)' 프로젝트를 준비하며 설계한 Deep Agent Architecture를 소개합니다. Spring Boot의 안정성과 Python의 AI 생태계를 결합한 하이브리드 구조입니다.


1. 전체 아키텍처 개요 (High-Level Design)

AI 에이전트 아키텍처의 핵심은 "순환 루프(Loop)"에 있습니다.

일반적인 웹 서비스가 Request → Response의 단방향 흐름을 가진다면, 에이전트는 목표를 달성할 때까지 [생각(Thought) → 행동(Action) → 관찰(Observation) → 재사고(Thought)]의 과정을 반복합니다. 마치 사람이 문제를 해결하는 방식과 유사하죠.

이 구조를 실제 서비스에 적용하기 위해, 저희 팀은 3계층(3-Tier) 구조를 채택했습니다.

A. 프론트엔드 (React)

  • 역할: 사용자 인터페이스 (채팅창, 시나리오 게임 화면)
  • 핵심: 사용자의 입력을 백엔드로 전달하고, AI 에이전트가 사고하는 과정(중간 단계)이나 최종 답변을 스트리밍(Streaming)으로 끊김 없이 보여주어 사용자 경험(UX)을 극대화합니다.

B. 메인 백엔드 (Spring Boot)

  • 역할: 서비스의 중추. API 게이트웨이, 사용자 인증(Auth), 비즈니스 로직, 정형 데이터(RDB) 저장을 담당합니다.
  • 연동: 모든 요청을 처리하되, AI의 추론이 필요한 복잡한 요청만 선별하여 AI 서비스(Python)로 넘겨줍니다.

C. AI 에이전트 서비스 (Python - FastAPI/Flask)

  • 역할: 서비스의 '뇌(Brain)'. LangChain이나 LangGraph가 구동되는 곳입니다.
  • 선정 이유: Java(LangChain4j)로도 구현 가능하지만, 최신 LLM 라이브러리와 도구 생태계가 압도적으로 Python에 집중되어 있어 유지보수와 기능 확장에 유리하다고 판단했습니다.

2. 상세 컴포넌트 설계: 에이전트의 뇌 구조

AI 에이전트 서비스(Python) 내부를 현미경으로 들여다보면, 다음과 같은 유기적인 컴포넌트들로 구성됩니다.

① 오케스트레이터 (Orchestrator / Controller)

  • 기술: LangGraph (상태 기반의 복잡한 흐름 제어에 탁월)
  • 역할: LLM과 도구 사이의 신호등 역할을 합니다. 현재 대화 상태(State)를 분석하여 "지금 검색이 필요한가? 아니면 바로 위로의 말을 건넬 때인가?"를 판단합니다.

② 메모리 (Memory): 상담 서비스의 핵심

심리 케어 서비스에서 가장 중요한 것은 '맥락'과 '기억'입니다. 이를 위해 메모리를 이원화했습니다.

  1. Short-term Memory (단기 기억): Redis 등을 사용하여 현재 세션의 대화 내역(History)을 저장합니다. 대화의 즉각적인 맥락을 파악합니다.
  2. Long-term Memory (장기 기억): Vector DB (Chroma, Pinecone 등)를 활용합니다.
    • 적용 예시: 사용자가 3일 전 "요즘 잠이 안 와"라고 했다면, 이를 벡터화해 저장해 둡니다. 오늘 대화 시 에이전트가 먼저 "지난번 불면증은 좀 어떠세요?"라고 물어볼 수 있게 하여, 사용자가 '케어받고 있다'는 느낌을 줍니다.

③ 도구 (Tools)

LLM이 필요할 때 꺼내 쓸 수 있는 함수들의 집합입니다.

  • 검색 도구: Tavily, Google Search API (최신 건강/의학 정보 검색)
  • 데이터 조회: Spring Boot API를 역호출하여 사용자의 진단 기록 조회
  • 게임 로직: 시나리오 게임 진행 상황 업데이트

3. 데이터 흐름 시나리오 (Sequence)

사용자가 "요즘 우울해서 잠이 안 오는데, 지난번 추천해준 차(Tea)가 뭐였지?"라고 물었을 때, 시스템은 어떻게 작동할까요?

  1. React: 메시지 전송 → Spring Boot
  2. Spring Boot: 사용자 인증 토큰 검증 후, 메시지를 Python AI 서버로 전달
  3. Python Agent (Brain):
    • (Thought 1): "사용자가 과거 정보를 묻고 있네. 그냥 답변할 수 없고 '기억 검색' 도구가 필요해."
    • (Action 1): Vector DB에서 추천 차, 불면증 키워드로 과거 대화 검색 실행.
    • (Observation 1): 검색 결과 카모마일 차 데이터 확보.
    • (Thought 2): "정보는 찾았고, 사용자가 우울하다고 했으니 위로의 말을 덧붙여 최종 답변을 만들자."
    • (Final Answer): "지난번에 카모마일 차를 추천해 드렸어요. 따뜻한 차 한 잔이 도움이 될 거예요. 요즘도 주무시는 게 많이 힘드신가요? 마음봄이 옆에서 도와드릴게요."
  4. Spring Boot: 답변 수신 및 DB 로그 저장 → React 응답

4. 개발자를 위한 구현 팁 (Pseudo Code)

LangGraph를 활용하여 이 구조를 구현할 때의 핵심 로직을 간단한 코드로 표현하면 다음과 같습니다.

from typing import TypedDict, Annotated, List
from langgraph.graph import StateGraph, END

# 1. 에이전트의 상태(State) 정의
# 대화가 진행되는 동안 유지되어야 할 데이터 구조
class AgentState(TypedDict):
    messages: List[BaseMessage] # 누적된 대화 내역
    user_emotion: str           # 사용자의 현재 감정 (심리 케어 프롬프트용)

# 2. 에이전트 노드 (두뇌 역할)
def call_model(state: AgentState):
    # 시스템 프롬프트에 '마음봄' 페르소나와 감정 상태 주입 (RAG/Prompt Engineering)
    system_prompt = (
        f"당신은 다정한 심리 케어 AI '마음봄'입니다. "
        f"현재 사용자 감정 상태: {state['user_emotion']}"
    )
    # LLM 호출
    response = llm.invoke([system_prompt] + state['messages'])
    return {"messages": [response]}

# 3. 워크플로우 정의 (Graph Construction)
workflow = StateGraph(AgentState)

workflow.add_node("agent", call_model) # 생각하는 노드
workflow.add_node("tools", tool_node)  # 검색/DB조회 노드

# 4. 조건부 엣지 설정 (The Loop)
# LLM의 판단에 따라 도구를 쓸지, 답변을 끝낼지 결정
workflow.add_conditional_edges(
    "agent",
    should_continue, # 판단 함수 (is_tool_call?)
    {
        "continue": "tools",
        "end": END
    }
)
workflow.add_edge("tools", "agent") # 도구 사용 후 다시 생각(agent)으로 복귀

app = workflow.compile()

마치며

'마음봄' 프로젝트는 단순한 정보 전달을 넘어, 사용자의 감정을 이해하고 기억하는 반려 AI를 지향합니다. 이를 위해 Spring Boot의 견고함 위에 Python AI 에이전트의 유연함을 얹은 아키텍처를 설계했습니다.

이 구조는 향후 시나리오 기반 게임 기능이나, 더 고도화된 심리 분석 모델을 붙이기에도 매우 유연한 확장성을 가집니다. AI 서비스를 기획하는 다른 개발자분들에게도 좋은 레퍼런스가 되기를 바랍니다.