LangChain을 활용한 Tool Calling # 1

2024. 11. 29. 02:30·AI/어플리케이션 개발

자연어 처리와 대화형 AI 모델을 통해 복잡한 문제를 해결하려면, 단순히 언어를 이해하는 것을 넘어서 다양한 툴을 활용할 필요가 있습니다. LangChain은 이러한 필요성을 충족시킬 수 있는 프레임워크로, 특히 Tool Calling 기능을 통해 외부 데이터와의 상호작용을 쉽게 만들어 줍니다. 이 글에서는 LangChain을 활용한 Tool Calling의 작동 원리와 실제 사용 방법을 구체적인 예제를 통해 소개하겠습니다.

 


 

LangChain이란?

LangChain은 자연어 처리 모델을 좀 더 강력하고 유연하게 사용할 수 있게 도와주는 Python 기반의 오픈소스 프레임워크입니다. 이 프레임워크는 AI 모델과 다양한 외부 도구를 연결하는 데 초점을 맞추고 있어, AI 모델이 API 호출, 데이터베이스 쿼리, 계산 작업 등을 직접 수행하도록 할 수 있습니다. Tool Calling은 이러한 외부 툴들과의 상호작용을 통해 문제를 해결하는 데 사용되는 LangChain의 핵심 기능 중 하나입니다. LangChain에 대한 추가적인 정보는 블로그의 이전 포스트를 참고해주세요.

 

LLM 애플리케이션 개발 훑어보기 - LangChain #1 Intro 및 QuickStart

Introduction LangChain은 인공 지능(AI) 및 그 기계 학습 하위 집합으로 작업하는 소프트웨어 개발자가 대규모 언어 모델을 다른 외부 구성 요소와 결합하여 LLM 기반 애플리케이션을 개발할 수 있는 오

dytis.tistory.com

 

Tool Calling의 개념

Tool Calling은 말 그대로 특정 작업을 수행할 수 있는 툴을 호출하는 것을 의미합니다. 예를 들어, AI가 날씨 정보를 제공해야 할 때, AI가 직접 날씨 API를 호출하여 사용자가 원하는 정보를 전달하는 방식입니다. LangChain을 통해 LLM(Large Language Model)이 직접 툴을 호출하고, 그 결과를 사용하여 사용자에게 답변을 제공할 수 있습니다. Tool Calling에 대한 추가적인 정보는 블로그의 이전 포스트를 참고해주세요.

 

LLM 어플리케이션에서의 Tool Calling: AI가 더 똑똑해지는 방법

LLM(대형 언어 모델) 어플리케이션이 갈수록 더 많은 일들을 할 수 있게 되면서, "Tool calling" 기능은 그중에서도 가장 주목할 만한 혁신 중 하나로 자리 잡고 있습니다. 이 기능은 AI가 외부의 도구

dytis.tistory.com

 


 

How to: create tools

 

How to create tools | 🦜️🔗 LangChain

When constructing an agent, you will need to provide it with a list of Tools that it can use. Besides the actual function that is called, the Tool consists of several components:

python.langchain.com

 

에이전트를 구성할 때는 에이전트가 사용할 수 있는 도구 목록을 제공해야 합니다. 호출되는 실제 함수 외에도 도구는 여러 구성 요소로 구성됩니다.

속성 (Attribute) 타입 (Type) 설명 (Description)
name str LLM 또는 에이전트에 제공된 툴 세트 내에서 고유해야 합니다.
description str 툴이 무엇을 하는지 설명합니다. LLM이나 에이전트가 컨텍스트로 사용합니다.
args_schema pydantic.BaseModel 선택 사항이지만 권장되며, 콜백 핸들러를 사용하는 경우 필수입니다. 예상되는 매개변수에 대한 정보(예: few-shot 예시) 또는 유효성 검사를 제공할 수 있습니다.
return_direct boolean 에이전트에만 관련이 있습니다. True일 경우, 툴을 호출한 후 에이전트는 결과를 사용자에게 직접 반환하고 멈춥니다.

 

LangChain은 다음을 통해 도구 생성을 지원합니다:

  • 함수(Function);
  • LangChain Runnables;
  • BaseTool을 서브클래싱하여 구현 -- 이 방법은 가장 유연하지만, 더 많은 노력과 코드가 필요합니다.

대부분의 경우 함수에서 도구를 생성하는 것으로 충분하며, 간단한 @tool 데코레이터를 통해 이를 수행할 수 있습니다. 더 많은 설정이 필요한 경우(예: 동기 및 비동기 구현 모두 지정) StructuredTool.from_function 클래스 메서드를 사용할 수 있습니다.

 

함수에서 Tool 생성하기: @tool decorator

@tool 데코레이터는 사용자 정의 도구를 정의하는 가장 간단한 방법입니다. 기본적으로 함수 이름을 도구 이름으로 사용하지만, 첫 번째 인수로 문자열을 전달하여 이를 재정의할 수 있습니다. 또한, 함수의 docstring을 도구의 설명으로 사용하므로 반드시 docstring을 제공해야 합니다.

from langchain_core.tools import tool


@tool
def multiply(a: int, b: int) -> int:
    """Multiply two numbers."""
    return a * b


# Let's inspect some of the attributes associated with the tool.
print(multiply.name)
print(multiply.description)
print(multiply.args)

 

비동기 구현을 생성하려면, 다음과 같이 작성할 수 있습니다:

from langchain_core.tools import tool


@tool
async def amultiply(a: int, b: int) -> int:
    """Multiply two numbers."""
    return a * b

 

@tool은 annotations, nested schemas 및 기타 기능의 파싱을 지원합니다:

from typing import Annotated, List


@tool
def multiply_by_max(
    a: Annotated[str, "scale factor"],
    b: Annotated[List[int], "list of ints over which to take maximum"],
) -> int:
    """Multiply a by the maximum of b."""
    return a * max(b)


multiply_by_max.args_schema.schema()

 

도구 이름과 JSON 인수를 tool 데코레이터에 전달하여 커스터마이징할 수도 있습니다.

from pydantic import BaseModel, Field


class CalculatorInput(BaseModel):
    a: int = Field(description="first number")
    b: int = Field(description="second number")


@tool("multiplication-tool", args_schema=CalculatorInput, return_direct=True)
def multiply(a: int, b: int) -> int:
    """Multiply two numbers."""
    return a * b


# Let's inspect some of the attributes associated with the tool.
print(multiply.name)
print(multiply.description)
print(multiply.args)
print(multiply.return_direct)

 

Docstring parsing

@tool은 선택적으로 Google Style docstring을 구문 분석하고 docstring 구성 요소(예: arg 설명)를 도구 스키마의 관련 부분에 연결할 수 있습니다:

@tool(parse_docstring=True)
def foo(bar: str, baz: int) -> str:
    """The foo.

    Args:
        bar: The bar.
        baz: The baz.
    """
    return bar


foo.args_schema.schema()

 

 

함수에서 Tool 생성하기: StructuredTool

StructuredTool.from_function 클래스 메서드는 추가 코드를 크게 필요로 하지 않고도 @tool 데코레이터보다 좀 더 많은 구성 가능성을 제공합니다.

from langchain_core.tools import StructuredTool


def multiply(a: int, b: int) -> int:
    """Multiply two numbers."""
    return a * b


async def amultiply(a: int, b: int) -> int:
    """Multiply two numbers."""
    return a * b


calculator = StructuredTool.from_function(func=multiply, coroutine=amultiply)

print(calculator.invoke({"a": 2, "b": 3}))
print(await calculator.ainvoke({"a": 2, "b": 5}))

 

class CalculatorInput(BaseModel):
    a: int = Field(description="first number")
    b: int = Field(description="second number")


def multiply(a: int, b: int) -> int:
    """Multiply two numbers."""
    return a * b


calculator = StructuredTool.from_function(
    func=multiply,
    name="Calculator",
    description="multiply numbers",
    args_schema=CalculatorInput,
    return_direct=True,
    # coroutine= ... <- you can specify an async method if desired as well
)

print(calculator.invoke({"a": 2, "b": 3}))
print(calculator.name)
print(calculator.description)
print(calculator.args)

 

 

Runnables에서 tool 생성하기

문자열이나 사전 입력을 허용하는 LangChain Runnables는 as_tool 메서드를 사용하여 도구로 변환할 수 있으며, 이를 통해 인수에 대한 이름, 설명 및 추가 스키마 정보를 지정할 수 있습니다.

from langchain_core.language_models import GenericFakeChatModel
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_messages(
    [("human", "Hello. Please respond in the style of {answer_style}.")]
)

# Placeholder LLM
llm = GenericFakeChatModel(messages=iter(["hello matey"]))

chain = prompt | llm | StrOutputParser()

as_tool = chain.as_tool(
    name="Style responder", description="Description of when to use tool."
)
as_tool.args

 

 

Subclass BaseTool

BaseTool에서 하위 클래스화하여 사용자 정의 도구를 정의할 수 있습니다. 이렇게 하면 도구 정의에 대한 최대 제어가 가능하지만 더 많은 코드를 작성해야 합니다.

from typing import Optional, Type

from langchain_core.callbacks import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain_core.tools import BaseTool
from pydantic import BaseModel, Field


class CalculatorInput(BaseModel):
    a: int = Field(description="first number")
    b: int = Field(description="second number")


# Note: It's important that every field has type hints. BaseTool is a
# Pydantic class and not having type hints can lead to unexpected behavior.
class CustomCalculatorTool(BaseTool):
    name: str = "Calculator"
    description: str = "useful for when you need to answer questions about math"
    args_schema: Type[BaseModel] = CalculatorInput
    return_direct: bool = True

    def _run(
        self, a: int, b: int, run_manager: Optional[CallbackManagerForToolRun] = None
    ) -> str:
        """Use the tool."""
        return a * b

    async def _arun(
        self,
        a: int,
        b: int,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        # If the calculation is cheap, you can just delegate to the sync implementation
        # as shown below.
        # If the sync calculation is expensive, you should delete the entire _arun method.
        # LangChain will automatically provide a better implementation that will
        # kick off the task in a thread to make sure it doesn't block other async code.
        return self._run(a, b, run_manager=run_manager.get_sync())

multiply = CustomCalculatorTool()
print(multiply.name)
print(multiply.description)
print(multiply.args)
print(multiply.return_direct)

print(multiply.invoke({"a": 2, "b": 3}))
print(await multiply.ainvoke({"a": 2, "b": 3}))

 

 

Handling Tool Errors

에이전트와 함께 도구를 사용하는 경우, 에이전트가 오류를 복구하고 실행을 계속할 수 있도록 오류 처리 전략이 필요할 수 있습니다. 간단한 전략으로는 도구 내부에서 ToolException을 발생시키고 handle_tool_error를 사용하여 오류 핸들러를 지정하는 것입니다. 오류 핸들러가 지정되면, 예외가 잡히고 오류 핸들러가 도구에서 반환할 출력을 결정하게 됩니다.

handle_tool_error를 True, 문자열 값, 또는 함수로 설정할 수 있습니다. 함수인 경우, 해당 함수는 ToolException을 매개변수로 받아 값을 반환해야 합니다. 단순히 ToolException을 발생시키는 것만으로는 효과가 없다는 점에 유의해야 합니다. 도구의 handle_tool_error를 먼저 설정해야 하며, 기본값은 False입니다.

from langchain_core.tools import ToolException


def get_weather(city: str) -> int:
    """Get weather for the given city."""
    raise ToolException(f"Error: There is no city by the name of {city}.")

또한, 에러를 함수를 사용하여 처리할 수 있습니다.

 

 

Returning artifacts of Tool execution

때때로 도구의 실행 결과에서 체인 또는 에이전트의 다운스트림 구성 요소에서 접근할 수 있게 하고 싶지만, 모델 자체에는 노출하고 싶지 않은 아티팩트가 존재할 수 있습니다. 예를 들어, 도구가 Document와 같은 사용자 정의 객체를 반환하는 경우, 해당 출력에 대한 뷰나 메타데이터를 모델에 전달하고 싶지만, 원시 출력을 모델에 전달하고 싶지 않을 수 있습니다. 동시에 이러한 전체 출력을 다른 곳에서, 예를 들어 다운스트림 도구에서 접근할 수 있기를 원할 수 있습니다.

Tool과 ToolMessage 인터페이스는 도구 출력 중 모델을 위한 부분(ToolMessage.content)과 모델 외부에서 사용하기 위한 부분(ToolMessage.artifact)을 구분할 수 있게 해줍니다.

도구에서 메시지 콘텐츠와 다른 아티팩트를 구분하도록 하려면 도구를 정의할 때 response_format="content_and_artifact"를 지정하고 (content, artifact) 튜플을 반환해야 합니다.

import random
from typing import List, Tuple

from langchain_core.tools import tool


@tool(response_format="content_and_artifact")
def generate_random_ints(min: int, max: int, size: int) -> Tuple[str, List[int]]:
    """Generate size random ints in the range [min, max]."""
    array = [random.randint(min, max) for _ in range(size)]
    content = f"Successfully generated array of {size} random ints in [{min}, {max}]."
    return content, array

 

ToolCall(도구 호출 모델에서 생성된 것과 같은)을 사용하여 도구를 호출하는 경우 도구에서 생성된 콘텐츠와 아티팩트가 모두 포함된 ToolMessage를 받게 됩니다

 

 

저작자표시

'AI > 어플리케이션 개발' 카테고리의 다른 글

LangChain을 활용한 Tool Calling # 3  (0) 2024.11.29
LangChain을 활용한 Tool Calling # 2  (3) 2024.11.29
LLM 어플리케이션에서의 Tool Calling: AI가 더 똑똑해지는 방법  (0) 2024.11.29
LLM 애플리케이션 개발 훑어보기 - LangChain #3 Model I/O  (1) 2024.01.23
LLM 애플리케이션 개발 훑어보기 - LangChain #2 LangChain Expression Language (LCEL)  (0) 2024.01.22
'AI/어플리케이션 개발' 카테고리의 다른 글
  • LangChain을 활용한 Tool Calling # 3
  • LangChain을 활용한 Tool Calling # 2
  • LLM 어플리케이션에서의 Tool Calling: AI가 더 똑똑해지는 방법
  • LLM 애플리케이션 개발 훑어보기 - LangChain #3 Model I/O
pfldy2850
pfldy2850
인공지능의 서비스화와 현실화에 관심이 많은 엔지니어입니다.
  • pfldy2850
    DEV.DY
    Github LinkedIn
  • 전체
    오늘
    어제
    • All (104)
      • AI (68)
        • 어플리케이션 개발 (11)
        • 모델 인퍼런스 (9)
        • 검색 시스템 (11)
        • MLOps (8)
        • 기술,논문 리뷰 (7)
        • Lecture notes (10)
        • 오픈소스 릴리즈 노트 (12)
      • Infra (4)
        • Kubernetes (1)
        • Service Mesh (1)
        • Service Proxy (1)
        • Storage (1)
      • Data Engineering (4)
        • Spark (3)
        • Kafka (1)
        • Delta Lake (0)
      • 컴퓨터 공학 (2)
        • 소프트웨어 공학 (2)
      • 개발 (15)
        • ReactJS (8)
        • NodeJS (2)
        • Python (3)
        • Pytorch (1)
        • git (1)
      • 영어공부 (2)
        • GPT로 영어 회화 공부 (2)
      • 활동 (2)
        • 2017 NDC (2)
      • 기타 (1)
      • 레거시 (6)
        • OS (6)
  • 인기 글

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
pfldy2850
LangChain을 활용한 Tool Calling # 1
상단으로

티스토리툴바