LLM 개발 입문 (6) - 2

루나·2026년 2월 12일

LLM STUDY

목록 보기
12/31
post-thumbnail

본 포스팅은 "Do it! LLM을 활용한 AI 에이전트 개발 입문"을 독학하며 쓴 글입니다.
내돈내산 포스팅임을 참고해주시면 감사하겠습니다.
2026년 2월 13일 기준으로 작성되었습니다.


Chapter 6

AI 투자자

본 포스팅에서는 펑션 콜링에 대해 알아보고 이를 활용하는 코드를 작성해보겠습니다

1. GPT와 미국 주식 이야기하기

'요새 코스피 지수가 얼마야?' 또는 '애플 주식을 팔아야 할까 사야 할까?'
이런 대화를 GPT와 하기 위해서는 GPT가 최신 주식 정보를 알 수 있어야 한다

이제부터 yfinance 라는 파이썬 라이브러리를 사용해 미국 주식 정보를 쉽게 가져와서 GPT와 대화해보자
yfinance를 사용하면 주가, 재무제표, 거래량 등 다양한 데이터를 데이터 프레임 형태로 가져올 수 있다

일단 터미널 창에서 yfinance를 설치하도록 하자

pip install yfinance

을 이용하여 가상환경에 yfinance를 설치한다

yfinance.ipynb 파일을 생성한 후 다음과 같은 코드를 실행시켜 보자

  • 에러 발생
    기본적으로 난 코딩하는 파일들을 바탕화면의 "코딩" 폴더에 넣어놓고 있다
    그런데 이렇게 하니까 [Failed to perform, curl: (77) error setting certificate verify locations:] 이런 에러가 발생했다
    구글링을 하면서 원인을 찾아보다가 폴더명이 특수문자가 들어가면 이런 경우가 종종 있다고 한다
    참고한 링크 : 깃허브
import yfinance as yf

# 마이크로소프트(MSFT)에 대한 Ticker 객체 요청
msft = yf.Ticker("MSFT")

# Ticker 객체의 정보 출력
display(msft.info)


코드를 실행해보니 마이크로소프트의 기본 정보들이 출력된다

이제 최근 5일간의 주가 정보만 확인해보자
여기서 period는 가져올 데이터의 기간을 의미한다
예를들어. 3일간의 데이터는 '3d', 2개월간의 데이터는 '2mo' , 1년간의 데이터는 '1y'로 입력한다

hist = msft.history(period= "5d")
display(hist)


이제 우리는 주가 정보를 데이터프레임의 형태로 확인할 수 있게 되었다!!

이 데이터 프레임에서 각 열의 정보는 아래 표와 같다

열 이름설명
Open(시가)거래 시작 시점의 주가
High(고가)해당 거래일 동안의 최고 가격
Low(저가)해당 거래일 동안의 최저 가격
Close(종가)해당 거래일 마지막 시점의 주가
Volume(거래량)해당 거래일 동안 거래된 주식의 총 수량
Dividends(배당금)주식 배당금
Stock Splits(주식 분할)해당 거래일에 발생한 주식 분할 비율, 없으면 0으로 표기

해당 종목에 대한 애널리스트들의 분석 결과도 찾아볼 수 있다!!
아래 코드는 msft 객체의 recommendations 속성을 표기한다
recommendations yfinance에서 제공하는 속성으로 주식 분석가들이 이 주식에 대해 내린 추천을 포함하는 판다스 데이터프레임을 보여준다

msft.recommendations


사진에서 period는 분석가들이 추천한 시점을 의미한다
0m 은 현재, -1m은 1개월 전을 의미하고 등급은 strongBuy 부터 strongSell까지 총 5등급으로 분류된다

2. GPT에서 사용할 yfinance 관련 함수 만들기

GPT가 최신 주가 정보에 기반해서 답변하도록 하려면 필요한 기능을 함수로 만들어서 펑션 콜링을 활용해야 한다

이전 포스팅에서 만든 gpt_functions.py 파일을 활용해서 회사의 기본 정보와 최신 주가 정보를 가져 오고 투자 의견을 알려 주는 함수를 만들어보자

우선 회사의 기본정보를 가져오는 get_yf_stock_info 함수를 생성하자

# gpt_functions.py
import yfinance as yf

def get_yf_stock_info(ticker : str):
  stock = yf.Ticker(ticker)
  info = stock.info
  print(info)
  return str(info)

if __name__ == "__main__":
  # get_current_time('America/New_York')
  info = get_yf_stock_info('AAPL')
  • stock = yf.Ticker(ticker)
    정보를 가져올 회사를 선택한다
  • return str(info)
    .info는 딕션너리 형태로 반환되어서 GPT에 바로 전달할 수 없다
    따라서 str(info)를 이용해서 딕셔너리를 string으로 캐스팅해서 전달한다

위의 코드는 애플의 정보를 출력해준다 결과를 확인해보자
되게 복잡하게 다양한 내용이 들어가있는것을 볼 수 있다

이제 get_yf_stock_info 함수의 설명을 tools에 추가해서 GPT에서 이 함수를 사용할 수 있도록 만들어보자
또한 description에 함수의 설명을 적고 ticker는 필수 항목으로 지정한다

tools = [
   {
    "type" : "function",
    "function" : 
      {"name" : "get_yf_stock_info",
      "description" : "해당 종목의 Yahoo Finance 정보를 반환합니다",
      "parameters" : {
        "type" : "object",
        "properties" : {
          'ticker' : {
            'type' : 'string',
            'description' : 'Yahoo Finance 정보를 반환할 종목의 티커를 입력하세요. (예 : AAPL)',
            }
          },
          "required" : ['ticker']
        }
      }
  }
]

그리고 스트림릿에 연결된 GPT에서 get_yf_stock_info 함수를 사용할 수 있도록 지난 포스팅에서 만든 what_time_is_it_streamlit.py 파일에서 코드를 수정해보자

# stock_info_streamlit.py
from gpt_functions import get_current_time, tools, get_yf_stock_info
from openai import OpenAI
from dotenv import load_dotenv
import os
import json   # GPT가 JSON 형태의 문자열을 반환할때 읽기 위한 라이브러리
import streamlit as st

load_dotenv()
api_key = os.getenv('OPENAI_API_KEY')

client = OpenAI(api_key = api_key)

def get_ai_response(messages, tools = None):
  response = client.chat.completions.create(
    model = "gpt-4o",
    messages = messages,
    tools = tools
  )

  return response

st.title("💬 Chatbot")

if "messages" not in st.session_state:
  st.session_state["messages"] = [
    {"role" : "system", "content" : "너는 사용자를 도와주는 상담사야"}
  ]

for msg in st.session_state.messages:
    if msg["role"] == "assistant" or msg["role"] == "user":
      st.chat_message(msg["role"]).write(msg["content"])

if user_input := st.chat_input():
  st.session_state.messages.append({"role": "user", "content": user_input})
  st.chat_message("user").write(user_input)

  ai_response = get_ai_response(st.session_state.messages, tools = tools)
  ai_message = ai_response.choices[0].message
  print(ai_message)

  tool_calls = ai_message.tool_calls

  if tool_calls:
    # 반복문을 이용해서 함수를 차례대로 실행할 수 있도록 함
    for tool_call in tool_calls:
      tool_name = tool_call.function.name
      tool_call_id = tool_call.id

      # 추가된 부분
      arguments = json.loads(tool_call.function.arguments)

      if tool_name == "get_current_time":
        st.session_state.messages.append({
          "role" : "function",
          "tool_call_id" : tool_call_id,
          "name" : tool_name,
          "content" : get_current_time(timezone = arguments['timezone']),   # 함수 실행 결과를 content로 설정
        })

      ## 기존 코드에서 추가된 부분
      elif tool_name == "get_yf_stock_info":
        st.session_state.messages.append({
          "role" : "function",
          "tool_call_id" : tool_call_id,
          "name" : tool_name,
          "content" : get_yf_stock_info(ticker = arguments['ticker']),   # 함수 실행 결과를 content로 설정
        })

    st.session_state.messages.append({"role" : "system", "content" : "이제 주어진 결과를 바탕으로 답변할 차례다"})

    ai_response = get_ai_response(st.session_state.messages)
    ai_message = ai_response.choices[0].message

  st.session_state.messages.append({
    "role" : "assistant",
    "content" : ai_message.content
  })

  print("AI\t: " + ai_message.content)
  st.chat_message("assistant").write(ai_message.content)

기존의 코드와 달라진 점은

elif tool_name == "get_yf_stock_info":

부분을 추가해서 우리가 만든 get_yf_stock_info도 GPT가 사용할 수 있도록 했다는 점이다

이제 streamlit run (파일명).py 로 코드를 실행하고 질문을 해보자

테슬라에 대해 질문을 하고 이전 포스팅에서 만든 get_current_time 함수도 적절하게 잘 실행하는지 확인하기 위해 테슬라 본사 기준으로 지금 몇시인지도 물어보고 올바르게 대답하는 것을 확인해보았다

물론 이 포스팅을 적고 있는 현재 테슬라의 본사는 텍사스에 위치하는데 이 부분에 대해서는 GPT에서 오류가 난 것 같다
재질문을하니 텍사스의 시간을 다시 알려주긴 함...ㅎㅎ

3. 코드 리팩토링

사용할 함수가 앞으로 점점 많아질것 같으니 미리 코드를 리팩토링해보자

지금까지의 코드에서는 tool_name이 get_current_time인지 get_yf_stock_info 인지에 따라 매번 st.session_state_messages에 추가하는 부분이 반복되었다
하지만 호출하는 함수만 다르고 거의 모든 구조가 비슷하니까 이를 좀 더 간단하게 바꿔보도록 하자

stock_info_streamlit.py 파일에서 if 문 안에서 함수를 실행한 결과를 func_result에 담고
st.session_state_messages에 추가하는 내용은 따로 분리한다

  if tool_calls:
    # 반복문을 이용해서 함수를 차례대로 실행할 수 있도록 함
    for tool_call in tool_calls:
      tool_name = tool_call.function.name
      tool_call_id = tool_call.id
      arguments = json.loads(tool_call.function.arguments)

      # 리팩토링된 부분
      if tool_name == "get_current_time":
        func_result = get_current_time(timezone = arguments['timezone'])

      elif tool_name == "get_yf_stock_info":
        func_result = get_yf_stock_info(ticker = arguments['ticker'])
        
      st.session_state.messages.append({
        "role" : "function",
        "tool_call_id" : tool_call_id,
        "name" : tool_name,
        "content" : func_result,
      })

    st.session_state.messages.append({"role" : "system", "content" : "이제 주어진 결과를 바탕으로 답변할 차례다"})

    ai_response = get_ai_response(st.session_state.messages)
    ai_message = ai_response.choices[0].message

if 문을 위와 같이 변경하면 더욱 많은 함수가 추가 되어도 elif 구문만 추가하면 된다는 점이다
이렇게 코드를 리팩토링하면 줄 수도 줄어들고 훨씬 가독성이 좋아진다

4. 종목 최근 주가 정보와 추천 정보 가져오기

같은 방식으로 최근 주가 기록을 가져오는 함수 get_yf_stock_history 와 추천 정보를 가져오는 함수 get_yf_stock_recommendations을 만들어보자

함수들을 모아놓은 gpt_functions.py에서 작업하면 된다

def get_yf_stock_history(ticker : str, period : str):
  stock = yf.Ticker(ticker)
  history = stock.history(period = period)
  history_md = history.to_markdown()  #데이터프레임을 마크다운 형식으로 변환
  print(history_md)
  return history_md

def get_yf_stock_recommendations(ticker : str):
  stock = yf.Ticker(ticker)
  recommendations = stock.recommendations
  recommendations_md = recommendations.to_markdown()  #데이터프레임을 마크다운 형식으로 변환
  print(recommendations_md)
  return recommendations_md

if __name__ == "__main__":
  # get_current_time('America/New_York')
  # info = get_yf_stock_info('AAPL')
  get_yf_stock_history('AAPL', '5d')
  print('---------------')
  get_yf_stock_recommendations('AAPL')

위와 같이 함수를 추가하고 터미널에서 코드를 실행시켜보자
처음 코드를 실행시키면 tabulate 모듈이 없어서 에러가 발생하는데

pip install tabulate

를 이용해서 라이브러리를 설치하면 정상적으로 코드가 실행된다

이렇게 데이터 프레임을 마크다운 형식으로 바꿔진 것을 터미널에서 확인할 수 있다

이제 추가한 함수 두개를 스트림릿에서 채팅할 때 활용할 수 있도록 tools에 설명을 넣어야 한다

  {
    "type" : "function",
    "function" : 
      {"name" : "get_yf_stock_history",
      "description" : "해당 종목의 Yahoo Finance 주가 정보를 반환합니다",
      "parameters" : {
        "type" : "object",
        "properties" : {
          'ticker' : {
            'type' : 'string',
            'description' : 'Yahoo Finance 주가 정보를 반환할 종목의 티커를 입력하세요. (예 : AAPL)',
          },
          'period' : {
            'type' : 'string',
            'description' : 'Yahoo Finance 정보를 반환할 조회할 기간을 입력하세요. (예 : 1d, 5d, 1mo, 1y, 5y)',
            }
          },
          "required" : ['ticker', 'period']
        }
      }
  },

  {
      "type" : "function",
      "function" : 
        {"name" : "get_yf_stock_recommendations",
        "description" : "해당 종목의 Yahoo Finance 추천 정보를 반환합니다",
        "parameters" : {
          "type" : "object",
          "properties" : {
            'ticker' : {
              'type' : 'string',
              'description' : 'Yahoo Finance 추천 정보를 반환할 종목의 티커를 입력하세요. (예 : AAPL)',
              }
            },
            "required" : ['ticker']
          }
        }
  }

해당 코드를 기존의 tools에 추가해보도록 하자

그리고 stock_into_streamlit.py에 get_yf_stock_history와 get_yf_recommendations 도 import 해준다
또한 함수가 추가되었으니 if~elif 구문에 해당 함수들도 추가해준다

      # 리팩토링된 부분
      if tool_name == "get_current_time":
        func_result = get_current_time(timezone = arguments['timezone'])

      elif tool_name == "get_yf_stock_info":
        func_result = get_yf_stock_info(ticker = arguments['ticker'])

      elif tool_name == "get_yf_stock_history":
        func_result = get_yf_stock_history(ticker = arguments['ticker'], period = arguments['period'])

      elif tool_name == "get_yf_recommendations":
        func_result = get_yf_recommendations(ticker = arguments['ticker'])

이제 streamlit run (파일명).py 로 코드를 실행시켜보자


질문을 했을 때 내용은 올바르게 받아왔지만 터미널에서 보이던 표는 스트림릿에서 보이지 않았다
그래서 GPT를 이용해서 어떻게 해결하면 좋을지 물어봤다

우선 gpt_functions.py에서 get_yf_stock_history의 return값을 변경한다

def get_yf_stock_history(ticker : str, period : str):
  stock = yf.Ticker(ticker)
  history = stock.history(period = period)
  history_md = history.to_markdown()  #데이터프레임을 마크다운 형식으로 변환
  print(history_md)
  return history

또한 stock_info_streamlit.py에서 함수 이름이 get_yf_stock_history일 때 처리부분을 아래와 같이 수정한다

elif tool_name == "get_yf_stock_history":
        func_result = get_yf_stock_history(ticker = arguments['ticker'], 
                                           period = arguments['period'])
        #스트림릿에서는 데이터 프레임으로 출력시킴
        st.dataframe(func_result)
        #GPT에는 마크다운으로 변형시켜서 전달
        func_result = func_result.to_markdown()

이렇게 코드를 수정하고 다시 스트림릿을 실행하면 사진과 같이 스트림릿에서도 표를 확인할 수 있다

그리고 해당 주식의 매수를 추천하는지 물어보면....

get_yf_stock_recommendations 함수를 호출하고 알맞게 답변해준다

5. 마무리

이렇게 yfinance를 이용해서 미국 주식 정보를 얻어오고 사용하는 방법에 대해 알아보았다
예전에 AI 자동 주식 투자 봇 만들기를 해보려다가 포기한 적이 있었는데
(국내 주식 정보를 다 컴퓨터에 다운로드 받아서 저장하고 하루하루 지날 때 마다 갱신했어야 했는데 DB만 해도 용량이 매우 컸다..)
이런 라이브러리가 있었다면 조금 더 편하게 개발할 수 있었을까 라는 생각이 들었다

다음 포스팅에서는 지금까지와는 관계가 없어보이지만...?
스트림 출력하기를 실습해보려고 한다
(근데 진짜 왜 갑자기 주식 다루다가 스트림 출력하기로 가는걸까)

profile
Per ardua ad astra

0개의 댓글