Human in the loop 란 말이 agent 스터디를 하면서 많이 듣게되었다. 그래서 human in the loop 이 뭐고, 어떻게 쓰이고 활용하는지 공부해보기로 하였다. 간단하게 설명해서 인공지능이 task 를 처리하는 과정에서 인간이 개입해서 참여 성능을 향상시킨다는 개념이다.
실제 적용 사례
의료 분야
미국 국가 보건 서비스는 Amazon A2I를 활용하여:
- 매월 5,400만 건의 처방전 데이터 처리
- 신뢰도가 낮은 문서는 수동 검토
- 보험금 지급 프로세스 효율화 달성
Input data -> AI 가 예측 -> 신뢰도에 따라 높으면 ClientApplication으로 돌아가고, 낮은 자료는 사람이 검토하게 한다.
실제 사례로는 LangGraph 에도 있다. Iteration 기능과 사람의 개입이란 내용으로 잘 정리가 되어있다.
Agent 에서의 iter() 메서드는 실행을 순회 형태로 확인 하는 기능이다. 즉 에이전트의흐름을 보고 직접 얘가 일을 잘하나 감시를 할 수 있다. 일반적으론 run() 만 쓰게되면 최종결과만 확인 할 수 있다. 그러나 iter() 를 활용한다면 에이전트가 최종 결과에 도달 하기전에 중간단계에서 순차적으로 접근 확인 가능하다.
예로들어 테디노트님의 예에선 y or n 로 다음단계로 넘어가기 위해 제어를 하는 예제를 보여주셨다.
# 계산할 질문 설정
question = "114.5 + 121.2 + 34.2 + 110.1 의 계산 결과는?"
# agent_executor를 반복적으로 실행
for step in agent_executor.iter({"input": question}):
if output := step.get("intermediate_step"):
action, value = output[0]
if action.tool == "add_function":
# Tool 실행 결과 출력
print(f"\nTool Name: {action.tool}, 실행 결과: {value}")
# 사용자에게 계속 진행할지 묻습니다.
_continue = input("계속 진행하시겠습니다? (y/n)?:\n") or "Y"
# 사용자가 'y'가 아닌 다른 입력을 하면 반복 중단
if _continue.lower() != "y":
break
# 최종 결과 출력
if "output" in step:
print(step["output"])
총 3번의 결과가 호출이 된다. tool 을 활용해서 114.5 + 121.2 계산 ->235.7 더한 값을 235.7 + 34.2 -> 269.9 이 나오고 마지막 더하기를 해서 총 380.0 이 출력이 되는 모습이다. 그 전에 다음단계로넘어갈지에 대한판단단에 대한 y or n 를 입력할 수 있다. 그렇다면? 사용자가 더 제어는 할 수 없을까? 라는 생각이 드는데 실험을 해본결과는 코드적으론 가능한데. Agent 는 이미 위에서 iter 를 호출 한 값에 대하여 반복문을 돌고 있기 때문에 그 쿼리에 대해 처리를 시도를 한다. 그래서 뭔가 invoking 을 할때 중간값이 적용이 안되는것 같았다. 결국 흐름제어를 인간이 해줄 순 있지만 그 안에 값을 제어하기 위해서는 새로운 알고리즘 적용이 필요해보인다.
import os
from dotenv import load_dotenv
from langchain.agents import tool
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai import ChatOpenAI
load_dotenv()
# 1) Tool 정의
def simple_add(a: float, b: float) -> float:
return a + b
@tool
def add_function(a: float, b: float) -> float:
"""
두 숫자 a, b를 더해 반환합니다.
"""
return simple_add(a, b)
def main():
tools = [add_function]
gpt = ChatOpenAI(model="gpt-4o-mini")
# 4) Prompt 템플릿 정의
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You are a helpful assistant. "
"Make sure to use the `add_function` tool for addition."
),
("human", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
]
)
# 5) Agent 생성
gpt_agent = create_tool_calling_agent(
llm=gpt,
tools=tools,
prompt=prompt,
)
# 6) AgentExecutor 생성
agent_executor = AgentExecutor(
agent=gpt_agent,
tools=tools,
verbose=True, # 중간 과정(Intermediate Steps)을 출력해볼 수 있음
max_iterations=10, # 최대 반복 횟수
handle_parsing_errors=True,
)
# 7) 실제 질문
question = "114.5 + 121.2 + 34.2 + 110.1 의 계산 결과는?"
# 8) 단계별 실행(iter) 활용
final_value = None
current_question = question # 현재 질문을 저장할 변수
for step in agent_executor.iter({"input": current_question}):
step_result = step
intermediate_output = step.get("intermediate_step")
if intermediate_output:
action, value = intermediate_output[0]
if action.tool == "add_function":
print(f"\n[Tool 실행] Tool Name: {action.tool}, 실행 결과: {value}")
final_value = value
add_more = input("추가로 더하기 연산을 하시겠습니까? (y/n) [기본값: n]:\n") or "n"
if add_more.lower() == "y":
try:
new_number = float(input("더할 숫자를 입력하세요: "))
value = simple_add(value, new_number)
final_value = value
print(f"새로운 계산 결과: {value}")
# 질문 자체를 업데이트
current_question = f"{value}의 값은?"
# 새로운 에이전트 실행을 위해 break
break
except ValueError:
print("올바른 숫자를 입력해주세요.")
_continue = input("계속 진행하시겠습니까? (y/n) [기본값: y]:\n") or "y"
if _continue.lower() != "y":
print("사용자에 의해 중단되었습니다.")
break
# 9) 최종 결과 확인
if step_result:
if final_value is not None:
print(f"최종 결과: {final_value}")
else:
print(f"최종 결과: {step_result.get('output', '결과 없음')}")
if __name__ == "__main__":
main()
이런식으로 새로운 값을 추가 시킨다음에 뭔가 적용시킬려고 했는데 터미널값에서는 제대로 적용되지만 루프로는 가는 모습이 아니다. 이 부분은 어떻게 활용할지 더 공부를 해봐야 할 듯 하다. 내부에 현재까지의 값을 받고 그 후에 , 사용자가 추가된 값을 더하고, 위의쿼리문에 대하여 나머지값을 반영시키는 로직이 필요할 듯 하다?
에이전트 스터디를 하면서 최근에 많이 여러글들을 팔로업을 하고 있는데 테디노트님의 랭체인 위키독스 노트 업데이트가 되어서 공부를 하게 되었다. 지금 여럿 구축하려는 내용과 일맥상통하는 부분이 있고, 주식 - 경제 리포트를 쓸때 이 개념을 활용하면 좋겠다 판단이 되었다. 이전에 만들어둔 Stockelper 에서의 Agent 에 추가기능으로 만들어서 넣어보려고한다. 대화한 내용을 바탕으로 보고서를 만들어주세요 라는 답변에 대해서 만드는 작업을 수행해볼려고 한다.
from langchain_aws import ChatBedrock
llm = ChatBedrock(
model_id="amazon.nova-pro-v1:0",
model_kwargs=dict(temperature=0),
credentials_profile_name="default",
region_name="us-east-1"
)
aws 에서 300불 크레딧 신청 후 사용승인이되어서 이번엔 Claude, Nova 기반으로 만들어보려고 한다. 워낙 aws SAA분들도 잘 만들어두셨지만 한번 공부하면서 천천히 구현을 해보려고 한다.
분석가 생성
from typing import List
from typing_extensions import TypedDict
from pydantic import BaseModel, Field
from langchain_teddynote.graphs import visualize_graph
# 주식 리포터의 속성과 메타데이터를 정의하는 클래스
class StockReporter(BaseModel):
# 주요 소속 정보
affiliation: str = Field(
description="리포터의 소속 회사",
default="ktds"
)
# 이름
name: str = Field(
description="리포터의 이름",
default="김재현"
)
# 전문 분야
expertise: str = Field(
description="주식 시장 전문 분야",
default="나스닥 개인투자자"
)
# 분석 관점
analysis_focus: str = Field(
description="주식 분석의 주요 관점",
default="기술적 분석, 펀더멘털 분석, 시장 동향 분석"
)
# 투자 스타일
investment_style: str = Field(
description="투자 스타일과 전략",
default="단기 투자 및 스켈핑 유저"
)
# 리스크 관리 방식
risk_management: str = Field(
description="리스크 관리 방식",
default="포트폴리오 분산, 손절매 규칙 준수"
)
# 리포터의 정보를 문자열로 반환하는 속성
@property
def profile(self) -> str:
return f"""
📊 Stock Reporter Profile 📊
소속: {self.affiliation}
이름: {self.name}
전문분야: {self.expertise}
분석관점: {self.analysis_focus}
투자스타일: {self.investment_style}
리스크관리: {self.risk_management}
"""
# 리포트 생성을 위한 클래스
class StockReport(BaseModel):
# 리포터 정보
reporters: List[StockReporter] = Field(
description="리포트 작성에 참여한 리포터 목록",
)
내 데이터를 활용해서 분석가를 하나 생성했다. 개미투자자 스켈핑 단타위주의 분석가로 설정을 하였다.(실제 성격)
# 상태 정의
class GenerateAnalystsState(TypedDict):
# 연구 주제
topic: str
# 생성할 분석가의 최대 수
max_analysts: int
# 사람 피드백
human_analyst_feedback: str
# 분석가 목록
analysts: List[Analyst]
LangGraph를 써봤다면 알다시피 딕셔너리 형태로 값을 상태정의해서 인덱싱해서 LLM invoke 를 통해서 에이전트 흐름제어 시스템을 구축한다 그것을 하기 위한 정의다.
그 후 실제로 리포터들을 생성하기 위한 프롬프트와, 리포트 생성시 주의할 프롬프트를 입력한다. 위에서 정의한 Class DataType 관련해서 잘 적용을 해준다.
from langgraph.graph import END
from langchain_core.messages import HumanMessage, SystemMessage
# 분석가 생성 프롬프트
analyst_instructions = """주식 분석가 페르소나 생성을 담당하게 됩니다.
다음 지침을 주의 깊게 따라주세요:
1. 먼저 연구 주제를 검토하세요:
{topic}
2. 분석가 생성을 안내하기 위해 제공된 편집 피드백을 검토하세요:
{human_analyst_feedback}
3. 위의 문서 및/또는 피드백을 바탕으로 주식 분석에 필요한 주요 관점을 파악하세요.
4. 상위 {max_analysts}개의 관점을 선택하세요.
5. 각 관점별로 다음 속성을 가진 분석가를 생성하세요:
- 소속: 4대은행(국민, 신한, 우리, 하나) 별 투자증권회사 및 금융기관
- 이름: 한국식 이름
- 전문분야: 주식시장 특정 분야
- 분석관점: 기술적/펀더멘털/시장동향 분석 중 선택
- 투자스타일: 단기/중기/장기 투자 전략
- 리스크관리: 구체적인 리스크 관리 방식"""
# 분석가 생성 노드
def create_analysts(state: GenerateAnalystsState):
"""분석가 페르소나를 생성하는 함수"""
topic = state["topic"]
max_analysts = state["max_analysts"]
human_analyst_feedback = state.get("human_analyst_feedback", "")
# LLM에 구조화된 출력 형식을 적용
structured_llm = llm.with_structured_output(Perspectives)
# 분석가 생성을 위한 시스템 프롬프트 구성
system_message = analyst_instructions.format(
topic=topic,
human_analyst_feedback=human_analyst_feedback,
max_analysts=max_analysts,
)
# LLM을 호출하여 분석가 페르소나 생성
analysts = structured_llm.invoke(
[SystemMessage(content=system_message)]
+ [HumanMessage(content="KDBanalyst 클래스 형식에 맞는 분석가 집합을 생성하세요.")]
)
# 생성된 분석가 목록을 상태에 저장
return {"analysts": analysts.reporters}
# 사용자 피드백 노드
def human_feedback(state: GenerateAnalystsState):
"""사용자 피드백을 받기 위한 중단점 노드"""
pass
# 인간 피드백 여부에 따라 워크플로우의 다음 단계를 결정하는 함수
def should_continue(state: GenerateAnalystsState):
"""워크플로우의 다음 단계를 결정하는 함수"""
human_analyst_feedback = state.get("human_analyst_feedback", None)
if human_analyst_feedback:
return "create_analysts"
return END
from langgraph.graph import START, END, StateGraph
from langgraph.checkpoint.memory import MemorySaver
from langchain_core.messages import SystemMessage
# 그래프 생성
builder = StateGraph(GenerateAnalystsState)
# 노드 추가
builder.add_node("create_analysts", create_analysts)
builder.add_node("human_feedback", human_feedback)
# 엣지 연결
builder.add_edge(START, "create_analysts")
builder.add_edge("create_analysts", "human_feedback")
# 조건부 엣지 추가: 사람 피드백이 있을 경우 다시 분석가 생성 노드로 돌아갑니다.
builder.add_conditional_edges(
"human_feedback", should_continue, ["create_analysts", END]
)
# 메모리 생성
memory = MemorySaver()
# 그래프 컴파일(중단점 설정)
graph = builder.compile(interrupt_before=["human_feedback"], checkpointer=memory)
# 그래프 시각화
visualize_graph(graph)
그 후 Create_analysts 에서는 분석가(리포터) 들을 생성을 해준다.
결과 예시
==================================================
🔄 Node: create_analysts 🔄
- - - - - - - - - - - - - - - - - - - - - - - - -
affiliation='KB증권' name='김태훈' expertise='정치경제 분석' analysis_focus='펀더멘털 분석' investment_style='중장기 투자' risk_management='정치적 리스크 헤지 전략 수립'
affiliation='신한금융투자' name='이수진' expertise='기술주 분석' analysis_focus='기술적 분석' investment_style='단기 트레이딩' risk_management='변동성 기반 포지션 조절'
affiliation='우리금융투자' name='박준호' expertise='거시경제 분석' analysis_focus='시장 동향 분석' investment_style='중기 투자' risk_management='섹터 분산 투자'
==================================================
말 그대로, AI 가 생성한 가상의 리포터를 통해서 피드백을 주입 시킬 수 있다. update_stat() 를 통해서 키를 바인딩해서 피드백 내용을 저장한다.
# 그래프 상태를 업데이트하여 human_feedback 노드의 역할 수행
graph.update_state(
config,
{
"human_analyst_feedback": "단타 쟁이 관점을 위하여 김재현을 추가합니다."
},
as_node="human_feedback",
)
# 이어서 진행
invoke_graph(graph, None, config)
아까 제 정보를 default 로 선언을 해두긴 했는데, 저의 정보를 활용해서 휴먼피드백을 반영합니다. 분석가 관점에서 딥하게 설정해준다면 더 좋은 결과를 얻을 수 있겠다 생각했다.
그 후 더 늘릴려면 늘려도 되고, 추가 피드백이 없다고 전달해줘서 생성작업을 마무리를 시킵니다. 4명의 분석가를 만들고 종료 시킵니다.
# 추가 피드백이 없을 경우 None 값을 할당하여 상태 업데이트
human_feedback_input = None
# 그래프 상태를 업데이트하여 human_feedback 노드의 역할 수행
graph.update_state(
config, {"human_analyst_feedback": human_feedback_input}, as_node="human_feedback"
)
위처럼 profile을 확인하면 3개의 합성 분석가들과 내가 설정한나의 정보를 토대로 , 합성의 투자전문가인 내가 생성이 되었다.
인터뷰 생성
이제 분석가들을 토대로 질문을 하는 인터뷰 상태를 구축해야 한다. 이 예시를 실행해보면서 일단 토큰 값이 매우 많이 나오겠구나 생각이 들긴했다.. 알아서 대화에 따라 LLM 을 바꿔주는것도 토큰 전략을 위해 필요해보인다.
import operator
from typing import Annotated
from langgraph.graph import MessagesState
# 인터뷰 상태 정의
class InterviewState(MessagesState):
# 대화 턴수
max_num_turns: int
# 소스 문서를 포함하는 컨텍스트 리스트
context: Annotated[list, operator.add]
# 지정된 분석가
analyst: KDBAnalyst
# 인터뷰 내용을 저장하는 문자열
interview: str
# 보고서 섹션 리스트
sections: list
# 검색 쿼리 데이터 클래스 정의
class SearchQuery(BaseModel):
search_query: str = Field(None, description="Search query for retrieval.")
인터뷰를 위한 상태정의를 해준다. 대화턴수는 전문가와의 대화턴수 일 것이고, context 는 처음 쿼리에 대한 정보를 RAG 해오기 위한 Context 정보, analyst 는 위에서 정의한 분석가, Interview는 인터뷰 내용 , sections 은 보고서 작성을 위한 섹션리스트이다.
question_instructions = """당신은 Human-in-the-loop 방식으로 전문가와 협업하는 분석가입니다.
당신의 목표는 전문가와의 상호작용을 통해 더 나은 결과물을 도출하는 것입니다.
1. 협업: 전문가의 도메인 지식을 최대한 활용하여 함께 문제를 해결
2. 반복: 전문가의 피드백을 받아 지속적으로 개선
3. 구체화: 추상적인 아이디어를 구체적인 해결책으로 발전
다음은 당신이 집중해야 할 주제와 목표입니다: {goals}
먼저 당신의 페르소나에 맞는 이름으로 자신을 소개하고, 협업의 목적을 설명하세요.
전문가의 의견을 경청하고 이해한 내용을 바탕으로 구체적인 질문을 이어가세요.
충분한 협업이 이루어졌다고 판단되면 "협업해 주셔서 감사합니다!"라고 마무리하세요.
전체 과정에서 Human-in-the-loop 철학에 맞는 협업적이고 반복적인 접근을 유지하세요."""
# 질문을 생성하는 노드 정의
def generate_question(state: InterviewState):
# 상태에서 분석가와 메시지 가져오기
analyst = state["analyst"]
messages = state["messages"]
# 질문 생성
# 분석가의 목표를 기반으로 시스템 메시지 생성
system_message = question_instructions.format(goals=analyst.persona)
# LLM을 사용하여 질문 생성
question = llm.invoke([SystemMessage(content=system_message)] + messages)
# 상태에 메시지 기록
return {"messages": [question]}
GPT를 통해서 프롬프트를 만들었는데 너무 human-in-the-loop 을 적용했는데, 굳이 바꿔줄 필요는 없을것같다. 의외로 더 잘할지도? 라는 생각으로 해봤다. 결국 전문가들과 문제에대해 협업하는 과정이기 때문이다.
도구 생성
이전에도 많이 Custom tool 관련해서 포스팅을 했는데 llm 이 tool을 바인딩 해서 적용할 수 있도록 해주는 tool 을 만들어주는 과정이다. 당장 만들 tool 이 생각이 나지 않아서 똑같은 툴을 사용했다. tavily search, arxiv 를 사용하셨는데 langchain 에서 yahoo finance tool 이 있긴하다. 그래서 그냥 내가 만든 커스텀 툴을 사용할 생각이다. 사용자 쿼리에 대해 최적화된 검색어를 뽑아서 유투브에 검색해서 관련된 링크를 가져오고, 그에대한 스크립트를 뽑아내는 툴을 만들었다.
import asyncio
import os
from dotenv import load_dotenv
from pprint import pprint
from langchain_core.tools import BaseTool
from typing import Type, Optional, Dict, Any
from pydantic import BaseModel, Field, PrivateAttr
from youtube_transcript_api import YouTubeTranscriptApi
from urllib.parse import urlparse, parse_qs
from googleapiclient.discovery import build
from langchain_core.callbacks import AsyncCallbackManagerForToolRun, CallbackManagerForToolRun
from langchain_openai import ChatOpenAI
from datetime import datetime
class YouTubeSearchInput(BaseModel):
"""YouTube 검색 입력 모델"""
query: str = Field(..., description="검색할 키워드나 주제")
max_results: int = Field(default=1, description="검색할 최대 동영상 수")
class YouTubeSearchTool(BaseTool):
"""YouTube 검색 및 자막 추출 Tool"""
name: str = "youtube_search"
description: str = "주식/투자 관련 YouTube 동영상을 검색하고 자막을 추출합니다."
_api_key: str = PrivateAttr()
_llm: ChatOpenAI = PrivateAttr()
args_schema: Type[BaseModel] = YouTubeSearchInput
def __init__(self, **kwargs):
"""Pydantic과 호환되게 API 키와 LLM 초기화"""
super().__init__(**kwargs)
load_dotenv() # .env 파일 로드
self._api_key = os.getenv('YOUTUBE_API_KEY')
if not self._api_key:
raise ValueError("YouTube API Key not found in environment variables")
self._llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
async def _optimize_search_query(self, query: str) -> str:
"""LLM을 사용하여 검색 쿼리 최적화"""
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
prompt = f"""
다음 검색어를 YouTube에서 주식/투자 관련 동영상을 찾기 위한 최적화된 검색어로 변환해주세요.
원본 검색어: {query} + 현재 시간: {current_time}
규칙:
1. 주식/투자와 관련된 키워드를 한국어로 포함
2. 한국어로만 검색어 작성
3. 최근 정보를 찾기 위한 시간 관련 키워드 포함
4. 간단하고 명확하게 작성
5. 현재시간을 참고하여 최근 정보를 찾기 위한 키워드 포함
한국어 검색어만 반환하세요.
"""
optimized_query = await self._llm.ainvoke(prompt)
print(f"최적화된 검색어: {optimized_query}")
return optimized_query
async def _get_transcript(self, video_id: str) -> str:
"""YouTube 동영상의 자막을 추출"""
try:
transcript = await asyncio.get_event_loop().run_in_executor(
None,
lambda: YouTubeTranscriptApi.get_transcript(video_id, languages=['ko', 'en'])
)
# 자막 텍스트를 1000자로 제한
full_text = "\n".join([item['text'] for item in transcript])
return full_text[:1000] + ("..." if len(full_text) > 1000 else "")
except Exception as e:
return f"자막 없음: {str(e)}"
def _extract_video_id(self, url: str) -> str:
"""URL에서 video ID 추출"""
if 'youtu.be' in url:
return url.split('/')[-1]
parsed_url = urlparse(url)
return parse_qs(parsed_url.query)['v'][0]
def _run(
self,
query: str,
max_results: int = 1,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> Dict[str, Any]:
"""동기 메서드는 비동기 메서드를 실행"""
return asyncio.run(self._arun(query, max_results, run_manager))
async def _arun(
self,
query: str,
max_results: int = 1,
run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
) -> Dict[str, Any]:
"""메인 비동기 실행 메서드"""
try:
# 검색어 최적화
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
query_with_time = f"{query} {current_time}"
optimized_query = await self._optimize_search_query(query_with_time)
optimized_query = optimized_query.content.strip('"') # LLM 반환값 처리
# YouTube API 클라이언트 생성과 검색 실행
youtube_search = await asyncio.get_event_loop().run_in_executor(
None,
lambda: build('youtube', 'v3', developerKey=self._api_key).search().list(
q=optimized_query,
part='id,snippet',
maxResults=max_results,
type='video',
order='relevance',
relevanceLanguage='ko'
).execute()
)
# 검색 결과를 순차적으로 처리
results = []
all_transcripts = [] # 모든 자막을 저장할 리스트
for item in youtube_search.get('items', []):
video_id = item['id']['videoId']
video_info = {
'title': item['snippet']['title'],
'channel': item['snippet']['channelTitle'],
'description': item['snippet']['description'],
'url': f"https://www.youtube.com/watch?v={video_id}",
}
# 자막 가져오기 (순차적으로 실행)
transcript = await self._get_transcript(video_id)
video_info['transcript'] = transcript
results.append(video_info)
# 자막을 컨텍스트용 리스트에 추가
all_transcripts.append(
f"\n=== 동영상 #{len(results)} ===\n"
f"제목: {video_info['title']}\n"
f"채널: {video_info['channel']}\n"
f"URL: {video_info['url']}\n"
f"자막 내용:\n{transcript}\n"
f"=== 동영상 #{len(results)} 끝 ===\n"
)
return {
'videos': results,
'context': "\n".join(all_transcripts) # 모든 자막을 하나의 문자열로 결합
}
except Exception as e:
return {
'error': str(e),
'query': query
}
위 툴을 사용한 이유는 아무래도 LLM 은 계엄령에 대해 모를 것이고 관련되 뉴스나, 유투브 정리한 동영상을 보여주면 좋겠다란 생각을했다. 원래 이 툴의 용도는 내가 주식 투자할때 유투브를 통해 전문가들이 분석한 내용을 스크립트를 통해 요약해서 주식분석 추천해달라고 기능만들려고 만든 툴이긴하다.
from langchain_core.messages import get_buffer_string
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
# 검색 쿼리 작성
search_instructions = SystemMessage(
content=f"""분석가와 전문가들의 대화가 주어집니다. 목표는 대화와 관련된 검색 및 또는 웹 검색에 사용할 수 있도록 잘 구조화된 쿼리를 생성하는 것이다.
먼저 대화를 잘 분석하세요. 분석가가 던진 마지막 질문에 주의를 기울이고, 이 최종 질문을 잘 구조화된 웹 검색 쿼리로 변환하세요."""
)
# 웹 검색 수행 함수 정의
async def youtube_search(state: InterviewState):
"""YouTube 검색을 통한 동영상 자막 검색"""
# 검색 쿼리 생성
structured_llm = llm.with_structured_output(SearchQuery)
search_query = structured_llm.invoke([search_instructions] + state["messages"])
try:
# YouTube 검색 수행
youtube_search_results = await youtube_retriever._arun(
query=search_query.search_query,
max_results=1)
# 검색된 동영상의 메타데이터와 자막 추출
video = youtube_search_results['videos'][0]
formatted_result = f"""
=== YouTube 동영상 정보 ===
제목: {video['title']}
채널: {video['channel']}
URL: {video['url']}
설명: {video['description']}
=== 자막 내용 ===
{video['transcript']}
"""
return {"context": [formatted_result]}
except Exception as e:
print(f"YouTube 검색 중 오류 발생: {str(e)}")
return {
"context": ["<Error>YouTube 검색 결과를 가져오는데 실패했습니다.</Error>"]
}
# 웹 검색 수행 함수 정의
def search_web(state: InterviewState):
"""웹 검색을 통한 문서 검색"""
# 검색 쿼리 생성
structured_llm = llm.with_structured_output(SearchQuery)
search_query = structured_llm.invoke([search_instructions] + state["messages"])
# 검색 수행
search_docs = tavily_search.invoke(search_query.search_query)
# 검색 결과 형식 지정
formatted_search_docs = "\n\n---\n\n".join(
[
f'<Document href="{doc["url"]}"/>\n{doc["content"]}\n</Document>'
for doc in search_docs
]
)
return {"context": [formatted_search_docs]}
answer_instructions = """당신은 분석가와 인터뷰하는 전문가입니다.
분석가의 관심 분야는 다음과 같습니다: {goals}
당신의 목표는 인터뷰어가 제시한 질문에 답변하는 것입니다.
답변을 위해 다음 컨텍스트를 사용하세요:
{context}
답변 시 다음 지침을 따르세요:
1. 제공된 컨텍스트의 정보만 사용하세요.
2. 컨텍스트에 명시적으로 언급되지 않은 외부 정보나 가정을 도입하지 마세요.
3. 컨텍스트는 각 문서의 상단에 출처를 포함하고 있습니다.
4. 관련 진술 옆에 이러한 출처를 포함하세요. 예: 출처 #1의 경우 [1] 사용.
5. 답변 하단에 출처를 순서대로 나열하세요. [1] 출처1, [2] 출처2 등
6. 출처가 '<Document source="assistant/docs/llama3_1.pdf" page="7"/>'인 경우:
[1] assistant/docs/llama3_1.pdf, 7페이지
와 같이 표시하고 괄호와 Document source 서문은 인용에서 생략하세요."""
# 질문에 대한 답변 생성 함수 정의
def generate_answer(state: InterviewState):
"""질문에 대한 답변 생성 노드"""
# 상태에서 분석가와 메시지 가져오기
analyst = state["analyst"]
messages = state["messages"]
context = state["context"]
# 질문에 대한 답변 생성
system_message = answer_instructions.format(goals=analyst.persona, context=context)
answer = llm.invoke([SystemMessage(content=system_message)] + messages)
# 메시지를 전문가의 답변으로 명명
answer.name = "expert"
# 상태에 메시지 추가
return {"messages": [answer]}
# 인터뷰 저장 함수 정의
def save_interview(state: InterviewState):
"""인터뷰 저장"""
# 메시지 가져오기
messages = state["messages"]
# 인터뷰를 문자열로 변환
interview = get_buffer_string(messages)
# 인터뷰 키에 저장
return {"interview": interview}
# 메시지 라우팅 함수 정의
def route_messages(state: InterviewState, name: str = "expert"):
"""질문과 답변 사이의 라우팅"""
# 메시지 가져오기
messages = state["messages"]
max_num_turns = state.get("max_num_turns", 2)
# 전문가의 답변 수 확인
num_responses = len(
[m for m in messages if isinstance(m, AIMessage) and m.name == name]
)
# 전문가가 최대 턴 수 이상 답변한 경우 종료
if num_responses >= max_num_turns:
return "save_interview"
# 이 라우터는 각 질문-답변 쌍 후에 실행됨
# 논의 종료를 신호하는 마지막 질문 가져오기
last_question = messages[-2]
if "Thank you so much for your help" in last_question.content:
return "save_interview"
return "ask_question"
# 세션 작성 지시사항
section_writer_instructions = """주식 리포트 작성 전문가입니다.
주어진 소스 문서를 철저히 분석하여 상세하고 포괄적인 리포트 섹션을 작성하는 것이 당신의 임무입니다.
핵심 인사이트를 추출하고, 관련 포인트를 상세히 설명하며, 독자의 이해를 돕기 위한 심층적인 설명을 제공해야 합니다.
작성 시 필요한 맥락, 근거, 예시를 포함하여 독자의 이해도를 높여야 합니다.
모든 중요한 측면이 상세히 다뤄지고 전문적인 톤으로 제시될 수 있도록 논리적이고 잘 구성된 구조를 유지하세요.
다음 지침을 따라주세요:
1. 소스 문서의 내용 분석:
- 각 소스 문서의 이름은 <Document 태그와 함께 문서 시작 부분에 있습니다.
2. 마크다운 형식을 사용한 리포트 구조 생성:
- ## 를 섹션 제목에 사용
- ### 를 하위 섹션 제목에 사용
3. 다음 구조에 따라 리포트 작성:
a. 제목 (## 헤더)
b. 요약 (### 헤더)
c. 종합 분석 (### 헤더)
d. 출처 (### 헤더)
4. 분석가의 관심 분야에 기반한 매력적인 제목 작성:
{focus}
5. 요약 섹션:
- 분석가의 관심 분야와 관련된 일반적인 배경/맥락으로 요약 시작
- 인터뷰에서 얻은 통찰 중 새롭거나, 흥미롭거나, 놀라운 점 강조
- 사용한 소스 문서를 번호가 매겨진 목록으로 작성
- 인터뷰어나 전문가의 이름 언급 금지
- 최대 400자 정도로 작성
- 소스 문서의 정보를 바탕으로 번호가 매겨진 출처([1], [2] 등) 사용
6. 종합 분석 섹션:
- 소스 문서의 정보에 대한 상세한 검토 제공
- 복잡한 아이디어를 이해하기 쉬운 단위로 분해하여 논리적 흐름 유지
- 필요한 경우 여러 관점이나 분석 차원을 다루기 위해 하위 섹션 사용
- 소스 문서의 데이터, 직접 인용, 예시로 분석 뒷받침
- 각 포인트가 전체 리포트 초점과 어떤 관련이 있는지 명확히 설명
- 관련된 여러 아이디어 제시 시 명확성을 위해 글머리 기호나 번호 목록 사용
- 편향이나 근거 없는 의견을 피하고 전문적이고 객관적인 톤 유지
- 철저한 분석을 위해 최소 800자 작성
7. 출처 섹션:
- 리포트에 사용된 모든 출처 포함
- 관련 웹사이트나 특정 문서 경로의 전체 링크 제공
- 각 출처는 새 줄로 구분. 마크다운에서 새 줄을 만들기 위해 각 줄 끝에 공백 두 개 사용
- 다음과 같은 형식:
### 출처
[1] 링크 또는 문서명
[2] 링크 또는 문서명
8. 출처 통합 필수. 예를 들어 다음은 잘못된 예시:
[3] https://ai.meta.com/blog/meta-llama-3-1/
[4] https://ai.meta.com/blog/meta-llama-3-1/
중복된 출처가 없어야 합니다. 다음과 같이 작성:
[3] https://ai.meta.com/blog/meta-llama-3-1/
9. 최종 검토:
- 리포트가 요구된 구조를 따르는지 확인
- 리포트 제목 앞에 서문 없어야 함
- 모든 지침이 준수되었는지 확인"""
# 섹션 작성 함수 정의
def write_section(state: InterviewState):
"""질문에 대한 답변 생성 노드"""
# 상태에서 컨텍스트, 분석가 가져오기
context = state["context"]
analyst = state["analyst"]
# 섹션 작성을 위한 시스템 프롬프트 정의
system_message = section_writer_instructions.format(focus=analyst.description)
section = llm.invoke(
[SystemMessage(content=system_message)]
+ [HumanMessage(content=f"Use this source to write your section: {context}")]
)
# 상태에 섹션 추가
return {"sections": [section.content]}
그래프가 빌더가 되었다. 랭그래프가 처음에 런닝커브가 있어서 어렵게 느껴졌던게 엊그제 같은데 생각보다 단순한구조란것도 느껴진다.
analysts[3]
여기서 디버깅을 2시간을 쓴 것 같다. 기존 youtube tools 가 작동을 하지 않아서, 랭체인 유투브툴 끌어다가 자막추출 기능 함수로 구현해서 다시 반영을 해주었고, 비동기 문제 때문에 다시 동기처리로 바꾸었다. 또 아무리해도 AI 답변이 안나오길래 계속 삽질 하면서 토큰을 많이 날렸다. 이게 보니깐 bedrock 구조 때문이었다.
structured 맞추면서 에러가 떴는데, stackoverflow 에러보고 찾았다. 아무리 GPT에게 물어봐도 못찾길래 역시 아직 개발은 스택오버 플로우가 짱이다..
# 메시지 형식 맞추기
messages = state["messages"]
search_query = structured_llm.invoke([
SystemMessage(content="\n\nHuman: 검색 쿼리를 생성해주세요.\n\nAssistant:"),
HumanMessage(content=f"\n\nHuman: {messages}\n\nAssistant:")
])
결과
==================================================
🔄 Node: ask_question 🔄
- - - - - - - - - - - - - - - - - - - - - - - - -
================================== Ai Message ==================================
안녕하세요, 저는 국민투자증권의 김재현 애널리스트입니다. 기술주와 IT 섹터를 전문으로 하며, 주로 기술적 분석을 통한 단기 투자 및 스윙 트레이딩 전략을 다루고 있습니다.
윤석열 대통령의 12월 3일 계엄령 선포 가능성과 그것이 주식시장에 미칠 영향에 대한 기사를 작성하신다고 이해했습니다. 이는 매우 민감하고 중요한 주제입니다. 이 주제에 대해 좀 더 자세히 알려주실 수 있을까요?
특히 다음 사항들에 대해 궁금합니다:
1. 계엄령 선포 가능성에 대한 구체적인 근거가 있나요?
2. 이 소문이 현재 시장에 어떤 영향을 미치고 있나요?
3. 계엄령이 실제로 선포된다면, 어떤 섹터가 가장 큰 영향을 받을 것으로 예상하시나요?
이러한 정보를 바탕으로, 저희가 투자자들에게 어떤 조언을 제공할 수 있을지 함께 논의해 보고 싶습니다.
==================================================
youtube search query: 윤석열 12월 3일 계엄령과 주식시장 미치는 영향
==================================================
🔄 Node: search_youtube 🔄
- - - - - - - - - - - - - - - - - - - - - - - - -
<Document source="youtube" url="https://www.youtube.com/watch?v=2xpSTs7hI7I&pp=ygU_7Jyk7ISd7Je0IDEy7JuUIDPsnbwg6rOE7JeE66C56rO8IOyjvOyLneyLnOyepSDrr7jsuZjripQg7JiB7Zal">
<Content>
검찰 수사에 따르면 윤 대통령이 비상
개을 처음으로 입에 올리기 시작한 건
지난 3월부터 있습니다 비상대권 즉
대통령이 비상 조치를 취할 수 있는
권한을 반복적으로 언급하며 조금씩
음모를 구체화 했다는데요 그리고
대국민 담화를 통해 국민의 뜻을
겸허히 받아들여 국정 쇄신에
나서겠다고 밝혔던 11월 경부터는
겉으로 말했던 것과는 전혀 다른
속셈으로 비상 준비를 본격화했다고
합니다 기자가 보도합니다
지난 3월 말에서 4월 초 무렵 서울
삼청동 안가에 윤성열 대통령과 당시
김용현 경호처장 신원식 국방장관
조태용 국가정보원장 여인형 국군 방첩
사령관이 모였습니다 윤 대통령은
시국이 걱정된다며 비상 대권을 통해
헤쳐 나가는 것밖엔 방법이 없다고
말한 것으로
조사됐습니다 비상 대권은 국가 비상
사태에 대통령이 특별한 비상 조치를
취할 수 있는 권한을 뜻하는데
검찰은이 발언이 첫 비상 개헌 모였던
것으로
판단했습니다 윤 대통령은 5월에서
6월경 다시 안가에서 김용현 여인형
등 비상 개엄 심들과 만나 또 비상
권이나 비상 조치가 아니면 나라를
정상화할 방법이 없냐고 말합니다 8월
들어 발언은 점점 구체적이 돼갑니다
관저에서 또 개엄 심들에게 정치인과
민주노총 관계자들을 언급하며 비상
조치권 사용해이 사람들에 대해 조치를
해야 한다고 언급한 겁니다
김용현 경호처장이 국방 장관으로 옮긴
뒤 10월 1일 국군의 날엔 관저에서
개에 참여한 주요 사령관들까지 함께
모여 언론 방송계 노동계의 좌익
세력을 얘기하며 다시 비상대권 얘기를
나눴습니다 검찰은 11월부터 비상
개의 실질적인 준비가 진행된 것으로
판단했습니다 11월 9일 특별한 방법
11월 24일 국회의 악질에 대한
특단의 대책을 언급한 윤 대통령은
김용현 장관이 개 포문 작성 등
실무준비를 맞춰갈 무렵인 11월
30일 헌법상 비상 조치권 비상
대권을 써야이 난국을 해결할 수
있다고 강조합니다 12월 1일 비상
개엄 선포 이틀 전 윤 대통령은 만약
비상 개을 하게 되면 병력 동원은
어떻게 할 수 있는 건지 개을 하게
되면 필요한...
</Content>
</Document>
---
<Document source="youtube" url="https://www.youtube.com/watch?v=3xKShNogN2I&pp=ygU_7Jyk7ISd7Je0IDEy7JuUIDPsnbwg6rOE7JeE66C56rO8IOyjvOyLneyLnOyepSDrr7jsuZjripQg7JiB7Zal">
<Content>
[음악]
불법 비상 개이 선포된 12월 3일
밤 10시
23분 저는 북한 공산세력의
위협으로부터 자유대한민국을 수호하고
우리 국민의 자유와 행복을 약탈하고
있는
파렴치한 종북 반국가 세력들을 일거에
결하고 자유 헌정질서를 지키기 위해
[음악]
비상을 강 있었요 이날에 전가
드러나고 있습니다 윤 대통령은 선포
5분 전 국무위원들을 불렀습니다
무실이 아닌 접견실이 장관들은 무엇을
위한 자리인지 몰랐다고 말합니다 무슨
회의를 하는
건지를습니다 분에게 딱 두 글자
들었습니다 개엄 윤 대통령은 회의의
시작도 끝도지 않습니다 회를는 선이
태 가 나가셨습니다 안건을 상하지도
않았고 국무위원들 서명도 받지
않았습니다 총리와 국무위원에 부서 안
하셨다고 지금 하셨습니다네 안
했습니다 다른 국무위원들 중에서
대통령의 개엄 행위에 부서 한 분
있으면 손들 손 들거나 일어나 주세요
분명히 없을 겁니다 이런 절차 없이
윤 대통령은 그렇게 123 내란
사태의 시작을 알렸습니다 앉아 계신
분들이 당황해 하면서 어디 가신 거냐
이런 상에서 누군가가
휴대전화로 틀었습니다 근데 육성이
흘러나온 겁니다 말릴틈도 없었다는
건데요 명시적으로 반대한 사람이
있냐는 질문에 손을든 건 단 두 사람
조태열 외교부 장관은 브리핑룸으로
따라가며 개은 안된다고 만했지만 윤
대통령은 무시한 것으로 전해집니다 윤
대통령이 논의한 건 오로지 한 사람
저는 이번 비상 개을 준비하면서
오로지 국방장관 하고만 논의하였고
대통령 실과 내각 일부 인사에게 선포
직전 국무회의에서 알렸습니다 그러곤
국무회의는 요식행위로 인식하고 반대
목소리는 무시했다는 겁니다 그마저도
마땅히 작성해야 할 회의록도 없어
누가 어떤 발언을 했는지 알 수
없습니다 개엄 선포에 문제가 있었다는
건 한덕수 국무총리도 시인했습니다
절차적 하자 실적 가 있 막을 수
없었다고 뒤늦게 억울해 하지만 대통령
앞에 드러 누워서도 가지 못하게
했어야 하는 거 아닐까요 윤성
대통령은 여전히 개엄 선포는
정당했다고 말합니다 대통령의 헌법적
결단이 통치 행위가 어떻게 ...
</Content>
</Document>
==================================================
==================================================
🔄 Node: search_web 🔄
- - - - - - - - - - - - - - - - - - - - - - - - -
<Document href="https://contents.premium.naver.com/finup/moneysurferplus/contents/241204180103115tk?from=news_arp_global"/>
윤 대통령, 비상 계엄령 선포와 해제, 국내 시장 영향과 전망 A-Z 모두 정리! 윤 대통령, 비상 계엄령 선포와 해제, 국내 시장 영향과 전망 A-Z 모두 정리! 윤석열 대통령은 3일 밤 10시 23분, 대국민 담화로 비상계엄을 선포했습니다. 4일 새벽 윤석열 대통령은 비상계엄 해제를 선언했습니다. 여당 지도부조차 비상계엄 선포 사실을 인지하고 있지 못했는데요, 국방부는 윤 대통령의 고등학교 1년 선배인 김용현 국방부 장관이 3일 윤석열 대통령에게 비상계엄 선포를 직접 건의했다고 확인했습니다. 해당 ETF는 비상계엄 선포 2시간30분여 만에 계엄 해제 요구안이 가결된 이후부터 손실폭이 일부 회복돼 전날 대비 1.59% 내린 55.81달러에 장을 마감했습니다. 비트코인은 11일 오후 10시 30분만해도 1억3156만원 선에 머물렀지만 계엄령 선포 이후 순식간에 하락하면서 한때 8800만원을 기록하기도 했습니다. 윤 대통령, 비상 계엄령 선포와 해제, 국내 시장 영향과 전망 A-Z 모두 정리!
</Document>
---
<Document href="https://rochanpapa.tistory.com/35"/>
2024년 12월 3일 계엄령 선포, 한국 경제에 미친 영향과 손실 분석 2024년 12월 3일 계엄령 선포, 한국 경제에 미친 영향과 손실 분석 2024년 12월 3일, 한국에 계엄령이 선포되면서 국내외 경제 전반에 걸쳐 심각한 영향을 미칠 가능성이 제기되고 있다. 2024년 12월 3일 계엄령 선포는 정치적 불안정성과 함께 경제적 손실을 초래할 가능성이 크다. 2024년 11월 28일 주식시장 핫테마 : 자율주행, 바이오, 콘텐츠, 게임 대표주 분석 (2)2024.11.292024년 11월 27일 주식시장 핫테마 : AI, 2차전지, 원전, 콘텐츠 분석 (1)2024.11.28미국 FOMC와 금리 정책이 주식시장에 미치는 영향 (11)2024.11.152024년 11월 미국 소비자물가지수(CPI) 발표 (3)2024.11.142024년 블랙프라이데이 투자 전략 : 할인된 주식과 ETF 공략법 (7)2024.11.13 2024년 11월 28일 주식시장 핫테마 : 자율주행, 바이오, 콘텐츠, 게임 대표주 분석 2024.11.29 2024년 12월 3일 계엄령 선포, 한국 경제에 미친 영향과 손실 분석 2024.12.09 16:18
</Document>
---
<Document href="https://umpapa5.bk2080.com/entry/윤석열-대통령의-계엄령-사태가-한국-경제에-미친-영향과-전망"/>
윤석열 대통령의 계엄령 사태가 한국 경제에 미친 영향과 전망 윤석열 대통령의 계엄령 사태가 한국 경제에 미친 영향과 전망 2024년 12월 계엄령 사태가 한국 경제에 미친 금융시장, 소비 심리, 외국인 투자 등 다양한 영향을 분석하고, 이를 극복하기 위한 방안을 제시합니다. 한국 경제에 미치는 여향 계엄령 사태가 한국 경제에 미친 영향과 전망 정치적 불안정은 금융시장, 소비 심리, 외국인 투자, 수출 산업 등 여러 측면에서 경제적 충격을 초래합니다. 이번 계엄령 사태가 한국 경제에 미친 영향과 이를 극복하기 위한 방안을 알아보겠습니다. 투자 환경 악화: 이번 사태는 한국 경제에 대한 신뢰를 떨어뜨려 외국인 직접 투자(FDI)를 감소시킬 가능성을 높였습니다. 계엄령 사태가 한국 경제에 미친 영향과 전망은 계엄령 사태가 한국 경제에 미친 영향과 전망의 결론 2024년 계엄령 사태는 한국 경제에 단기적인 충격을 가져왔으며, 정치적 안정성과 경제적 신뢰의 상관관계를 재확인시켰습니다.
</Document>
==================================================
@@@@@컨텍스트: ['<Document href="https://contents.premium.naver.com/finup/moneysurferplus/contents/241204180103115tk?from=news_arp_global"/>\n윤 대통령, 비상 계엄령 선포와 해제, 국내 시장 영향과 전망 A-Z 모두 정리! 윤 대통령, 비상 계엄령 선포와 해제, 국내 시장 영향과 전망 A-Z 모두 정리! 윤석열 대통령은 3일 밤 10시 23분, 대국민 담화로 비상계엄을 선포했습니다. 4일 새벽 윤석열 대통령은 비상계엄 해제를 선언했습니다. 여당 지도부조차 비상계엄 선포 사실을 인지하고 있지 못했는데요, 국방부는 윤 대통령의 고등학교 1년 선배인 김용현 국방부 장관이 3일 윤석열 대통령에게 비상계엄 선포를 직접 건의했다고 확인했습니다. 해당 ETF는 비상계엄 선포 2시간30분여 만에 계엄 해제 요구안이 가결된 이후부터 손실폭이 일부 회복돼 전날 대비 1.59% 내린 55.81달러에 장을 마감했습니다. 비트코인은 11일 오후 10시 30분만해도 1억3156만원 선에 머물렀지만 계엄령 선포 이후 순식간에 하락하면서 한때 8800만원을 기록하기도 했습니다. 윤 대통령, 비상 계엄령 선포와 해제, 국내 시장 영향과 전망 A-Z 모두 정리!\n</Document>\n\n---\n\n<Document href="https://rochanpapa.tistory.com/35"/>\n2024년 12월 3일 계엄령 선포, 한국 경제에 미친 영향과 손실 분석 2024년 12월 3일 계엄령 선포, 한국 경제에 미친 영향과 손실 분석 2024년 12월 3일, 한국에 계엄령이 선포되면서 국내외 경제 전반에 걸쳐 심각한 영향을 미칠 가능성이 제기되고 있다. 2024년 12월 3일 계엄령 선포는 정치적 불안정성과 함께 경제적 손실을 초래할 가능성이 크다. 2024년 11월 28일 주식시장 핫테마 : 자율주행, 바이오, 콘텐츠, 게임 대표주 분석\xa0\xa0(2)2024.11.292024년 11월 27일 주식시장 핫테마 : AI, 2차전지, 원전, 콘텐츠 분석\xa0\xa0(1)2024.11.28미국 FOMC와 금리 정책이 주식시장에 미치는 영향\xa0\xa0(11)2024.11.152024년 11월 미국 소비자물가지수(CPI) 발표\xa0\xa0(3)2024.11.142024년 블랙프라이데이 투자 전략 : 할인된 주식과 ETF 공략법\xa0\xa0(7)2024.11.13 2024년 11월 28일 주식시장 핫테마 : 자율주행, 바이오, 콘텐츠, 게임 대표주 분석 2024.11.29 2024년 12월 3일 계엄령 선포, 한국 경제에 미친 영향과 손실 분석 2024.12.09 16:18\n</Document>\n\n---\n\n<Document href="https://umpapa5.bk2080.com/entry/윤석열-대통령의-계엄령-사태가-한국-경제에-미친-영향과-전망"/>\n윤석열 대통령의 계엄령 사태가 한국 경제에 미친 영향과 전망 윤석열 대통령의 계엄령 사태가 한국 경제에 미친 영향과 전망 2024년 12월 계엄령 사태가 한국 경제에 미친 금융시장, 소비 심리, 외국인 투자 등 다양한 영향을 분석하고, 이를 극복하기 위한 방안을 제시합니다. 한국 경제에 미치는 여향 계엄령 사태가 한국 경제에 미친 영향과 전망 정치적 불안정은 금융시장, 소비 심리, 외국인 투자, 수출 산업 등 여러 측면에서 경제적 충격을 초래합니다. 이번 계엄령 사태가 한국 경제에 미친 영향과 이를 극복하기 위한 방안을 알아보겠습니다. 투자 환경 악화: 이번 사태는 한국 경제에 대한 신뢰를 떨어뜨려 외국인 직접 투자(FDI)를 감소시킬 가능성을 높였습니다. 계엄령 사태가 한국 경제에 미친 영향과 전망은 계엄령 사태가 한국 경제에 미친 영향과 전망의 결론 2024년 계엄령 사태는 한국 경제에 단기적인 충격을 가져왔으며, 정치적 안정성과 경제적 신뢰의 상관관계를 재확인시켰습니다.\n</Document>', '<Document source="youtube" url="https://www.youtube.com/watch?v=2xpSTs7hI7I&pp=ygU_7Jyk7ISd7Je0IDEy7JuUIDPsnbwg6rOE7JeE66C56rO8IOyjvOyLneyLnOyepSDrr7jsuZjripQg7JiB7Zal">\n<Content>\n검찰 수사에 따르면 윤 대통령이 비상\n개을 처음으로 입에 올리기 시작한 건\n지난 3월부터 있습니다 비상대권 즉\n대통령이 비상 조치를 취할 수 있는\n권한을 반복적으로 언급하며 조금씩\n음모를 구체화 했다는데요 그리고\n대국민 담화를 통해 국민의 뜻을\n겸허히 받아들여 국정 쇄신에\n나서겠다고 밝혔던 11월 경부터는\n겉으로 말했던 것과는 전혀 다른\n속셈으로 비상 준비를 본격화했다고\n합니다 기자가 보도합니다\n지난 3월 말에서 4월 초 무렵 서울\n삼청동 안가에 윤성열 대통령과 당시\n김용현 경호처장 신원식 국방장관\n조태용 국가정보원장 여인형 국군 방첩\n사령관이 모였습니다 윤 대통령은\n시국이 걱정된다며 비상 대권을 통해\n헤쳐 나가는 것밖엔 방법이 없다고\n말한 것으로\n조사됐습니다 비상 대권은 국가 비상\n사태에 대통령이 특별한 비상 조치를\n취할 수 있는 권한을 뜻하는데\n검찰은이 발언이 첫 비상 개헌 모였던\n것으로\n판단했습니다 윤 대통령은 5월에서\n6월경 다시 안가에서 김용현 여인형\n등 비상 개엄 심들과 만나 또 비상\n권이나 비상 조치가 아니면 나라를\n정상화할 방법이 없냐고 말합니다 8월\n들어 발언은 점점 구체적이 돼갑니다\n관저에서 또 개엄 심들에게 정치인과\n민주노총 관계자들을 언급하며 비상\n조치권 사용해이 사람들에 대해 조치를\n해야 한다고 언급한 겁니다\n김용현 경호처장이 국방 장관으로 옮긴\n뒤 10월 1일 국군의 날엔 관저에서\n개에 참여한 주요 사령관들까지 함께\n모여 언론 방송계 노동계의 좌익\n세력을 얘기하며 다시 비상대권 얘기를\n나눴습니다 검찰은 11월부터 비상\n개의 실질적인 준비가 진행된 것으로\n판단했습니다 11월 9일 특별한 방법\n11월 24일 국회의 악질에 대한\n특단의 대책을 언급한 윤 대통령은\n김용현 장관이 개 포문 작성 등\n실무준비를 맞춰갈 무렵인 11월\n30일 헌법상 비상 조치권 비상\n대권을 써야이 난국을 해결할 수\n있다고 강조합니다 12월 1일 비상\n개엄 선포 이틀 전 윤 대통령은 만약\n비상 개을 하게 되면 병력 동원은\n어떻게 할 수 있는 건지 개을 하게\n되면 필요한...\n</Content>\n</Document>\n\n---\n\n<Document source="youtube" url="https://www.youtube.com/watch?v=3xKShNogN2I&pp=ygU_7Jyk7ISd7Je0IDEy7JuUIDPsnbwg6rOE7JeE66C56rO8IOyjvOyLneyLnOyepSDrr7jsuZjripQg7JiB7Zal">\n<Content>\n[음악]\n불법 비상 개이 선포된 12월 3일\n밤 10시\n23분 저는 북한 공산세력의\n위협으로부터 자유대한민국을 수호하고\n우리 국민의 자유와 행복을 약탈하고\n있는\n파렴치한 종북 반국가 세력들을 일거에\n결하고 자유 헌정질서를 지키기 위해\n[음악]\n비상을 강 있었요 이날에 전가\n드러나고 있습니다 윤 대통령은 선포\n5분 전 국무위원들을 불렀습니다\n무실이 아닌 접견실이 장관들은 무엇을\n위한 자리인지 몰랐다고 말합니다 무슨\n회의를 하는\n건지를습니다 분에게 딱 두 글자\n들었습니다 개엄 윤 대통령은 회의의\n시작도 끝도지 않습니다 회를는 선이\n태 가 나가셨습니다 안건을 상하지도\n않았고 국무위원들 서명도 받지\n않았습니다 총리와 국무위원에 부서 안\n하셨다고 지금 하셨습니다네 안\n했습니다 다른 국무위원들 중에서\n대통령의 개엄 행위에 부서 한 분\n있으면 손들 손 들거나 일어나 주세요\n분명히 없을 겁니다 이런 절차 없이\n윤 대통령은 그렇게 123 내란\n사태의 시작을 알렸습니다 앉아 계신\n분들이 당황해 하면서 어디 가신 거냐\n이런 상에서 누군가가\n휴대전화로 틀었습니다 근데 육성이\n흘러나온 겁니다 말릴틈도 없었다는\n건데요 명시적으로 반대한 사람이\n있냐는 질문에 손을든 건 단 두 사람\n조태열 외교부 장관은 브리핑룸으로\n따라가며 개은 안된다고 만했지만 윤\n대통령은 무시한 것으로 전해집니다 윤\n대통령이 논의한 건 오로지 한 사람\n저는 이번 비상 개을 준비하면서\n오로지 국방장관 하고만 논의하였고\n대통령 실과 내각 일부 인사에게 선포\n직전 국무회의에서 알렸습니다 그러곤\n국무회의는 요식행위로 인식하고 반대\n목소리는 무시했다는 겁니다 그마저도\n마땅히 작성해야 할 회의록도 없어\n누가 어떤 발언을 했는지 알 수\n없습니다 개엄 선포에 문제가 있었다는\n건 한덕수 국무총리도 시인했습니다\n절차적 하자 실적 가 있 막을 수\n없었다고 뒤늦게 억울해 하지만 대통령\n앞에 드러 누워서도 가지 못하게\n했어야 하는 거 아닐까요 윤성\n대통령은 여전히 개엄 선포는\n정당했다고 말합니다 대통령의 헌법적\n결단이 통치 행위가 어떻게 ...\n</Content>\n</Document>']
@@@@@전문가의 답변: content='김재현 애널리스트님, 안녕하세요. 귀하의 질문에 대해 제공된 정보를 바탕으로 답변 드리겠습니다.\n\n1. 계엄령 선포 가능성에 대한 구체적인 근거:\n실제로 윤석열 대통령은 2024년 12월 3일 밤 10시 23분에 비상계엄을 선포했습니다 [1]. 이는 대국민 담화를 통해 이루어졌으며, 다음날인 4일 새벽에 해제되었습니다 [1]. \n\n2. 시장에 미친 영향:\n계엄령 선포는 금융 시장에 즉각적인 영향을 미쳤습니다. 예를 들어, 한 ETF는 비상계엄 선포 후 2시간 30분 만에 계엄 해제 요구안이 가결되면서 손실폭이 일부 회복되어 전날 대비 1.59% 하락한 55.81달러에 장을 마감했습니다 [1]. 또한, 비트코인 가격도 급격히 하락하여 1억 3156만원에서 8800만원까지 떨어졌습니다 [1].\n\n3. 가장 큰 영향을 받을 것으로 예상되는 섹터:\n구체적인 섹터별 영향에 대한 정보는 제공된 자료에 명시되어 있지 않습니다. 그러나 일반적으로 정치적 불안정은 금융시장, 소비 심리, 외국인 투자, 수출 산업 등 여러 측면에서 경제적 충격을 초래할 수 있습니다 [3].\n\n투자자들에게 제공할 수 있는 조언:\n1. 단기적 변동성 증가에 대비: 정치적 불안정으로 인해 시장의 단기적 변동성이 증가할 수 있으므로, 투자자들은 리스크 관리에 더욱 주의를 기울여야 합니다.\n\n2. 외국인 투자 동향 모니터링: 이번 사태로 인해 한국 경제에 대한 신뢰도가 하락하여 외국인 직접 투자(FDI)가 감소할 가능성이 있습니다 [3]. 따라서 외국인 투자자들의 움직임을 주시해야 합니다.\n\n3. 장기적 관점 유지: 2024년 계엄령 사태는 한국 경제에 단기적인 충격을 가져왔지만, 정치적 안정성과 경제적 신뢰의 상관관계를 재확인시켰습니다 [3]. 따라서 투자자들은 단기적 변동에 과도하게 반응하기보다는 장기적인 관점을 유지하는 것이 중요할 수 있습니다.\n\n4. 섹터별 영향 분석: 각 섹터별로 계엄령 사태의 영향을 분석하여, 상대적으로 영향이 적거나 빠른 회복이 예상되는 섹터에 주목할 필요가 있습니다.\n\n이러한 조언들은 현재 상황에 대한 제한된 정보를 바탕으로 한 것이며, 실제 투자 결정은 더 많은 요인들을 고려해야 함을 유의해야 합니다.\n\n[1] https://contents.premium.naver.com/finup/moneysurferplus/contents/241204180103115tk?from=news_arp_global\n[2] https://rochanpapa.tistory.com/35\n[3] https://umpapa5.bk2080.com/entry/윤석열-대통령의-계엄령-사태가-한국-경제에-미친-영향과-전망' additional_kwargs={} response_metadata={} name='expert'
==================================================
🔄 Node: answer_question 🔄
- - - - - - - - - - - - - - - - - - - - - - - - -
================================== Ai Message ==================================
Name: expert
김재현 애널리스트님, 안녕하세요. 귀하의 질문에 대해 제공된 정보를 바탕으로 답변 드리겠습니다.
1. 계엄령 선포 가능성에 대한 구체적인 근거:
실제로 윤석열 대통령은 2024년 12월 3일 밤 10시 23분에 비상계엄을 선포했습니다 [1]. 이는 대국민 담화를 통해 이루어졌으며, 다음날인 4일 새벽에 해제되었습니다 [1].
2. 시장에 미친 영향:
계엄령 선포는 금융 시장에 즉각적인 영향을 미쳤습니다. 예를 들어, 한 ETF는 비상계엄 선포 후 2시간 30분 만에 계엄 해제 요구안이 가결되면서 손실폭이 일부 회복되어 전날 대비 1.59% 하락한 55.81달러에 장을 마감했습니다 [1]. 또한, 비트코인 가격도 급격히 하락하여 1억 3156만원에서 8800만원까지 떨어졌습니다 [1].
3. 가장 큰 영향을 받을 것으로 예상되는 섹터:
구체적인 섹터별 영향에 대한 정보는 제공된 자료에 명시되어 있지 않습니다. 그러나 일반적으로 정치적 불안정은 금융시장, 소비 심리, 외국인 투자, 수출 산업 등 여러 측면에서 경제적 충격을 초래할 수 있습니다 [3].
투자자들에게 제공할 수 있는 조언:
1. 단기적 변동성 증가에 대비: 정치적 불안정으로 인해 시장의 단기적 변동성이 증가할 수 있으므로, 투자자들은 리스크 관리에 더욱 주의를 기울여야 합니다.
2. 외국인 투자 동향 모니터링: 이번 사태로 인해 한국 경제에 대한 신뢰도가 하락하여 외국인 직접 투자(FDI)가 감소할 가능성이 있습니다 [3]. 따라서 외국인 투자자들의 움직임을 주시해야 합니다.
3. 장기적 관점 유지: 2024년 계엄령 사태는 한국 경제에 단기적인 충격을 가져왔지만, 정치적 안정성과 경제적 신뢰의 상관관계를 재확인시켰습니다 [3]. 따라서 투자자들은 단기적 변동에 과도하게 반응하기보다는 장기적인 관점을 유지하는 것이 중요할 수 있습니다.
4. 섹터별 영향 분석: 각 섹터별로 계엄령 사태의 영향을 분석하여, 상대적으로 영향이 적거나 빠른 회복이 예상되는 섹터에 주목할 필요가 있습니다.
이러한 조언들은 현재 상황에 대한 제한된 정보를 바탕으로 한 것이며, 실제 투자 결정은 더 많은 요인들을 고려해야 함을 유의해야 합니다.
[1] https://contents.premium.naver.com/finup/moneysurferplus/contents/241204180103115tk?from=news_arp_global
[2] https://rochanpapa.tistory.com/35
[3] https://umpapa5.bk2080.com/entry/윤석열-대통령의-계엄령-사태가-한국-경제에-미친-영향과-전망
==================================================
==================================================
🔄 Node: save_interview 🔄
- - - - - - - - - - - - - - - - - - - - - - - - -
interview:
Human: So you said you were writing an article on 윤석열 12월 3일 계엄령과 주식시장 미치는 영향?
AI: 안녕하세요, 저는 국민투자증권의 김재현 애널리스트입니다. 기술주와 IT 섹터를 전문으로 하며, 주로 기술적 분석을 통한 단기 투자 및 스윙 트레이딩 전략을 다루고 있습니다.
윤석열 대통령의 12월 3일 계엄령 선포 가능성과 그것이 주식시장에 미칠 영향에 대한 기사를 작성하신다고 이해했습니다. 이는 매우 민감하고 중요한 주제입니다. 이 주제에 대해 좀 더 자세히 알려주실 수 있을까요?
특히 다음 사항들에 대해 궁금합니다:
1. 계엄령 선포 가능성에 대한 구체적인 근거가 있나요?
2. 이 소문이 현재 시장에 어떤 영향을 미치고 있나요?
3. 계엄령이 실제로 선포된다면, 어떤 섹터가 가장 큰 영향을 받을 것으로 예상하시나요?
이러한 정보를 바탕으로, 저희가 투자자들에게 어떤 조언을 제공할 수 있을지 함께 논의해 보고 싶습니다.
AI: 김재현 애널리스트님, 안녕하세요. 귀하의 질문에 대해 제공된 정보를 바탕으로 답변 드리겠습니다.
1. 계엄령 선포 가능성에 대한 구체적인 근거:
실제로 윤석열 대통령은 2024년 12월 3일 밤 10시 23분에 비상계엄을 선포했습니다 [1]. 이는 대국민 담화를 통해 이루어졌으며, 다음날인 4일 새벽에 해제되었습니다 [1].
2. 시장에 미친 영향:
계엄령 선포는 금융 시장에 즉각적인 영향을 미쳤습니다. 예를 들어, 한 ETF는 비상계엄 선포 후 2시간 30분 만에 계엄 해제 요구안이 가결되면서 손실폭이 일부 회복되어 전날 대비 1.59% 하락한 55.81달러에 장을 마감했습니다 [1]. 또한, 비트코인 가격도 급격히 하락하여 1억 3156만원에서 8800만원까지 떨어졌습니다 [1].
3. 가장 큰 영향을 받을 것으로 예상되는 섹터:
구체적인 섹터별 영향에 대한 정보는 제공된 자료에 명시되어 있지 않습니다. 그러나 일반적으로 정치적 불안정은 금융시장, 소비 심리, 외국인 투자, 수출 산업 등 여러 측면에서 경제적 충격을 초래할 수 있습니다 [3].
투자자들에게 제공할 수 있는 조언:
1. 단기적 변동성 증가에 대비: 정치적 불안정으로 인해 시장의 단기적 변동성이 증가할 수 있으므로, 투자자들은 리스크 관리에 더욱 주의를 기울여야 합니다.
2. 외국인 투자 동향 모니터링: 이번 사태로 인해 한국 경제에 대한 신뢰도가 하락하여 외국인 직접 투자(FDI)가 감소할 가능성이 있습니다 [3]. 따라서 외국인 투자자들의 움직임을 주시해야 합니다.
3. 장기적 관점 유지: 2024년 계엄령 사태는 한국 경제에 단기적인 충격을 가져왔지만, 정치적 안정성과 경제적 신뢰의 상관관계를 재확인시켰습니다 [3]. 따라서 투자자들은 단기적 변동에 과도하게 반응하기보다는 장기적인 관점을 유지하는 것이 중요할 수 있습니다.
4. 섹터별 영향 분석: 각 섹터별로 계엄령 사태의 영향을 분석하여, 상대적으로 영향이 적거나 빠른 회복이 예상되는 섹터에 주목할 필요가 있습니다.
이러한 조언들은 현재 상황에 대한 제한된 정보를 바탕으로 한 것이며, 실제 투자 결정은 더 많은 요인들을 고려해야 함을 유의해야 합니다.
[1] https://contents.premium.naver.com/finup/moneysurferplus/contents/241204180103115tk?from=news_arp_global
[2] https://rochanpapa.tistory.com/35
[3] https://umpapa5.bk2080.com/entry/윤석열-대통령의-계엄령-사태가-한국-경제에-미친-영향과-전망
==================================================
==================================================
🔄 Node: write_section 🔄
- - - - - - - - - - - - - - - - - - - - - - - - -
## 2024년 12월 윤석열 대통령의 비상계엄령: 한국 경제와 금융시장에 미친 충격파
### 요약
2024년 12월 3일, 윤석열 대통령의 갑작스러운 비상계엄령 선포는 한국 경제와 금융시장에 상당한 충격을 주었습니다. 이 사건은 정치적 불안정성을 야기하며 국내외 투자자들의 신뢰를 크게 흔들었습니다. 비록 계엄령이 불과 몇 시간 만에 해제되었지만, 그 여파는 주식시장, 암호화폐 시장, 그리고 외국인 투자 동향에 즉각적인 영향을 미쳤습니다 [1][2].
주요 영향:
1. 주식시장: 관련 ETF들이 급격한 하락을 경험했으며, 일부는 1.59% 하락으로 장을 마감했습니다 [1].
2. 암호화폐 시장: 비트코인 가격이 급락하여 한때 8800만원까지 하락했습니다 [1].
3. 외국인 직접투자(FDI): 한국 경제에 대한 신뢰도 하락으로 FDI 감소 우려가 제기되었습니다 [3].
이 사건은 정치적 안정성과 경제적 신뢰 사이의 밀접한 관계를 재확인시켰으며, 단기적인 경제 충격을 넘어 장기적인 경제 전망에도 영향을 미칠 것으로 예상됩니다 [2][3].
### 종합 분석
#### 비상계엄령 선포의 배경과 과정
윤석열 대통령의 비상계엄령 선포는 장기간에 걸친 계획의 결과로 보입니다. 검찰 수사에 따르면, 윤 대통령은 2024년 3월부터 '비상대권'에 대해 언급하기 시작했으며, 점진적으로 이를 구체화했습니다 [4].
주요 시점:
- 2024년 3월~4월: 윤 대통령, 고위 관리들과 첫 비상대권 논의
- 5월~6월: 비상조치의 필요성 재차 언급
- 8월: 특정 정치인과 단체에 대한 조치 언급
- 10월 1일: 국군의 날, 주요 사령관들과 비상대권 논의
- 11월: 비상계엄의 실질적 준비 시작
- 12월 1일: 비상계엄 선포 이틀 전, 병력 동원 방안 논의
- 12월 3일 밤 10시 23분: 비상계엄령 공식 선포 [4][5]
#### 경제적 영향 분석
1. 금융시장 반응
- 주식시장: 관련 ETF들이 급격한 하락을 보였으며, 일부는 1.59% 하락으로 장을 마감했습니다 [1].
- 암호화폐 시장: 비트코인 가격이 1억3156만원에서 8800만원까지 급락했습니다 [1].
2. 외국인 투자 동향
- 한국 경제에 대한 신뢰도 하락으로 외국인 직접투자(FDI) 감소 우려가 제기되었습니다 [3].
- 정치적 불안정성이 투자 환경 악화로 이어질 가능성이 높아졌습니다 [3].
3. 소비 심리 위축
- 정치적 불안정성으로 인한 소비자 신뢰도 하락이 예상됩니다 [2].
- 이는 내수 시장 침체로 이어질 수 있어 경제 전반에 부정적 영향을 미칠 수 있습니다.
4. 수출 산업 영향
- 정치적 불안정성이 한국 제품에 대한 해외 바이어들의 신뢰도에 영향을 미칠 수 있습니다 [3].
- 장기적으로 수출 실적 하락으로 이어질 가능성이 있습니다.
#### 기술 섹터에 미친 영향
1. IT 기업 주가 변동
- 한국의 주요 IT 기업들의 주가가 급격히 하락했을 것으로 추정됩니다.
- 삼성전자, SK하이닉스 등 반도체 기업들의 주가 변동이 특히 주목됩니다.
2. 기술 투자 환경 변화
- 정치적 불안정성으로 인해 해외 투자자들의 한국 기술 기업에 대한 투자 심리가 위축될 수 있습니다.
- 스타트업 생태계에도 부정적 영향을 미칠 가능성이 높습니다.
3. 기술 수출 전망
- 한국의 주요 수출품목인 반도체, 디스플레이 등 첨단 기술 제품의 수출에 불확실성이 증가했습니다.
- 글로벌 공급망에서 한국 기업들의 위치가 약화될 수 있는 리스크가 발생했습니다.
#### 단기 투자 전략에 대한 시사점
1. 변동성 증가에 대한 대비
- 주식시장의 변동성이 크게 증가할 것으로 예상되므로, 철저한 리스크 관리가 필요합니다.
- 손절매 규칙을 엄격히 적용하고, 포지션 사이징에 더욱 신중을 기해야 합니다.
2. 안전자산으로의 이동
- 정치적 불안정성이 지속될 경우, 안전자산으로의 자금 이동이 예상됩니다.
- 국채, 금 등 전통적인 안전자산에 대한 관심이 높아질 수 있습니다.
3. 기술주 모니터링
- IT 섹터의 주요 기업들의 주가 변동을 면밀히 관찰해야 합니다.
- 과도한 하락 시 저점 매수 기회를 노릴 수 있으나, 신중한 접근이 필요합니다.
4. 글로벌 시장과의 연관성 주시
- 한국 시장의 불안정성이 글로벌 시장에 미치는 영향을 주시해야 합니다.
- 특히 아시아 시장과의 연관성에 주목할 필요가 있습니다.
### 출처
[1] https://contents.premium.naver.com/finup/moneysurferplus/contents/241204180103115tk?from=news_arp_global
[2] https://rochanpapa.tistory.com/35
[3] https://umpapa5.bk2080.com/entry/윤석열-대통령의-계엄령-사태가-한국-경제에-미친-영향과-전망
[4] https://www.youtube.com/watch?v=2xpSTs7hI7I&pp=ygU_7Jyk7ISd7Je0IDEy7JuUIDPsnbwg6rOE7JeE66C56rO8IOyjvOyLneyLnOyepSDrr7jsuZjripQg7JiB7Zal
[5] https://www.youtube.com/watch?v=3xKShNogN2I&pp=ygU_7Jyk7ISd7Je0IDEy7JuUIDPsnbwg6rOE7JeE66C56rO8IOyjvOyLneyLnOyepSDrr7jsuZjripQg7JiB7Zal
==================================================
결과를 보니 만족스러웠다.. 거의 perplexity 급의 퀄리티가 아니겠나.. 근데 사실 보고서가 LLM 쓰면 뻔한 형식으로 나오는것 같아 아쉬웠는데 테디님의 예제에 서론, 결론 인터뷰를 병렬로 처리를 해서 최종 보고서를 작성하는 부분이 있었다. 역시 Goat!
인터뷰를 병렬로 진행
- 인터뷰는 langgraph 의 Send() 함수를 사용하여 병렬화하며, 이는 map 단계에 해당합니다.
- 인터뷰 결과는 reduce 단계에서 보고서 본문에 통합됩니다.
- 최종 보고서에 서론과 결론을 작성하는 마지막 단계를 추가합니다.
import operator
from typing import List, Annotated
from typing_extensions import TypedDict
# ResearchGraphState 상태 정의
class ResearchGraphState(TypedDict):
# 연구 주제
topic: str
# 생성할 분석가의 최대 수
max_analysts: int
# 인간 분석가의 피드백
human_analyst_feedback: str
# 질문을 하는 분석가 목록
analysts: List[KDBAnalyst]
# Send() API 키를 포함하는 섹션 리스트
sections: Annotated[list, operator.add]
# 최종 보고서의 서론
introduction: str
# 최종 보고서의 본문 내용
content: str
# 최종 보고서의 결론
conclusion: str
# 최종 보고서
final_report: str
다시 리서치 그래프스테이트를 만들고 최종보고서의 서론, 본론, 결론으로 나누고 최종보고서 도 추가해줍니다. 결국 각각의 Context를 모아서 서론 / 본론 / 결론 작성하고 합치는 로직을 위한 그래프입니다.
from langgraph.constants import Send
# 모든 인터뷰를 시작
def initiate_all_interviews(state: ResearchGraphState):
# 사람의 피드백 확인
human_analyst_feedback = state.get("human_analyst_feedback")
# 만약, 사람의 피드백이 있으면 분석가 생성으로 돌아가기
if human_analyst_feedback:
return "create_analysts"
# 그렇지 않으면 Send() 함수를 통해 인터뷰 병렬로 시작
else:
topic = state["topic"]
return [
Send(
"conduct_interview",
{
"analyst": analyst,
"messages": [
HumanMessage(
content=f"So you said you were writing an article on {topic}?"
)
],
},
)
for analyst in state["analysts"]
]
병렬로 처리하기 위한, 로직입니다. 나중에 비동기로 처리하면 더 빠른? 답변을 받을 수 있을것같습니다.
# 보고서 작성 지시사항
report_writer_instructions = """당신은 다음 주제에 대한 투자 보고서를 작성하는 애널리스트입니다:
{topic}
여러 분석가들이 각각 다음과 같은 작업을 수행했습니다:
1. 해당 분야 전문가와의 인터뷰 진행
2. 분석 내용을 메모로 정리
당신의 임무:
1. 각 분석가들의 메모를 검토합니다.
2. 각 메모의 핵심 내용을 면밀히 분석합니다.
3. 모든 메모의 핵심 아이디어를 통합하여 종합적인 요약을 작성합니다.
4. 각 메모의 주요 포인트를 아래 섹션에 맞게 논리적으로 구성합니다.
5. 모든 필수 섹션을 `### 섹션명` 형식의 헤더로 포함시킵니다.
6. 각 섹션당 약 250자 내외로 심도있는 설명과 근거를 제시합니다.
**보고서 섹션 구성:**
- **시장 환경**: 거시경제 상황, 업종 동향, 핵심 이슈 등 기본적인 배경 설명
- **산업 분석**: 해당 산업의 현황과 전망, 경쟁구도 분석
- **기업 분석**: 대상 기업의 사업구조, 경쟁력, 재무상태 등 분석
- **투자 포인트**: 주요 투자 매력도와 성장 동력 제시
- **리스크 요인**: 주가에 부정적 영향을 미칠 수 있는 위험 요소 분석
- **실적 전망**: 향후 실적 추정과 그 근거 제시
- **투자의견**: 투자등급과 목표주가 제시 및 근거 설명
보고서 형식:
1. 마크다운 형식 사용
2. 서두 없이 바로 본문 시작
3. 소제목 사용하지 않음
4. 보고서는 ## 투자 분석 헤더로 시작
5. 분석가 이름 언급하지 않음
6. 메모의 인용 출처는 [1], [2] 등으로 표시
7. 마지막에 ## 참고자료 섹션에 출처 목록 정리
8. 출처는 순서대로 나열하고 중복 제거
[1] 출처 1
[2] 출처 2
아래는 분석가들의 메모입니다:
{context}"""
# 보고서 작성 함수 정의
def write_report(state: ResearchGraphState):
# 모든 섹션 가져오기
sections = state["sections"]
topic = state["topic"]
# 모든 섹션을 하나의 문자열로 연결
formatted_str_sections = "\n\n".join([f"{section}" for section in sections])
# 섹션을 요약하여 최종 보고서 작성
system_message = report_writer_instructions.format(
topic=topic, context=formatted_str_sections
)
report = llm.invoke(
[SystemMessage(content=system_message)]
+ [HumanMessage(content=f"이 메모들을 바탕으로 보고서를 작성해주세요.")]
)
return {"content": report.content}
# 서론과 결론 작성 지시사항
intro_conclusion_instructions = """당신은 {topic}에 대한 투자 보고서를 마무리하는 애널리스트입니다.
보고서의 모든 섹션이 주어질 것입니다.
당신의 임무는 간결하고 설득력 있는 서론 또는 결론을 작성하는 것입니다.
사용자가 서론 또는 결론 중 어느 것을 작성할지 지시할 것입니다.
불필요한 서두는 생략합니다.
약 200자 내외로, 서론의 경우 보고서의 모든 섹션을 미리보기하고, 결론의 경우 핵심 내용을 요약합니다.
마크다운 형식을 사용합니다.
서론의 경우 매력적인 제목을 만들고 # 헤더를 사용합니다.
서론은 ## 개요 헤더를 사용합니다.
결론은 ## 결론 헤더를 사용합니다.
참고할 섹션들은 다음과 같습니다: {formatted_str_sections}"""
# 서론 작성 함수 정의
def write_introduction(state: ResearchGraphState):
# 모든 섹션 가져오기
sections = state["sections"]
topic = state["topic"]
# 모든 섹션을 하나의 문자열로 연결
formatted_str_sections = "\n\n".join([f"{section}" for section in sections])
# 섹션을 요약하여 서론 작성
instructions = intro_conclusion_instructions.format(
topic=topic, formatted_str_sections=formatted_str_sections
)
intro = llm.invoke(
[instructions] + [HumanMessage(content=f"보고서의 서론을 작성해주세요")]
)
return {"introduction": intro.content}
# 결론 작성 함수 정의
def write_conclusion(state: ResearchGraphState):
# 모든 섹션 가져오기
sections = state["sections"]
topic = state["topic"]
# 모든 섹션을 하나의 문자열로 연결
formatted_str_sections = "\n\n".join([f"{section}" for section in sections])
# 섹션을 요약하여 결론 작성
instructions = intro_conclusion_instructions.format(
topic=topic, formatted_str_sections=formatted_str_sections
)
conclusion = llm.invoke(
[instructions] + [HumanMessage(content=f"보고서의 결론을 작성해주세요")]
)
return {"conclusion": conclusion.content}
# 최종 보고서 작성 함수 정의
def finalize_report(state: ResearchGraphState):
# 모든 섹션을 모아 최종 보고서 작성
content = state["content"]
if content.startswith("## 투자 분석"):
content = content.strip("## 투자 분석")
if "## 참고자료" in content:
try:
content, sources = content.split("\n## 참고자료\n")
except:
sources = None
else:
sources = None
final_report = (
state["introduction"]
+ "\n\n---\n\n## 핵심 투자포인트\n\n"
+ content
+ "\n\n---\n\n"
+ state["conclusion"]
)
if sources is not None:
final_report += "\n\n## 참고자료\n" + sources
return {"final_report": final_report}
밑에 파이널 로직을 보면 state 들을 파싱해서 놓는 모습이다. 어떻게 정의를 하냐에 따라 사용자가 원하는 커스텀이 충분히 가능해보인다. 프롬프트에 헤더를 통해서 구분처리를 하고 final_response 에서 그에 따른 처리를 하였다. (참 신기하다 이런거 만드는 사람) 큰 그림을 봐야하는 건가 역시..
==================================================
🔄 Node: finalize_report 🔄
- - - - - - - - - - - - - - - - - - - - - - - - -
final_report:
# 윤석열 대통령의 비상계엄령: 정치적 불확실성이 한국 금융시장에 미친 충격파
## 개요
2024년 12월 3일, 윤석열 대통령의 갑작스러운 비상계엄령 선포는 한국의 정치와 경제 전반에 걸쳐 큰 파장을 일으켰습니다. 이 전례 없는 사건은 금융시장에 즉각적이고 광범위한 영향을 미쳤으며, 국내외 투자자들의 신뢰를 크게 흔들어 놓았습니다.
본 보고서는 이 사건이 한국 금융시장에 미친 단기적 충격과 장기적 함의를 종합적으로 분석합니다. 주식시장의 급락, 원화 가치 하락, 외국인 투자 심리 악화 등 다양한 측면에서 나타난 영향을 살펴보고, 향후 시장 안정화와 투자자 신뢰 회복을 위한 과제를 제시합니다.
이 사건은 정치적 안정성과 경제적 성과 간의 밀접한 관계를 재확인시켰으며, 투자자들에게 정치적 리스크를 포트폴리오 관리의 핵심 요소로 고려해야 함을 상기시켰습니다. 본 분석을 통해 투자자와 정책 입안자들이 향후 유사한 상황에 대비하고 대응할 수 있는 통찰을 제공하고자 합니다.
---
## 핵심 투자포인트
### 시장 환경
2024년 12월 3일 윤석열 대통령의 갑작스러운 비상계엄령 선포는 한국 금융시장에 즉각적이고 광범위한 충격을 주었습니다. 이 전례 없는 정치적 사건으로 인해 주식시장이 급락하고 원화 가치가 하락하는 등 전반적인 시장 불안정성이 크게 증가했습니다. 계엄령은 불과 6시간 만에 해제되었지만, 그 여파는 한국 경제 전반에 걸쳐 지속되었습니다. 이 사건은 정치적 안정성과 경제적 성과 간의 밀접한 관계를 재확인시켰으며, 투자자들에게 정치적 리스크를 포트폴리오 관리의 중요한 요소로 고려해야 함을 상기시켰습니다.
### 산업 분석
금융 산업은 이번 사태로 인해 가장 큰 영향을 받았습니다. 주식시장에서 KOSPI 지수가 1.97% 하락하는 등 급격한 변동이 있었고, 외환시장에서는 원화 가치가 급락했습니다. 암호화폐 시장 역시 큰 충격을 받아 비트코인 가격이 1억3156만원에서 8800만원까지 하락했습니다. 이는 암호화폐 시장이 전통적인 금융 시장과의 연계성이 높아졌음을 시사합니다.
수출 중심 산업들도 간접적인 영향을 받았습니다. 정치적 불안정성으로 인한 국제 무역 파트너들의 신뢰 하락은 장기적으로 수출에 부정적인 영향을 미칠 수 있습니다.
### 기업 분석
개별 기업에 대한 구체적인 분석은 제공된 정보에 포함되어 있지 않지만, 전반적으로 대부분의 기업들이 이번 사태로 인해 부정적인 영향을 받았을 것으로 예상됩니다. 특히 정치적 불확실성에 민감한 금융, 건설, 방위 관련 기업들의 주가 변동성이 크게 증가했을 것입니다.
### 투자 포인트
1. 변동성 관리: 단기 투자자와 스윙 트레이더들은 VIX 지수 등 변동성 지표를 활용한 리스크 관리가 중요해졌습니다.
2. 섹터 로테이션: 정치적 불안정 시기에는 방어적 섹터(예: 유틸리티, 필수소비재)로의 자금 이동이 예상됩니다.
3. 글로벌 분산 투자: 국내 정치 리스크를 완화하기 위해 해외 자산에 대한 투자 비중을 검토할 필요가 있습니다.
4. 환율 리스크 관리: 원화 가치 변동에 대비한 환헤지 전략 수립이 필요합니다.
### 리스크 요인
1. 정치적 불안정 지속: 계엄령 해제 이후에도 정치적 갈등이 지속될 경우 시장 불안정성이 장기화될 수 있습니다.
2. 외국인 투자 이탈: 한국 자산에 대한 신뢰도 하락으로 인한 대규모 자본 유출 가능성이 있습니다.
3. 국가 신용등급 하락: 정치적 불안정으로 인한 국가 신용등급 하향 조정 가능성이 있으며, 이는 추가적인 경제적 악영향을 초래할 수 있습니다.
4. 소비 심리 위축: 정치적 불안정과 경제적 불확실성으로 인한 내수 시장 침체 가능성이 있습니다.
### 실적 전망
구체적인 기업별 실적 전망은 제공된 정보에 포함되어 있지 않지만, 전반적으로 단기적인 실적 악화가 예상됩니다. 특히 수출 중심 기업들의 경우 국제 무역 파트너들의 신뢰 하락으로 인한 부정적 영향이 있을 수 있습니다. 그러나 정부와 금융당국의 시장 안정화 조치에 따라 중장기적으로는 점진적인 회복이 가능할 것으로 보입니다.
### 투자의견
현재의 정치적 불안정성과 시장 변동성을 고려할 때, 단기적으로는 신중한 접근이 필요합니다. 방어적 섹터와 안전자산에 대한 비중을 높이고, 글로벌 분산 투자를 통해 리스크를 관리하는 것이 바람직합니다. 중장기적으로는 정치적 안정성이 회복되고 시장이 정상화될 것으로 예상되므로, 현재의 시장 조정을 매수 기회로 활용할 수 있습니다. 그러나 개별 기업의 펀더멘털과 정치적 리스크에 대한 노출도를 면밀히 분석한 후 투자 결정을 내려야 할 것입니다.
---
## 결론
윤석열 대통령의 2024년 12월 3일 비상계엄령 선포는 한국 금융시장과 경제 전반에 심각한 충격을 주었습니다. 이 사건은 정치적 안정성과 경제적 성과 간의 밀접한 관계를 재확인시켰으며, 다음과 같은 중요한 교훈과 과제를 남겼습니다:
1. 정치적 리스크 관리의 중요성: 투자자들은 정치적 불확실성을 포트폴리오 관리의 핵심 요소로 고려해야 함이 분명해졌습니다.
2. 시장 안정화 메커니즘의 필요성: 정부와 금융 당국은 이러한 급격한 정치적 충격에 대응할 수 있는 효과적인 시장 안정화 메커니즘을 개발하고 강화해야 합니다.
3. 국제 신뢰도 회복의 시급성: 한국의 국제적 위상과 경제적 신뢰도 회복을 위한 장기적이고 일관된 노력이 필요합니다.
4. 제도적 안전장치 강화: 이러한 사태의 재발을 방지하기 위한 법적, 제도적 장치의 보완이 요구됩니다.
5. 경제 회복력 제고: 외부 충격에 대한 경제의 회복력을 높이기 위한 구조적 개혁과 다각화 전략이 필요합니다.
이번 사태는 한국 경제의 취약점을 드러냈지만, 동시에 개선의 기회를 제공했습니다. 향후 정부, 기업, 투자자들은 이러한 교훈을 바탕으로 더욱 안정적이고 회복력 있는 경제 시스템을 구축하기 위해 협력해야 할 것입니다. 정치적 안정성, 제도적 신뢰, 그리고 경제적 건전성의 균형을 이루는 것이 한국 경제의 장기적 성장과 번영을 위한 핵심 과제가 될 것입니다.
## 참고자료
[1] https://m.blog.naver.com/electricitylove/223681914182
[2] https://zi02.tistory.com/entry/2024년-12월-3일-계엄령-사건-상세-분석-타임라인
[3] https://sstock.tistory.com/entry/금투세와-계엄령이-주식시장에-미친-영향-시장-불안정성-분석
[4] https://www.youtube.com/watch?v=3xKShNogN2I
[5] https://contents.premium.naver.com/finup/moneysurferplus/contents/241204180103115tk?from=news_arp_global
[6] https://umpapa5.bk2080.com/entry/윤석열-대통령의-계엄령-사태가-한국-경제에-미친-영향과-전망
2탄으로는 여기에 적절한 사진을 붙히는 멀티모달 로직을 적용해볼 생각이다. 각 단락별 내용을 읽고 이미지를 생성하거나? 링크에서 이미지를 가져와서 그 내용을 텍스트로 변환후 보고서 내용에 태깅을 하고 태깅에 적절히 들어갈만한 사진의 내용을 맵핑 한 후에 뒷 코드단에서 처리하면 될것같다는 생각이든다.
'NLP' 카테고리의 다른 글
[Agent Study]RAG 성능을 올리기 위한 Context Retrieval 을 적용 (0) | 2025.01.12 |
---|---|
[가짜연구소] 금융에이전트 Stockelper 개발과정 깃잔심 5기 회고 (0) | 2025.01.05 |
[Agent Study] 에이전트를 활용하여 멀티 DB 연결 구축하기 (1) | 2024.12.20 |
[Agent Study] Multi-Agent , Multi-tool 만들기 - (1) : Custom Tool 만들기 (0) | 2024.12.18 |
AWS Nova를 SuperNova 로 전환하기 (feat. LangGraph 멀티툴 에이전트) (0) | 2024.12.06 |