LLMOps

AI Agent 구현해보기

ChatGPT를 이용한 간단한 주식 agent 봇 만들기

AI Agent 구현해보기

2022년 11월 30일 ChatGPT가 세상에 공개된 이후, 우리는 급격한 변화의 물결을 체감하고 있다.

그중에서도 특히 주목받는 개념이 바로 AI Agent다. 조금 늦은 감이 있지만, 시대의 흐름을 놓치지 않기 위해 이 개념을 차근차근 살펴보고 간단한 AI Agent를 직접 구현해보고자 한다.

AI Agent??

AI Agent라는 단어를 처음 접했을 때, 나는 이것이 기존 AI 어시스턴트(Assistant)의 다른 표현일 뿐이라고 생각했다.

하지만 둘 사이에는 중요한 차이가 있어서, 이 개념을 먼저 명확히 하고자 한다.

관련 내용을 검색하던 중, GCP docs에서 유용한 정보를 발견했다. 링크는 아래와 같다.

이 문서는 AI Agent를 “AI를 사용해 사용자를 대신하여 목표를 추구하고 태스크를 완료하는 소프트웨어 시스템”이라고 정의한다.

반면 내가 혼동했던 AI Assistant는 “사용자와 직접 협업하고 자연어 및 입력을 이해하여 응답하며 태스크를 수행하도록 설계된 AI 에이전트”라고 설명하고 있다.

예를 들어, AI Assistant는 애플의 Siri나 Amazon의 Alexa처럼 사용자의 질문에 답하고 사용자와 상호작용하며 태스크를 수행한다.

반면 AI Agent는 더 높은 수준의 자율성을 가지며, 자율주행 시스템처럼 특정 목표를 달성하기 위해 독립적으로 의사결정을 내린다.

물론 AI Assistant와 AI Agent 사이의 경계를 명확히 구분 짓기는 어렵다.

화자는 IDE로 cursor를 사용하고 있다. (이제 cursor가 없으면 개발을 못하는 사람이 되었다…)

cursor에는 이미 AI Agent가 도입되어 있다.

위의 사진과 같이 Agent에 목표를 주면, 이를 해결하기 위해서 나의 폴더 구조를 확인하기도 하고, LLM이 가지고 있는 지식을 이용하기도 하고, 필요한 경우 웹에서 검색하기도 하는 등 다양한 방법으로 목표를 수행해 나간다.

작업 도중 에러가 발생할 경우, 이를 해결하기 위해 스스로 원인을 찾아 다른 방법으로 문제를 해결하기도 한다.

AI Agent 실습: 직접 구현하기

직접 실습해보는 것이 가장 이해하기 쉽기에, 간단한 AI Agent를 구현해보려고 한다.

구현할 AI Agent는 주식 가격을 조회하는 간단한 봇이다.

사용한 환경은 아래와 같다.

사용한 환경

  • python 3.12
  • openai - gpt4o-mini
  • yfinance

관련된 전체 코드는 아래의 깃헙 레포지토리에서 확인할 수 있다.

간단한 flow 소개

구현할 봇은 다음과 같은 순서로 동작한다.

  1. 사용자가 질문을 입력한다.
  2. GPT가 질문에서 주식명을 추출하고 해당 종목코드를 반환한다.
  3. yfinance 라이브러리로 종목코드의 주식 정보를 가져온다.
  4. GPT가 데이터를 보기 좋게 정리하여 출력한다.

이제 위 flow를 코드로 구현해보자.

먼저 각 단계별로 필요한 함수를 구현하고, 이를 main 함수에서 호출할 것이다.

Agent를 구성하는 함수는 다음과 같다.

  • act(): 메인 흐름을 제어하는 함수
  • get_stock_code_from_gpt(): 주식 종목 코드를 추출하는 함수
  • get_stock_price(): 주식 가격 정보를 가져오는 함수
  • answer_paraphrase(): 최종 답변을 생성하는 함수

각 함수의 구현 내용을 살펴보자.

먼저 flow를 위한 act() 함수를 살펴보자.

def act(user_input):
    """사용자 입력에 따라 행동 결정"""

    stock_code = get_stock_code_from_gpt(user_input)
    add_ks_mark = f"{stock_code.stock_code}.KS"
    stock_info = get_stock_price(add_ks_mark)
    answer = answer_paraphrase(stock_info, user_input)
    return answer

이 함수는 사용자의 입력을 받아 주식 정보를 조회하고 응답을 생성하는 전체 흐름을 관리한다.

일종의 간단한 LLM 파이프라인이라고 생각하면 편할 것 같다.

다음은 사용자의 질문을 처리하는 main 함수이다.

def main():
    """main function"""
    agent = StockAgent()

    while True:
        user_input = input("유저의 질문: ")
        if user_input == "exit":
            break
        response = agent.act(user_input)
        print(response)

이 함수는 간단한 while문을 통해 사용자의 질문을 받아 처리한다.

이제 본격적으로 AI Agent를 구현하는 부분이다.

GPT를 통해 유저의 질문속에 포함된 주식을 추출하고, 해당 주식종목의 코드를 반환한다.

class StockCode(BaseModel):
    """주식 종목 코드를 반환하는 모델"""

    stock_code: str

def get_stock_code_from_gpt(user_input: str) -> StockCode | None:
    """주식 종목 코드를 반환하기 위한 함수"""
    messages = [
        {
            "role": "system",
            "content": "너는 유저의 질문에 포함된 주식종목의 주식코드를 찾아내는 프로그램이야. 유저의 질문에 포함된 주식종목의 주식코드를 찾아내서 주식코드를 반환해줘",
        },
        {
            "role": "user",
            "content": f"아래의 질문을 통해, 주식종목 코드를 알려줘. 주식 종목 코드는 '000000'처럼, 6자리 숫자로 이루어져 있어. \n 유저의 질문: {user_input}",
        },
    ]
    response = client.beta.chat.completions.parse(
        model="gpt-4o-mini",
        messages=messages,
        max_tokens=150,
        temperature=0.7,
        response_format=StockCode,
    )
    return response.choices[0].message.parsed

유저의 질문속에서 주식종목이 있으면 해당 주식종목 코드를 추출하도록 프롬프트를 구성했다.

이후 추출된 주식종목 코드와 yfinance 라이브러리 통해 주식정보 데이터를 추출한다.

def get_stock_price(ticker_symbol: str) -> dict:
    """주식 가격 정보를 가져오기 위한 함수"""
    try:
        # yfinance 라이브러리를 사용하여 주식 정보 가져오기
        ticker = yf.Ticker(ticker_symbol)
        info = ticker.info

        # 필요한 정보 추출
        current_price = info.get("currentPrice", "정보 없음")
        previous_close = info.get("previousClose", "정보 없음")
        company_name = info.get("longName", ticker_symbol)

        # 가격 변동 계산
        if current_price != "정보 없음" and previous_close != "정보 없음":
            change = current_price - previous_close
            change_percent = (change / previous_close) * 100
            change_str = f"{change:.2f} ({change_percent:.2f}%)"
        else:
            change_str = "정보 없음"

        return {
            "success": True,
            "company_name": company_name,
            "ticker": ticker_symbol,
            "current_price": current_price,
            "previous_close": previous_close,
            "change": change_str,
        }
    except Exception as e:
        return {"success": False, "error": str(e)}

yfinance는 야후 파이낸셜을 통해 주식종목코드의 데이터를 가져오는 라이브러리인데, 국내 주식종목은 모두 있는건 아닌 것 같다.

마지막으로 얻어낸 데이터를 GPT를 통해 답변을 생성한다.

def answer_paraphrase(answer_data: dict, user_input: str) -> str | None:
    """주식 정보데이터를 가지고 답변을 위한 파라프라이즈 함수"""
    messages = [
        {
            "role": "system",
            "content": "너는 유저의 질문에 대한 답변을 만들어주는 프로그램이야. 유저의 질문에 대한 답변을 만들어줘",
        },
        {
            "role": "user",
            "content": f"유저의 질문: {user_input}, 데이터: {answer_data}",
        },
    ]
    response = client.beta.chat.completions.parse(
        model="gpt-4o-mini",
        messages=messages,
        temperature=0.7,
    )
    return response.choices[0].message.content

이렇게 구축된 코드를 실행하면 아래와 같은 간단한 AI Agen가 생성한다.

실행 결과물 예시:

유저의 질문: 기아 자동차 주가가 얼마지?
기아 자동차의 현재 주가는 84,300원입니다. 이전 종가는 84,600원이었으며, 현재 주가는 300원(-0.35%) 하락했습니다.
유저의 질문: 삼성전자는 얼마야?
삼성전자의 현재 주가는 53,500원입니다. 이전 종가는 53,200원이었으며, 오늘은 300원 (0.56%) 상승했습니다.

여담

위와 같이 간단한 AI Agent를 구현해보았다. 사실 이미 대부분의 LLM에서 웹검색을 통해서 내부 로직으로 위와같은 방식 없이도 충분히 Agent 기능을 수행하고 있다.

특히 추론형 모델(Chain of Thought)들이 답을 얻어내는 과정을 보면, 다음과 같은 과정이 포함되어 있을 것이라고 추측된다.

참고로 OpenAI에서는 이미 agent를 쉽게 구축하라고 API를 만들어 두기도 했다.