Skip to content

TaskerJang/Market-Analysis-Agent

Repository files navigation

Market Analysis Agent

ν”„λ‘œμ νŠΈ κ°œμš”

금육 μ‹œμž₯ 뢄석을 μœ„ν•œ AI μ—μ΄μ „νŠΈ μ‹œμŠ€ν…œμœΌλ‘œ, LangGraphλ₯Ό ν™œμš©ν•œ λ©€ν‹° μ—μ΄μ „νŠΈ μ•„ν‚€ν…μ²˜λ₯Ό κ΅¬ν˜„ν•©λ‹ˆλ‹€.

ν”„λ‘œμ νŠΈ ꡬ쑰

+------------------+     +------------------+     +------------------+
|                  |     |                  |     |                  |
|  Client Request  +---->+  FastAPI Server  +---->+  SupervisorNode  |
|                  |     |                  |     |                  |
+------------------+     +------------------+     +--------+---------+
                                                           |
                                                           |
                                                           v
                         +---------------------------+-----+-----+---------------------------+
                         |                           |           |                           |
                         v                           v           v                           v
              +----------+-----------+    +----------+----+    +-+------------+    +---------+-----------+
              |                      |    |               |    |              |    |                     |
              | NaverNewsSearcherNode|    | Future Node 1 |    | Future Node 2|    | ReportAssistantNode |
              |                      |    |               |    |              |    |                     |
              +----------------------+    +---------------+    +--------------+    +---------------------+

                                    LangGraph Multi-Agent Architecture 

μ‹œμž‘ν•˜κΈ°

μ˜μ‘΄μ„± 관리λ₯Ό μœ„ν•΄ κ°€λŠ₯ν•˜λ©΄ uvλ₯Ό μ‚¬μš©ν•˜κΈ°λ₯Ό ꢌμž₯ν•©λ‹ˆλ‹€.

using uv(recommended)

  • how to install uv
pip install uv 
# or
curl -LsSf https://astral.sh/uv/install.sh | sh
  • run market-analysis
git clone https://github.com/FinAgent-Lab/market-analysis-team

cd market-analysis-team

uv sync

uv run main.py

using pip

git clone https://github.com/FinAgent-Lab/market-analysis-team

cd market-analysis-team

python -m venv .venv

source .venv/bin/activate

pip install -r requirements.txt

python main.py

μ½”λ“œ μŠ€νƒ€μΌ 체크

μ½”λ“œλ₯Ό 일관성 있게 μœ μ§€ν•˜κΈ° μœ„ν•΄ ruff 도ꡬλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. 이 λ„κ΅¬λŠ” λ§Žμ€ μ˜€ν”ˆμ†ŒμŠ€ ν”„λ‘œμ νŠΈμ—μ„œ ν‘œμ€€μ— κ°€κΉκ²Œ μ‚¬μš©λ˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 이 도ꡬλ₯Ό μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” pipλ₯Ό μ΄μš©ν•΄μ„œ μ„€μΉ˜ν•΄λ„ 되고 uv 도ꡬλ₯Ό μ‚¬μš©ν•΄λ„ λ©λ‹ˆλ‹€.

μ—¬κΈ°μ„œλŠ” uv 도ꡬ인 uvxλ₯Ό μ‚¬μš©ν•˜λŠ” 방법을 μ„€λͺ…ν•©λ‹ˆλ‹€.

$ uvx ruff check --fix
$ uvx ruff format

μ—μ΄μ „νŠΈ μΆ”κ°€ 및 μ‚¬μš©μž μΈν„°νŽ˜μ΄μŠ€ 연동

μ—μ΄μ „νŠΈ κ°œλ°œν•˜λ©° μ—μ΄μ „νŠΈμ˜ λ™μž‘μ„±μ„ μˆ˜μ›”ν•˜κ²Œ ν™•μΈν•˜κ³ μž ν•˜μ˜€μŠ΅λ‹ˆλ‹€. 이λ₯Ό μœ„ν•΄ λ³Έ ν”„λ‘œμ νŠΈλŠ” UI λ˜λŠ” APIλ₯Ό ν™œμš©ν•©λ‹ˆλ‹€.

μ—μ΄μ „νŠΈ λ…Έλ“œλ₯Ό μΆ”κ°€ν•˜λŠ” 법

κ΅¬ν˜„μ²΄λŠ” 좔상 클래슀 Nodeλ₯Ό μ‹€μ²΄ν™”ν•˜μ—¬ μž‘μ„±ν•©λ‹ˆλ‹€. 좔상 클래슀 Node의 μ£Όμš” ν•¨μˆ˜λŠ” __call__, _run, _invoke, invoke이며, 개발 μ‹œμ—λŠ” _run ν•¨μˆ˜μ™€ _invoke ν•¨μˆ˜(선택사항)λ₯Ό μž‘μ„±ν•©λ‹ˆλ‹€. _run ν•¨μˆ˜λŠ” SupervisorNode와 연결을 μœ„ν•œ ν•¨μˆ˜μž…λ‹ˆλ‹€. _invoke ν•¨μˆ˜λŠ” API μ„œλ²„λ₯Ό 톡해 λ³„λ„μ˜ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ°–κ³  μ‹Άλ‹€λ©΄ κ΅¬ν˜„ν•©λ‹ˆλ‹€. 클래슀 κ΄€κ³„λ„λŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€. 좔상화-싀체화

  1. src/graph/nodes/κ²½λ‘œμ— μ—μ΄μ „νŠΈ μ½”λ“œλ₯Ό μž‘μ„±ν•©λ‹ˆλ‹€.
  2. μ½”λ“œλŠ” λ‹€μŒκ³Ό 같이 μž‘μ„±ν•©λ‹ˆλ‹€.
class NaverNewsSearcherNode(Node):
    def __init__(self):
        super().__init__()
        # μ—μ΄μ „νŠΈμ—κ²Œ 역할을 λΆ€μ—¬ν•˜κΈ° μœ„ν•œ ν”„λ‘¬ν”„νŠΈμž…λ‹ˆλ‹€.
        # κ²½μš°μ— λ”°λΌμ„œλŠ” ν•„μš”μ—†μ„ 수 μžˆμŠ΅λ‹ˆλ‹€.
        self.system_prompt = (
            "You are a news search agent for korean news using naver search api."
            "Only use korean source and data to conduct news search."
            "Do nothing else"
        )
        self.agent = None
        self.tools = [NaverNewsSearch(sort="date")]


    # Supervisor λ…Έλ“œμ—μ„œ ν˜ΈμΆœν–ˆμ„ μ‹œμ˜ λ‘œμ§μ„ κ΅¬ν˜„ν•˜λŠ” ν•¨μˆ˜. μ‹€μ œλ‘œλŠ” base node의 runν•¨μˆ˜μ—μ„œ 이 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•©λ‹ˆλ‹€.
    def _run(self, state: dict) -> dict:

        # region [μ—μ΄μ „νŠΈ λ™μž‘ 둜직 κ΅¬ν˜„]
        # -----------------------------------------------------------------------
        if self.agent is None:
            assert state["llm"] is not None, "The State model should include llm"
            llm = state["llm"]
            self.agent = create_react_agent(
                llm,
                self.tools,
                prompt=self.system_prompt,
            )
        result = self.agent.invoke(state)
        # ----------------------------------------------------------------------
        # endregion [μ—μ΄μ „νŠΈ λ™μž‘ 둜직 κ΅¬ν˜„ 끝]
        self.logger.info(f"   result: \n{result['messages'][-1].content}")
        # 이 뢀뢄은 동일할 κ²ƒμœΌλ‘œ μ˜ˆμƒν•©λ‹ˆλ‹€. 
        return Command(
            update={
                "messages": [
                    HumanMessage(
                        content=result["messages"][-1].content,
                        name="naver_news_searcher",
                    )
                ]
            },
            goto="supervisor",
        )

    # _run ν•¨μˆ˜μ™€ μœ μ‚¬ν•˜λ‚˜, apiλ₯Ό 톡해 λ™μž‘μ„ ν™•μΈν•˜κΈ° μœ„ν•œ ν•¨μˆ˜. supervisorμ™€λŠ” 상관 μ—†μŠ΅λ‹ˆλ‹€. 
    # 이 뢀뢄은 base node의 invokeν•¨μˆ˜μ—μ„œ ν˜ΈμΆœν•©λ‹ˆλ‹€.
    # api μ„œλ²„μ— λ…ΈμΆœν•˜κΈ° μœ„ν•΄ λ³„λ„μ˜ ν•¨μˆ˜λ‘œ λΆ„λ¦¬ν•˜μ˜€μœΌλ©°, μ—”λ“œν¬μΈνŠΈ κ²½λ‘œλŠ” μ†Œλ¬Έμž 및 Nodeλ₯Ό μ œκ±°ν•œ ν˜•νƒœμž…λ‹ˆλ‹€.
    # - μ˜ˆμ‹œ : SampleNode 클래슀둜 μ½”λ“œλ₯Ό μž‘μ„± μ‹œ, μ—”λ“œν¬μΈνŠΈλŠ” /api/sample μž…λ‹ˆλ‹€. 
    # OpenWebUI에 μ—°λ™ν•˜κΈ° μ›ν•œλ‹€λ©΄ RawResponse λͺ¨λΈλ‘œ 리턴할 수 μžˆλ„λ‘ μž‘μ„±ν•©λ‹ˆλ‹€. 
    def _invoke(self, query: str) -> RawResponse:
        agent = self.agent or create_react_agent(
            ChatOpenAI(model=self.DEFAULT_LLM_MODEL),
            self.tools,
            prompt=self.system_prompt,
        )
        result = agent.invoke({"messages": [("human", query)]})
        return RawResponse(answer=result["messages"][-1].content)

main.py νŒŒμΌμ—μ„œ λΉŒλ”λ₯Ό μ΄μš©ν•˜μ—¬ λ‹€μŒκ³Ό 같이 λ…Έλ“œλ₯Ό μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

graph_builder.add_node(NaverNewsSearcherNode())

μ—μ΄μ „νŠΈ μΆ”κ°€ ν›„ API 연동

API μ„œλ²„μ˜ κΈ°λ³Έ ν¬νŠΈλŠ” 8000번이며, μ„œλ²„ 호슀트의 /docs경둜λ₯Ό 톡해 λͺ…μ„Έλ₯Ό 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

  • 예: http://localhost:8000/docs

API ν™”λ©΄

OpenWebUI에 μΆ”κ°€ν•˜λŠ” 법

OpenWebUI에 μΆ”κ°€ν•˜κΈ° μœ„ν•΄μ„œλŠ” pipeline μ½”λ“œ μž‘μ„±μ΄ ν•„μš”ν•©λ‹ˆλ‹€. μ˜ˆμ‹œ μ½”λ“œλŠ” pipelines/agent_pipeline_example.pyλ₯Ό μ°Έκ³ ν•©λ‹ˆλ‹€. pipeline μ½”λ“œλ₯Ό μž‘μ„±ν•œ ν›„, 메인 λΈŒλžœμΉ˜μ— λ³‘ν•©ν•˜λ©΄ 배포 과정에 λ™μ μœΌλ‘œ 톡합이 μ΄λ£¨μ–΄μ§‘λ‹ˆλ‹€.

...
class Pipeline:
    class Valves(BaseModel):
        pass

    def __init__(self):
        # self.name 에 λͺ¨λΈ 이름 μ„€μ •
        self.name = "Market Analysis - Naver News Searcher"
        # self.agent_name은 api μ„œλ²„μ˜ ν•΄λ‹Ή μ—μ΄μ „νŠΈ μ—”λ“œν¬μΈνŠΈ μ΄λ¦„μœΌλ‘œ μž‘μ„±
        self.agent_name = "navernewssearcher"
        ...

OpenWebUI에 접속해보면 λ‹€μŒκ³Ό 같이 μΆ”κ°€λ˜μ–΄μžˆμŒμ„ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

OpenWebUI연동

파일ꡬ쑰

/
β”œβ”€β”€ .env                        # κ°œμΈλ³„ API Keyλ“± ν™˜κ²½λ³€μˆ˜ μ„€μ •
β”œβ”€β”€ .env.tamplate               # ν™˜κ²½λ³€μˆ˜ ν…œν”Œλ¦Ώ
β”œβ”€β”€ requirements.txt            # ν•„μˆ˜ 라이브러리
β”œβ”€β”€ pyproject.toml              # ν”„λ‘œμ νŠΈ μ„€μ •
β”œβ”€β”€ main.py                     # 전체 μ›Œν¬ν”Œλ‘œμš° μ •μ˜ 및 μ„œλΉ„μŠ€ μ‹œμž‘μ 
β”œβ”€β”€ startup.py                  # μ˜μ‘΄μ„± μ£Όμž… μ»¨ν…Œμ΄λ„ˆ μ„€μ •
β”œβ”€β”€ api/                        # API μ„œλ²„ κ΄€λ ¨ λͺ¨λ“ˆ
β”‚   └── server.py               # FastAPI μ„œλ²„ κ΅¬ν˜„
β”œβ”€β”€ src/                        # μ†ŒμŠ€ μ½”λ“œ
β”‚   β”œβ”€β”€ graph/                  # LangGraph κ΄€λ ¨ λͺ¨λ“ˆ
β”‚   β”‚   β”œβ”€β”€ builder.py          # κ·Έλž˜ν”„ λΉŒλ” 클래슀
β”‚   β”‚   └── nodes/              # κ·Έλž˜ν”„ λ…Έλ“œ λͺ¨λ“ˆ
β”‚   β”‚       β”œβ”€β”€ base.py         # κΈ°λ³Έ λ…Έλ“œ 클래슀
β”‚   β”‚       β”œβ”€β”€ supervisor.py   # μŠˆνΌλ°”μ΄μ € λ…Έλ“œ
β”‚   β”‚       β”œβ”€β”€ naver_news_searcher.py # 넀이버 λ‰΄μŠ€ 검색 λ…Έλ“œ
β”‚   β”‚       β”œβ”€β”€ ...             # 기타 μΆ”κ°€ λ…Έλ“œ
β”‚   β”‚       └── report_assistant.py    # λ³΄κ³ μ„œ μž‘μ„± λ…Έλ“œ
β”‚   β”œβ”€β”€ models/                 # 데이터 λͺ¨λΈ
β”‚   β”‚   └── graph_state.py      # κ·Έλž˜ν”„ μƒνƒœ λͺ¨λΈ
β”‚   β”œβ”€β”€ tools/                  # 도ꡬ λͺ¨λ“ˆ
β”‚   └── utils/                  # μœ ν‹Έλ¦¬ν‹° ν•¨μˆ˜
β”‚       └── logger.py           # λ‘œκΉ… μ„€μ •
β”œβ”€β”€ images/                     # 도컀 이미지 κ΄€λ ¨ 파일
β”‚   └── backend/                
β”‚       └── Dockerfile          # λ°±μ—”λ“œ 도컀 파일
└── tests/                      # ν…ŒμŠ€νŠΈ μ½”λ“œ

License

This project is licensed under the MIT License.

About

πŸ€– Pseudo Lab μ‹œμž₯ 뢄석 μ—μ΄μ „νŠΈ ν”„λ‘œμ νŠΈ

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 6