본문 바로가기
  • think normal
새로워지기/마흔의 생활코딩

LangGraph - 실습 5. Multi-agent Collaboration

by 청춘만화 2024. 5. 29.

LangGraph - 에이전트 유형별 실습

intro
Agent Executor

Chat Executor
Agent Supervisor
Hierarchical Agent Teams
👉  Multi-agent Collaboration

 


[터미널] 환경 변수 및 깃헙 설정 
root 폴더에 환경변수 파일과 깃푸시 배재 파일을 생성한다.

.env 작성
.gitignore 작성

 
[터미널] 가상환경 설정 및 실행
(옵션)가상 환경을 설정하고 실행한다( LangGraph_Agents는 개인적으로 작성한 임의의 이름)

설정 :  python -m venv LangGraph_Agents
실행(mac) :  source LangGraph_Agents/bin/activate

 
환경 변수 로드

from dotenv import load_dotenv
load_dotenv() 

 

 


시작에 앞서 전체적인 구조를 살펴보자

사실상 앞의 예제들의 반복이다. 실습 4번의 그래프가 일종의? 프랙탈(Fractal) 구조와 비슷했다면, 실습 5번은 레고에 가까운 것 같다.
새로운? 부분이 있다면, 상태 정보를 기반으로 다음 단계를 결정하는 라우터 함수가 있는 'Edge Logic'구간이 있다는 것이다. 

 

 

 

 

 

We first define our tools and make some helper functions.

  

Create Agents

from langchain_core.messages import (
    BaseMessage,
    ToolMessage,
    HumanMessage,
)
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langgraph.graph import END, StateGraph

def create_agent(llm, tools, system_message: str):
    """Create an agent."""
    prompt = ChatPromptTemplate.from_messages(
        [
            (
                "system",
                """당신은 다른 어시스턴트들과 협업하는 유용한 AI 어시스턴트입니다. 
                제공된 도구를 사용하여 질문에 대한 답을 찾아가는 과정을 진행합니다.
                완전히 대답할 수 없더라도 괜찮습니다. 
                다른 도구를 사용하는 다른 어시스턴트가 당신의 중단한 부분을 도와줄 것입니다. 
                작업의 지속서을 위해 할 수 있는 부분을 먼저 실행하세요.
                본인 또는 다른 어시스턴트가 최종 답변이나 결과물을 가지고 있는 경우, 
                응답 앞에 'FINAL ANSWER'이라는 말을 붙여 팀의 작업이 정상적으로 중단할 수 있도록 하세요."""
                " 그리고 당신은 다음 도구에 액세스할 수 있습니다:  {tool_names}.\\n{system_message}",
            ),
            MessagesPlaceholder(variable_name="messages"),
        ]
    )
    prompt = prompt.partial(system_message=system_message)
    prompt = prompt.partial(tool_names=", ".join([tool.name for tool in tools]))
    return prompt | llm.bind_tools(tools)

 

Define tools

from langchain_core.tools import tool
from typing import Annotated
from langchain_experimental.utilities import PythonREPL
from langchain_community.tools.tavily_search import TavilySearchResults

tavily_tool = TavilySearchResults(max_results=5)

# 경고: 이것은 로컬에서 코드를 실행하는 것으로, 샌드박스에서 실행되지 않을 때는 안전하지 않을 수 있습니다
repl = PythonREPL()

@tool
def python_repl(
    code: Annotated[str, "파이썬 코드는 차트를 생성을 위해 실행될 코드입니다."]
):
    """이것을 사용하여 파이썬 코드를 실행합니다. 
    만약 네가 결과값을 보기를 원한다면 너는 `print(...)`를 사용하여 출력해야 합니다.
    이것은 사용자에게 표시됩니다 """
    try:
        result = repl.run(code)
    except BaseException as e:
        return f"실행에 실패했습니다. 오류: {repr(e)}"
    result_str = f"성공적으로 실행되었습니다:\\n```python\\n{code}\\n```\\nStdout: {result}"
    return (
        result_str + "\\n\\n모든 작업을 완료했다면 'FINAL ANSWER'를 응답하십시오."
    )

 

 

 

Now, We will create the individual agents below and tell them
how to talk to each other using LangGraph.

Create graph

01 Define State

import operator
from typing import Annotated, Sequence, TypedDict

from langchain_openai import ChatOpenAI
from typing_extensions import TypedDict

# 이 클래스는 그래프 안에 있는 각 노드 사이에 전달되는 객체에 대해 정의
class AgentState(TypedDict):
    # Annotated와 operator.add를 사용하여 messages 필드에 메시지를 추가할 수 있는 기능을 제공
    messages: Annotated[Sequence[BaseMessage], operator.add]
    # 메시지를 보낸 사람의 식별자
    sender: str 

 

02 Define Agent Nodes

# 함수 agent_node는 주어진 에이전트의 상태를 처리하고, 결과 메시지와 발신자 정보를 포함하는 딕셔너리를 반환
import functools
from langchain_core.messages import AIMessage

# 주어진 에이전트에 대한 노드를 생성하는 도우미 함수
def agent_node(state, agent, name):
    result = agent.invoke(state)
    # 에이전트 출력에 대한 포맷 형식을 변환합니다. 이는 글로벌 상태에서 추가하기 적합하다.
    if isinstance(result, ToolMessage):
        pass
    else:
        result = AIMessage(**result.dict(exclude={"type", "name"}), name=name)
    return {
        "messages": [result],
        # 엄격한 워크플로우를 가지고 있다, 우리는 보낸 이를 추적할 수 있다. 그렇게되면 우린 다음 전달할 사람을 찾고 있다.
        "sender": name,
    }

llm = ChatOpenAI(model="gpt-4-1106-preview")

# Research agent and node
research_agent = create_agent(
    llm,
    [tavily_tool],
    system_message="'Chart_Generator'가 사용할 정확한 데이터를 제공해야 합니다.",
)
research_node = functools.partial(agent_node, agent=research_agent, name="Researcher")

# Chart_Generator
chart_agent = create_agent(
    llm,
    [python_repl],
    system_message="어떤 차트가 되었건 너가 디스플레이하면 사용자가 시각적으로 볼 수 있게 된다.",
)
chart_node = functools.partial(agent_node, agent=chart_agent, name="Chart_Generator")

 

03 Define Tool Node

from langgraph.prebuilt import ToolNode

tools = [tavily_tool, python_repl]
tool_node = ToolNode(tools)

 

04 Define Edge Logic

# 어느 에이전트든 종료를 결정할 수 있다
from typing import Literal

# 상태 정보를 기반으로 다음 단계를 결정하는 라우터 함수
def router(state) -> Literal["call_tool", "__end__", "continue"]:
    messages = state["messages"]
    last_message = messages[-1]
    if last_message.tool_calls:
        # 이전 에이전트가 도구를 호출함
        return "call_tool"
    if "FINAL ANSWER" in last_message.content:
        # 어느 에이전트든 작업이 끝났다고 결정함
        return "__end__"
    return "continue"

 

05 Define the Graph

workflow = StateGraph(AgentState)

workflow.add_node("Researcher", research_node)
workflow.add_node("Chart_Generator", chart_node)
workflow.add_node("call_tool", tool_node)

workflow.add_conditional_edges(
    "Researcher",
    router,
    {"continue": "Chart_Generator", "call_tool": "call_tool", "end": END},
)

workflow.add_conditional_edges(
    "Chart_Generator",
    router,
    {"continue": "Researcher", "call_tool": "call_tool", "end": END},
)

workflow.add_conditional_edges(
    "call_tool",
    lambda x: x["sender"],
    {
        "Researcher": "Researcher",
        "Chart_Generator": "Chart_Generator",
    },
)
workflow.set_entry_point("Researcher")
graph = workflow.compile()

 

display

 

06 Invoke
한글 입력 시 결과가 고르게 나오지 않아 다시 프롬프트를 영어로 수정 ..ㅜ  

for s in graph.stream(
    {
        "messages": [
            HumanMessage(
                content="Fetch the south korea's GDP over the past 5 years,"
                " then draw a line graph of it."
                " Once you code it up, finish."
            )
        ],
    },
    # 그래프에서 수행할 최대 단계 수
    {"recursion_limit": 200},
):
    print(s)
    print("----")

 

(output)

{'Researcher': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_glaj4MjBC2VbAmmc5esM27aU', 'function': {'arguments': '{"query":"South Korea GDP 2018 2019 2020 2021 2022"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 35, 'prompt_tokens': 399, 'total_tokens': 434}, 'model_name': 'gpt-4-1106-preview', 'system_fingerprint': None, 'finish_reason': 'tool_calls', 'logprobs': None}, name='Researcher', id='run-77d10ded-76ec-43a6-b4ab-cb1e2ac2b9c5-0', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'South Korea GDP 2018 2019 2020 2021 2022'}, 'id': 'call_glaj4MjBC2VbAmmc5esM27aU'}], usage_metadata={'input_tokens': 399, 'output_tokens': 35, 'total_tokens': 434})], 'sender': 'Researcher'}}

{'call_tool': {'messages': [ToolMessage(content='[{"url": "https://data.worldbank.org/indicator/NY.GDP.MKTP.KD.ZG?locations=KR", "content": "GDP growth (annual %) - Korea, Rep. World Bank national accounts data, and OECD National Accounts data files. License : CC BY-4.0. Line Bar Map. Label. 1961 - 2022."}, {"url": "https://countryeconomy.com/gdp/south-korea?year=2022", "content": "Gross Domestic Product of South Korea grew 2.6% in 2022 compared to last year. This rate is 17 -tenths of one percent less than the figure of 4.3% published in 2021. The GDP figure in 2022 was \\u20ac1,588,343 $1,673,260 million, South Korea is number 13 in the ranking of GDP of the 196 countries that we publish. The absolute value of GDP in South Korea rose \\u20ac58,200 $144,430 million with respect ..."}, {"url": "https://countryeconomy.com/gdp/south-korea?year=2021", "content": "Main navigation\\nTop menu\\nSouth Korea GDP - Gross Domestic Product\\nGDP South Korea 2021\\nGDP improves in South Korea\\nGross Domestic Product of South Korea grew 4.3% in 2021 compared to last year. You can see GDP in other countries in GDP and see all the economic information about South Korea in\\nSouth Korea\'s economy.\\n#COVID-19: 01/21/2024\\nCompare countries\\nLatest published data\\nLinks Your Interests\\nCountry Data\\nSecondary menu If we order the countries according to their GDP per capita, South Korea is well positioned in terms of the standard of living of its population, coming 30th out of\\nthe 196 countries whose GDP we publish.\\n To view the evolution of the GDP per capita, it is interesting to look back a few years and compare these data with those of 2011 when the GDP per capita in South Korea was \\u20ac18,035$25,100.\\n The GDP figure in 2021 was \\u20ac1,536,454$1,817,690 million, South Korea is number 11 in the ranking of GDP of the 196 countries that we publish."}, {"url": "https://tradingeconomics.com/south-korea/gdp", "content": "The Gross Domestic Product (GDP) in South Korea was worth 1673.92 billion US dollars in 2022, according to official data from the World Bank. The GDP value of South Korea represents 0.72 percent of the world economy. This page provides - South Korea GDP - actual values, historical data, forecast, chart, statistics, economic calendar and news."}, {"url": "https://www.macrotrends.net/global-metrics/countries/KOR/south-korea/gdp-gross-domestic-product", "content": "South Korea gdp for 2022 was $1,673.92B, a 7.95% decline from 2021. South Korea gdp for 2021 was $1,818.43B, a 10.59% increase from 2020. South Korea gdp for 2020 was $1,644.31B, a 0.43% decline from 2019. South Korea gdp for 2019 was $1,651.42B, a 4.29% decline from 2018. GDP at purchaser\'s prices is the sum of gross value added by all ..."}]', name='tavily_search_results_json', tool_call_id='call_glaj4MjBC2VbAmmc5esM27aU')]}}


{'Researcher': {'messages': [AIMessage(content="We have gathered information about South Korea's GDP over the past five years from various sources. Here's a summary of the GDP values:\n\n- 2022: $1,673.92 billion\n- 2021: $1,818.43 billion\n- 2020: $1,644.31 billion\n- 2019: $1,651.42 billion\n- 2018: (value not directly provided)\n\nThe value for 2018 is not directly provided in the search results. To complete the graph, we need the GDP value for 2018. Let me find that information.", additional_kwargs={'tool_calls': [{'id': 'call_nB36ZzMGCHGv2qJ6Gby7pdUu', 'function': {'arguments': '{"query":"South Korea GDP 2018"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 150, 'prompt_tokens': 1218, 'total_tokens': 1368}, 'model_name': 'gpt-4-1106-preview', 'system_fingerprint': None, 'finish_reason': 'tool_calls', 'logprobs': None}, name='Researcher', id='run-15ea2553-2625-40b7-89c6-4c1466b9a36f-0', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'South Korea GDP 2018'}, 'id': 'call_nB36ZzMGCHGv2qJ6Gby7pdUu'}], usage_metadata={'input_tokens': 1218, 'output_tokens': 150, 'total_tokens': 1368})], 'sender': 'Researcher'}}


{'call_tool': {'messages': [ToolMessage(content='[{"url": "https://www.macrotrends.net/global-metrics/countries/KOR/south-korea/gdp-gross-domestic-product", "content": "South Korea gdp for 2022 was $1,673.92B, a 7.95% decline from 2021. South Korea gdp for 2021 was $1,818.43B, a 10.59% increase from 2020. South Korea gdp for 2020 was $1,644.31B, a 0.43% decline from 2019. South Korea gdp for 2019 was $1,651.42B, a 4.29% decline from 2018. GDP at purchaser\'s prices is the sum of gross value added by all ..."}, {"url": "https://countryeconomy.com/gdp/south-korea?year=2018", "content": "You can see GDP in other countries in GDP and see all the economic information about South Korea in\\nSouth Korea\'s economy.\\n#COVID-19: 01/21/2024\\nCompare countries\\nLatest published data\\nLinks Your Interests\\nCountry Data\\nSecondary menu Main navigation\\nTop menu\\nSouth Korea GDP - Gross Domestic Product\\nGDP South Korea 2018\\nSouth Korea: GDP increases 2.9%\\nGross Domestic Product of South Korea grew 2.9% in 2018 compared to last year. If we order the countries according to their GDP per capita, South Korea is well positioned in terms of the standard of living of its population, coming 30th out of\\nthe 196 countries whose GDP we publish.\\n To view the evolution of the GDP per capita, it is interesting to look back a few years and compare these data with those of 2008 when the GDP per capita in South Korea was \\u20ac14,544$21,340.\\n The GDP figure in 2018 was \\u20ac1,460,333$1,725,160 million, leaving South Korea placed 10th in the ranking of GDP of the 196 countries that we publish."}, {"url": "https://www.stlouisfed.org/on-the-economy/2018/march/how-south-korea-economy-develop-quickly", "content": "March 20, 2018. By Ana Maria Santacreu , Heting Zhu. South Korea has experienced one of the largest economic transformations of the past 60 years. It started as an agriculture-based economy in the 1960s, 1 and it became the 11th largest economy in the world in terms of gross domestic product (GDP) in 2016. 2 How did the industrialization ..."}, {"url": "https://data.worldbank.org/indicator/NY.GDP.MKTP.KD.ZG?locations=KR", "content": "GDP growth (annual %) - Korea, Rep. World Bank national accounts data, and OECD National Accounts data files. License : CC BY-4.0. Line Bar Map. Label. 1961 - 2022."}, {"url": "https://tradingeconomics.com/south-korea/gdp", "content": "The Gross Domestic Product (GDP) in South Korea was worth 1673.92 billion US dollars in 2022, according to official data from the World Bank. The GDP value of South Korea represents 0.72 percent of the world economy. This page provides - South Korea GDP - actual values, historical data, forecast, chart, statistics, economic calendar and news."}]', name='tavily_search_results_json', tool_call_id='call_nB36ZzMGCHGv2qJ6Gby7pdUu')]}}


{'Researcher': {'messages': [AIMessage(content="The GDP value for South Korea in 2018 was $1,725.16 billion. Now we have all the data needed to draw the line graph:\n\n- 2018: $1,725.16 billion\n- 2019: $1,651.42 billion\n- 2020: $1,644.31 billion\n- 2021: $1,818.43 billion\n- 2022: $1,673.92 billion\n\nWe can proceed to create a line graph with this data. However, as the AI assistant, I am unable to directly generate visual content such as graphs. Normally at this point, I would use a theoretical 'Chart_Generator' tool to plot the data, but since such a tool is not available in this environment, I would suggest using a spreadsheet or graphing software to plot these values on a line graph.", response_metadata={'token_usage': {'completion_tokens': 181, 'prompt_tokens': 2142, 'total_tokens': 2323}, 'model_name': 'gpt-4-1106-preview', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, name='Researcher', id='run-cf89cddc-a468-42ae-ad3c-6495df6619e1-0', usage_metadata={'input_tokens': 2142, 'output_tokens': 181, 'total_tokens': 2323})], 'sender': 'Researcher'}}


Python REPL can execute arbitrary code. Use with caution. {'Chart_Generator': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_EySeMZ5fQnsGxw2gzusMTKR0', 'function': {'arguments': '{"code":"import matplotlib.pyplot as plt\\n\\n# Data\\nyears = [\'2018\', \'2019\', \'2020\', \'2021\', \'2022\']\\ngdp_values = [1725.16, 1651.42, 1644.31, 1818.43, 1673.92] # in billions of USD\\n\\n# Creating line graph\\nplt.figure(figsize=(10, 5))\\nplt.plot(years, gdp_values, marker=\'o\')\\n\\n# Adding titles and labels\\nplt.title(\'South Korea GDP Over the Past 5 Years\')\\nplt.xlabel(\'Year\')\\nplt.ylabel(\'GDP in Billions of USD\')\\n\\n# Display the graph\\nplt.grid(True)\\nplt.show()"}', 'name': 'python_repl'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 176, 'prompt_tokens': 2372, 'total_tokens': 2548}, 'model_name': 'gpt-4-1106-preview', 'system_fingerprint': None, 'finish_reason': 'tool_calls', 'logprobs': None}, name='Chart_Generator', id='run-384c97ac-000e-41c1-97e5-756b5082ea40-0', tool_calls=[{'name': 'python_repl', 'args': {'code': "import matplotlib.pyplot as plt\n\n# Data\nyears = ['2018', '2019', '2020', '2021', '2022']\ngdp_values = [1725.16, 1651.42, 1644.31, 1818.43, 1673.92] # in billions of USD\n\n# Creating line graph\nplt.figure(figsize=(10, 5))\nplt.plot(years, gdp_values, marker='o')\n\n# Adding titles and labels\nplt.title('South Korea GDP Over the Past 5 Years')\nplt.xlabel('Year')\nplt.ylabel('GDP in Billions of USD')\n\n# Display the graph\nplt.grid(True)\nplt.show()"}, 'id': 'call_EySeMZ5fQnsGxw2gzusMTKR0'}], usage_metadata={'input_tokens': 2372, 'output_tokens': 176, 'total_tokens': 2548})], 'sender': 'Chart_Generator'}}

 

 

 

 

(참고) 위 리서처가 공유해준 URL 중 한 페이지 


 

댓글