Chamada de ferramentas com o Ollama

Autor

Joshua Noble

Data Scientist

Chamada de ferramentas com o Ollama

A chamada de ferramentas em grandes modelos de linguagem (LLMs) é a capacidade do LLM de interagir com ferramentas, serviços ou APIs externos para executar tarefas. Isso permite que os LLMs ampliem sua funcionalidade, aprimorando sua capacidade de lidar com tarefas do mundo real que podem exigir acesso a dados externos, informações em tempo real ou aplicações específicas. Quando um LLM usa uma ferramenta de pesquisa na web, ele pode chamar a web para buscar dados em tempo real que não estão disponíveis nos dados de treinamento do modelo. Outros tipos de ferramentas podem incluir Python para cálculos, análise de dados ou visualização, ou chamar um endpoint de serviço para dados. A chamada de ferramentas pode tornar um chatbot mais dinâmico e adaptável, permitindo que apresente respostas mais precisas, relevantes e detalhadas com base em dados em tempo real ou tarefas especializadas fora de sua base de conhecimento imediata. Frameworks populares para chamada de ferramentas incluem o Langchain e, agora, o Ollama.

O Ollama é uma plataforma que oferece modelos de IA locais de código aberto para uso em dispositivos pessoais, para que os usuários possam executar LLMs diretamente em seus computadores. Diferentemente de serviços como a API da OpenAI, não há necessidade de uma conta, pois o modelo está na sua máquina local. O Ollama se concentra na privacidade, no desempenho e na facilidade de uso, permitindo que os usuários acessem e interajam com os modelos de IA sem enviar dados para servidores externos. Isso pode ser particularmente atraente para aqueles que se preocupam com a privacidade de dados ou que desejam evitar a dependência de APIs externas. A plataforma do Ollama foi projetada para ser fácil de configurar e usar, e é compatível com vários modelos, oferecendo aos usuários uma variedade de ferramentas para processamento de linguagem natural, geração de código e outras tarefas de IA diretamente em seu próprio hardware. É adequado para uma arquitetura de chamada de ferramentas, porque pode acessar todos os recursos de um ambiente local, incluindo dados, programas e software personalizado.

Neste tutorial, você aprenderá a configurar a chamada de ferramentas usando o Ollama para examinar um sistema de arquivos local, uma tarefa que seria difícil de realizar com um LLM remoto. Muitos modelos do Ollama estão disponíveis para chamada de ferramentas e criação de agentes de IA, como o Mistral e o Llama 3.2. Há uma lista completa disponível no site do Ollama. Neste caso, usaremos o IBM Granite 3.2 Densi, que é compatível com a ferramenta. Os modelos 2B e 8B são LLMs densos somente de texto, treinados para compatibilidade com casos de uso baseados em ferramentas e para geração aumentada de recuperação (RAG), simplificando a geração de código, tradução e correção de bugs.

O bloco de notas deste tutorial pode ser baixado do Github aqui.

Etapa 1: Instale o Ollama

Primeiro, baixe o ollama em https://ollama.com/download e instale-o em seu sistema operacional. No OSX, isso é feito por meio de um arquivo .dmg, no Linux por meio de um único comando shell e no Windows com um instalador. Talvez você precise de acesso de administrador em sua máquina para executar o instalador.

Você pode testar se o ollama está instalado corretamente abrindo um terminal ou prompt de comando e digitando:

ollama -v 

 

Etapa 2: Instale as bibliotecas

Em seguida, você adicionará as importações iniciais. Essa demonstração usará a biblioteca ollama python para se comunicar com o ollama e a biblioteca pymupdf para ler arquivos PDF no sistema de arquivos.

!pip install pymupdf

import ollama
import os
import pymupdf

 

Em seguida, você extrairá o modelo que usará ao longo deste tutorial. Isso baixa os pesos do modelo do ollama para o seu computador local e os armazena para uso sem a necessidade de fazer chamadas de API remotas mais tarde.

!ollama pull granite3.2
!ollama pull granite3.2-vision

Etapa 3: Defina as ferramentas

Agora, você definirá as ferramentas às quais a instância das ferramentas ollama terá acesso. Como a intenção das ferramentas é ler arquivos e examinar imagens no sistema de arquivos local, você criará duas funções python para cada uma dessas ferramentas. A primeira é chamadasearch_text_files e requer uma palavra-chave para pesquisar nos arquivos locais. Para os fins desta demonstração, o código busca apenas arquivos em uma pasta específica, mas poderia ser estendido para incluir um segundo parâmetro que define em qual pasta a ferramenta fará a busca.

Você poderia usar a correspondência simples de string para ver se a palavra-chave está no documento, mas como o ollama facilita a chamada de llms locais,search_text_files usará o Granite 3.2 para determinar se a palavra-chave descreve o texto do documento. Isso é feito lendo o documento em uma string chamadadocument_text. Em seguida, a função chama ollama.chat e solicita ao modelo o seguinte:

"Respond only 'yes' or 'no', do not add any additional information. Is the following text about " + keyword + "? " + document_text 

Se o modelo responder “sim”, a função retornará o nome do arquivo que contém a palavra-chave que o usuário indicou no prompt. Se nenhum dos arquivos parecer conter as informações, a função retornará "Nenhum" como uma string.

Essa função pode ser executada lentamente na primeira vez porque o ollama baixará o Granite 3.2 Dense. 

def search_text_files(keyword: str) -> str:
  
  directory = os.listdir("./files/")
  for fname in directory:
    
    # look through all the files in our directory that aren't hidden files
    if os.path.isfile("./files/" + fname) and not fname.startswith('.'):

        if(fname.endswith(".pdf")):
           
           document_text = ""
           doc = pymupdf.open("./files/" + fname)

           for page in doc: # iterate the document pages
               document_text += page.get_text() # get plain text (is in UTF-8)
               
           doc.close()

           prompt = "Respond only 'yes' or 'no', do not add any additional information. Is the following text about " + keyword + "? " + document_text 

           res = ollama.chat(
                model="granite3.2:8b",
                messages=[{'role': 'user', 'content': prompt}]
            )

           if 'Yes' in res['message']['content']:
                return "./files/" + fname

        elif(fname.endswith(".txt")):

            f = open("./files/" + fname, 'r')
            file_content = f.read()
            
            prompt = "Respond only 'yes' or 'no', do not add any additional information. Is the following text about " + keyword + "? " + file_content 

            res = ollama.chat(
                model="granite3.2:8b",
                messages=[{'role': 'user', 'content': prompt}]
            )
           
            if 'Yes' in res['message']['content']:
                f.close()
                return "./files/" + fname

  return "None"

A segunda ferramenta se chama search_image_files  e é necessária uma palavra-chave para pesquisar nas fotos locais. A pesquisa é feita usando o modelo de descrição de imagem Granite 3.2 Vision via ollama. Esse modelo retorna uma descrição de texto de cada arquivo de imagem na pasta e procura pela palavra-chave na descrição. Um dos pontos fortes do uso do ollama é que os sistemas multiagentes podem ser facilmente construídos para chamar um modelo para outro.

A função retorna uma string, que é o nome do arquivo cuja descrição contém a palavra-chave que o usuário indicou no prompt.

def search_image_files(keyword:str) -> str:

    directory = os.listdir("./files/")
    image_file_types = ("jpg", "png", "jpeg")

    for fname in directory:

        if os.path.isfile("./files/" + fname) and not fname.startswith('.') and fname.endswith(image_file_types):
            res = ollama.chat(
                model="granite3.2-vision",
                messages=[
                    {
                        'role': 'user',
                        'content': 'Describe this image in short sentences. Use simple phrases first and then describe it more fully.',
                        'images': ["./files/" + fname]
                    }
                ]
            )

            if keyword in res['message']['content']:
                return "./files/" + fname
    
    return "None"

Etapa 4: Defina as ferramentas para o Ollama

Agora que as funções para o ollama chamar foram definidas, você configurará as informações da ferramenta para o próprio ollama. O primeiro passo é criar um objeto que associe o nome da ferramenta às funções para chamada da função ollama:

available_functions = {
  'Search inside text files':search_text_files,
  'Search inside image files':search_image_files
}

Em seguida, configure uma matriz de ferramentas para informar ao ollama a quais ferramentas ele terá acesso e o que essas ferramentas exigem. Essa é uma matriz com um esquema de objeto por ferramenta que informa ao framework de chamadas de ferramentas do ollama como chamar a ferramenta e o que ela retorna.

No caso das duas ferramentas que você criou anteriormente, são funções que exigem um parâmetro keyword . No momento, apenas as funções são compatíveis, embora isso possa mudar no futuro. A descrição da função e do parâmetro ajudam o modelo a chamar a ferramenta corretamente. O Descrição campo para a função de cada ferramenta é passado para o LLM quando ele seleciona a ferramenta a ser usada. O Descrição da palavra-chave é passada para o modelo quando ele gera os parâmetros que serão passados para a ferramenta. Ambos são locais em que você pode procurar para ajuste fino de prompts quando você criar suas próprias aplicações de chamada de ferramentas com o ollama.

# tools don't need to be defined as an object but this helps pass the correct parameters
# to the tool call itself by giving the model a prompt of how the tool is to be used
ollama_tools=[
     {
      'type': 'function',
      'function': {
        'name': 'Search inside text files',
        'description': 'This tool searches in PDF or plaintext or text files in the local file system for descriptions or mentions of the keyword.',
        'parameters': {
          'type': 'object',
          'properties': {
            'keyword': {
              'type': 'string',
              'description': 'Generate one keyword from the user request to search for in text files',
            },
          },
          'required': ['keyword'],
        },
      },
    },
    {
      'type': 'function',
      'function': {
        'name': 'Search inside image files',
        'description': 'This tool searches for photos or image files in the local file system for the keyword.',
        'parameters': {
          'type': 'object',
          'properties': {
            'keyword': {
              'type': 'string',
              'description': 'Generate one keyword from the user request to search for in image files',
            },
          },
          'required': ['keyword'],
        },
      },
    },
  ]


Você usará a definição dessas ferramentas quando chamar o ollama com a entrada do usuário.

Etapa 5: Passe a entrada do usuário para o Ollama

Agora é hora de passar a entrada do usuário para o ollama e fazer com que ele retorne os resultados das chamadas de ferramentas. Primeiro, certifique-se de que o ollama esteja em execução no seu sistema:

# if ollama is not currently running, start it
import subprocess
subprocess.Popen(["ollama","serve"], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)

Se o ollama estiver em execução, isso retornará:

<Popen: returncode: None args: ['ollama', 'serve']>

Agora, peça a entrada do usuário. Você também pode codificar a entrada ou recuperar de uma interface de bate-papo, dependendo da configuração de sua aplicação. A input  função aguardará a entrada do usuário antes de continuar.

# input
user_input = input("What would you like to search for?")
print(user_input)

Por exemplo, se o usuário inserir "Informações sobre cachorros", esta célula será impressa:

Information about dogs

Agora, a consulta do usuário é passada para o próprio ollama. As mensagens precisam de uma função para o usuário e o conteúdo que o usuário insere. Isso é passado para o ollama usando a função chat . O primeiro parâmetro é o modelo que você deseja usar, neste caso o Granite 3.2 Dense. Depois, a mensagem com a entrada do usuário e, por fim, a matriz de ferramentas que você configurou anteriormente.

O chat função gerará uma saída selecionando qual ferramenta usar e quais parâmetros devem ser passados para ela nas chamadas de ferramentas subsequentes.

messages = [{'role': 'user', 'content':user_input}]

response: ollama.ChatResponse = ollama.chat(
   
  # set which model we're using
  'granite3.2:8b',

  # use the message from the user
  messages=messages,

  tools=ollama_tools
)

Agora que o modelo gerou chamadas de ferramentas na saída, execute todas as chamadas de ferramenta com os parâmetros que o modelo gerou e verifique a saída. Nessa aplicação, o Granite 3.2 Dense é usado para gerar a saída final, de modo que os resultados das chamadas de ferramentas são adicionados à entrada inicial do usuário e, em seguida, passados para o modelo.

Várias chamadas de ferramentas podem retornar correspondências de arquivos; portanto, as respostas são coletadas em uma matriz que é então transmitida ao Granite 3.2 para gerar uma resposta. O prompt que precede os dados instrui o modelo como responder:

If the tool output contains one or more file names, then give the user only the filename found. Do not add additional details. 
If the tool output is empty ask the user to try again. Here is the tool output: 

Então, a saída final é gerada usando os nomes de arquivos retornados ou 

# this is a place holder that to use to see whether the tools return anything 
output = []

if response.message.tool_calls:
  
  # There may be multiple tool calls in the response
  for tool_call in response.message.tool_calls:

    # Ensure the function is available, and then call it
    if function_to_call := available_functions.get(tool_call.function.name):
      print('Calling tool: ', tool_call.function.name, ' \n with arguments: ', tool_call.function.arguments)
      tool_res = function_to_call(**tool_call.function.arguments)

      print(" Tool response is " + str(tool_res))

      if(str(tool_res) != "None"):
        output.append(str(tool_res))
        print(tool_call.function.name, ' has output: ', output)
    else:
      print('Could not find ', tool_call.function.name)

  # Now chat with the model using the tool call results
  # Add the function response to messages for the model to use
  messages.append(response.message)

  prompt = '''
    If the tool output contains one or more file names, 
    then give the user only the filename found. Do not add additional details. 
    If the tool output is empty ask the user to try again. Here is the tool output: 
  '''

  messages.append({'role': 'tool', 'content': prompt + " " + ", ".join(str(x) for x in output)})
  
  # Get a response from model with function outputs
  final_response = ollama.chat('granite3.2:8b', messages=messages)
  print('Final response:', final_response.message.content)

else:

  # the model wasn't able to pick the correct tool from the prompt
  print('No tool calls returned from model')

Usando os arquivos fornecidos para este tutorial, o prompt "Informações sobre cachorros" retornará:

    Calling tool:  Search inside text files  
     with arguments:  {'keyword': 'dogs'}
     Tool response is ./files/File4.pdf
    Search inside text files  has output:  ['./files/File4.pdf']
    Calling tool:  Search inside image files  
     with arguments:  {'keyword': 'dogs'}
     Tool response is None
    Final response: The keyword "dogs" was found in File4.pdf.

É possível ver que o Granite 3.2 selecionou a palavra-chave correta da entrada, "cães", e pesquisou os arquivos na pasta, encontrando a palavra-chave em um arquivo PDF. Como os resultados do LLM não são puramente determinísticos, você pode obter resultados ligeiramente diferentes com o mesmo prompt ou prompts muito semelhantes.

Soluções relacionadas
Agentes de IA para empresas

Crie, implemente e gerencie assistentes e agentes de IA potentes que automatizam fluxos de trabalho e processos com a IA generativa.

    Explore o watsonx Orchestrate
    Soluções de agentes de IA da IBM

    Construa o futuro do seu negócio com soluções de IA em que você pode confiar.

    Explore soluções de agentes de IA
    Serviços de IA do IBM® Consulting

    Os serviços de IA da IBM Consulting ajudam a reinventar a forma como as empresas trabalham com IA para gerar transformação.

    Explore os serviços de inteligência artificial
    Dê o próximo passo

    Se você optar por personalizar aplicativos e habilidades criados previamente ou criar e implementar serviços agênticos personalizados usando um estúdio de IA, a plataforma IBM watsonx tem aquilo de que você precisa.

    Explore o watsonx Orchestrate Explore o watsonx.ai