우리 프로젝트는 실제적으로 1개의 채팅창 화면을 챗봇이라하고...

이 챗봇에게 회사상품, 회사HR기준,아이디어제작기, 심리상담, 보고서자동화 기능을 처리하기위해서 만들었다.

 

1개의 챗봇이 여러기능을 하기위해서 각 모듈별로 작업을 했던거고

 

이제 각자  모듈이 완성되어가고 있는 시점에 , 챗봇의 역할이 매우 중요해졌음..

구조적으로 에이전트 완성은 되었으나... 나중에 기억하기위해서라도 정리를 좀 해두... 해야겠다.

 

 

 

 

 

캐릭터는 숨길 수 있도록 토글기능 넣어뒀고, 채팅창도 크게 키우고....

 

아래와 같은 챗봇 1개에서 여러개의 모듈을 LLM이 알아서 호출할 수 있도록 구현해두었다.(아직 미구현된 기능들은 플로차트에 빠져있음)

 

 

 

먼저 챗봇에서  멀티에이전트를 불러온다.

 

export async function sendMultiAgentMessage(userMessage) {
  try {
    console.log('🤖 Multi-Agent 메시지 전송:', userMessage);

    // 세션 ID 가져오기 (실패해도 계속 진행)
    let sessionId = null;
    try {
      sessionId = await getOrCreateMultiAgentSession();
    } catch (error) {
      console.warn('⚠️ 세션 생성 실패, 세션 없이 진행:', error);
      // 세션 없이도 진행 가능 (백엔드가 선택적으로 처리)
    }

    const headers = {
      'Content-Type': 'application/json',
    };

    if (accessToken) {
      headers['Authorization'] = `Bearer ${accessToken}`;
    }

    const requestBody = {
      query: userMessage
    };

    if (sessionId) {
      requestBody.session_id = sessionId;
    }

    const response = await fetch(`${API_BASE_URL}/multi-agent/query`, {
      method: 'POST',
      headers: headers,
      credentials: 'include',
      body: JSON.stringify(requestBody)
    });

    if (!response.ok) {
      const errorText = await response.text();
      console.error(`❌ Multi-Agent API 호출 실패: ${response.status} ${response.statusText}`, errorText);
      throw new Error(`Multi-Agent API 호출 실패: ${response.status} ${response.statusText}`);
    }

    const result = await response.json();
    console.log('🤖 Multi-Agent 응답:', result);

    return result;

  } catch (error) {
    console.error('❌ Multi-Agent API 오류:', error);
    throw error;
  }
}

 

 

const response = await fetch(`${API_BASE_URL}/multi-agent/query`, {
method: 'POST',
headers: headers,
credentials: 'include',
body: JSON.stringify(requestBody)
});

 

요 문구 부분이 백엔드 API를 호출하게된다. 

 

그럼 엔드포인트를 관리하는 multi_agent.py 파일은..

내부 로직에 따라 각모듈을 찾아주는 역할을하는데 그게..아래 부분이다.

 

# Supervisor agent 싱글톤 가져오는 함수
def get_supervisor_agent() -> SupervisorAgent:
    
    global _supervisor_agent
    if _supervisor_agent is None:
        _supervisor_agent = SupervisorAgent()
    return _supervisor_agent

# 사용자 질문을 적절한 에이전트에게 전달하는 함수
@router.post("/query", response_model=MultiAgentResponse)
async def multi_agent_query(
    request: MultiAgentRequest,
    supervisor: SupervisorAgent = Depends(get_supervisor_agent)
):

    try:
        response = await supervisor.process(request)
        return response
    except Exception as e:
        raise HTTPException(
            status_code=500,
            detail=f"Multi-Agent 처리 중 오류 발생: {str(e)}"
        )

# 사용 가능한 에이전트 목록 조회
@router.get("/agents", response_model=List[Dict[str, Any]])
async def get_available_agents(
    supervisor: SupervisorAgent = Depends(get_supervisor_agent)
):

    try:
        agents = supervisor.get_available_agents()
        return agents
    except Exception as e:
        raise HTTPException(
            status_code=500,
            detail=f"에이전트 목록 조회 중 오류 발생: {str(e)}"
        )

 

 

 

그럼 슈퍼바이저는.. 아래내용인 프롬프트 엔지니어링을 통해서 필요한 모듈을 찾아가게 한다. 

 

**당신의 역할:**
1. 사용자의 질문을 이해하고 의도를 파악합니다.
2. 질문에 포함된 키워드와 맥락을 분석합니다.
3. 질문에 가장 적합한 전문 에이전트를 선택합니다.
4. 선택한 에이전트에게 작업을 위임하고 결과를 받습니다.
5. 최종 결과를 사용자에게 명확하고 친절하게 전달합니다.

**사용 가능한 전문 에이전트:**
1,2 생략!!!

3. **brainstorming_tool**: 창의적 아이디어 발상 및 브레인스토밍 지원
   - 사용 조건:
     * 사용자가 구체적인 아이디어나 해결책을 필요로 하는 상황
     * 단순한 정보 질문이 아닌, 실제로 아이디어 생성을 원하는 경우
     * "브레인스토밍이 뭐야?" 같은 개념 설명 요청은 chatbot_tool 사용
   - 트리거 상황:
     * 명시적 요청: "브레인스토밍 해줘", "아이디어 만들어줘", "기획 도와줘"
     * 막힌 상황: "좋은 생각이 안 떠올라", "기획이 막혔어", "아이디어가 필요해"
     * 창의적 요구: "새로운 방법이 필요해", "참신한 아이디어 좀", "혁신적인 접근법"
   - 예시 (도구 사용 O):
     * "새로운 마케팅 아이디어를 내고 싶어"
     * "프로젝트 기획이 막혔는데 도와줘"
     * "좋은 생각이 안 떠올라"
     * "브레인스토밍 해줘"
     * "창의적인 해결책이 필요해"
   - 예시 (도구 사용 X - chatbot_tool 사용):
     * "브레인스토밍이 뭐야?" → 개념 설명 요청
     * "아이디어를 만든다는 게 뭐야?" → 정보 질문
     * "브레인스토밍 방법 알려줘" → 기법 설명 요청


4,5,6~ 생략 !!! 

**에이전트 선택 가이드:**
1. **"브레인스토밍"이라는 단어가 명시적으로 포함되면 무조건 brainstorming_tool을 선택하세요.**
2. 질문에 포함된 키워드를 먼저 확인하세요.
3. 여러 에이전트의 키워드가 겹치면, 질문의 주요 목적을 파악하세요.
4. 감정적 표현(힘들어, 우울해 등)이 있으면 therapy_tool을 우선 고려하세요.
5. 회사/업무 관련 정보 요청은 rag_tool을 사용하세요.
6. 일반적인 인사나 잡담은 chatbot_tool을 사용하세요.

**중요한 규칙:**
- 질문의 핵심 의도를 정확히 파악하세요.
- 가장 적합한 에이전트 하나를 선택하세요.
- **brainstorming_tool을 선택한 경우, 절대 직접 답변을 생성하지 말고 에이전트의 안내 메시지만 그대로 전달하세요.**
- **적절한 에이전트(도구)를 사용하는 경우, 챗봇이 직접 길게 설명하지 말고 간결하게 해당 모듈 사용을 안내하세요.**
- 에이전트의 응답을 그대로 사용자에게 전달하세요.
- 한국어로 응답하세요.
"""

 

 

이 문장을 지피티(LLM)이 챗봇으로써 파악하고 실행할 모듈을 찾아가게한다.

 

ai 답변을 빌어 ..

  1. Python 코드 (
     
    BrainstormingAgent):
    • 사용자님이 작성하신 이 클래스는 **실제 작업자(Worker)**입니다.
    • 하지만 LLM(Supervisor)은 이 파이썬 코드를 직접 읽거나 실행할 수 없습니다.
  2. 도구 등록 (
    ):
    •  
      supervisor.py에서 를 호출할 때, 이 에이전트가 **"도구(Tool)"**라는 형태로 포장되어 LLM에게 전달됩니다.
    • 이때 LLM에게는 코드가 아니라 **JSON 스키마(설명서)**만 전달됩니다.
    • 예시: "이 도구의 이름은 이고, 
       
      query라는 문자열 인자를 받으며, 창의적인 아이디어가 필요할 때 사용합니다."
  3. LLM의 판단 (Function Calling):
    • Supervisor(LLM)가 사용자 질문("아이디어 만들어줘")을 받으면, 프롬프트에 적힌 규칙을 보고 생각합니다.
    • "아, 이건 을 써야겠군!"
    • 그리고 LLM은 텍스트 답변 대신 **특수한 신호(JSON)**를 뱉어냅니다.
    • 출력 예시: 
  4. 실제 실행 (Runtime):
    • LangGraph 프레임워크가 이 신호를 감지하고, 실제로 Python의 
       
      process() 함수를 실행합니다.
    • 그리고 그 결과()를 다시 LLM에게 돌려줍니다.

 

 

요렇게 해서 최종적으로 

"""
Brainstorming Agent

브레인스토밍 및 창의적 아이디어 제안 에이전트
기존 BrainstormingService를 활용합니다.
"""

from typing import Dict, Any, Optional
from .base_agent import BaseAgent

# 브레인스토밍 에이전트 클래스
class BrainstormingAgent(BaseAgent):

    # 초기화 함수    
    def __init__(self):
        super().__init__(
            name="brainstorming",
            description="창의적인 아이디어 발상과 브레인스토밍 기법을 제안하는 에이전트입니다. "
                       "문제 해결, 아이디어 도출, 창의적 사고 방법 등을 안내합니다."
        )
        # Lazy loading: 실제 사용 시에만 BrainstormingService 로드
        self._brainstorming_service = None
    
    # @property: 메소드를 변수처럼 사용할 수 있게 해주는 기능
    @property
    def brainstorming_service(self):
        """BrainstormingService lazy loading"""
        if self._brainstorming_service is None:
            from app.domain.brainstorming.service import BrainstormingService
            self._brainstorming_service = BrainstormingService()
        return self._brainstorming_service
    
    # 브레인스토밍 진행하는 비동기 함수
    async def process(self, query: str, context: Optional[Dict[str, Any]] = None) -> str:

        try:
            # Supervisor가 이 에이전트를 선택했다는 것은
            # 사용자가 아이디어/브레인스토밍이 필요한 상황이라는 의미
            # RAG 검색 없이 바로 브레인스토밍 도구 사용을 제안
            
            print(f"[BrainstormingAgent] 쿼리: {query}")
            print(f"[BrainstormingAgent] 브레인스토밍 도구 제안 모드")
            
            # 사용자의 쿼리에서 주제 추출 (간단하게)
            # 예: "빵집 매출 증대 아이디어" -> "빵집 매출 증대"
            topic_hint = ""
            if "빵집" in query or "카페" in query or "가게" in query:
                topic_hint = "관련 "
            elif "마케팅" in query:
                topic_hint = "마케팅 "
            elif "프로젝트" in query or "기획" in query:
                topic_hint = "프로젝트 "
            
            # 간결한 제안 메시지 반환
            return f"SUGGESTION: 브레인스토밍 도구로 {topic_hint}아이디어를 함께 만들어볼까요? 🚀"
            
        except Exception as e:
            print(f"[BrainstormingAgent] 오류: {e}")
            return f"브레인스토밍 제안 중 오류가 발생했습니다: {str(e)}"
    
    # 브레인스토밍 에이전트 기능 목록 리턴
    def get_capabilities(self) -> list:
        
        return [
            "창의적 아이디어 제안",
            "브레인스토밍 기법 안내",
            "문제 해결 방법 제시",
            "협업 방법 제안",
            "혁신적 사고 촉진",
        ]

요녀석이 .. 메인모듈을 찾아간다. 

 

 

복잡하구나....

초보 개발자 지망생이 이걸 ai 없이 짤수있나 ?... ㅋㅋㅋ 

개념만 머리에...

+ Recent posts