07-langchain-tools

2024. 1. 17. 17:34langchain

건축 도구

LLM 에이전트는 ChatGPT 도입 이후 LLM이 폭발적으로 증가함에 따라 탄생한 가장 강력하고 매력적인 기술 중 하나입니다.

에이전트를 사용하면 LLM에게 도구에 대한 액세스 권한을 부여할 수 있습니다. 이러한 도구를 사용하면 웹 검색, 수학 계산, 코드 실행 등을 수행할 수 있으므로 본질적으로 무한한 가능성이 제공됩니다.

LangChain에서 사용할 수 있는 사전 구축된 도구가 많이 있지만 실제 시나리오에서는 사용 사례의 요구 사항에 맞는 맞춤형 도구를 구축해야 합니다.

시작하려면 이 노트북에서 사용할 필수 구성 요소 라이브러리를 설치해야 합니다.

In [ ]:
!python3 -m venv langchain
!source langchain/bin/activate

!pip install -qU langchain openai transformers

맞춤 도구를 구축하는 방법을 살펴보겠습니다. 도구 구축 프로세스의 흐름을 이해할 수 있도록 몇 가지 간단한 예부터 시작하겠습니다.

간단한 계산기 도구

다음과 같이 정의할 매우 간단한 원주 계산 도구부터 시작하겠습니다.

In [ ]:
from langchain.tools import BaseTool
from math import pi
from typing import Union


class CircumferenceTool(BaseTool):
    name = "원주 계산기"
    description = "use this tool when you need to calculate a circumference using the radius of a circle"

    def _run(self, radius: Union[int, float]):
        return float(radius)*2.0*pi
    
    def _arun(self, radius: Union[int, float]):
        raise NotImplementedError("This tool does not support async")

BaseTool 템플릿을 사용하여 이와 같은 도구를 정의할 때 name 및 description 속성을 ​​정의해야 합니다. 지금은 비동기적으로 메소드는 도구가 메소드가 기본적으로 호출됩니다.

에이전트 LLM과 대화 메모리를 초기화해야 합니다. LLM의 경우 OpenAI의 gpt-3.5-turbo을 사용합니다.

In [ ]:
import os
from langchain.chat_models import ChatOpenAI
from langchain.chains.conversation.memory import ConversationBufferWindowMemory

OPENAI_API_KEY = os.environ.get('OPENAI_API_KEY') or 'OPENAI_API_KEY'

# initialize LLM (we use ChatOpenAI because we'll later define a `chat` agent)
llm = ChatOpenAI(
    openai_api_key=OPENAI_API_KEY,
    temperature=0,
    model_name='gpt-3.5-turbo'
)
# initialize conversational memory
conversational_memory = ConversationBufferWindowMemory(
    memory_key='chat_history',
    k=5,
    return_messages=True
)

이제 에이전트 자체를 초기화합니다. 위에서 정의한 원주 도구를 사용하려면 해당 도구를 목록에 추가한 다음 initialize_agent 내의 tools 매개변수에 전달해야 합니다.

In [ ]:
from langchain.agents import initialize_agent

tools = [CircumferenceTool()]

# initialize agent with tools
agent = initialize_agent(
    agent='chat-conversational-react-description',
    tools=tools,
    llm=llm,
    verbose=True,
    max_iterations=3,
    early_stopping_method='generate',
    memory=conversational_memory
)

이제 원의 둘레를 계산하도록 요청해 보겠습니다.

In [ ]:
agent("can you calculate the circumference of a circle that has a radius of 7.81mm")
In [ ]:
(7.81 * 2) * pi

대답은 정답에 가깝지만 정확하지는 않습니다. 위의 출력에서 ​​모델이 원주 계산기 도구를 사용하지 않기로 결정했음을 알 수 있습니다. 이는 모델이 질문에 답할 수 있는 능력에 (거짓) 자신감을 갖고 있기 때문입니다.

이 문제를 해결하려면 프롬프트에서 모델에게 할 수 없음을 알려야 합니다.

In [ ]:
# existing prompt
print(agent.agent.llm_chain.prompt.messages[0].prompt.template)

LLM이 수학에 형편없다 라는 점을 강조하기 위해 기존 시스템 메시지를 수정해 보겠습니다.

In [ ]:
sys_msg = """Assistant is a large language model trained by OpenAI.

Assistant is designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, Assistant is able to generate human-like text based on the input it receives, allowing it to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.

Assistant is constantly learning and improving, and its capabilities are constantly evolving. It is able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. Additionally, Assistant is able to generate its own text based on the input it receives, allowing it to engage in discussions and provide explanations and descriptions on a wide range of topics.

Unfortunately, Assistant is terrible at maths. When provided with math questions, no matter how simple, assistant always refers to it's trusty tools and absolutely does NOT try to answer math questions by itself

Overall, Assistant is a powerful system that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether you need help with a specific question or just want to have a conversation about a particular topic, Assistant is here to assist.
"""

그리고 프롬프트를 업데이트하세요.

In [ ]:
new_prompt = agent.agent.create_prompt(
    system_message=sys_msg,
    tools=tools
)

agent.agent.llm_chain.prompt = new_prompt

이제 다시 시도해 보겠습니다.

In [ ]:
agent("can you calculate the circumference of a circle that has a radius of 7.81mm")

이제 모델은 원주 계산기를 사용하여 정답을 얻습니다.m

여러 매개변수가 있는 도구

도구는 여러 매개변수를 처리할 수도 있습니다. 피타고라스 도구를 만들어 보겠습니다. 이 도구는 변의 길이 및/또는 각도의 조합이 주어지면 삼각형의 빗변을 계산하는 데 도움이 됩니다.

In [ ]:
from typing import Optional
from math import sqrt, cos, sin

desc = (
    "use this tool when you need to calculate the length of an hypotenuse "
    "given one or two sides of a triangle and/or an angle (in degrees). "
    "To use the tool you must provide at least two of the following parameters "
    "['adjacent_side', 'opposite_side', 'angle']."
)

class PythagorasTool(BaseTool):
    name = "Hypotenuse calculator"
    description = desc

    def _run(
        self,
        adjacent_side: Optional[Union[int, float]] = None,
        opposite_side: Optional[Union[int, float]] = None,
        angle: Optional[Union[int, float]] = None
    ):
        # check for the values we have been given
        if adjacent_side and opposite_side:
            return sqrt(float(adjacent_side)**2 + float(opposite_side)**2)
        elif adjacent_side and angle:
            return adjacent_side / cos(float(angle))
        elif opposite_side and angle:
            return opposite_side / sin(float(angle))
        else:
            return "Could not calculate the hypotenuse of the triangle. Need two or more of `adjacent_side`, `opposite_side`, or `angle`."
    
    def _arun(self, query: str):
        raise NotImplementedError("This tool does not support async")

tools = [PythagorasTool()]
In [ ]:
new_prompt = agent.agent.create_prompt(
    system_message=sys_msg,
    tools=tools
)

agent.agent.llm_chain.prompt = new_prompt
# update the agent tools
agent.tools = tools
In [ ]:
agent("두 변의 길이가 51cm, 34cm인 삼각형이 있는 경우, 빗변의 길이는 얼마입니까")

더욱 발전된 도구 사용법

우리는 매우 간단한 도구의 두 가지 간단한 예를 만들었습니다. 대부분의 시나리오에서 우리는 좀 더 복잡한 작업을 수행하고 싶을 것이므로 좀 더 흥미로운 작업을 만들어 보겠습니다.

우리는 Hugging GPT 문서에서 영감을 얻을 것입니다. 여기서는 본질적으로 다양한 작업을 위해 훈련된 오픈 소스 모델의 앙상블이 무엇인지 다른 사람들에게 설명합니다. , 이는 LLM에 의해 제어됩니다. 이 예에서는 Salesforce/blip-image-captioning-large.라는 이미지에 캡션을 추가할 수 있는 기존 오픈 소스 모델 중 하나를 사용하겠습니다.

In [ ]:
import torch
from transformers import BlipProcessor, BlipForConditionalGeneration

hf_model = "Salesforce/blip-image-captioning-large"
device = 'cuda' if torch.cuda.is_available() else 'cpu'

processor = BlipProcessor.from_pretrained(hf_model)
model = BlipForConditionalGeneration.from_pretrained(hf_model).to(device)

이미지에 대한 캡션을 생성하려면 먼저 해당 이미지를 다운로드하여 PIL 이미지 개체로 열어야 합니다.

In [ ]:
import requests
from PIL import Image

img_url = 'https://images.unsplash.com/photo-1616128417859-3a984dd35f02?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2372&q=80' 
image = Image.open(requests.get(img_url, stream=True).raw).convert('RGB')
image

이제 모델을 사용하여 이미지를 처리하고 processor model.generate를 사용하여 캡션을 생성합니다.

In [ ]:
# unconditional image captioning
inputs = processor(image, return_tensors="pt").to(device)

out = model.generate(**inputs, max_new_tokens=20)
print(processor.decode(out[0], skip_special_tokens=True))

완벽합니다. 이 프로세스를 새로운 이미지 캡션 도구의 논리로 사용할 수 있습니다. 먼저 도구 클래스를 정의해 보겠습니다.

In [ ]:
desc = (
    "use this tool when given the URL of an image that you'd like to be "
    "described. It will return a simple caption describing the image."
)

class ImageCaptionTool(BaseTool):
    name = "Image captioner"
    description = desc

    def _run(self, url: str):
        # download the image and convert to PIL object
        image = Image.open(requests.get(img_url, stream=True).raw).convert('RGB')
        # preprocess the image
        inputs = processor(image, return_tensors="pt").to(device)
        # generate the caption
        out = model.generate(**inputs, max_new_tokens=20)
        # get the caption
        caption = processor.decode(out[0], skip_special_tokens=True)
        return caption
    
    def _arun(self, query: str):
        raise NotImplementedError("This tool does not support async")

tools = [ImageCaptionTool()]

에이전트 프롬프트를 다시 초기화하고 새 도구 목록을 반영하도록 tools 속성을 ​​설정해 보겠습니다.

In [ ]:
sys_msg = """Assistant is a large language model trained by OpenAI.

Assistant is designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, Assistant is able to generate human-like text based on the input it receives, allowing it to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.

Assistant is constantly learning and improving, and its capabilities are constantly evolving. It is able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. Additionally, Assistant is able to generate its own text based on the input it receives, allowing it to engage in discussions and provide explanations and descriptions on a wide range of topics.

Overall, Assistant is a powerful system that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether you need help with a specific question or just want to have a conversation about a particular topic, Assistant is here to assist.
"""

new_prompt = agent.agent.create_prompt(
    system_message=sys_msg,
    tools=tools
)

agent.agent.llm_chain.prompt = new_prompt
# update the agent tools
agent.tools = tools
In [ ]:
agent(f"What does this image show?\n{img_url}")

조금 더 시도해 볼까요.

In [ ]:
img_url = "https://images.unsplash.com/photo-1502680390469-be75c86b636f?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2370&q=80"
image = Image.open(requests.get(img_url, stream=True).raw).convert('RGB')
image
In [ ]:
agent(f"what is in this image?\n{img_url}")
In [ ]:
img_url = "https://images.unsplash.com/photo-1680382948929-2d092cd01263?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2365&q=80"
image = Image.open(requests.get(img_url, stream=True).raw).convert('RGB')
image
In [ ]:
agent(f"what is in this image?\n{img_url}")

상당히 좋아 보입니다. 당연히 훨씬 더 복잡한 도구를 구축하거나 단순히 에이전트에 새 도구를 추가할 수 있습니다.

 

출처 : https://github.com/pinecone-io/examples/blob/master/learn/generation/langchain/handbook/07-langchain-tools.ipynb

 

'langchain' 카테고리의 다른 글

10-langchain-multi-query  (0) 2024.01.19
08-langchain-retrieval-agent  (0) 2024.01.18
03-1-langchain-conversational-memory  (1) 2024.01.16
09-langchain-streaming  (0) 2024.01.15
06-langchain-agents  (1) 2024.01.14