데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      Langchain과 Langgraph의 Agent구현의 차이점.

      Teus 25.06.19
      14,437 4 1
      DEVOTEE 요약
      본 블로그는 Langchain과 Langgraph의 `create_react_agent` 함수 차이를 이해하고, 두 도구의 장단점을 비교합니다. Langchain은 클라이언트 측에서 Prompt를 처리하고 Tool 사용을 모델에 유도하며, 모든 모델에서 사용이 가능하지만 Production 환경에 적합하지 않다는 한계가 있습니다. 반면 Langgraph는 LLM 서비스 측에서 Prompt를 처리하고 Tool Call API를 활용해 더욱 효율적으로 MCP와 같은 최신 기술 트렌드에 대응하지만, Private LLM 환경에 따라 제약이 있을 수 있습니다.
      DEVOTEE 추천 블로그

      안녕하세요. Teus입니다.


      이번 포스팅은 현재 LLM Agent을 구현하기 위해서 가장 많이 쓰이는 Langchain과 Langgraph의 create_react_agent

      함수의 차이점에 대해서 간략하게 알아봅니다.


      0. LLM Agent

      Agent는 보통은 특수한 영역 또는 기능에 특화된 일꾼 입니다.

      근데 여기에 이게 Tools를 추가해서

      유저의 요청에 따라, 상황에 맞는 Tool를 사용해서 기존에 학습하지 못했던 기능을 가능케 합니다.

      이를위해서 ReAct(Reasoning and Action) Agent를 사용하게 됩니다.

      이때 기존 포스팅을 통해서, Scratch부터 Agent를 만들어 봤지만

      실제 Production에서는 Langchain이나 Langgraph를 사용하게 됩니다.


      1. Langchain의 create_react_agent

      공식 API 문서

      Langchain에서는 create_react_agent 함수를 통해서 Agent를 만들 수 있고

      prompt를 통해서 Agent가 어떤 Chain Of Thought 를 진행할지 기술하게 됩니다.

      #홈페이지 Example
      from langchain import hub
      from langchain_community.llms import OpenAI
      from langchain.agents import AgentExecutor, create_react_agent
      
      from langchain_core.prompts import PromptTemplate
      
      template = '''Answer the following questions as best you can. You have access to the following tools:
      
      {tools}
      
      Use the following format:
      
      Question: the input question you must answer
      Thought: you should always think about what to do
      Action: the action to take, should be one of [{tool_names}]
      Action Input: the input to the action
      Observation: the result of the action
      ... (this Thought/Action/Action Input/Observation can repeat N times)
      Thought: I now know the final answer
      Final Answer: the final answer to the original input question
      
      Begin!
      
      Question: {input}
      Thought:{agent_scratchpad}'''
      
      prompt = PromptTemplate.from_template(template)
      model = OpenAI()
      tools = ...
      
      agent = create_react_agent(model, tools, prompt)
      agent_executor = AgentExecutor(agent=agent, tools=tools)
      
      agent_executor.invoke({"input": "hi"})
      
      # Use with chat history
      from langchain_core.messages import AIMessage, HumanMessage
      agent_executor.invoke(
          {
              "input": "what's my name?",
              # Notice that chat_history is a string
              # since this prompt is aimed at LLMs, not chat models
              "chat_history": "Human: My name is Bob\nAI: Hello Bob!",
          }
      )

      그래서 사용자의 prompt작성 수준에 따라서 Agent의 Tools Call능력이나, Reasoning능력이 달라지게 됩니다.

      하지만 API문서에서 보면, 아래와 같은 문구를 확인할 수가 있습니다.

      Warning
      
      This implementation is based on the foundational ReAct paper but is older and not 
      well-suited for production applications. For a more robust and feature-rich 
      implementation, we recommend using the create_react_agent function from the LangGraph 
      library. See the [reference doc](https://langchain-
      ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.crea
      te_react_agent) for more information.

      Langchain Agent는 Production 용도에는 적합하지 않다는 내용이네요.

      Langchain의 경우 prompt를 이용해서 Agent가 Tool을 사용하게 유도합니다.

      이 덕분에 Tool Call이 학습되지 않은 모델에서도 Tool을 사용할 수 있다는 장점이 있습니다.


      2. Langgraph의 create_react_agent

      공식 API 문서

      Langgraph의 경우 동일한 이름의 create_react_agent 함수를 제공합니다.

      대신 차이점을 보이는게

      Langgraph의 공식 문서에서는

      prompt입력에 대한 가이드 라던가, 복잡한 prompt를 입력하라고 안내해주지 않습니다.

      #공식예제
      #https://langchain-ai.github.io/langgraph/agents/agents/#2-create-an-agent
      from langgraph.prebuilt import create_react_agent
      
      def get_weather(city: str) -> str:  
          """Get weather for a given city."""
          return f"It's always sunny in {city}!"
      
      agent = create_react_agent(
          model="anthropic:claude-3-7-sonnet-latest",  
          tools=[get_weather],  
          prompt="You are a helpful assistant"  
      )
      
      # Run the agent
      agent.invoke(
          {"messages": [{"role": "user", "content": "what is the weather in sf"}]}
      )


      3. 둘이 뭔 차이에요?

      비고

      Langchain

      Langgraph

      prompt

      Reasoing과정 직접 작성

      단순한 Agent의 역할부여

      ReAct의구현

      prompt로 정의+Langchain내부 구현

      Langgraph로 구현

      Function call

      prompt를 이용해서 LLM이 Tool을 사용하게 유도

      LLM 학습 당시 구현한 Tool Call API사용

      Tool 사용 가능 모델

      모든 모델

      Tool Call이 가능한 Model

      두 라이브러리의 실제 vLLM 또는 OpenAI로 보내지는 prompt를 확인하기 위해서 아래 코드를 사용합니다.

      #langchain
      import logging
      import requests
      from langchain.agents import (
          AgentExecutor,
          create_react_agent,
      )
      from langchain_core.tools import Tool
      from langchain_openai import ChatOpenAI
      
      import logging
      # Set up logging
      logging.basicConfig(level=logging.DEBUG)
      logger = logging.getLogger(__name__)
      
      #logging을 통해서 debbuging진행
      class LoggingChatOpenAI(ChatOpenAI):
          def _call(self, prompt: str, stop=None) -> str:
              logger.debug(f"Prompt: {prompt}")
              logger.debug(f"Stop: {stop}")
              response = super()._call(prompt, stop)
              logger.debug(f"Response: {response}")
              return response
      
      
      # Use the LoggingChatOpenAI class instead of ChatOpenAI
      model = LoggingChatOpenAI(
          model="MyModel",
          temperature=0,
          max_tokens=None,
          timeout=None,
          max_retries=2,
          api_key="mytoken", 
          base_url="http://myvllmservice/v1",
      )
      
      # Define a very simple tool function that returns the current time
      def get_weather(city: str) -> str:  
          """Get weather for a given city."""
          return f"It's always sunny in {city}!"
          
      # List of tools available to the agent
      tools = [
          Tool(
              name="Weather",  # Name of the tool
              func=get_weather,  # Function that the tool will execute
              # Description of the tool
              description=get_weather.__doc__,
          ),
      ]
      
      # Initialize a ChatOpenAI model
      from langchain_core.prompts import PromptTemplate
      
      template = '''Answer the following questions as best you can. You have access to the following tools:
      
      {tools}
      
      Use the following format:
      
      Question: the input question you must answer
      Thought: you should always think about what to do
      Action: the action to take, should be one of [{tool_names}]
      Action Input: the input to the action
      Observation: the result of the action
      ... (this Thought/Action/Action Input/Observation can repeat N times)
      Thought: I now know the final answer
      Final Answer: the final answer to the original input question
      
      Begin!
      
      Question: {input}
      Thought:{agent_scratchpad}'''
      
      prompt = PromptTemplate.from_template(template)
      
      # Create the ReAct agent using the create_react_agent function
      agent = create_react_agent(
          llm=model,
          tools=tools,
          prompt=prompt,
          stop_sequence=True,
      )
      
      # Create an agent executor from the agent and tools
      agent_executor = AgentExecutor.from_agent_and_tools(
          agent=agent,
          tools=tools,
          verbose=True,
      )
      
      # Run the agent with a test query
      response = agent_executor.invoke({"input": "tell me what time is it now"})
      
      # Print the response from the agent
      print("response:", response)
      #langgraph
      from mcp import ClientSession, StdioServerParameters
      from mcp.client.stdio import stdio_client
      from langchain_mcp_adapters.tools import load_mcp_tools
      from langgraph.prebuilt import create_react_agent
      from langchain_openai import ChatOpenAI
      import asyncio
      
      import logging
      # Set up logging
      logging.basicConfig(level=logging.DEBUG)
      logger = logging.getLogger(__name__)
      
      class LoggingChatOpenAI(ChatOpenAI):
          def _call(self, prompt: str, stop=None) -> str:
              logger.debug(f"Prompt: {prompt}")
              logger.debug(f"Stop: {stop}")
              response = super()._call(prompt, stop)
              logger.debug(f"Response: {response}")
              return response
      
      def get_weather(city: str) -> str:  
          """Get weather for a given city."""
          return f"It's always sunny in {city}!"
      
      # Use the LoggingChatOpenAI class instead of ChatOpenAI
      model = LoggingChatOpenAI(
          model="MyModel",
          temperature=0,
          max_tokens=None,
          timeout=None,
          max_retries=2,
          api_key="mytoken", 
          base_url="http://myvllmservice/v1",
      )
      # MCP Server 설정(이경우 Client.py파일과 Server.py파일이 같은 위치에 있음)
      server_params = StdioServerParameters(
          command="python",
          # Make sure to update to the full absolute path to your math_server.py file
          args=["weather_server_stdio.py"],
      )
      from langchain_core.prompts import PromptTemplate
      
      template = '''Answer the following questions as best you can. You have access to the following tools:
      
      {tools}
      
      Use the following format:
      
      Question: the input question you must answer
      Thought: you should always think about what to do
      Action: the action to take, should be one of [{tool_names}]
      Action Input: the input to the action
      Observation: the result of the action
      ... (this Thought/Action/Action Input/Observation can repeat N times)
      Thought: I now know the final answer
      Final Answer: the final answer to the original input question
      
      Begin!
      
      Question: {input}
      Thought:{agent_scratchpad}'''
      
      # MCP Python SDK를 활용해서 MCP Server를 사용함
      async def run_agent():
          async with stdio_client(server_params) as (read, write):
              async with ClientSession(read, write) as session:
                  # Initialize the connection
                  await session.initialize()
      
                  # MCP Server에 있는 Tool리스트를 가지고 옵니다.
                  tools = await load_mcp_tools(session)
      
                  # Tools와 Model을 사용해서 Agent 생성
                  agent = create_react_agent(
                      model = model,
                      tools = tools,
                      prompt = template
                  )
                  
                  # Agent한테 Query를 진행해, Agent가 알아서 tools을 사용하게 만듭니다.
                  agent_response = await agent.ainvoke({"messages": "what's time is it now?. i'm live in seoul city. find about city seoul"})
                  return agent_response
      
      # Run the async function
      if __name__ == "__main__":
          result = asyncio.run(run_agent())
          print(result)
      #weather_server_stdio.py
      from mcp.server.fastmcp import FastMCP
      import datetime
      
      mcp = FastMCP("Weather")
      
      @mcp.tool()
      async def get_weather(location: str) -> str:
          """Get weather for location."""
          return "It's always sunny in New York"
      
      if __name__ == "__main__":
          mcp.run(transport="stdio")

      이제 코드를 실행시키고, 디버깅 로그를 확인해봅니다.

      #langchain을 사용한 경우
      DEBUG:openai._base_client:Request options: {'method': 'post', 'url': 
      '/chat/completions', 'files': None, 'idempotency_key': 'stainless-python-retry-
      75c082d1-3005-4aa5-9924-8b88f7afb4b3', 'json_data': {'messages': [{'content': 'Answer 
      the following questions as best you can. You have access to the following 
      tools:\n\nTime(city: str) -> str - Get weather for a given city.\n\nUse the following 
      format:\n\nQuestion: the input question you must answer\nThought: you should always 
      think about what to do\nAction: the action to take, should be one of [Time]\nAction 
      Input: the input to the action\nObservation: the result of the action\n... (this 
      Thought/Action/Action Input/Observation can repeat N times)\nThought: I now know the 
      final answer\nFinal Answer: the final answer to the original input 
      question\n\nBegin!\n\nQuestion: how about weather in seoul?\nThought:', 'role': 
      'user'}], 'model': 'Gemma-3-27b-it', 'stop': ['\nObservation'], 'stream': True, 
      'temperature': 0.0}}

      prompt만 따로 빼서보면

      Answer the following questions as best you can. You have access to the following tools:
      Time(city: str) -> str - Get weather for a given city.
      
      Use the following format:
      
      Question: the input question you must answer
      Thought: you should always think about what to do
      Action: the action to take, should be one of [Time]
      Action Input: the input to the action
      Observation: the result of the action
      ... (this Thought/Action/Action Input/Observation can repeat N times)
      Thought: I now know the final answer\nFinal Answer: the final answer to the original input question
      
      Begin!
      
      Question: how about weather in seoul?
      Thought:'

      requests를 보내기 전에 이미 prompt부분이 Agent정의때 사용된 {input}, {tools}, {tools_names}, {agent_scratchppad} 가 이미 포맷팅이 된 것을 확인할 수 있습니다.

      실제로 requests를 보내기 이전에 prompt 포맷팅이 진행되는 것음

      langchain의 create_react_agent 소스코드에서도 확인할 수가 있습니다.

      #https://python.langchain.com/api_reference/_modules/langchain/agents/react/agent.html#create_react_agent
      def create_react_agent(
          llm: BaseLanguageModel,
          tools: Sequence[BaseTool],
          prompt: BasePromptTemplate,
          output_parser: Optional[AgentOutputParser] = None,
          tools_renderer: ToolsRenderer = render_text_description,
          *,
          stop_sequence: Union[bool, list[str]] = True,
      ) -> Runnable:
          
          missing_vars = {"tools", "tool_names", "agent_scratchpad"}.difference(
              prompt.input_variables + list(prompt.partial_variables)
          )
          if missing_vars:
              raise ValueError(f"Prompt missing required variables: {missing_vars}")
      
          prompt = prompt.partial(
              tools=tools_renderer(list(tools)),
              tool_names=", ".join([t.name for t in tools]),
          )
          ...

      반면 Langgraph를 확인해보면

      DEBUG:openai._base_client:Request options: {'method': 'post', 'url': 
      '/chat/completions', 'files': None, 'idempotency_key': 'stainless-python-retry-
      2ce447ef-a0e2-434c-94a2-5577d9ffcbb7', 'json_data': {'messages': [{'content': 'Answer 
      the following questions as best you can. You have access to the following 
      tools:\n\n{tools}\n\nUse the following format:\n\nQuestion: the input question you 
      must answer\nThought: you should always think about what to do\nAction: the action to 
      take, should be one of [{tool_names}]\nAction Input: the input to the 
      action\nObservation: the result of the action\n... (this Thought/Action/Action 
      Input/Observation can repeat N times)\nThought: I now know the final answer\nFinal 
      Answer: the final answer to the original input question\n\nBegin!\n\nQuestion: 
      {input}\nThought:{agent_scratchpad}', 'role': 'system'}, {'content': "what's time is 
      it now?. i'm live in seoul city. find about city seoul", 'role': 'user'}], 'model': 
      'Gemma-3-27b-it', 'stream': False, 'temperature': 0.0, 'tools': [{'type': 'function', 
      'function': {'name': 'get_current_time', 'description': 'useful tools when you need 
      to know current time', 'parameters': {'properties': {'city': {'type': 'string'}}, 
      'required': ['city'], 'type': 'object'}}}]}}

      Langgraph는 prompt가 포맷팅 되지 않고 그대로 전달되게 됩니다.

      여기서 Langchain과의 큰 차이점은 requests의 parameter로 tools가 전달되게 됩니다.

      'tools': [
          {'type': 'function',
          'function': {
              'name': 'get_current_time',
              'description': 'useful tools when you need to know current time', 
              'parameters': {
                  'properties': {
                      'city': {'type': 'string'}
                  }, 'required': ['city'],
                      'type': 'object'
                  }
              }
          }
      ]


      4. 정리

      • Langchain : Client Side에서 prompt를 처리함

      • Langgraph : LLM Service Side에서 prompt를 처리함

      외부 환경에서 상용 서비스(ChatGPT, Gemini, Claude)를 이용할 경우

      langgraph로 tool call API를 이용할 수가 있습니다.

      그렇기 때문에 이런경우는 정상적으로 Tool을 사용하는 Agent를 구현할 수 있습니다.

      특히나 요즘 MCP가 대세인데, MCP를 사용하기 위해서는 Langgraph를 이용하는 것이 좋습니다,

      하지만 vLLM등을 이용하는 Private LLM환경에서는

      Tool Call이 허용되지 않는 모델이나, vLLM 설정에 따라 Tool Call이 불가능 할 수 있습니다.

      이런 경우에 Agent를 구현하기 위해서 Langchain을 사용한 Agent구현을 고려해 볼 수 있습니다.

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      Teus 님의 최신 블로그

      더보기

      DEVOTEE 추천 블로그

      동영상 기고하기