제퍼넷 로고

LangChain의 LangGraph를 사용하여 AI 코딩 에이전트 구축

시간

개요

AI 코딩 에이전트를 사용하는 애플리케이션이 엄청나게 급증했습니다. LLM의 품질이 향상되고 추론 비용이 감소함에 따라 유능한 AI 에이전트를 구축하는 것이 점점 더 쉬워지고 있습니다. 게다가 툴링 생태계가 빠르게 발전하고 있어 복잡한 AI 코딩 에이전트를 더 쉽게 구축할 수 있게 되었습니다. Langchain 프레임워크는 이 분야의 선두주자였습니다. 프로덕션에 바로 사용할 수 있는 AI 애플리케이션을 만드는 데 필요한 모든 도구와 기술이 있습니다.

하지만 지금까지는 한 가지가 부족했습니다. 그리고 이는 주기성을 갖춘 다중 에이전트 협업입니다. 이는 문제를 전문 에이전트에게 나누어 위임할 수 있는 복잡한 문제를 해결하는 데 매우 중요합니다. AI 코딩 에이전트 간의 다중 행위자 상태 기반 협업을 수용하도록 설계된 Langchain 프레임워크의 일부인 LangGraph가 등장하는 곳입니다. 또한 이 기사에서는 LangGraph와 이를 사용하여 에이전트를 구축하는 동안 LangGraph의 기본 구성 요소에 대해 논의할 것입니다.

학습 목표

  • LangGraph가 무엇인지 이해하세요.
  • 상태 저장 에이전트 구축을 위한 LangGraph의 기본 사항을 살펴보세요.
  • TogetherAI를 탐색하여 다음과 같은 오픈 액세스 모델에 액세스하세요. DeepSeek코더.
  • 단위 테스트를 작성하기 위해 LangGraph를 사용하여 AI 코딩 에이전트를 구축합니다.
랭체인

이 기사는 데이터 과학 블로그.

차례

랭그래프란 무엇인가요?

LangGraph는 LangChain 생태계의 확장입니다. LangChain을 사용하면 여러 도구를 사용하여 작업을 실행할 수 있는 AI 코딩 에이전트를 구축할 수 있지만 단계 전반에 걸쳐 여러 체인이나 행위자를 조정할 수는 없습니다. 이는 복잡한 작업을 수행하는 에이전트를 만드는 데 중요한 동작입니다. LangGraph는 이러한 점을 염두에 두고 고안되었습니다. 에이전트 워크플로를 순환 그래프 구조로 처리합니다. 여기서 각 노드는 함수 또는 Langchain Runnable 개체를 나타내고 가장자리는 노드 간의 연결입니다. 

LangGraph의 주요 기능은 다음과 같습니다. 

  • 노드: 도구와 같은 모든 기능 또는 Langchain Runnable 개체입니다.
  • 가장자리: 노드 사이의 방향을 정의합니다.
  • 상태 저장 그래프: 기본 그래프 유형입니다. 노드를 통해 데이터를 처리하면서 상태 개체를 관리하고 업데이트하도록 설계되었습니다.

LangGraph는 이를 활용하여 에이전트 동작에 중요한 상태 지속성을 갖춘 순환 LLM 호출 실행을 촉진합니다. 건축은 다음에서 영감을 얻습니다. 프레 겔 과 아파치 빔

이 기사에서는 메소드를 사용하여 Python 클래스에 대한 Pytest 단위 테스트를 작성하기 위한 에이전트를 구축합니다. 이것이 워크플로입니다.

랭체인

간단한 단위 테스트를 작성하기 위한 AI 코딩 에이전트를 구축하면서 개념에 대해 자세히 논의하겠습니다. 그럼 코딩 부분으로 가보겠습니다.

하지만 그 전에 개발 환경을 설정해 봅시다.

종속성 설치

우선 먼저. 다른 Python 프로젝트와 마찬가지로 가상 환경을 만들고 활성화합니다.

python -m venv auto-unit-tests-writer
cd auto-unit-tests-writer
source bin/activate

이제 종속성을 설치하십시오.

!pip install langgraph langchain langchain_openai colorama

모든 라이브러리와 해당 클래스를 가져옵니다.

from typing import TypedDict, List
import colorama
import os

from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage
from langchain_core.messages import HumanMessage
from langchain_core.runnables import RunnableConfig

from langgraph.graph import StateGraph, END
from langgraph.pregel import GraphRecursionError

또한 테스트 케이스를 위한 디렉터리와 파일을 만들고 싶을 것입니다. 수동으로 파일을 만들거나 Python을 사용할 수 있습니다.

# Define the paths.
search_path = os.path.join(os.getcwd(), "app")
code_file = os.path.join(search_path, "src/crud.py")
test_file = os.path.join(search_path, "test/test_crud.py")

# Create the folders and files if necessary.
if not os.path.exists(search_path):
    os.mkdir(search_path)
    os.mkdir(os.path.join(search_path, "src"))
    os.mkdir(os.path.join(search_path, "test"))

이제 인메모리 CRUD 앱용 코드로 crud.py 파일을 업데이트하세요. 이 코드 조각을 사용하여 단위 테스트를 작성하겠습니다. 이를 위해 Python 프로그램을 사용할 수 있습니다. 아래 프로그램을 code.py 파일에 추가하겠습니다.

#crud.py
code = """class Item:
    def __init__(self, id, name, description=None):
        self.id = id
        self.name = name
        self.description = description

    def __repr__(self):
        return f"Item(id={self.id}, name={self.name}, description={self.description})"

class CRUDApp:
    def __init__(self):
        self.items = []

    def create_item(self, id, name, description=None):
        item = Item(id, name, description)
        self.items.append(item)
        return item

    def read_item(self, id):
        for item in self.items:
            if item.id == id:
                return item
        return None

    def update_item(self, id, name=None, description=None):
        for item in self.items:
            if item.id == id:
                if name:
                    item.name = name
                if description:
                    item.description = description
                return item
        return None

    def delete_item(self, id):
        for index, item in enumerate(self.items):
            if item.id == id:
                return self.items.pop(index)
        return None

    def list_items(self):
        return self.items"""
        
with open(code_file, 'w') as f:
  f.write(code)

LLM 설정

이제 이 프로젝트에서 사용할 LLM을 지정하겠습니다. 여기서 사용할 모델은 작업 및 리소스 가용성에 따라 다릅니다. GPT-4, Gemini Ultra 또는 GPT-3.5와 같은 독점적이고 강력한 모델을 사용할 수 있습니다. 또한 Mixtral 및 Llama-2와 같은 개방형 모델을 사용할 수도 있습니다. 이 경우 코드 작성이 포함되므로 DeepSeekCoder-33B 또는 Llama-2 코더와 같은 미세 조정된 코딩 모델을 사용할 수 있습니다. 이제 Anayscale, Abacus 및 Together와 같은 LLM 추론을 위한 여러 플랫폼이 있습니다. DeepSeekCoder를 추론하기 위해 Together AI를 사용하겠습니다. 그러니, API 키 앞으로 나아가기 전에 Together에서. 

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(base_url="https://api.together.xyz/v1",
    api_key="your-key",
    model="deepseek-ai/deepseek-coder-33b-instruct")

Together API는 OpenAI SDK와 호환되므로 base_url 매개변수를 다음으로 변경하여 Langchain의 OpenAI SDK를 사용하여 Together에서 호스팅되는 모델과 통신할 수 있습니다. “https://api.together.xyz/v1”. api_key에서 Together API 키를 전달하고 모델 대신 모델명 투게더에서 만나보실 수 있습니다.

에이전트 상태 정의

이것은 LangGraph의 중요한 부분 중 하나입니다. 여기에서는 실행 전반에 걸쳐 에이전트의 상태를 추적하는 역할을 담당하는 AgentState를 정의합니다. 이는 주로 에이전트의 상태를 유지하는 엔터티가 있는 TypedDict 클래스입니다. AgentState를 정의해 보겠습니다.

class AgentState(TypedDict):
    class_source: str
    class_methods: List[str]
    tests_source: str

위의 AgentState 클래스에서 class_source는 원본 Python 클래스, 클래스의 메서드를 저장하는 class_methods, 단위 테스트 코드를 위한 test_source를 저장합니다. 실행 단계 전반에 걸쳐 사용하기 위해 이를 AgentState로 정의했습니다. 

이제 AgentState를 사용하여 그래프를 정의합니다.

# Create the graph.
workflow = StateGraph(AgentState)

앞서 언급했듯이 이것은 상태 저장 그래프이며 이제 상태 개체를 추가했습니다.

노드 정의

이제 AgentState를 정의했으므로 노드를 추가해야 합니다. 그렇다면 노드란 정확히 무엇입니까? LangGraph에서 노드는 단일 작업을 수행하는 Langchain 도구와 같은 실행 가능한 개체 또는 함수입니다. 우리의 경우에는 클래스 메서드를 찾는 함수, 단위 테스트를 추론하고 상태 개체에 업데이트하는 함수, 테스트 파일에 쓰는 함수 등 여러 노드를 정의할 수 있습니다.

또한 LLM 메시지에서 코드를 추출하는 방법도 필요합니다. 방법은 다음과 같습니다.

def extract_code_from_message(message):
    lines = message.split("n")
    code = ""
    in_code = False
    for line in lines:
        if "```" in line:
            in_code = not in_code
        elif in_code:
            code += line + "n"
    return code

여기의 코드 조각에서는 코드가 삼중따옴표 안에 있다고 가정합니다.

이제 노드를 정의해 보겠습니다.

import_prompt_template = """Here is a path of a file with code: {code_file}.
Here is the path of a file with tests: {test_file}.
Write a proper import statement for the class in the file.
"""
# Discover the class and its methods.
def discover_function(state: AgentState):
    assert os.path.exists(code_file)
    with open(code_file, "r") as f:
        source = f.read()
    state["class_source"] = source

    # Get the methods.
    methods = []
    for line in source.split("n"):
        if "def " in line:
            methods.append(line.split("def ")[1].split("(")[0])
    state["class_methods"] = methods

    # Generate the import statement and start the code.
    import_prompt = import_prompt_template.format(
        code_file=code_file,
        test_file=test_file
    )
    message = llm.invoke([HumanMessage(content=import_prompt)]).content
    code = extract_code_from_message(message)
    state["tests_source"] = code + "nn"

    return state


# Add a node to for discovery.
workflow.add_node(
    "discover",
    discover_function
)

위의 코드 조각에서는 코드를 검색하는 함수를 정의했습니다. AgentState에서 코드를 추출합니다. 클래스_소스 요소를 사용하여 클래스를 개별 메소드로 분석하고 프롬프트와 함께 LLM에 전달합니다. 출력은 AgentState의 테스트_소스 요소. 단위 테스트 케이스에 대해서만 import 문을 작성하도록 합니다.

또한 StateGraph 개체에 첫 번째 노드를 추가했습니다.

이제 다음 노드로 넘어갑니다. 

또한 여기서 필요한 몇 가지 프롬프트 템플릿을 설정할 수 있습니다. 이는 필요에 따라 변경할 수 있는 샘플 템플릿입니다.

# System message template.

system_message_template = """You are a smart developer. You can do this! You will write unit 
tests that have a high quality. Use pytest.

Reply with the source code for the test only. 
Do not include the class in your response. I will add the imports myself.
If there is no test to write, reply with "# No test to write" and 
nothing more. Do not include the class in your response.

Example:

```
def test_function():
    ...
```

I will give you 200 EUR if you adhere to the instructions and write a high quality test. 
Do not write test classes, only methods.
"""

# Write the tests template.
write_test_template = """Here is a class:
'''
{class_source}
'''

Implement a test for the method "{class_method}".
"""

이제 노드를 정의합니다.

# This method will write a test.
def write_tests_function(state: AgentState):

    # Get the next method to write a test for.
    class_method = state["class_methods"].pop(0)
    print(f"Writing test for {class_method}.")

    # Get the source code.
    class_source = state["class_source"]

    # Create the prompt.
    write_test_prompt = write_test_template.format(
        class_source=class_source,
        class_method=class_method
    )
    print(colorama.Fore.CYAN + write_test_prompt + colorama.Style.RESET_ALL)

    # Get the test source code.
    system_message = SystemMessage(system_message_template)
    human_message = HumanMessage(write_test_prompt)
    test_source = llm.invoke([system_message, human_message]).content
    test_source = extract_code_from_message(test_source)
    print(colorama.Fore.GREEN + test_source + colorama.Style.RESET_ALL)
    state["tests_source"] += test_source + "nn"

    return state

# Add the node.
workflow.add_node(
    "write_tests",
    write_tests_function
)

여기서는 LLM이 각 메서드에 대한 테스트 사례를 작성하고 이를 AgentState의 테스트_소스 요소로 업데이트하고 워크플로 StateGraph 개체에 추가하도록 합니다.

가장자리

이제 두 개의 노드가 있으므로 노드 사이의 실행 방향을 지정하기 위해 노드 사이의 가장자리를 정의하겠습니다. LangGraph는 주로 두 가지 유형의 에지를 제공합니다.

  • 조건부 가장자리: 실행 흐름은 에이전트의 응답에 따라 달라집니다. 이는 워크플로에 주기성을 추가하는 데 중요합니다. 에이전트는 일부 조건에 따라 다음에 이동할 노드를 결정할 수 있습니다. 이전 노드로 돌아갈지, 현재를 반복할지, 다음 노드로 이동할지 여부입니다.
  • 일반 가장자리: 이는 항상 이전 노드를 호출한 후에 노드가 호출되는 일반적인 경우입니다.

discover와 write_tests를 연결하는 데 조건이 필요하지 않으므로 일반 Edge를 사용하겠습니다. 또한 실행이 시작되어야 하는 위치를 지정하는 진입점을 정의합니다.

# Define the entry point. This is where the flow will start.
workflow.set_entry_point("discover")

# Always go from discover to write_tests.
workflow.add_edge("discover", "write_tests")

실행은 메소드 발견으로 시작하여 테스트 작성 기능으로 이동합니다. 테스트 파일에 단위 테스트 코드를 작성하려면 다른 노드가 필요합니다.

# Write the file.
def write_file(state: AgentState):
    with open(test_file, "w") as f:
        f.write(state["tests_source"])
    return state

# Add a node to write the file.
workflow.add_node(
    "write_file",
    write_file)

이것이 마지막 노드이므로 write_tests와 write_file 사이의 가장자리를 정의합니다. 이것이 우리가 할 수 있는 방법입니다.

# Find out if we are done.
def should_continue(state: AgentState):
    if len(state["class_methods"]) == 0:
        return "end"
    else:
        return "continue"

# Add the conditional edge.
workflow.add_conditional_edges(
    "write_tests",
    should_continue,
    {
        "continue": "write_tests",
        "end": "write_file"
    }
)

add_conditional_edge 함수는 write_tests 함수, class_methods 항목을 기반으로 수행할 단계를 결정하는 should_continue 함수, 문자열을 키로, 기타 함수를 값으로 사용하는 매핑을 사용합니다.

엣지는 write_tests에서 시작하고 should_continue의 출력에 따라 매핑의 옵션 중 하나를 실행합니다. 예를 들어, 상태["class_methods"]가 비어 있지 않으면 모든 메서드에 대한 테스트를 작성하지 않은 것입니다. write_tests 함수를 반복하고, 테스트 작성이 끝나면 write_file이 실행됩니다.

모든 방법에 대한 테스트가 다음에서 추론되었을 때 LLM, 테스트가 테스트 파일에 기록됩니다.

이제 클로저를 위한 워크플로 개체에 마지막 가장자리를 추가합니다.

# Always go from write_file to end.
workflow.add_edge("write_file", END)

워크플로 실행

마지막으로 남은 일은 워크플로를 컴파일하고 실행하는 것이었습니다.

# Create the app and run it
app = workflow.compile()
inputs = {}
config = RunnableConfig(recursion_limit=100)
try:
    result = app.invoke(inputs, config)
    print(result)
except GraphRecursionError:
    print("Graph recursion limit reached.")

그러면 앱이 호출됩니다. 재귀 제한은 특정 워크플로에 대해 LLM이 추론되는 횟수입니다. 한도를 초과하면 워크플로가 중지됩니다.

터미널이나 노트북에서 로그를 볼 수 있습니다. 간단한 CRUD 앱의 실행 로그입니다.

랭체인

많은 무거운 작업은 기본 모델에 의해 수행됩니다. 이것은 Deepseek 코더 모델을 사용한 데모 애플리케이션이었습니다. 더 나은 성능을 위해 GPT-4 또는 Claude Opus, haiku 등을 사용할 수 있습니다.

 웹 서핑, 주가 분석 등을 위해 Langchain 도구를 사용할 수도 있습니다.

LangChain 대 LangGraph

이제 문제는 LangChain을 사용할 때와 언제 사용할 것인가입니다. 랭그래프.

목표가 서로 조정되는 다중 에이전트 시스템을 만드는 것이라면 LangGraph가 적합합니다. 그러나 작업을 완료하기 위해 DAG 또는 체인을 생성하려는 경우 LangChain 표현 언어가 가장 적합합니다.

왜 랭그래프를 사용하나요?

LangGraph는 기존의 많은 솔루션을 개선할 수 있는 강력한 프레임워크입니다. 

  • RAG 파이프라인 개선: LangGraph는 순환 그래프 구조로 RAG를 확장할 수 있습니다. 검색된 개체의 품질을 평가하기 위해 피드백 루프를 도입할 수 있으며, 필요한 경우 쿼리를 개선하고 프로세스를 반복할 수 있습니다.
  • 다중 에이전트 워크플로: LangGraph는 다중 에이전트 워크플로를 지원하도록 설계되었습니다. 이는 더 작은 하위 작업으로 나누어진 복잡한 작업을 해결하는 데 중요합니다. 공유 상태를 가진 다양한 에이전트와 다양한 LLM 및 도구가 협력하여 단일 작업을 해결할 수 있습니다.
  • 고리 안에 갇힌 사람: LangGraph에는 Human-in-the-Loop 워크플로가 내장되어 있습니다. 이는 사람이 다음 노드로 이동하기 전에 상태를 검토할 수 있음을 의미합니다.
  • 기획대행: LangGraph는 LLM 플래너가 사용자 요청을 계획 및 분해하고, 실행자가 도구 및 기능을 호출하고, LLM이 이전 출력을 기반으로 답변을 종합하는 플래닝 에이전트를 구축하는 데 매우 적합합니다.
  • 다중 모드 에이전트: LangGraph는 비전 지원 에이전트와 같은 다중 모드 에이전트를 구축할 수 있습니다. 웹 네비게이터.

실제 사용 사례

복잡한 AI 코딩 에이전트가 도움이 될 수 있는 분야는 많습니다. 

  1. 개인 에이전트질문: 전자 기기에 Jarvis와 같은 비서가 있어서 텍스트, 음성, 심지어 제스처를 통해 명령에 따라 작업을 도울 준비가 되어 있다고 상상해 보세요. 이는 AI 에이전트의 가장 흥미로운 용도 중 하나입니다!
  2. AI 강사: 챗봇은 훌륭하지만 한계가 있습니다. 적절한 도구를 갖춘 AI 에이전트는 기본적인 대화 이상의 기능을 수행할 수 있습니다. 사용자 피드백을 기반으로 교육 방법을 조정할 수 있는 가상 AI 강사는 판도를 바꿀 수 있습니다.
  3. 소프트웨어 UX: AI 에이전트를 통해 소프트웨어의 사용자 경험을 향상시킬 수 있습니다. 에이전트는 애플리케이션을 수동으로 탐색하는 대신 음성 또는 제스처 명령을 사용하여 작업을 수행할 수 있습니다.
  4. 공간 컴퓨팅: AR/VR 기술이 대중화되면서 AI 에이전트에 대한 수요도 늘어날 것입니다. 에이전트는 주변 정보를 처리하고 필요에 따라 작업을 실행할 수 있습니다. 이는 곧 AI 에이전트의 가장 좋은 사용 사례 중 하나가 될 수 있습니다.
  5. LLM OS: 에이전트가 일류 시민이 되는 AI 우선 운영 체제입니다. 에이전트는 일상적이고 복잡한 작업을 담당합니다.

결론

LangGraph는 순환 상태 저장 다중 행위자 에이전트 시스템을 구축하기 위한 효율적인 프레임워크입니다. 이는 원래 LangChain 프레임워크의 공백을 메웁니다. LangChain의 확장이기 때문에 우리는 LangChain 생태계의 모든 장점을 누릴 수 있습니다. LLM의 품질과 기능이 향상됨에 따라 복잡한 작업 흐름을 자동화하기 위한 에이전트 시스템을 만드는 것이 훨씬 쉬워질 것입니다. 따라서 기사의 주요 내용은 다음과 같습니다. 

주요 요점

  • LangGraph는 LangChain의 확장으로, 이를 통해 주기적, 상태 저장, 다중 행위자 에이전트 시스템을 구축할 수 있습니다.
  • 노드와 간선으로 그래프 구조를 구현합니다. 노드는 기능이나 도구이고, 에지는 노드 간의 연결입니다.
  • 가장자리에는 조건부와 일반의 두 가지 유형이 있습니다. 조건부 가장자리에는 서로 이동하는 동안 조건이 있으며 이는 워크플로에 순환성을 추가하는 데 중요합니다.
  • LangGraph는 순환 다중 행위자 에이전트를 구축하는 데 선호되는 반면 LangChain은 체인 또는 방향성 비순환 시스템을 생성하는 데 더 좋습니다.

자주 묻는 질문

Q1. 랭그래프란 무엇인가요?

답변. LangGraph는 상태 저장 순환 다중 행위자 에이전트 시스템을 구축하기 위한 오픈 소스 라이브러리입니다. 이는 LangChain 생태계 위에 구축되었습니다.

Q2. LangChain 대신 LangGraph를 언제 사용해야 합니까?

답변. LangGraph는 순환 다중 행위자 에이전트를 구축하는 데 선호되는 반면 LangChain은 체인 또는 방향성 비순환 시스템을 생성하는 데 더 좋습니다.

Q3. AI 에이전트란 ​​무엇인가요?

답변. AI 에이전트는 환경과 상호 작용하고, 결정을 내리고, 최종 목표를 달성하기 위해 행동하는 소프트웨어 프로그램입니다.

Q4. AI 에이전트와 함께 사용하기에 가장 좋은 LLM은 무엇입니까?

답변. 이는 사용 사례와 예산에 따라 다릅니다. GPT 4는 가장 유능하지만 비용이 많이 듭니다. 코딩의 경우 DeepSeekCoder-33b가 훨씬 저렴한 옵션입니다. 

Q5. 체인과 에이전트의 차이점은 무엇입니까?

답변. 체인은 따라야 할 하드 코딩된 일련의 작업이며, 에이전트는 LLM 및 기타 도구(체인이기도 함)를 사용하여 정보에 따라 추론하고 행동합니다.

이 기사에 표시된 미디어는 Analytics Vidhya의 소유가 아니며 작성자의 재량에 따라 사용됩니다.

spot_img

최신 인텔리전스

spot_img