이전에 재무제표 데이터로 DB를 구축했으니 이 데이터를 이용해 사용자 쿼리에 대해 답변을 생성해 보도록하겠습니다.
1. DB 조회해서 데이터 가져오기
psycopg2.connect()을 사용해 디비에 연결된 상황고 query 변수로 사용자가 원하는 해외 기업이 input으로 들어왔다고 가정하고 진행하도록 하겠습니다.
def get_company_financial_data(conn, ticker):
"""특정 기업의 모든 재무 데이터 조회"""
cursor = conn.cursor()
# 기업 정보 확인
cursor.execute(
"SELECT ticker, company_name FROM companies WHERE ticker = %s", (ticker,)
)
company = cursor.fetchone()
if not company:
return None
ticker, company_name = company
# 재무 데이터 조회
cursor.execute(
"""
SELECT rt.name as report_type, m.name as metric, fd.value
FROM financial_data fd
JOIN metrics m ON fd.metric_id = m.id
JOIN report_types rt ON m.report_type_id = rt.id
WHERE fd.ticker = %s
ORDER BY rt.name, m.name
""",
(ticker,),
)
results = cursor.fetchall()
# 결과 포맷팅
formatted_data = {"ticker": ticker, "company_name": company_name, "financials": {}}
for report_type, metric, value in results:
if report_type not in formatted_data["financials"]:
formatted_data["financials"][report_type] = {}
formatted_data["financials"][report_type][metric] = value
return formatted_data
query="AAPL"
# 예시: 애플(AAPL) 재무 데이터 조회
financial_data = get_company_financial_data(conn, query)
해당 코드로 재무데이터를 조회하고 financial_data를 출력해보면
{'balance_sheet': {'Cash On Hand': '$53,775',
'Long Term Debt': '$83,956',
'Share Holder Equity': '$66,758',
'Total Assets': '$344,085',
'Total Current Assets': '$133,240',
'Total Current Liabilities': '$144,365',
'Total Liabilities': '$277,327',
'Total Liabilities And Share Holders Equity': '$344,085'},
'cash_flow': {'Cash Flow From Financial Activities': '$-39,371',
'Cash Flow From Investing Activities': '$9,792',
'Cash Flow From Operating Activities': '$29,935',
'Net Cash Flow': '$356'},
'financial_ratios': {'Book Value Per Share': '4.4385',
'Current Ratio': '0.9229',
'Debt/Equity Ratio': '1.45',
'Free Cash Flow Per Share': '1.7817',
'Gross Margin': '46.8825',
'Net Profit Margin': '29.2277',
'Operating Margin': '34.4586',
'ROA - Return On Assets': '10.5584',
'ROE - Return On Equity': '54.4204'},
'income_statement': {'Basic EPS': '$2.41',
'EBIT': '$42,832',
'EBITDA': '$45,912',
'EPS - Earnings Per Share': '$2.40',
'Gross Profit': '$58,275',
'Net Income': '$36,330',
'Operating Income': '$42,832',
'Pre-Tax Income': '$42,584',
'Revenue': '$124,300'}}
Json 형태로 데이터들이 잘 조회 된 모습을 볼 수 있습니다.
2. PromptTemplate으로 prompt 만들기
추후에 chain을 구성하기 위해 prompt를 PromptTemplate()를 사용해서 객체로 구성해주겠습니다. 그전에 먼저 .env 파일에 llm으로 사용할 OPENAI_API_KEY 에 대한 값을 저장해주고 load_dotenv()를 실행해줍니다.
from dotenv import load_dotenv
load_dotenv()
쿼리 조회를 해서 가져온 재무제표 데이터를 활용해 답변을 하는지 확인하기 위해, 재무제표 데이터를 사용했을때와 사용하지 않았을때 2개의 프롬프트로 나눠서 chain을 구성해보았습니다.
from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate
llm = ChatOpenAI(model="gpt-4o-mini")
template_1 = "너는 해외 금융 투자 전문가야. {ticker} 종목에 대해서 투자 판단을 내릴 수 있도록 보고서 형태로 일목요연하게 정리해줘."
template_2 = "너는 해외 금융 투자 전문가야. {ticker} 종목에 대해서 {context}를 활용해서 투자 판단을 내릴 수 있도록 보고서 형태로 일목요연하게 정리해줘."
prompt_1 = PromptTemplate(
template=template_1,
input_variables=["ticker"],
)
prompt_2 = PromptTemplate(
template=template_2,
input_variables=["ticker", "context"],
)
chain_1 = prompt_1 | llm
chain_2 = prompt_2 | llm
chain을 invoke()로 실행할때 프롬프트에에 지정한 input_variables의 값을 딕셔너리{ } 형태로 전달해주어야합니다. 그리고 content key 값을 출력하면 응답을 확인할 수 있습니다.
chain_1.invoke({"ticker": financial_data["ticker"]}).content
결과를 확인해보면
## AAPL (Apple Inc.) 투자 보고서
### 1. 개요
- **회사명**: Apple Inc.
- **티커**: AAPL
- **산업 분야**: 소비자 전자제품 및 기술
- **상장시장**: 나스닥
### 2. 최근 성과
- **주가동향**: 최근 1년간 AAPL 주가는 약 X% 상승했습니다. (X%는 실제 데이터를 기반으로 수정 필요)
- **시가총액**: 약 $X trillion (마찬가지로 데이터 보강 필요)
- **P/E 비율**: AAPL의 현재 주가수익비율(P/E)은 X로, 이는 같은 업종 내 평균인 Y와 비교할 때 (고평가/저평가)되며, 성장 잠재력을 반영합니다.
### 3. 재무 현황
- **매출 성장률**: 최근 분기 매출은 $X billion으로, 전년 대비 Y% 증가하였습니다.
- **순이익**: 순이익은 $X billion이며, 이는 증가 추세를 보이고 있습니다.
- **부채 비율**: 총 부채는 X%로 상대적으로 안전한 수준입니다.
- **현금 흐름**: AAPL은 강력한 자유 현금 흐름을 유지하고 있으며, 이는 배당금 지급 및 주식 재구매에 기여하고 있습니다.
### 4. 시장 동향
- **경쟁사 분석**: 주요 경쟁사로는 삼성전자, 구글, 마이크로소프트 등이 있으며, 이들과의 비교에서 AAPL의 시장 점유율이 X%로 나타났습니다.
- **소비자 트렌드**: 소비자 기술에 대한 수요 증가와 맞물려 AAPL의 아이폰, 아이패드 및 기타 제품의 판매가 호조를 보이고 있습니다.
### 5. 위험 요인
- **경쟁 심화**: 기술 발전과 시장의 변화로 인해 경쟁이 심화되고 있습니다.
- **거시경제적 요인**: 글로벌 경제 둔화 및 무역 긴장 등이 사업에 부정적인 영향을 줄 수 있습니다.
- **공급망 문제**: 코로나19 이후 공급망의 불안정성이 지속되고 있으며, 이는 생산 및 배송에 영향을 미칠 수 있습니다.
### 6. 결론 및 투자 판단
AAPL은 여전히 강력한 브랜드 파워와 견고한 재무 상태를 바탕으로 성장 가능성이 높습니다. 하지만 경직된 시장과 경쟁 심화, 거시경제적 요인들에 유의해야 합니다.
**투자 판단**:
- **매수**: 현재 주가가 저평가되어 있으며 향후 매출 성장 및 새로운 제품 출시가 기대되는 경우.
- **유지**: 주가가 상당히 상승하여 현재 경쟁 우위가 약해질 경우 보유를 유지.
- **매도**: 시장 불확실성 증가 시 판별이 필요한 매도 시점.
### 추가 권장 사항
- 정기적으로 재무 보고서 및 시장 동향을 주시하고, 전문가 의견 및 신뢰할 수 있는 데이터에 기반한 평가를 지속적으로 업데이트하는 것이 중요합니다.
---
(상기 자료의 숫자는 실제 시장 데이터에 따라 업데이트 필요)
보고서 형식으로 깔끔하게 정리한것 같지만, 내용을 살펴보면 구체적인 데이터도 없고 투자판단도 확실하게 내리지 않는 모습을 볼 수 있습니다. 이번엔 재무제표 데이터를 활용한 LLM의 답변을 살펴보겠습니다.
chain_2.invoke(
{"ticker": financial_data["ticker"], "context": financial_data["financials"]}
).content
똑같이 딕셔너리 형태로 input_variables의 값을 채워주고 결과를 확인해보았습니다.
# Apple Inc. (AAPL) 투자 분석 보고서
## 1. 회사 개요
Apple Inc. (AAPL)은 전 세계에서 가장 가치 있는 기술 기업 중 하나로, 하드웨어, 소프트웨어 및 서비스 분야에서 폭넓은 제품과 서비스를 제공합니다. 본 보고서는 AAPL의 재무 상태, 현금 흐름, 재무 비율 및 수익성을 분석하여 투자 판단을 돕기 위해 작성되었습니다.
## 2. 재무제표 요약
### 2.1. 대차대조표 (Balance Sheet)
- **현금 및 현금성 자산 (Cash On Hand)**: $53,775M
- **장기 부채 (Long Term Debt)**: $83,956M
- **주주 자본 (Share Holder Equity)**: $66,758M
- **총 자산 (Total Assets)**: $344,085M
- **총 현재 자산 (Total Current Assets)**: $133,240M
- **총 현재 부채 (Total Current Liabilities)**: $144,365M
- **총 부채 (Total Liabilities)**: $277,327M
- **부채 및 주주 자본 합계 (Total Liabilities And Share Holder Equity)**: $344,085M
### 2.2. 현금 흐름 (Cash Flow)
- **재무 활동으로 인한 현금 흐름 (Cash Flow From Financial Activities)**: $-39,371M
- **투자 활동으로 인한 현금 흐름 (Cash Flow From Investing Activities)**: $9,792M
- **운영 활동으로 인한 현금 흐름 (Cash Flow From Operating Activities)**: $29,935M
- **순 현금 흐름 (Net Cash Flow)**: $356M
### 2.3. 손익계산서 (Income Statement)
- **기본 주당순이익 (Basic EPS)**: $2.41
- **EBIT (세전 영업 이익)**: $42,832M
- **EBITDA (상각 전 영업 이익)**: $45,912M
- **주당 순이익 (EPS - Earnings Per Share)**: $2.40
- **총 수익 (Revenue)**: $124,300M
- **순이익 (Net Income)**: $36,330M
## 3. 재무 비율 분석
- **주당 장부가치 (Book Value Per Share)**: $4.44
- **유동 비율 (Current Ratio)**: 0.92
- **부채/자본 비율 (Debt/Equity Ratio)**: 1.45
- **자유 현금 흐름 주당 (Free Cash Flow Per Share)**: $1.78
- **총 이익률 (Gross Margin)**: 46.88%
- **순 이익률 (Net Profit Margin)**: 29.23%
- **영업 이익률 (Operating Margin)**: 34.46%
- **자산 수익률 (ROA)**: 10.56%
- **자기 자본 수익률 (ROE)**: 54.42%
## 4. 투자 판단
### 4.1. 강점
- **높은 수익성**: AAPL의 순 이익률(29.23%)과 영업 이익률(34.46%)은 업계 평균보다 높아 안정적인 수익 구조를 나타냅니다.
- **강력한 재무 구조**: 높은 자산 총액($344,085M)과 대비해 상대적으로 적은 부채(총 부채 $277,327M)는 재무적 안정성을 보여줍니다.
- **높은 ROE**: 54.42%의 자기 자본 수익률은 주주들에게 높은 이익을 가져다줄 잠재력을 보여줍니다.
### 4.2. 우려 사항
- **부채 비율**: 부채/자본 비율이 1.45로 상대적으로 높아, 향후 이자 지급 능력에 대한 우려를 초래할 수 있습니다.
- **유동성 문제**: 유동 비율(0.92)이 1 이하로, 단기 채무 상환 능력에 일부 부담이 있을 수 있습니다.
### 4.3. 결론
Apple Inc. (AAPL)은 강력한 재무 성과와 높은 수익성을 자랑하며, 안정적인 현금 흐름을 보여줍니다. 그러나 높은 부채 비율과 낮은 유동 비율은 잠재적인 위험 요소이므로, 주의가 필요합니다. 장기적인 투자 관점에서 볼 때, AAPL은 여전히 매력적인 투자처로 평가됩니다. 따라서, 투자 결정을 내리기 전에 보다 면밀한 시장 동향과 경쟁 환경 분석이 필요합니다.
## 5. 추천
AAPL 주식에 대한 투자는 중장기적으로 긍정적이지만, 시장의 변동성을 고려하여 적절한 포트폴리오 분산 및 리스크 관리를 권장합니다.
주어진 재무제표 데이터를 바탕으로 더 확실하게 수치화 된 보고서가 생성됐고, 데이터를 분석해서 기존 chain_1 대비 투자에 대한 조언과 적당한 판단도 내린 모습을 볼 수 있습니다.
3. Prompt 템플릿 관리하기
꼭 필요한 과정은 아니지만, 우리가 추후에 프롬프트를 계속 수정해간다거나 여러 종류의 프롬프트가 생겼을때 이를 LangChain Hub를 활용해서 쉽게 관리하는 방법을 간단하게 살펴보겠습니다. LangChain Hub를 사용하기 위해서는 LangSmith에서 API key를 꼭 발급받아줘야합니다.
LangChain Hub에는 내가 작성한 프롬프트를 자유롭게 업로드할 수 있고, 다른 사람이 작성하고 공유한 프롬프트도 손쉽게 사용할 수 있습니다. 우측에 보면 목적별 프롬프트가 다양하게 존재하는 모습을 볼 수 있습니다. 프롬프트를 가져오는 코드는 langchain을 활용해 아주
쉽게 작성할 수 있습니다.
from langchain import hub
# 가장 최신 버전의 프롬프트를 가져옵니다.
prompt = hub.pull("rlm/rag-prompt")
# 특정 버전의 프롬프트를 가져오려면 버전 해시를 지정하세요
prompt = hub.pull("rlm/rag-prompt:50442af1")
이제 제가 작성한 프롬프트를 Langchain Hub에 업로드해서 확인해보겠습니다.
from langchain import hub
# 프롬프트를 허브에 업로드합니다.
hub.push("{repo_full_name}", prompt_2)
코드는 굉장히 간단한데 문제가 조금 있었습니다. repo_full_name에 자신의 langsmith Id를 입력해야하는데 이 부분이 조금 어려웠습니다. 초기에는 Langsmith에 ID가 만들어지지않는게 default이기때문에 ID를 새로 만들어줘야합니다. 우선 공유되어있는 프롬프트중 하나를 아무거나 선택하고 우측상단에 Fork를 눌러줍니다.
prmpt name을 자유롭게 입력해주고 Fork를 누릅니다.
이제 여기서 Langsmith id를 입력하면 됩니다. 한번 설정하면 바꿀 수 없으니 신중하게 입력하면 되겠습니다. 그리고나서 다시 코드로 돌아가서 hub.push를 진행해보았습니다.
성공적으로 제 Langchain Hub 레파지토리에 프롬프트가 생성된 모습입니다. 혹시 몰라 hub.pull을 사용해 프롬프트가 잘 가져와지는지까지 테스트해보았습니다.
프롬프트가 잘 가져와지는 모습을 볼 수 있었습니다. 이제 앞으로 Langchain Hub를 사용해 목적에 맞는 프롬프트를 손쉽게 가져다 사용할 수 있고, 내가 사용하는 프롬프트들도 버전별로 업로드하면서 편리하게 유지보수할 수 있습니다.
참고자료
https://github.com/teddylee777/langchain-kr/blob/main/02-Prompt/01-PromptTemplate.ipynb
'FinAgent Lab' 카테고리의 다른 글
[DB] Postgresql DB 구축하기 (0) | 2025.03.26 |
---|---|
[crawling] 해외 기업 재무제표 crawling 해오기 (0) | 2025.03.25 |