FINλ¬Έμ² μ ν¬μλλ²κ΄μΌλ‘μ μ νν μ£Όμ μ 보 μ‘°νμ
ν¬μ νλ¨ μ§νλ₯Ό μ 곡νμ¬ μ¬μ©μμ ν¬μ μμ¬κ²°μ μ μ§μν©λλ€.
λ ν¬μ νλ¨ μ νκ±ΈκΉ? κΈμ΅ λ¬Έν΄λ ₯μ ν€μμ£Όλ μ£Όμ λΉμ Agent
λ¨μν μ£Όκ° μ‘°νλ₯Ό λμ΄μ
(1) μ¬λ¬΄κ±΄μ μ±κ³Ό (2) κΈ°μ
μ
μ±μ₯μ±μ μ’
ν©μ μΌλ‘ νκ°νμ¬
"μ΄ μ’
λͺ© μ§κΈ μ¬λ λ κΉ?"λΌλ ν¬μμλ€μ κ·Όλ³Έμ μ§λ¬Έμ μ λ¬Έκ° μμ€μ λ΅λ³μ μ 곡ν©λλ€.
μ΅μ’
μΆλ ₯ μμ:
[Finλ¬Έμ² μ’
ν© λ¦¬ν¬νΈ] π μ’
λͺ©: μΌμ±μ μ (005930.KS) π
κΈ°μ€μΌ: 2025-01-31
π μ¬λ¬΄ 건μ μ± μ§λ¨ μμ½:
- μ λμ±: μ°μ (μ λλΉμ¨ 180%, λΉμ’λΉμ¨ 85%)
- λ λ²λ¦¬μ§: λ§€μ°μ°μ (λΆμ±λΉμ¨ 95%, μ΄μ보μλ°°μ¨ 12λ°°)
- μμ΅μ±: λ³΄ν΅ (ROE 8.2%, μμ
μ΄μ΅λ₯ 7.5%)
π μμ₯ μ§ν κΈ°λ° μ±μ₯μ± λΆμ:
- PER 15.2λ°° (μ
κ³ νκ· 18.5λ°° λλΉ μ νκ°)
- PBR 1.8λ°° (μ₯λΆκ° λλΉ μ μ )
- μ λ리μ€νΈ λͺ©νκ°: 72,000μ (νμ¬κ° λλΉ +8.5%)
π AI μ’
ν© νλ¨ μμ½:
μ¬λ¬΄κ΅¬μ‘°κ° μμ μ μ΄κ³ νμ¬ μ νκ° κ΅¬κ°μ μμΉνμ¬ μ€μ₯κΈ° ν¬μκ΄μ μμ
λΆν λ§€μλ₯Ό κΆκ³ ν©λλ€.
μ 9ν λ―Έλμμ μ¦κΆ AI Festival
2025.06.25 ~ 2025.07.31
μ΄νμ€ (hayo0n) Β· κΉμ΄μ (shashamalone) Β· μ€μκ· (yoonwanggyu)
π¦ νλ‘μ νΈ λ£¨νΈ
βββ π data/ # λ°μ΄ν° μ μ₯ λλ ν 리
β βββ π krx_tickers_with_market.csv # νκ΅κ±°λμ μ’
λͺ© μ½λ λ° μμ₯ μ 보
β βββ π krx_tickers_cleaned.csv # κΈ°μ
μ½λ μ 보
βββ π langgraph/ # LangGraph κΈ°λ° AI μμ΄μ νΈ λͺ¨λ
β βββ π agent_core.py # μμ΄μ νΈ ν΅μ¬ λ‘μ§ λ° μν¬νλ‘μ°
β βββ π nodes.py # κ·Έλν λ
Έλ μ μ (κ° μ²λ¦¬ λ¨κ³)
β βββ π state.py # μμ΄μ νΈ μν κ΄λ¦¬ λ° λ°μ΄ν° ꡬ쑰
βββ π tools/ # μμ
λ³ λꡬ λͺ¨μ
β βββ π task1_tools.py # 1λ¨κ³ μμ
μ© λꡬλ€
β βββ π task2_tools.py # 2λ¨κ³ μμ
μ© λꡬλ€
β βββ π task3_tools.py # 3λ¨κ³ μμ
μ© λꡬλ€
β βββ π task5_tools.py # 5λ¨κ³ μμ
μ© λꡬλ€
βββ π .gitignore # μ μΈ νμΌ λͺ©λ‘
βββ π Dockerfile # Docker 컨ν
μ΄λ λΉλ μ€μ
βββ π data_fetcher.py # Redis λ°μ΄ν° μμ§ λ° μ²λ¦¬
βββ π main.py # λ©μΈ μ€ν νμΌ
βββ π prompt.py # AI ν둬ννΈ ν
νλ¦Ώ κ΄λ¦¬
βββ π redis_connector.py # Redis μΊμ μ°κ²° λ° κ΄λ¦¬
βββ π utils.py # κ³΅ν΅ μ νΈλ¦¬ν° ν¨μλ€
βββ π upload_to_redis.py # Redis λ°μ΄ν° μ
λ‘λ μ€ν¬λ¦½νΈ
βββ π requirements.txt # Python ν¨ν€μ§ μμ‘΄μ± λͺ©λ‘
-
π§ LLM : HyperClova X
λ€μ΄λ²μ λκ·λͺ¨ μΈμ΄λͺ¨λΈλ‘, νκ΅μ΄μ νΉνλ κ³ μ±λ₯ AI μλΉμ€λ₯Ό μ 곡ν©λλ€.
β ν¬μ κ΄λ ¨ μ§μμλ΅, μ£Όμ λΆμ, κΈμ΅ λ°μ΄ν° ν΄μ λ± μ λ¬Έμ μΈ ν¬μ μλ΄ μλΉμ€μ ν΅μ¬ μμ§μΌλ‘ νμ© -
π LangGraph
μν κΈ°λ° LLM νλ μμν¬λ‘, 볡μ‘ν μμ΄μ νΈ μν¬νλ‘μ°λ₯Ό μ μ°νκ² μ€κ³ν μ μμ΅λλ€.
β Agentic RAG νλ¦(Task λΆκΈ° β Tool νΈμΆ -> λ΅λ³ μμ±)μ ꡬν -
β‘ NCloud Cloud DB for Cache(Redis Cluster)
κ³ μ±λ₯ μΈλ©λͺ¨λ¦¬ λ°μ΄ν° μ€ν μ΄λ‘, μΊμ±κ³Ό μΈμ κ΄λ¦¬λ₯Ό λ΄λΉν©λλ€.
β yfinance λ°μ΄ν° (2024.01 ~ 2025.07) λ°μ΄ν° μ μ¬
β λ°μ λ°©ν₯:- λν μΈμ κ΄λ¦¬λ₯Ό ν΅ν λ©λͺ¨λ¦¬ μΊμ±
- λ°°μΉ μ»¨ν μ΄λ κ΅¬μΆ λ° λ°μ΄ν° TTL μ€μ μΌλ‘, μ΅κ·Ό μ£Όμ λ°μ΄ν°λ₯Ό μ£ΌκΈ°μ μΌλ‘ μ λ°μ΄νΈ
-
π¦ Yahoo Finance API
Yahoo Financeμ κ³΅κ° APIλ₯Ό νμ©ν Python λΌμ΄λΈλ¬λ¦¬λ‘, μ€μκ° λ° κ³Όκ±° μ£Όμ λ°μ΄ν°λ₯Ό μ 곡ν©λλ€.
β Redisμ μΊμ±λ λ°μ΄ν°κ° μμ κ²½μ° yfinance APIλ₯Ό νΈμΆνμ¬ λ°μ΄ν° λ‘λ -
π FastAPI
Python ASGI μΉ νλ μμν¬ β νμ ννΈ κΈ°λ° μλ λ¬Έμν & κ³ μ±λ₯ λΉλκΈ° μ²λ¦¬λ₯Ό μ§μν©λλ€.
β /agentβΒ·β/health μλν¬μΈνΈ ꡬν, CORS λ―Έλ€μ¨μ΄Β·lifespan ν μΌλ‘ Redis μ°κ²°Β·ν΄μ μλ κ΄λ¦¬ -
βοΈ NCloud IaaS (Ubuntu VM)
λ€μ΄λ²ν΄λΌμ°λ VPC νκ²½μ κ°μλ¨Έμ : Public Subnet(κ³΅μΈ IP) + Private Subnet(Redis Cluster) ꡬμ±λμ΄ μμ΅λλ€.
β μ ν리μΌμ΄μ μλ²(uvicorn) λ₯Ό IaaS μΈμ€ν΄μ€μ λ°°ν¬, VPC λ΄λΆμμ Redis Cluster μ μ -
π³ Docker
컨ν μ΄λνλ₯Ό ν΅ν μΌκ΄λ κ°λ° λ° λ°°ν¬ νκ²½μ μ 곡ν©λλ€.
β μ ν리μΌμ΄μ κ³Ό Redisλ₯Ό 컨ν μ΄λλ‘ κ΅¬μ±νμ¬ νκ²½ λ 립μ±κ³Ό λ°°ν¬ νΈμμ± ν보
π― Decision Task
- λͺ©μ : μ¬μ©μ μ§λ¬Έμ μ μ ν Taskλ‘ λΆλ₯
- ꡬν: [ROLE] β [TASK_DEFINITIONS] β [FEW_SHOT_EXAMPLES] β [USER_QUESTION]
# ROLE
λΉμ μ μ£Όμ μ 보 μμ€ν
μ μν μμ
λΆλ₯ λμ°λ―Έμ
λλ€.
λ€λ₯Έ λ§μ μ λ μΆλ ₯νμ§ λ§κ³ , λ΅λ³μ λ°λμ Task1Β·Task2Β·Task3Β·Task4 μ€ νλλ§ μΆλ ₯νμΈμ.# TASK DEFINITIONS
λΉμ μ μ무λ μ¬μ©μμ μ§λ¬Έμ λ€μ λ€ κ°μ§ μμ
(Task) μ€ νλλ‘ λΆλ₯νλ κ²μ
λλ€:
- Task 1: νκ΅ μ£Όμμμ₯(KOSPI/KOSDAQ)μ νΉμ λ μ§λ³ μ£Όκ°, μ§μ, κ±°λλ, λνΉ λ± κ³Όκ±° κΈμ΅ λ°μ΄ν° μ‘°ν
- Task 2: λ¨μν μμΉ μ‘°κ±΄ (λ±λ½λ₯ Β±N%, κ±°λλ μ λ λλΉ N% λ±)
- Task 3: κΈ°μ μ λΆμ μ§νμ λ§€λ§€ μ νΈ (RSI, μ΄λνκ· , λ³Όλ¦°μ λ°΄λ λ±)
- Task 4: ꡬ체μ μΈ κΈ°μ€μ΄λ μ‘°κ±΄μ΄ λͺ
μλμ§ μμμ ν΄μμ΄ νμν μ§λ¬Έ
- Task 5: ν¬μ νλ¨ λΆμ# FEW SHOT EXAMPLES
μλ μ μλ₯Ό μ°Έκ³ νμ¬ λΆλ₯νμΈμ:
Task 1:
- "2024-07-22 KOSPI μ§μλ?"
- "λνλ°©μ§μ 2025-04-25 μ’
κ°λ?"
Task 2 :
- "2025-05-27μ λ±λ½λ₯ μ΄ +20% μ΄μμΈ μ’
λͺ©μ λͺ¨λ 보μ¬μ€"
- "2025-05-21μ κ±°λλμ΄ 1000λ§μ£Ό μ΄μμΈ μ’
λͺ©μ λͺ¨λ 보μ¬μ€"
Task 3:
- "2025-03-06μ RSIκ° 20 μ΄νμΈ κ³Όλ§€λ μ’
λͺ©μ μλ €μ€"
- "2024-08-22μ κ±°λλμ΄ 20μΌ νκ· λλΉ 500% μ΄μ κΈμ¦ν μ’
λͺ©μ μλ €μ€"
Task 4 :
- "μ΅κ·Ό λ§μ΄ μ€λ₯Έ μ£Όμ"
- "κ³ μ λλΉ κ°μ₯ λ§μ΄ λ¨μ΄μ§ μ’
λͺ©"
Task 5 :
- "OO μ§κΈ μ¬λ λ κΉ?"
- "OOμ OOμμ μ° νλ¨ μ΄λ?"βοΈ Task1 ~ Task3
- λͺ©μ : HyperClova Xκ° μ¬μ©μ μ§λ¬Έμ λΆμνμ¬ μ ν©ν λꡬλ₯Ό μλ μ ν λ° μ€ν
- ꡬν: Langchain Tool λ°μ½λ μ΄ν°λ₯Ό HyperClova Xμ κ²°ν©
# λν μμ
@tool("answer_stock_query", description="νΉμ λ μ§μ νΉμ μ’
λͺ©μ μ’
κ°, μκ°, κ³ κ°, μ κ°, λ±λ½λ₯ κ³μ°")
def answer_stock_query(stock: str, target_date: str, field: str):
"""
νΉμ μ’
λͺ©(stock)μ νΉμ λ μ§(target_date)μ Open/Close/Low/High/change_rate(field)λ₯Ό λ°νν©λλ€.
Args:
stock (str): μ’
λͺ©λͺ
, μμ 'νμμ¦κΆ'
target_date (str): λ μ§, μμ '2025-03-12' (YYYY-MM-DD νμ)
field (str): μ‘°νν νλͺ©. μλ κ° μ€ νλμ¬μΌ ν©λλ€.
- "Open" : μκ°
- "High" : κ³ κ°
- "Low" : μ κ°
- "Close" : μ’
κ°
- "change_rate" : λ±λ½λ₯ (μ μΌ μ’
κ° λλΉ λ±λ½λ₯ , %)
- "Volumne" : κ±°λλ
Returns:
str: ν΄λΉ λ μ§μ νλμ λν κ°. μλ₯Ό λ€μ΄,
- "[2025-03-12] μ’
κ°: 13,800μ"
- "[2025-03-12] μκ°: 14,000μ"
- "[2025-03-12] λ±λ½λ₯ : -1.65%"
μμ μ§λ¬Έ:
- "KOSPIμμ λ‘―λ°μ§μ£Όμ 2024-07-05 μ’
κ°λ?"
- "μΌμμ ν
μ 2025-05-15 λ±λ½λ₯ μ?"
- "νλ€νΈμ 2024-11-20 μκ°λ?"
- "λνμμ§λμ΄λ§μ 2025-06-25 κ³ κ°λ?"
"""
# κ° Taskλ³ Tools List
Task1_Tools = [answer_stock_query, answer_market_index,answer_market_ranking,answer_stock_compare,answer_market_stock_compare,answer_market_ratio,answer_market_compare]
Task2_Tools = [answer_task2]
Task3_Tools = [rsi, detect_cross, price_vs_adj_ma, bollinger_bands, get_high_volume_stocks]
βοΈ Task 4 β λͺ¨νΈν μ§λ¬Έ μ λν λ° μ¬μ§μ
- λͺ©μ : βμ΅κ·Ό λ§μ΄ μ€λ₯Έ μ’ λͺ©β, βκ³ μ λλΉ νλ½ν μ£Όμβ λ± λͺ¨νΈν ννμ μ λννκ±°λ, λλ¬»κΈ°λ‘ λͺ νν 쑰건μ λ°μ μ λ’°λ μλ λ΅λ³ μμ±
- ꡬν: ν둬ννΈ κΈ°λ°μΌλ‘ μ§λ¬Έ μ λͺ¨νΈμ΄(μ: βμ΅κ·Όβ, βλ§μ΄β)λ₯Ό κ°μ§
- κΈ°μ€μ΄ μμΌλ©΄ κΈ°κ°/νΌμΌνΈ λ± μ νμ§ μ μ
- κΈ°μ€μ΄ λͺ νν κ²½μ° μμ 10κ° μ’ λͺ© + μμΉλ‘ μ λ μλ΅
- λν ν둬ννΈ: TASK4_FINAL_PROMPT
(μμ μ§λ¬Έ: βμ΅κ·Ό λ§μ΄ μ€λ₯Έ μ£Όμ λμΌ?β β βμ΅κ·Όμ λ³΄ν΅ 30μΌ κΈ°μ€μΌλ‘ νλ¨ν©λλ€. ... λ κΆκΈνμ κ°μ?β)
Tool λͺ©λ‘:
Task4_Tools = [TASK4_FINAL_PROMPT]βοΈ Task 5 β ν¬μ νλ¨ μ§λ¨ λ° μ’ ν© λΆμ
- λͺ©μ : μ¬μ©μμ μ§λ¬Έ(μ: "μ§κΈ μ¬λ λ κΉ?", "λ΄κ° μ° κ² μν νλ¨μ΄μΌ?")μ λΆμνμ¬, κΈ°μ μ μ¬λ¬΄ 건μ μ±, λ°Έλ₯μμ΄μ , μ λ리μ€νΈ μ견, μ΅κ·Ό 리μ€ν¬ μ΄μ λ±μ μ’ ν© νκ°νκ³ AI μ’ ν© νκ²°λ¬Έ νμμΌλ‘ μλ΅
- ꡬν:
- μ’ λͺ©λͺ μΆμΆ β ν°μ»€/κΈ°μ μ½λ λ§€ν
- yFinanceμ DART APIμμ λ°μ΄ν° μμ§
- LangChain Toolμ ν΅ν΄ LLM κΈ°λ° μ’ ν© ν둬ννΈ μμ± λ° νκ²°λ¬Έ μΆλ ₯
1. μ’
λͺ© μΆμΆ λ° ν°μ»€ λ§€ν
- `get_info_stock()` ν¨μλ μμ°μ΄μμ μ’
λͺ©λͺ
μ μΆμΆνκ³ ν°μ»€λ₯Ό λ°ν
2. μ λ κΈ°μ
μ±μ₯μ± λΆμ (yfinance)
- `get_yfinance_data()`λ‘ Yahoo Finance APIλ₯Ό ν΅ν΄ κΈ°μ
μ μμΈ, μ¬λ¬΄μ ν, μ λ리μ€νΈ μ견, λ΄μ€ λ±μ μμ§, PER, PBR, νμ¬κ°, λͺ©νκ°, μΆμ² λ±μ κ°μ Έμ΄
3. 곡μμ 보 κΈ°λ° λ¦¬μ€ν¬ λΆμ (DART)
- `get_dart_disclosure_data()`μμ DART μ μ곡μμμ€ν
μμ κΈ°μ
μ μ¬λ¬΄μ ν, κ°μ¬λ³΄κ³ μ, 곡μ μ 보 λ±μ μμ§
4. LLM ν둬ννΈ κ΅¬μ± λ° νΈμΆ
- μ±μ₯μ± λΆμμ `format_growth_prompt()`λ‘, 리μ€ν¬ λΆμμ `format_growth_prompt()`λ‘ λΆμ ν둬ννΈλ₯Ό λ§λ€κ³ ,
`generate_investment_prompt_summary()`μμ μ΅μ’
"FINλ¬Έμ² " νκ²°λ¬Έ λΆμ κ²°κ³Όλ₯Ό λ°μμ΄
5. μ΅μ’
λ°ν ν¬λ§·
- μμ°μ΄λ‘ βνμ¬ μ νκ°μΈκ°?β, β리μ€ν¬λ μλκ°?β, βμ§κΈ μ¬λ λλκ°?βλ₯Ό νκ°νκ³ βFinλ¬Έμ² νκ²°λ¬ΈβμΌλ‘ λ§λ¬΄λ¦¬
- μ¦, λ¨μν μ£Όμμ 보λ₯Ό ν΅ν΄ κΈ°μ
μ νλ¨νλ κ²μ΄ μλ "μ±μ₯μ± + 건μ μ± + 리μ€ν¬" λ±μ κ²°ν©ν ν΅ν©μ κΈ°μ
λΆμ ꡬ쑰1οΈβ£ μλ² κΈ°λ
docker build -t agent-m .
docker rm -f agent-m
docker run -d -p 8000:8000 --env-file .env --name agent-m agent-m2οΈβ£ ν¬μ€ 체ν¬
curl http://49.50.128.78:8000/healthμν λ°ν νμΈ
{"status":"ok"}
3οΈβ£ μ§λ¬Έ νΈμΆ
curl -G --data-urlencode "question=2025-02-25μ RSIκ° 30 μ΄νμΈ μ’
λͺ©μ?" \
http://49.50.128.78:8000/agent \
-H "Authorization: Bearer $NCP_CLOVASTUDIO_API_KEY" \
-H "X-NCP-CLOVASTUDIO-REQUEST-ID: req-001".png)

