#
사용자 정의 도구와 프롬프트

Transformers와 관련하여 어떤 도구와 에이전트가 있는지 잘 모르신다면 Transformers Agents 페이지를 먼저 읽어보시기 바랍니다.

Transformers Agents는 실험 중인 API로 언제든지 변경될 수 있습니다. API 또는 기반 모델이 변경되기 쉽기 때문에 에이전트가 반환하는 결과도 달라질 수 있습니다.

에이전트에게 권한을 부여하고 새로운 작업을 수행하게 하려면 사용자 정의 도구와 프롬프트를 만들고 사용하는 것이 무엇보다 중요합니다. 이 가이드에서는 다음과 같은 내용을 살펴보겠습니다:

- 프롬프트를 사용자 정의하는 방법
- 사용자 정의 도구를 사용하는 방법
- 사용자 정의 도구를 만드는 방법

##
프롬프트를 사용자 정의하기

Transformers Agents에서 설명한 것처럼 에이전트는 `run()` 및 `chat()` 모드에서 실행할 수 있습니다. `run`(실행) 모드와 `chat`(채팅) 모드 모두 동일한 로직을 기반으로 합니다. 에이전트를 구동하는 언어 모델은 긴 프롬프트에 따라 조건이 지정되고, 중지 토큰에 도달할 때까지 다음 토큰을 생성하여 프롬프트를 완수합니다. `chat` 모드에서는 프롬프트가 이전 사용자 입력 및 모델 생성으로 연장된다는 점이 두 모드의 유일한 차이점입니다. 이를 통해 에이전트가 과거 상호작용에 접근할 수 있게 되므로 에이전트에게 일종의 메모리를 제공하는 셈입니다.

###
프롬프트의 구조

어떻게 프롬프트 사용자 정의를 잘 할 수 있는지 이해하기 위해 프롬프트의 구조를 자세히 살펴봅시다. 프롬프트는 크게 네 부분으로 구성되어 있습니다.

- 1. 도입: 에이전트가 어떻게 행동해야 하는지, 도구의 개념에 대한 설명.
- 2. 모든 도구에 대한 설명. 이는 런타임에 사용자가 정의/선택한 도구로 동적으로 대체되는 `<<all_tools>>` 토큰으로 정의됩니다.
- 3. 작업 예제 및 해당 솔루션 세트.
- 4. 현재 예제 및 해결 요청.

각 부분을 더 잘 이해할 수 있도록 짧은 버전을 통해 `run` 프롬프트가 어떻게 보이는지 살펴보겠습니다:

    I will ask you to perform a task, your job is to come up with a series of simple commands in Python that will perform the task.
    [...]
    You can print intermediate results if it makes sense to do so.

    Tools:
    - document_qa: This is a tool that answers a question about a document (pdf). It takes an input named `document` which should be the document containing the information, as well as a `question` that is the question about the document. It returns a text that contains the answer to the question.
    - image_captioner: This is a tool that generates a description of an image. It takes an input named `image` which should be the image to the caption and returns a text that contains the description in English.
    [...]

    Task: "Answer the question in the variable `question` about the image stored in the variable `image`. The question is in French."

    I will use the following tools: `translator` to translate the question into English and then `image_qa` to answer the question on the input image.

    Answer:
    ```py
    translated_question = translator(question=question, src_lang="French", tgt_lang="English")
    print(f"The translated question is {translated_question}.")
    answer = image_qa(image=image, question=translated_question)
    print(f"The answer is {answer}")
    ```

    Task: "Identify the oldest person in the `document` and create an image showcasing the result as a banner."

    I will use the following tools: `document_qa` to find the oldest person in the document, then `image_generator` to generate an image according to the answer.

    Answer:
    ```py
    answer = document_qa(document, question="What is the oldest person?")
    print(f"The answer is {answer}.")
    image = image_generator("A banner showing " + answer)
    ```

    [...]

    Task: "Draw me a picture of rivers and lakes"

    I will use the following

도입(“도구:” 앞의 텍스트)에서는 모델이 어떻게 작동하고 무엇을 해야 하는지 정확하게 설명합니다. 에이전트는 항상 같은 방식으로 작동해야 하므로 이 부분은 사용자 정의할 필요가 없을 가능성이 높습니다.

두 번째 부분(“도구” 아래의 글머리 기호)은 `run` 또는 `chat`을 호출할 때 동적으로 추가됩니다. 정확히 `agent.toolbox`에 있는 도구 수만큼 글머리 기호가 있고, 각 글머리 기호는 도구의 이름과 설명으로 구성됩니다:

    - <tool.name>: <tool.description>

문서 질의응답 도구를 가져오고 이름과 설명을 출력해서 빠르게 확인해 보겠습니다.

    from transformers import load_tool

    document_qa = load_tool("document-question-answering")
    print(f"- {document_qa.name}: {document_qa.description}")

그러면 다음 결과가 출력됩니다:

    - document_qa: This is a tool that answers a question about a document (pdf). It takes an input named `document` which should be the document containing the information, as well as a `question` that is the question about the document. It returns a text that contains the answer to the question.

여기서 도구 이름이 짧고 정확하다는 것을 알 수 있습니다. 설명은 두 부분으로 구성되어 있는데, 첫 번째 부분에서는 도구의 기능을 설명하고 두 번째 부분에서는 예상되는 입력 인수와 반환 값을 명시합니다.

에이전트가 도구를 올바르게 사용하려면 좋은 도구 이름과 도구 설명이 매우 중요합니다. 에이전트가 도구에 대해 알 수 있는 유일한 정보는 이름과 설명뿐이므로, 이 두 가지를 정확하게 작성하고 도구 상자에 있는 기존 도구의 스타일과 일치하는지 확인해야 합니다. 특히 이름에 따라 예상되는 모든 인수가 설명에 코드 스타일로 언급되어 있는지, 예상되는 유형과 그 유형이 무엇인지에 대한 설명이 포함되어 있는지 확인하세요.

도구에 어떤 이름과 설명이 있어야 하는지 이해하려면 엄선된 Transformers 도구의 이름과 설명을 확인하세요. `Agent.toolbox` 속성을 가진 모든 도구를 볼 수 있습니다.

세 번째 부분에는 에이전트가 어떤 종류의 사용자 요청에 대해 어떤 코드를 생성해야 하는지 정확하게 보여주는 엄선된 예제 세트가 포함되어 있습니다. 에이전트를 지원하는 대규모 언어 모델은 프롬프트에서 패턴을 인식하고 새로운 데이터로 패턴을 반복하는 데 매우 능숙합니다. 따라서 에이전트가 실제로 올바른 실행 가능한 코드를 생성할 가능성을 극대화하는 방식으로 예제를 작성하는 것이 매우 중요합니다.

한 가지 예를 살펴보겠습니다:

    Task: "Identify the oldest person in the `document` and create an image showcasing the result as a banner."

    I will use the following tools: `document_qa` to find the oldest person in the document, then `image_generator` to generate an image according to the answer.

    Answer:
    ```py
    answer = document_qa(document, question="What is the oldest person?")
    print(f"The answer is {answer}.")
    image = image_generator("A banner showing " + answer)
    ```

작업 설명, 에이전트가 수행하려는 작업에 대한 설명, 마지막으로 생성된 코드, 이 세 부분으로 구성된 프롬프트는 모델에 반복하여 제공됩니다. 프롬프트의 일부인 모든 예제는 이러한 정확한 패턴으로 되어 있으므로, 에이전트가 새 토큰을 생성할 때 정확히 동일한 패턴을 재현할 수 있습니다.

프롬프트 예제는 Transformers 팀이 선별하고 일련의 problem statements에 따라 엄격하게 평가하여 에이전트의 프롬프트가 에이전트의 실제 사용 사례를 최대한 잘 해결할 수 있도록 보장합니다.

프롬프트의 마지막 부분은 다음에 해당합니다:

    Task: "Draw me a picture of rivers and lakes"

    I will use the following

이는 에이전트가 완료해야 할 최종적인 미완성 예제입니다. 미완성 예제는 실제 사용자 입력에 따라 동적으로 만들어집니다. 위 예시의 경우 사용자가 다음과 같이 실행했습니다:

    agent.run("Draw me a picture of rivers and lakes")

사용자 입력 - 즉 Task: “Draw me a picture of rivers and lakes”가 프롬프트 템플릿에 맞춰 “Task: <task> \n\n I will use the following”로 캐스팅됩니다. 이 문장은 에이전트에게 조건이 적용되는 프롬프트의 마지막 줄을 구성하므로 에이전트가 이전 예제에서 수행한 것과 정확히 동일한 방식으로 예제를 완료하도록 강력하게 영향을 미칩니다.

너무 자세히 설명하지 않더라도 채팅 템플릿의 프롬프트 구조는 동일하지만 예제의 스타일이 약간 다릅니다. 예를 들면:

    [...]

    =====

    Human: Answer the question in the variable `question` about the image stored in the variable `image`.

    Assistant: I will use the tool `image_qa` to answer the question on the input image.

    ```py
    answer = image_qa(text=question, image=image)
    print(f"The answer is {answer}")
    ```

    Human: I tried this code, it worked but didn't give me a good result. The question is in French

    Assistant: In this case, the question needs to be translated first. I will use the tool `translator` to do this.

    ```py
    translated_question = translator(question=question, src_lang="French", tgt_lang="English")
    print(f"The translated question is {translated_question}.")
    answer = image_qa(text=translated_question, image=image)
    print(f"The answer is {answer}")
    ```

    =====

    [...]

`run` 프롬프트의 예와는 반대로, 각 `chat` 프롬프트의 예에는 Human(사람)과 Assistant(어시스턴트) 간에 하나 이상의 교환이 있습니다. 모든 교환은 `run` 프롬프트의 예와 유사한 구조로 되어 있습니다. 사용자의 입력이 Human: 뒤에 추가되며, 에이전트에게 코드를 생성하기 전에 수행해야 할 작업을 먼저 생성하라는 메시지가 표시됩니다. 교환은 이전 교환을 기반으로 할 수 있으므로 위와 같이 사용자가 ”이 코드를 시도했습니다”라고 입력하면 이전에 생성된 에이전트의 코드를 참조하여 과거 교환을 참조할 수 있습니다.

`.chat`을 실행하면 사용자의 입력 또는 작업이 미완성된 양식의 예시로 캐스팅됩니다:

    Human: <user-input>\n\nAssistant:

그러면 에이전트가 이를 완성합니다. `run` 명령과 달리 `chat` 명령은 완료된 예제를 프롬프트에 추가하여 에이전트에게 다음 `chat` 차례에 대한 더 많은 문맥을 제공합니다.

이제 프롬프트가 어떻게 구성되어 있는지 알았으니 어떻게 사용자 정의할 수 있는지 살펴봅시다!

###
좋은 사용자 입력 작성하기

대규모 언어 모델이 사용자의 의도를 이해하는 능력이 점점 더 향상되고 있지만, 에이전트가 올바른 작업을 선택할 수 있도록 최대한 정확성을 유지하는 것은 큰 도움이 됩니다. 최대한 정확하다는 것은 무엇을 의미할까요?

에이전트는 프롬프트에서 도구 이름 목록과 해당 설명을 볼 수 있습니다. 더 많은 도구가 추가될수록 에이전트가 올바른 도구를 선택하기가 더 어려워지고 실행할 도구의 올바른 순서를 선택하는 것은 더욱 어려워집니다. 일반적인 실패 사례를 살펴보겠습니다. 여기서는 분석할 코드만 반환하겠습니다.

    from transformers import HfAgent

    agent = HfAgent("https://api-inference.huggingface.co/models/bigcode/starcoder")

    agent.run("Show me a tree", return_code=True)

그러면 다음 결과가 출력됩니다:

    ==Explanation from the agent==
    I will use the following tool: `image_segmenter` to create a segmentation mask for the image.

    ==Code generated by the agent==
    mask = image_segmenter(image, prompt="tree")

우리가 원했던 결과가 아닐 수도 있습니다. 대신 나무 이미지가 생성되기를 원할 가능성이 더 높습니다. 따라서 에이전트가 특정 도구를 사용하도록 유도하려면 도구의 이름과 설명에 있는 중요한 키워드를 사용하는 것이 매우 유용할 수 있습니다. 한번 살펴보겠습니다.

    agent.toolbox["image_generator"].description

    'This is a tool that creates an image according to a prompt, which is a text description. It takes an input named `prompt` which contains the image description and outputs an image.

이름과 설명은 “image”, “prompt”, “create” 및 “generate” 키워드를 사용합니다. 이 단어들을 사용하면 더 잘 작동할 가능성이 높습니다. 프롬프트를 조금 더 구체화해 보겠습니다.

    agent.run("Create an image of a tree", return_code=True)

이 코드는 다음 프롬프트를 만들어냅니다:

    ==Explanation from the agent==
    I will use the following tool `image_generator` to generate an image of a tree.

    ==Code generated by the agent==
    image = image_generator(prompt="tree")

훨씬 낫네요! 저희가 원했던 것과 비슷해 보입니다. 즉, 에이전트가 작업을 올바른 도구에 올바르게 매핑하는 데 어려움을 겪고 있다면 도구 이름과 설명에서 가장 관련성이 높은 키워드를 찾아보고 이를 통해 작업 요청을 구체화해 보세요.

###
도구 설명 사용자 정의하기

앞서 살펴본 것처럼 에이전트는 각 도구의 이름과 설명에 액세스할 수 있습니다. 기본 도구에는 매우 정확한 이름과 설명이 있어야 하지만 특정 사용 사례에 맞게 도구의 설명이나 이름을 변경하는 것이 도움이 될 수도 있습니다. 이는 매우 유사한 여러 도구를 추가했거나 특정 도메인(예: 이미지 생성 및 변환)에만 에이전트를 사용하려는 경우에 특히 중요해질 수 있습니다.

일반적인 문제는 이미지 생성 작업에 많이 사용되는 경우 에이전트가 이미지 생성과 이미지 변환/수정을 혼동하는 것입니다. 예를 들어,

    agent.run("Make an image of a house and a car", return_code=True)

그러면 다음 결과가 출력됩니다:

    ==Explanation from the agent==
    I will use the following tools `image_generator` to generate an image of a house and `image_transformer` to transform the image of a car into the image of a house.

    ==Code generated by the agent==
    house_image = image_generator(prompt="A house")
    car_image = image_generator(prompt="A car")
    house_car_image = image_transformer(image=car_image, prompt="A house")

결과물이 우리가 여기서 원하는 것과 정확히 일치하지 않을 수 있습니다. 에이전트가 `image_generator`와 `image_transformer`의 차이점을 이해하기 어려워서 두 가지를 함께 사용하는 경우가 많은 것 같습니다.

여기서 `image_transformer`의 도구 이름과 설명을 변경하여 에이전트가 도울 수 있습니다. “image” 및 “prompt”와 약간 분리하기 위해 `modifier`라고 대신 부르겠습니다:

    agent.toolbox["modifier"] = agent.toolbox.pop("image_transformer")
    agent.toolbox["modifier"].description = agent.toolbox["modifier"].description.replace(
        "transforms an image according to a prompt", "modifies an image"
    )

이제 “modify”은 새 이미지 프로세서를 사용하라는 강력한 신호이므로 위의 프롬프트에 도움이 될 것입니다. 다시 실행해 봅시다.

    agent.run("Make an image of a house and a car", return_code=True)

여기서 다음과 같은 결과를 얻게 됩니다:

    ==Explanation from the agent==
    I will use the following tools: `image_generator` to generate an image of a house, then `image_generator` to generate an image of a car.

    ==Code generated by the agent==
    house_image = image_generator(prompt="A house")
    car_image = image_generator(prompt="A car")

우리가 염두에 두었던 것과 확실히 더 가까워졌습니다! 하지만 집과 자동차가 모두 같은 이미지에 포함되면 좋겠습니다. 작업을 단일 이미지 생성에 더 집중하면 도움이 될 것입니다:

    agent.run("Create image: 'A house and car'", return_code=True)

    ==Explanation from the agent==
    I will use the following tool: `image_generator` to generate an image.

    ==Code generated by the agent==
    image = image_generator(prompt="A house and car")

에이전트는 여전히 특히 여러 개체의 이미지를 생성하는 것과 같이 약간 더 복잡한 사용 사례에서 취약한 경우가 많습니다. 앞으로 몇 달 안에 에이전트 자체와 기본 프롬프트가 더욱 개선되어 에이전트가 다양한 사용자 입력에 더욱 강력하게 대응할 수 있도록 할 예정입니다.

###
전체 프롬프트 사용자 정의하기

사용자에게 최대한의 유연성을 제공하기 위해 위에 설명된 전체 프롬프트 템플릿을 사용자가 덮어쓸 수 있습니다. 이 경우 사용자 정의 프롬프트에 소개 섹션, 도구 섹션, 예제 섹션 및 미완성 예제 섹션이 포함되어 있는지 확인하세요. `run` 프롬프트 템플릿을 덮어쓰려면 다음과 같이 하면 됩니다:

    template = """ [...] """

    agent = HfAgent(your_endpoint, run_prompt_template=template)

에이전트가 사용 가능한 도구를 인식하고 사용자의 프롬프트를 올바르게 삽입할 수 있도록 `<<all_tools>>` 문자열과 `<<prompt>>`를 `template` 어딘가에 정의해야 합니다.

마찬가지로 `chat` 프롬프트 템플릿을 덮어쓸 수 있습니다. `chat` 모드에서는 항상 다음과 같은 교환 형식을 사용한다는 점에 유의하세요:

    Human: <<task>>

    Assistant:

따라서 사용자 정의 `chat` 프롬프트 템플릿의 예제에서도 이 형식을 사용하는 것이 중요합니다. 다음과 같이 인스턴스화 할 때 `chat` 템플릿을 덮어쓸 수 있습니다.

    template = """ [...] """

    agent = HfAgent(url_endpoint=your_endpoint, chat_prompt_template=template)

에이전트가 사용 가능한 도구를 인식할 수 있도록 `<<all_tools>>` 문자열을 `template` 어딘가에 정의해야 합니다.

두 경우 모두 커뮤니티의 누군가가 호스팅하는 템플릿을 사용하려는 경우 프롬프트 템플릿 대신 저장소 ID를 전달할 수 있습니다. 기본 프롬프트는 이 저장소를 예로 들 수 있습니다.

Hub의 저장소에 사용자 정의 프롬프트를 업로드하여 커뮤니티와 공유하려면 다음을 확인하세요:

- 데이터 세트 저장소를 사용하세요.
- `run` 명령에 대한 프롬프트 템플릿을 `run_prompt_template.txt`라는 파일에 넣으세요.
- `chat` 명령에 대한 프롬프트 템플릿을 `chat_prompt_template.txt`라는 파일에 넣으세요.

##
사용자 정의 도구 사용하기

이 섹션에서는 이미지 생성에 특화된 두 가지 기존 사용자 정의 도구를 활용하겠습니다:

- 더 많은 이미지 수정을 허용하기 위해 huggingface-tools/image-transformation을 diffusers/controlnet-canny-tool로 대체합니다.
- 기본 도구 상자에 이미지 업스케일링을 위한 새로운 도구가 추가되었습니다: diffusers/latent-upscaler-tool가 기존 이미지 변환 도구를 대체합니다.

편리한 `load_tool()` 함수를 사용하여 사용자 정의 도구를 가져오는 것으로 시작하겠습니다:

    from transformers import load_tool

    controlnet_transformer = load_tool("diffusers/controlnet-canny-tool")
    upscaler = load_tool("diffusers/latent-upscaler-tool")

에이전트에게 사용자 정의 도구를 추가하면 도구의 설명과 이름이 에이전트의 프롬프트에 자동으로 포함됩니다. 따라서 에이전트가 사용 방법을 이해할 수 있도록 사용자 정의 도구의 설명과 이름을 잘 작성해야 합니다. `controlnet_transformer`의 설명과 이름을 살펴보겠습니다:

    print(f"Description: '{controlnet_transformer.description}'")
    print(f"Name: '{controlnet_transformer.name}'")

그러면 다음 결과가 출력됩니다:

    Description: 'This is a tool that transforms an image with ControlNet according to a prompt.
    It takes two inputs: `image`, which should be the image to transform, and `prompt`, which should be the prompt to use to change it. It returns the modified image.'
    Name: 'image_transformer'

이름과 설명이 정확하고 큐레이팅 된 도구 세트(curated set of tools)의 스타일에 맞습니다. 다음으로, `controlnet_transformer`와 `upscaler`로 에이전트를 인스턴스화해 봅시다:

    tools = [controlnet_transformer, upscaler]
    agent = HfAgent("https://api-inference.huggingface.co/models/bigcode/starcoder", additional_tools=tools)

이 명령을 실행하면 다음 정보가 표시됩니다:

    image_transformer has been replaced by <transformers_modules.diffusers.controlnet-canny-tool.bd76182c7777eba9612fc03c0
    8718a60c0aa6312.image_transformation.ControlNetTransformationTool object at 0x7f1d3bfa3a00> as provided in `additional_tools`

큐레이팅된 도구 세트에는 이미 ‘image_transformer’ 도구가 있으며, 이 도구는 사용자 정의 도구로 대체됩니다.

기존 도구와 똑같은 작업에 사용자 정의 도구를 사용하려는 경우 기존 도구를 덮어쓰는 것이 유용할 수 있습니다. 에이전트가 해당 작업에 능숙하기 때문입니다. 이 경우 사용자 정의 도구가 덮어쓴 도구와 정확히 동일한 API를 따라야 하며, 그렇지 않으면 해당 도구를 사용하는 모든 예제가 업데이트되도록 프롬프트 템플릿을 조정해야 한다는 점에 유의하세요.

업스케일러 도구에 지정된 ‘image_upscaler’라는 이름 아직 기본 도구 상자에는 존재하지 않기 때문에, 도구 목록에 해당 이름이 간단히 추가되었습니다. 에이전트가 현재 사용할 수 있는 도구 상자는 언제든지 `agent.toolbox` 속성을 통해 확인할 수 있습니다:

    print("\n".join([f"- {a}" for a in agent.toolbox.keys()]))

    - document_qa
    - image_captioner
    - image_qa
    - image_segmenter
    - transcriber
    - summarizer
    - text_classifier
    - text_qa
    - text_reader
    - translator
    - image_transformer
    - text_downloader
    - image_generator
    - video_generator
    - image_upscaler

에이전트의 도구 상자에 `image_upscaler`가 추가된 점을 주목하세요.

이제 새로운 도구를 사용해봅시다! Transformers Agents Quickstart에서 생성한 이미지를 다시 사용하겠습니다.

    from diffusers.utils import load_image

    image = load_image(
        "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/rivers_and_lakes.png"
    )

이미지를 아름다운 겨울 풍경으로 바꿔 봅시다:

    image = agent.run("Transform the image: 'A frozen lake and snowy forest'", image=image)

    ==Explanation from the agent==
    I will use the following tool: `image_transformer` to transform the image.

    ==Code generated by the agent==
    image = image_transformer(image, prompt="A frozen lake and snowy forest")

새로운 이미지 처리 도구는 이미지를 매우 강력하게 수정할 수 있는 ControlNet을 기반으로 합니다. 기본적으로 이미지 처리 도구는 512x512 픽셀 크기의 이미지를 반환합니다. 이를 업스케일링할 수 있는지 살펴봅시다.

    image = agent.run("Upscale the image", image)

    ==Explanation from the agent==
    I will use the following tool: `image_upscaler` to upscale the image.

    ==Code generated by the agent==
    upscaled_image = image_upscaler(image)

에이전트는 업스케일러 도구의 설명과 이름만 보고 방금 추가한 업스케일러 도구에 “이미지 업스케일링”이라는 프롬프트를 자동으로 매핑하여 올바르게 실행했습니다.

다음으로 새 사용자 정의 도구를 만드는 방법을 살펴보겠습니다.

###
새 도구 추가하기

이 섹션에서는 에이전트에게 추가할 수 있는 새 도구를 만드는 방법을 보여 드립니다.

####
새 도구 만들기

먼저 도구를 만드는 것부터 시작하겠습니다. 특정 작업에 대해 가장 많은 다운로드를 받은 Hugging Face Hub의 모델을 가져오는, 그다지 유용하지는 않지만 재미있는 작업을 추가하겠습니다.

다음 코드를 사용하면 됩니다:

    from huggingface_hub import list_models

    task = "text-classification"

    model = next(iter(list_models(filter=task, sort="downloads", direction=-1)))
    print(model.id)

`text-classification`(텍스트 분류) 작업의 경우 `'facebook/bart-large-mnli'`를 반환하고, `translation`(번역) 작업의 경우 `'google-t5/t5-base'`를 반환합니다.

이를 에이전트가 활용할 수 있는 도구로 변환하려면 어떻게 해야 할까요? 모든 도구는 필요한 주요 속성을 보유하는 슈퍼클래스 `Tool`에 의존합니다. 이를 상속하는 클래스를 만들어 보겠습니다:

    from transformers import Tool

    class HFModelDownloadsTool(Tool):
        pass

이 클래스에는 몇 가지 요구사항이 있습니다:

- 도구 자체의 이름에 해당하는 `name` 속성. 수행명이 있는 다른 도구와 호환되도록 `model_download_counter`로 이름을 지정하겠습니다.
- 에이전트의 프롬프트를 채우는 데 사용되는 속성 `description`.
- `inputs` 및 `outputs` 속성. 이를 정의하면 Python 인터프리터가 유형에 대한 정보에 입각한 선택을 하는 데 도움이 되며, 도구를 허브에 푸시할 때 gradio 데모를 생성할 수 있습니다. 두 속성 모두 값은 ‘텍스트’, ‘이미지’ 또는 ‘오디오’가 될 수 있는 예상 값의 리스트입니다.
- 추론 코드가 포함된 `__call__` 메소드. 이것이 우리가 위에서 다루었던 코드입니다!

이제 클래스의 모습은 다음과 같습니다:

    from transformers import Tool
    from huggingface_hub import list_models

    class HFModelDownloadsTool(Tool):
        name = "model_download_counter"
        description = (
            "This is a tool that returns the most downloaded model of a given task on the Hugging Face Hub. "
            "It takes the name of the category (such as text-classification, depth-estimation, etc), and "
            "returns the name of the checkpoint."
        )

        inputs = ["text"]
        outputs = ["text"]

        def __call__(self, task: str):
            model = next(iter(list_models(filter=task, sort="downloads", direction=-1)))
            return model.id

이제 도구를 손쉽게 사용할 수 있게 되었습니다. 도구를 파일에 저장하고 메인 스크립트에서 가져옵니다. 이 파일의 이름을 `model_downloads.py`로 지정하면 결과적으로 가져오기 코드는 다음과 같습니다:

    from model_downloads import HFModelDownloadsTool

    tool = HFModelDownloadsTool()

다른 사람들이 이 기능을 활용할 수 있도록 하고 초기화를 더 간단하게 하려면 네임스페이스 아래의 Hub로 푸시하는 것이 좋습니다. 그렇게 하려면 `tool` 변수에서 `push_to_hub`를 호출하면 됩니다:

    tool.push_to_hub("hf-model-downloads")

이제 허브에 코드가 생겼습니다! 마지막 단계인 에이전트가 코드를 사용하도록 하는 단계를 살펴보겠습니다.

####
에이전트가 도구를 사용하게 하기

이제 이런 식으로 허브에 존재하는 도구를 인스턴스화할 수 있습니다(도구의 사용자 이름은 변경하세요): We now have our tool that lives on the Hub which can be instantiated as such (change the user name for your tool):

    from transformers import load_tool

    tool = load_tool("lysandre/hf-model-downloads")

이 도구를 에이전트에서 사용하려면 에이전트 초기화 메소드의 `additional_tools` 매개변수에 전달하기만 하면 됩니다:

    from transformers import HfAgent

    agent = HfAgent("https://api-inference.huggingface.co/models/bigcode/starcoder", additional_tools=[tool])

    agent.run(
        "Can you read out loud the name of the model that has the most downloads in the 'text-to-video' task on the Hugging Face Hub?"
    )

그러면 다음과 같은 결과가 출력됩니다:

    ==Code generated by the agent==
    model = model_download_counter(task="text-to-video")
    print(f"The model with the most downloads is {model}.")
    audio_model = text_reader(model)

    ==Result==
    The model with the most downloads is damo-vilab/text-to-video-ms-1.7b.

and generates the following audio.

Audio

LLM에 따라 일부는 매우 취약하기 때문에 제대로 작동하려면 매우 정확한 프롬프트가 필요합니다. 에이전트가 도구를 잘 활용하기 위해서는 도구의 이름과 설명을 잘 정의하는 것이 무엇보다 중요합니다.

###
기존 도구 대체하기

에이전트의 도구 상자에 새 항목을 배정하기만 하면 기존 도구를 대체할 수 있습니다. 방법은 다음과 같습니다:

    from transformers import HfAgent, load_tool

    agent = HfAgent("https://api-inference.huggingface.co/models/bigcode/starcoder")
    agent.toolbox["image-transformation"] = load_tool("diffusers/controlnet-canny-tool")

다른 도구로 교체할 때는 주의하세요! 이 작업으로 에이전트의 프롬프트도 조정됩니다. 작업에 더 적합한 프롬프트가 있으면 좋을 수 있지만, 다른 도구보다 더 많이 선택되거나 정의한 도구 대신 다른 도구가 선택될 수도 있습니다.

##
gradio-tools 사용하기

gradio-tools는 Hugging Face Spaces를 도구로 사용할 수 있는 강력한 라이브러리입니다. 기존의 많은 Spaces뿐만 아니라 사용자 정의 Spaces를 사용하여 디자인할 수 있도록 지원합니다.

우리는 `Tool.from_gradio` 메소드를 사용하여 `gradio_tools`에 대한 지원을 제공합니다. 예를 들어, 프롬프트를 개선하고 더 나은 이미지를 생성하기 위해 `gradio-tools` 툴킷에서 제공되는 `StableDiffusionPromptGeneratorTool` 도구를 활용하고자 합니다.

먼저 `gradio_tools`에서 도구를 가져와서 인스턴스화합니다:

    from gradio_tools import StableDiffusionPromptGeneratorTool

    gradio_tool = StableDiffusionPromptGeneratorTool()

해당 인스턴스를 `Tool.from_gradio` 메소드에 전달합니다:

    from transformers import Tool

    tool = Tool.from_gradio(gradio_tool)

이제 일반적인 사용자 정의 도구와 똑같이 관리할 수 있습니다. 이를 활용하여 `a rabbit wearing a space suit’(우주복을 입은 토끼)라는 프롬프트를 개선했습니다:

    from transformers import HfAgent

    agent = HfAgent("https://api-inference.huggingface.co/models/bigcode/starcoder", additional_tools=[tool])

    agent.run("Generate an image of the `prompt` after improving it.", prompt="A rabbit wearing a space suit")

모델이 도구를 적절히 활용합니다:

    ==Explanation from the agent==
    I will use the following  tools: `StableDiffusionPromptGenerator` to improve the prompt, then `image_generator` to generate an image according to the improved prompt.

    ==Code generated by the agent==
    improved_prompt = StableDiffusionPromptGenerator(prompt)
    print(f"The improved prompt is {improved_prompt}.")
    image = image_generator(improved_prompt)

마지막으로 이미지를 생성하기 전에:

gradio-tools는 다른 모달리티로 작업할 때에도 텍스트 입력 및 출력을 필요로 합니다. 이 구현은 이미지 및 오디오 객체에서 작동합니다. 현재는 이 두 가지가 호환되지 않지만 지원 개선을 위해 노력하면서 빠르게 호환될 것입니다.

##
향후 Langchain과의 호환성

저희는 Langchain을 좋아하며 매우 매력적인 도구 모음을 가지고 있다고 생각합니다. 이러한 도구를 처리하기 위해 Langchain은 다른 모달리티와 작업할 때에도 텍스트 입력과 출력을 필요로 합니다. 이는 종종 객체의 직렬화된(즉, 디스크에 저장된) 버전입니다.

이 차이로 인해 transformers-agents와 Langchain 간에는 멀티 모달리티가 처리되지 않습니다. 향후 버전에서 이 제한이 해결되기를 바라며, 이 호환성을 달성할 수 있도록 열렬한 Langchain 사용자의 도움을 환영합니다.

저희는 더 나은 지원을 제공하고자 합니다. 도움을 주고 싶으시다면, 이슈를 열어 의견을 공유해 주세요.