Crie um sistema de gerenciamento de contratos multiagentes com o BeeAI e o Granite

Autor

Anna Gutowska

AI Engineer, Developer Advocate

IBM

Neste tutorial, você construirá um sistema multiagentes totalmente local com o IBM® Granite usando o BeeAI no Python. Esses agentes colaborarão para negociar um acordo contratual para serviços de paisagismo entre duas empresas, levando em consideração as tendências do mercado e as restrições orçamentárias internas. O fluxo de trabalho será composto por um agente consultor de orçamento, agente sintetizador de contratos, agente de pesquisa na web e agente consultor de aquisição. Dados o contrato, os dados orçamentários, o setor de serviço e os nomes da empresa fornecidos pelo usuário, os agentes colaboram para produzir um e-mail para negociar os termos do contrato em favor do cliente.

O que é o BeeAI?

O BeeAI, lançado pela IBM® Research e agora doado à Linux Foundation, é uma plataforma de IA agêntica de código aberto que oferece aos desenvolvedores a capacidade de criar agentes de IA a partir de qualquer framework.1

Um agente de inteligência artifical (IA) refere-se a um sistema ou programa criado usando grandes modelos de linguagem (LLM) para realizar tarefas de forma autônoma em nome de um usuário ou de outro sistema, projetando seu fluxo de trabalho e usando as ferramentas disponíveis . Os agentes de IA são mais avançados do que os chatbots de LLMs tradicionais, já que podem acessar ferramentas predefinidas, planejar ações futuras e exigir pouca ou nenhuma intervenção humana para resolver e automatizar problemas complexos.

O antecessor do BeeAI é o Bee Agent Framework, um framework de código aberto específico para a criação de agentes de LLMs únicos. Por outro lado, o BeeAI oferece um ecossistema mais avançado para criar e orquestrar fluxos de trabalho multiagentes.

A BeeAI é:

  • Independente de framework.
  • Disponível em TypeScript e Python.
  • Desenvolvido com base no Agent Communication Protocol (ACP) projetado pela IBM Research, que leva o Model Context Protocol (MCP) um passo adiante, padronizando a forma como os agentes se comunicam entre si. O ACP traz agentes de vários frameworks, como LangGraphCrewAI e BeeAI, em um tempo de execução constante.2
  • Integrado ao Arize Phoenix, uma ferramenta de código aberto para rastrear o comportamento de agentes, permitindo a observabilidade. Mais informações sobre depuração de seus agentes por meio do registro e telemetria disponíveis podem ser encontradas na documentação oficial.
  • Capaz de ser executado de forma totalmente local em sua máquina. Os agentes também podem ser implementados em ambientes compartilhados.
  • Fornece interfaces unificadas para diversas funcionalidades, incluindo chat, embeddings e produções estruturadas, como JSON, possibilitando a troca perfeita de modelos sem exigir alterações no seu código existente.

Etapas

Este guia passo a passo pode ser encontrado em nosso repositório do GitHub na forma de um Jupyter Notebook.

Etapa 1. Configure seu ambiente

Primeiro precisamos configurar nosso ambiente cumprindo alguns pré-requisitos.
1. Neste tutorial, não usaremos uma interface de programação de aplicativos (API) como as disponíveis no IBM watsonx.ai e na OpenAI. Em vez disso, podemos instalar a versão mais recente do Ollama para executar o modelo localmente.
A maneira mais simples de instalar o Ollama para macOS, Linux e Windows é por meio da página da web: https://ollama.com/download. Essa etapa instalará um aplicativo de barra de menus para executar o servidor Ollama em segundo plano e mantê-lo atualizado com os lançamentos mais recentes.
Ou então, você pode instalar o Ollama com homebrew em seu terminal:

brew install ollama

Se instalar a partir do preparo ou compilar a partir do código-fonte, você precisa inicializar o servidor central:

ollama serve

2. Existem vários LLMs compatíveis com chamadas de ferramentas, como os mais recentes modelos Llama da Meta e os modelos Mistral da Mistral IA. Para este tutorial, usaremos o modelo Granite 3.3 de código aberto da IBM. Este modelo apresenta recursos aprimorados de raciocínio e seguimento de instruções.3 Obtenha o modelo mais recente do Granite 3.3 executando o seguinte comando em seu terminal.

ollama pull granite3.3:8b

3. Para evitar conflitos de dependência de pacotes, vamos configurar um ambiente virtual. Para criar um ambiente virtual com o Python versão 3.11.9, execute o seguinte comando em seu terminal.

python3.12 -m venv .venv

Em seguida, para ativar o ambiente, execute:

source .venv/bin/activate

4. Seu arquivo requirements.txt deve conter os seguintes pacotes. Esses pacotes são necessários para criar agentes com o framework BeeAI e incorporar as classes LangChain necessárias para a inicialização da ferramenta.

beeai-framework
beeai-framework[duckduckgo]
langchain-core
langchain-community
pandas

Para instalar esses pacotes, execute o seguinte comando em seu terminal.

pip install -r requirements.txt

5. Crie um novo arquivo Python chamado bee-script.py executando esse comando em seu terminal:

touch bee-script.py

Na parte superior do arquivo Python novo, inclua as instruções de importação para as bibliotecas e módulos necessários.

import asyncio
import pandas as pd
import os
import traceback
import sys

from beeai_framework.backend import ChatModel
from beeai_framework.tools.search.duckduckgo import DuckDuckGoSearchTool
from beeai_framework.workflows.agent import AgentWorkflow, AgentWorkflowInput
from beeai_framework.errors import FrameworkError
from beeai_framework.adapters.langchain import LangChainTool
from langchain_core.tools import StructuredTool
from typing import Any

Etapa 2. Crie uma instância de seu agente e fluxo de trabalho

Em um método principal assíncrono usando asyncio , vamos incorporar as classes ChatModel e AgentWorkflow para instanciar nosso Granite LLM e fluxo de trabalho. Podemos simplesmente fornecer o ID do modelo Ollama, bem como um nome de fluxo de trabalho. A instanciação desse fluxo de trabalho nos permite adicionar agentes e criar nosso sistema multiagentes. Adicione esse método principal a seu arquivo Python.

async def main() -> None:
    llm = ChatModel.from_name("ollama:granite3.3:8b")
    workflow = AgentWorkflow(name="Procurement")

Para uma visualização do fluxo de trabalho agêntico, consulte o diagrama a seguir.

Fluxo de trabalho agêntico para gerenciamento de contratos Fluxo de trabalho agêntico para gerenciamento de contratos

Vamos montar cada componente desse fluxo de trabalho nas etapas a seguir.

Etapa 3. Solicite a entrada do usuário

Nosso fluxo de trabalho depende da entrada do usuário. As entradas iniciais necessárias são os nomes das empresas clientes e contratadas. O seguinte texto será enviado ao usuário quando o fluxo de trabalho for executado em uma etapa posterior. Adicione o código a seguir ao método principal.

client_company = input("Please enter the client company: ") #Example: Company A
contractor_company = input("Please enter the contractor company: ") #Example: Company B

Também precisaremos dos nomes dos arquivos contendo o relatório de orçamento da empresa cliente,budget-data.csv , bem como o arquivo que contém o contrato entre as duas empresas, contract.txt . Em nosso exemplo, o contrato refere-se a serviços de paisagismo fornecidos pela empresa contratada à empresa cliente. Você encontra os arquivos de amostra em nosso repositório do GitHub. A estrutura do projeto deve se assemelhar à seguinte:

├── .venv/ # Virtual environment
├── bee-script.py # The Python script
├── contract.txt # The contract
└── budget-data.csv # Client's budget report

No código a seguir, também verificamos as extensões dos arquivos para ajudar a garantir que estejam alinhadas com o nosso formato previsto. Se algum dos arquivos for do tipo incorreto, será solicitado que o usuário tente novamente.

client_budget_file = input(f"Enter the file name of the budget report for {client_company} (in the same directory level): ") #Example: budget_data.csv
while os.path.splitext(client_budget_file)[1].lower() != ".csv":
    client_budget_file = input(f"Budget report must be in .csv format, please try again: ")

contract_file = input(f"Enter the file name of the contract between {client_company} and {contractor_company} (in the same directory level): ") #Example: contract.txt
while os.path.splitext(contract_file)[1].lower() != ".txt":
    contract_file = input(f"Contract must be in .txt format, please try again: ")

A última entrada do usuário necessária é o setor do serviço descrito no contrato. Essa entrada pode ser financeira, de construção ou outra.

service_industry = input(f"Enter the industry of the service described in this contract (e.g., finance, construction, etc.): ") #Example: landscaping

Etapa 4. Configure a ferramenta de orçamento

A primeira ferramenta que podemos criar em nosso sistema multiagentes é para o agente consultor de orçamento. Esse agente é responsável por ler os dados do orçamento do cliente. A função fornecida ao agente éget_budget_data , na qual o arquivo CSV que contém os dados do orçamento é lido, e uma mensagem de erro é retornada caso o arquivo não exista ou ocorra um erro inesperado. Para acessar o arquivo usando o nome de arquivo fornecido pelo usuário, primeiro precisamos recuperar o diretório atual. Podemos fazer isso usando o seguintemétodo os.

current_directory = os.getcwd()

Agora, vamos configurar a força motriz do agente, a get_budget_data função, que usa o diretório atual, bem como a entrada do usuário para acessar e ler o arquivo.

def get_budget_data():
    try:
        budget = pd.read_csv(os.path.join(current_directory, client_budget_file))
    except FileNotFoundError:
        return client_budget_file + " not found. Please check correct file name."
    except Exception as e:
        return f"An error occurred: {e}"
    return budget

Para garantir o uso adequado dessa ferramenta, vamos usar a classe StructuredTool do LangChain. Aqui, fornecemos a função, o nome da ferramenta, a descrição da ferramenta e definimos o parâmetro return_direct como verdadeiro ou falso. Este último parâmetro simplesmente informa ao agente se deve retornar a saída da ferramenta diretamente ou sintetizá-la.

get_budget = StructuredTool.from_function(
    func=get_budget_data,
    name="GetBudgetData",
    description=f"Returns the budget data for {client_company}.",
    return_direct=True,
)

Usando o adaptador LangChain do BeeAI, o LangChainTool, podemos finalizar a inicialização de nossa primeira ferramenta.

budget_tool = LangChainTool[Any](get_budget)

Etapa 5. Configure a ferramenta de contrato

A próxima ferramenta que podemos criar é para o agente sintetizador de contratos. Esse agente é responsável pela leitura do contrato entre o cliente e o prestador de serviços. A função fornecida ao agente é get_contract_data , na qual o arquivo de texto que contém o contrato é lido, e uma mensagem de erro é retornada caso o arquivo não exista ou ocorra um erro inesperado. O código necessário para essa etapa é semelhante ao da etapa 3.

def get_contract_data():
    try:
        with open(os.path.join(current_directory, contract_file), 'r') as file:
            content = file.read()
    except FileNotFoundError:
        return contract_file + " not found. Please check correct file name."
    except Exception as e:
        return f"An error occurred: {e}"
    return content
get_contract = StructuredTool.from_function(
    func=get_contract_data,
    name="GetContractData",
    description=f"Returns the contract details.",
    return_direct=True,
)
contract_tool = LangChainTool[Any](get_contract)

Etapa 6. Estabeleça o fluxo de trabalho do agente

Nesta etapa, podemos adicionar os vários agentes a nosso fluxo de trabalho. Vamos fornecer ao consultor de orçamento e aos agentes sintetizadores de contratos suas ferramentas personalizadas correspondentes. Também podemos definir o nome do agente, função, instruções, lista de ferramentas e LLM. 

workflow.add_agent(
    name="Budget Advisor",
    role="A diligent budget advisor",
    instructions="You specialize in reading internal budget data in CSV format.",
    tools=[budget_tool],
    llm=llm,
)

workflow.add_agent(
    name="Contract Synthesizer",
    role="A diligent contract synthesizer",
    instructions=f"You specialize in reading contracts.",
    tools=[contract_tool],
    llm=llm,
)

Para pesquisar na web em busca de tendências de mercado no setor relevante, podemos criar um agente com acesso ao LangChain criado previamente DuckDuckGoSearchTool . Essa ferramenta busca dados da web usando o mecanismo de busca DuckDuckGo.

workflow.add_agent(
    name="Web Search",
    role="A web searcher.",
    instructions=f"You can search the web for market trends, specifically in the {service_industry} industry.",
    tools=[DuckDuckGoSearchTool()],
    llm=llm,
)

O quarto e último agente em nosso sistema multiagentes é o consultor de aquisição. Esse agente é responsável por usar as informações recuperadas e sintetizadas pelos outros agentes para formular um e-mail convincente para a empresa contratante em favor do cliente. O e-mail deve considerar as tendências do mercado e as restrições orçamentárias internas do cliente para negociar os termos do contrato. Esse agente não requer nenhuma ferramenta externa, mas é orientado por suas instruções.

workflow.add_agent(
    name="Procurement Advisor",
    role="A procurement advisor",
    instructions=f"You write professional emails to {contractor_company} with convincing negotiations that factor in market trends and internal budget constraints. You represent {client_company}.",
    llm=llm,
)

Etapa 7. Execute o fluxo de trabalho do agente

Agora podemos finalizar nosso método principal com todo o nosso código até agora. No final do método principal, podemos incluir a execução do fluxo de trabalho agêntico. Dado a palavra-chaveawait , podemos gerenciar com eficiência a execução simultânea de tarefas e aguardar a execução de cada tarefa. Seu arquivo Python deve conter o seguinte código.

import asyncio
import pandas as pd
import os
import traceback
import sys

from beeai_framework.backend import ChatModel
from beeai_framework.tools.search.duckduckgo import DuckDuckGoSearchTool
from beeai_framework.workflows.agent import AgentWorkflow, AgentWorkflowInput
from beeai_framework.errors import FrameworkError
from beeai_framework.adapters.langchain import LangChainTool
from langchain_core.tools import StructuredTool
from typing import Any

async def main() -> None:

    llm = ChatModel.from_name("ollama:granite3.3:8b")

    workflow = AgentWorkflow(name="Procurement Agent")

    client_company = input("Please enter the client company: ")
    contractor_company = input("Please enter the contractor company name: ")

    client_budget_file = input(f"Enter the file name of the budget report for {client_company} (in the same directory level): ")
while os.path.splitext(client_budget_file)[1].lower() != ".csv":
        client_budget_file = input(f"Budget report must be in .csv format, please try again: ")

    contract_file = input(f"Enter the file name of the contract between {client_company} and {contractor_company} (in the same directory level): ")
while os.path.splitext(contract_file)[1].lower() != ".txt":
        contract_file = input(f"Contract must be in .txt format, please try again: ")

    service_industry = input(f"Enter the industry of the service described in this contract (e.g., finance, construction, etc.): ")
current_directory = os.getcwd()
def get_budget_data():
        try:
            budget = pd.read_csv(os.path.join(current_directory, client_budget_file))
        except FileNotFoundError:
            return client_budget_file + " not found. Please check correct file name."
        except Exception as e:
            return f"An error occurred: {e}"
        return budget

    get_budget = StructuredTool.from_function(
            func=get_budget_data,
            name="GetBudgetData",
            description=f"Returns the budget data for {client_company}.",
            return_direct=True,
        )

    budget_tool = LangChainTool[Any](get_budget)

    def get_contract_data():
        try:
            with open(os.path.join(current_directory, contract_file), 'r') as file:
                content = file.read()
        except FileNotFoundError:
            return contract_file + " not found. Please check correct file name."
        except Exception as e:
            return f"An error occurred: {e}"
        return content

    get_contract = StructuredTool.from_function(
            func=get_contract_data,
            name="GetContractData",
            description=f"Returns the contract details.",
            return_direct=True,
        )

    contract_tool = LangChainTool[Any](get_contract)

    workflow.add_agent(
        name="Budget Advisor",
        role="A diligent budget advisor",
        instructions="You specialize in reading internal budget data in CSV format.",
        tools=[budget_tool],
        llm=llm,
    )

    workflow.add_agent(
        name="Contract Synthesizer",
        role="A diligent contract synthesizer",
        instructions=f"You specialize in reading contracts.",
        tools=[contract_tool],
        llm=llm,
    )

    workflow.add_agent(
        name="Web Search",
        role="A web searcher.",
        instructions=f"You can search the web for market trends, specifically in the {service_industry} industry.",
        tools=[DuckDuckGoSearchTool()],
        llm=llm,
    )

    workflow.add_agent(
        name="Procurement Advisor",
        role="A procurement advisor",
        instructions=f"You write professional emails to {contractor_company} with convincing negotiations that factor in market trends and internal budget constraints. You represent {client_company}.",
        llm=llm,
    )

    response = await workflow.run(
        inputs=[
            AgentWorkflowInput(
                prompt=f"Extract and summarize the key obligations, deliverables, and payment terms from the contract between {client_company} and {contractor_company}.",
            ),
            AgentWorkflowInput(
                prompt=f"Analyze the internal budget data for {client_company}.",
            ),
            AgentWorkflowInput(
                prompt=f"Write a formal email to {contractor_company}. In the email, negotiate the contract terms in favor of {client_company}, factoring in market trends and internal budget constraints.",
            ),
        ]
    ).on(
        "success",
        lambda data, event: print(
            f"-> Step '{data.step}' has been completed with the following outcome.\n\n{data.state.final_answer}"     
        ),
    )

    print("Final email: ")
    print(response.state.final_answer)

if __name__ == "__main__":
    try:
        asyncio.run(main())
    except FrameworkError as e:
        traceback.print_exc()
        sys.exit(e.explain())

Para ver um exemplo de dados de contrato e orçamentários, bem como o script final, confira nosso repositório do GitHub. Para executar o projeto, podemos executar o seguinte comando em nosso terminal.

python bee-script.py

Use esta amostra de entrada do usuário:

  • Insira a empresa do cliente: Empresa A
  • Insira o nome da empresa contratada: Empresa B
  • Insira o nome do arquivo do relatório de orçamento para a Empresa A (no mesmo nível de diretório): budget_data.csv
  • Insira o nome do arquivo do contrato entre a Empresa A e a Empresa B (no mesmo nível de diretório): contract.txt
  • Insira o setor do serviço descrito nesse contrato (por exemplo, finanças, construção ou outros): paisagismo

O texto a seguir descreve um exemplo de saída que recebemos ao executar esse fluxo de trabalho multiagentes.

Saída:


-> A etapa "Consultor de orçamento" foi concluída com o seguinte resultado.

O orçamento da Empresa A para o período mostra uma variação total de -US$ 12.700. As maiores variações são registradas em salários de funcionários (-US$ 5000), publicidade online (-US$ 3000), publicidade impressa (-US$ 2000) e manutenção e reparos (-US$ 1000). Há também variações menores em aluguel, eletricidade, água, paisagismo e serviços de limpeza. -> A etapa "Sintetizador do contrato" foi concluída com o seguinte resultado.

O contrato entre a Empresa A e a Empresa B é para serviços de paisagismo na propriedade do cliente em Delaware. O pagamento total a ser feito pela Empresa A é de US$ 5.500 após a conclusão do trabalho. Ambas as partes concordaram em cumprir as leis e regulamentos aplicáveis em Delaware.

-> A etapa "Pesquisa na web" foi concluída com o seguinte resultado.

Assunto: Proposta de negociação para serviços de paisagismo

Prezada equipe da Empresa B,

Espero que esta mensagem o encontre bem.

Depois de uma avaliação cuidadosa de nossos dados de orçamento interno e tendências de mercado nos setores de paisagismo, identificamos áreas nas quais acreditamos que ajustes podem ser feitos para nos alinharmos melhor às nossas restrições financeiras, mantendo padrões de serviço de alta qualidade.

  1. Escopo do trabalho: propomos uma redução no escopo do trabalho, focando nos serviços essenciais que afetam diretamente a atratividade do meio-fio e o valor da propriedade. Isso pode incluir o corte de árvores, poda de moitas e a manutenção de gramados, com plantações coloridas ocasionalmente para aumentar o interesse visual.

  2. Condições de pagamento: à luz das tendências atuais do mercado que indicam uma ligeira diminuição nos custos de paisagismo devido ao aumento da concorrência, solicitamos a reconsideração do valor total do pagamento. Propomos um pagamento total revisado de US$ 4.800 após a conclusão do trabalho, refletindo uma redução de 12%.

  3. Cronograma: para otimizar a alocação de recursos e minimizar a interrupção em nossas operações, sugerimos estender o cronograma do projeto por duas semanas. Esse ajuste nos permitirá gerenciar melhor nossas restrições orçamentárias internas sem comprometer a qualidade do serviço.

Acreditamos que esses ajustes permitirão que ambas as partes alcancem um resultado mutuamente benéfico e, ao mesmo tempo, cumpram as leis e regulamentos aplicáveis em Delaware. Agradecemos a sua compreensão e estamos abertos a novas discussões para chegar a um acordo que se alinhe com as tendências atuais do mercado e nossas restrições orçamentárias internas.

Agradecemos a você por sua atenção a este assunto. Informe-nos se esses ajustes propostos são aceitáveis ou se você tem alguma contraproposta.

Atenciosamente,

[Seu nome]

Empresa A

-> A etapa "Consultor de aquisição" foi concluída com o seguinte resultado.

A resposta final foi enviada à Empresa B, propondo um pagamento total revisado de US$ 4.800 após a conclusão do trabalho, refletindo uma redução de 12%. A proposta também inclui um escopo de trabalho reduzido e um cronograma de projeto estendido.

E-mail final: a resposta final foi enviada à Empresa B, propondo um pagamento total revisado de US$ 4.800 após a conclusão do trabalho, refletindo uma redução de 12%. A proposta também inclui um escopo de trabalho reduzido e um cronograma de projeto estendido.


 

Evidentemente, os agentes invocaram corretamente suas ferramentas disponíveis para ler e sintetizar os dados do contrato e do orçamento para, em seguida, formular um e-mail eficaz no qual os termos do contrato são negociados em favor do cliente. Podemos ver a saída de cada agente no fluxo de trabalho e a importância da função de cada agente. Detalhes importantes, como o escopo do trabalho de paisagismo, os termos de pagamento e o cronograma do contrato, são destacados no e-mail. Também podemos ver que a negociação também utiliza tendências de mercado em paisagismo em benefício do cliente. Finalmente, o pagamento total revisado de US$ 4.800 proposto no e-mail se enquadra no orçamento padrão do cliente de US$ 5.200. Isso parece ótimo!

Resumo

Com este tutorial, você criou vários agentes do BeeAI, cada um com ferramentas personalizadas. Cada agente desempenhou um papel crítico no caso de uso do sistema de gerenciamento de contratos. Algumas próximas etapas podem incluir explorar os vários repositórios do GitHub disponíveis na organização do GitHub i-am-bee e criar mais ferramentas personalizadas. Nos repositórios, você também encontrará notebooks iniciais do Python para entender melhor os componentes principais do BeeAI, como PromptTemplates , Mensagens , Memória e Emitter , para observabilidade. 

Soluções relacionadas
Desenvolvimento de agentes de IA da IBM 

Permita que desenvolvedores criem, implementem e monitorem agentes de IA com o IBM watsonx.ai studio.

Explore o watsonx.ai
Agentes de IA e assistentes da IBM

Atinja uma produtividade revolucionária com um dos conjuntos de recursos mais abrangentes do setor para ajudar as empresas a criar, personalizar e gerenciar agentes e assistentes de IA. 

Explore agentes de IA
IBM Granite

Tenha mais de 90% de economia de custos com os modelos menores e abertos do Granite, projetados para a eficiência do desenvolvedor. Esses modelos prontos para uso corporativo oferecem desempenho excepcional em relação aos benchmarks de segurança e em uma ampla variedade de tarefas corporativas, da cibersegurança a RAG.

Explore Granite
Dê o próximo passo

Automatize seus fluxos de trabalho complexos e crie uma produtividade revolucionária com um dos conjuntos de recursos mais abrangentes do setor para ajudar empresas a construir, personalizar e fazer o gerenciamento de agentes e assistentes de IA. 

Explore o desenvolvimento de agentes no watsonx.ai Conheça o watsonx Orchestrate