Construção de um agente de raciocínio ReWOO usando o IBM Granite

Autor

Jobit Varughese

Technical Content Writer

IBM

Os grandes modelos de linguagem (LLMs) e suas variantes aprimoradas, os modelos de linguagem aumentada (ALMs), tornaram-se a espinha dorsal dos sistemas modernos de IA. Ao combinar a geração de linguagem poderosa com técnicas externas de recuperação de conhecimento, como a geração aumentada de recuperação (RAG), eles possibilitam um raciocínio avançado, a resposta a perguntas e a automação de tarefas em diversos domínios. No entanto, apesar de seus recursos notáveis, esses modelos muitas vezes enfrentam desafios como robustez inconsistente entre sistemas, alto uso de tokens, tempos de resposta lentos e ineficiências causadas por prompts repetitivos e contexto redundante, ao lidar com tarefas complexas. Essas limitações aumentam os custos operacionais e dificultam a escalabilidade e o desempenho em tempo real.

Para superar esses problemas, o framework ReWOO (raciocínio sem observação) oferece uma abodagem que se concentra em desacoplar o raciocínio da recuperação de conhecimento externo. Em vez de ter um único LLM tentando raciocinar, agir e observar de maneira intercalada, o ReWOO separa essas preocupações em módulos distintos, cada um potencialmente alimentado por um LLM, mas com uma função específica. Ao modularizar o processo em estágios distintos de planejamento, coleta de evidências e síntese, o ReWOO melhora a eficiência e a precisão dos tokens. Isso também facilita a depuração do sistema e permite fluxos de trabalho de IA mais simplificados e eficazes.

A metodologia por trás do ReWOO

O fluxo de trabalho do ReWOO gira em torno de três componentes principais: raciocínio passo a passo, chamadas de ferramentas e sumarização. Esses componentes são implementados em uma estrutura modular composta por três partes: o planejador, o trabalhador e o solucionador.

Planejador

O planejador divide a tarefa principal em uma sequência de subperguntas focadas, criando um blueprint claro. Em vez de pedir ao LLM que responda a uma pergunta complexa de uma só vez, o que pode levar a um uso sobrecarregado de tokens e respostas confusas, o planejador cria um blueprint ou um roteiro. Esse detalhamento passo a passo orienta o fluxo de trabalho e mantém o processo de raciocínio estruturado.

Trabalhador

O trabalhador chama ferramentas externas, como mecanismos de pesquisa ou bancos de dados, para recuperar informações relevantes e evidências necessárias para responder às subperguntas. Ele usa o LLM para formular respostas claras e concisas com base exclusivamente nas informações recuperadas. Essa fase de observação externa é mantida separada do processo de raciocínio para evitar repetição desnecessária de prompts e reduzir o consumo de tokens.

Solucionador

O solucionador sintetiza todos os insights coletados para gerar uma resposta final atualizada e bem estruturada. Essa separação modular ajuda a garantir um raciocínio eficiente, preciso e escalável com grandes modelos de linguagem.

Frameworks como o LangChain e LangGraph fornecem ferramentas poderosas para implementar a arquitetura ReWOO usando modelos do OpenAI, IBM Granite ou ferramentas especializadas como Serper e Tavily para pesquisa.

Neste tutorial, você irá explorar como criar um agente ReWOO que executa a tarefa de sumarização de conteúdo. Esse agente pode:

  • Dividir uma tarefa de alto nível em subperguntas
  • Usar a pesquisa na web para reunir contexto relevante para cada subpergunta
  • Gerar respostas usando o IBM Granite
  • Resumir os resultados em uma resposta final

Essa arquitetura é útil para:

  • Tarefas de sumarização
  • Respostas a perguntas sobre conhecimento externo
  • Raciocínio dinâmico e melhorado com ferramentas

Tecnologias usadas

Este tutorial passo a passo aproveita tecnologias de IA de ponta, incluindo:

  1. IBM Granite Instruct: um LLM poderoso para acompanhamento de instruções gerais, ideal para assistentes de IA em negócios e outros domínios.
  2. Transformers: uma biblioteca Python amplamente utilizada que fornece ferramentas para carregar, tokenizar e executar modelos de linguagem como o IBM Granite. Ele permite o processamento eficiente de entradas de texto e geração de saídas de modelos.

Etapas

Etapa 1: Configure seu ambiente

Este tutorial vai orientar você na configuração do seu ambiente de desenvolvimento local para executar um pipeline de raciocínio no estilo ReWOO usando o Jupyter Notebook. Você usará o modelo de linguagem IBM Granite e o Serper.dev para recuperação de pesquisa na web em tempo real.

Observação: nenhuma GPU é necessária, mas a execução pode ser mais lenta em sistemas baseados em CPU. Essa etapa abre um ambiente do Notebook, onde você poderá copiar o código deste tutorial. Este tutorial também está disponível no GitHub.

Etapa 2: Instale as dependências necessárias

Essas bibliotecas são necessárias para executar o pipeline do ReWOO e interagir com ferramentas externas:

transformers: carrega e executa o grande modelo de linguagem IBM Granite.

torch: um framework de deep learning necessário para executar o modelo de forma eficiente.

accelerate: otimiza o desempenho do modelo em todo o hardware (opcional).

requests: envia solicitações HTTP POST para APIs externas (como Serper).

!pip install transformers accelerate torch requests

Etapa 3: Importe as bibliotecas necessárias

Nesta etapa, importe as bibliotecas Python necessárias para construir os componentes principais do pipeline ReWOO.

transformers.AutoTokenizer: carrega o tokenizador que converte texto em tokens compatíveis com o modelo de idioma.

transformers.AutoModelForCausalLM: carrega o modelo de linguagem pré-treinado IBM Granite para gerar respostas.

transformers.pipeline: Fornece uma interface de alto nível para criar rapidamente um pipeline de geração de texto usando o tokenizador e o modelo.

import requests
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline

Etapa 4: Carregue o modelo IBM Granite e crie um pipeline de geração de texto

Nesta etapa, carregamos o modelo de linguagem IBM Granite e inicializamos um pipeline de geração de texto usando a biblioteca de transformadores do Hugging Face. Explore o modelo Granite 3.2 2B Instruct no Hugging Face aqui.

model_id = "ibm-granite/granite-3.2-2b-instruct": Especifica o nome do ponto de verificação do modelo IBM Granite hospedado no Hugging Face. Esse modelo é otimizado para tarefas que seguem instruções.

AutoTokenizer.from_pretrained(model_id): carrega o tokenizer associado ao modelo especificado. É responsável por converter texto de entrada em tokens e decodificar tokens de saída de volta em texto.

AutoModelForCausalLM.from_pretrained(model_id): carrega o modelo de idioma (Granite 3.2 2B Instruct) para tarefas de geração de texto, como resposta a perguntas ou sumarização.

pipeline("text-generation", model=model, tokenizer=tokenizer): cria um pipeline de geração de texto de alto nível que combina o modelo e o tokenizador, facilitando a geração de respostas a partir de prompts.

model_id = "ibm-granite/granite-3.2-2b-instruct"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id)
generator = pipeline("text-generation", model=model, tokenizer=tokenizer)

Etapa 5: Configure a API do Serper para recuperação de pesquisa na web

Nesta etapa, definimos uma função que atua como trabalhador na arquitetura ReWOO. Esse trabalhador usa uma ferramenta de pesquisa na web, Serper.dev, para recuperar informações relevantes e atualizadas da internet para apoiar o raciocínio e a geração de respostas. O Serper.dev é uma API rápida e leve que entrega resultados do Google Search em um formato estruturado, o que o torna ideal para a recuperação de informações em tempo real nos fluxos de trabalho de IA.

Essa configuração permite que o sistema ReWOO "observe" o mundo real, consultando fontes externas de conhecimento antes que o LLM tome as decisões finais.

Para usar o Serper no pipeline do ReWOO:

  1. Acesse https://serper.dev e crie uma conta gratuita.
  2. Após a inscrição, navegue até o dashboard e copie a chave de API.
  3. No código, armazene a chave de API de forma segura. Por enquanto, atribua-a diretamente, conforme mostrado após isto:

SERPER_API_KEY = "<YOUR_API_KEY>" # Substitua pela sua chave real

Observação: nunca carregue sua chave de API em repositórios públicos. Para configurações de produção ou de equipe, use arquivos .env ou variáveis de ambiente para mantê-la segura.

Captura de tela do ReWOO

def query_serper(question, num_results=3): define uma função que recebe uma pergunta de pesquisa e retorna trechos relevantes dos principais resultados da pesquisa.

payload = {"q": question, "num": num_results}: prepara a carga útil da consulta com o termo de pesquisa e o número de resultados a serem retornados.

response = requests.post(...): envia uma solicitação POST para a API do Serper com sua consulta e cabeçalhos.

response.raise_for_status(): Gera um erro se a resposta da API for inválida ou falhar.

snippets = ...: extrai o texto do trecho dos resultados da pesquisa orgânica.

return "\n".join(snippets): Junta e retorna os fragmentos como uma única string, servindo como contexto para o modelo de linguagem.

Observação: essa função forma a espinha dorsal da etapa de "observação" do ReWOO, onde evidências externas são coletadas para raciocínio adicional. Certifique-se de que sua chave de API seja válida e não tenha limitação de taxa durante o teste.

SERPER_API_KEY = "your_serper_api_key_here" # Replace with your actual key
def query_serper(question, num_results=3):
    url = "https://google.serper.dev/search"
    headers = {
            "X-API-KEY": SERPER_API_KEY,
            "Content-Type": "application/json"
}
    payload = {"q": question, "num": num_results}
    response = requests.post(url, headers=headers, json=payload)
    response.raise_for_status()
    data = response.json()
    snippets = [item.get("snippet", "") for item in data.get("organic", [])]
    return "\n".join(snippets)

Etapa 6: Gere respostas informadas usando a função expert

Nesta etapa, definimos a função expert(), que atua como solucionador na arquitetura do ReWOO. O solucionador sintetiza as evidências externas recuperadas e gera uma resposta final usando o modelo de linguagem.

def expert(question: str) -> str: a função expert() pega uma pergunta (string) e retorna uma resposta (string) gerada pelo modelo Granite. Funciona pesquisando na web com o Serper.dev, coletando informações relevantes e usando-as para gerar uma resposta clara e completa.

context = query_serper(question): usa a ferramenta de pesquisa na web Serper para recuperar informações relevantes (trabalhador).

prompt = f"""...""": cria um prompt que instrui o modelo a responder usando apenas o contexto recuperado.

generator(...): chama o modelo Granite para gerar uma resposta com base no prompt de entrada.

for _ in range(5): esse ciclo permite que o modelo gere uma resposta em blocos, até cinco vezes. Ajuda se a resposta for longa e não puder ser concluída de uma só vez.

generated_text += new_text: acrescenta cada novo fragmento de texto para formar a resposta completa.

if new_text.endswith(...): se a resposta parecer completa (termina com um ponto final, ponto de interrogação ou ponto de exclamação) e tiver palavras suficientes (mais de 50), interrompe o ciclo.

return generated_text.strip(): retorna a resposta final limpa.

Observação: o formato do prompt é importante, pois garante que o modelo não "alucine" ou fique fora do tópico. Deve se ater ao que está no contexto. Limitamos cada fragmento da geração a 120 tokens para controlar a produção e gerenciar o uso de recursos de forma eficiente, evitando o uso excessivo de tokens.

def expert(question: str) -> str:
    context = query_serper(question) # your retrieval function
    prompt = f"""You are a knowledgeable expert. Based ONLY on the context below, answer the question clearly and concisely in your own words.
Do NOT mention any sources or references.
Context:
{context}
Question: {question}
Answer:"""
    input_prompt = prompt
    generated_text = ""
    last_generated = ""
    for _ in range(5): # up to 5 chunks
        outputs = generator(
            input_prompt,
            max_new_tokens=120,
            do_sample=False,
            eos_token_id=tokenizer.eos_token_id,
            # no invalid flags like 'temperature' here
        )
        text = outputs[0]["generated_text"]
        new_text = text[len(input_prompt):].strip()
        # Stop if no new content
        if new_text == last_generated:
            break
        generated_text += new_text + " "
        input_prompt = prompt + generated_text
        last_generated = new_text
        if new_text.endswith(('.', '!', '?')) and len(generated_text.split()) > 50:
            break
    return generated_text.strip()

Etapa 7: Defina o módulo do planejador

Nesta etapa, definimos a função Planner, que divide uma tarefa de entrada ampla em subperguntas menores e bem definidas, um princípio fundamental do raciocínio passo a passo do ReWOO.

def planner(task: str): isso define uma função chamada planner, que aceita uma tarefa de argumento único (uma string descrevendo a tarefa a ser executada).

topic = task.replace("Summarize", "").replace("the novella", "").strip(): Extraia o assunto principal (por exemplo, o título ou tema) da tarefa. Ele limpa a entrada removendo frases de prompt comuns como "Resuma" e "a novela" e, em seguida, apara os espaços em branco iniciais e finais para isolar o tópico central.

return [ ... ]: retorna uma lista de perguntas específicas que orientam o módulo trabalhador.

Observação: é possível ampliar essa lista com subperguntas mais específicas, dependendo da profundidade e da natureza do tópico de entrada.

def planner(task: str):
topic = task.replace("Summarize", "").replace("the novella", "").strip()
return [
f"What is the main plot related to {topic}?",
f"Who are the key characters in {topic}?",
f"What themes are explored in {topic}?"
]

Etapa 8: Defina o sumarizador final (módulo solucionador)

Nesta etapa, definimos a função final_summarizer, que atua como um solucionador no pipeline do ReWOO. Essa função pega as sub-respostas (evidências) fornecidas pelo trabalhador e gera um resumo recém-escrito e coerente usando o modelo de linguagem.

def final_summarizer(task: str, sub_answers: dict) -> str: define a função que recebe a tarefa original e as sub-respostas e retorna um resumo conciso.

insights = "\n".join(sub_answers.values()): Combina todas as respostas em uma única string separada por novas linhas para inclusão no prompt.

base_prompt = f"""...""": constrói o prompt básico que instrui o modelo a resumir os insights fornecidos. Orienta o modelo para gerar um novo resumo com base apenas em sub-respostas.

max_total_tokens = 400: define um limite superior para a contagem de tokens gerados para evitar saída excessivamente longas.

max_loops = 5: permite até cinco iterações de geração para construir progressivamente o resumo.

for in range(maxloops): loops para gerar fragmentos de texto usando o modelo de linguagem.

response = generator(..., max_new_tokens=100, ...): utiliza o gerador (objeto do pipeline) para gerar até 100 novos tokens em cada ciclo. O modo de amostragem (do_sample=True) permite variação e criatividade na resposta.

if summary.endswith(...) or total_tokens_used >= max_total_tokens: termina o ciclo se o resumo for concluído com pontuação adequada ou atingir o limite de tokens.

return summary.strip(): Retorna o resumo final sem defeitos, sem espaços à direita.

def final_summarizer(task: str, sub_answers: dict) -> str:
    insights = "\n".join(sub_answers.values())
    base_prompt = f"""You are an expert summarizer. Based on the following insights, write a fresh, concise summary of the text. The summary must be newly written and must end in a complete sentence with proper punctuation.
Insights:
{insights}
Summary:"""
    summary = ""
    current_prompt = base_prompt
    max_total_tokens = 400
    total_tokens_used = 0
    max_loops = 5
    for _ in range(max_loops):
        response = generator(current_prompt, max_new_tokens=100, do_sample=True, top_p=0.9, eos_token_id=tokenizer.eos_token_id)
        chunk = response[0]["generated_text"][len(current_prompt):].strip()
        summary += " " + chunk
        summary = summary.strip()
        total_tokens_used += len(chunk.split())
        if summary.endswith(('.', '!', '?')) or total_tokens_used >= max_total_tokens:
            break
        # Prepare prompt for next loop
        current_prompt = base_prompt + summary
    return summary.strip()

Etapa 9: Orquestre o agente do ReWOO com a função solver

Nesta etapa, definimos a função solver, que representa o estágio final no pipeline do ReWOO. Ela orquestra o processo completo usando o planejador, chamando o especialista (trabalhador) e gerando um resumo usando o final_summarizer (resolvedor). A arquitetura do ReWOO permite o raciocínio multietapas, dividindo a tarefa principal em subperguntas usando um planejador. Cada subpergunta é abordada de forma independente por um módulo especializado, e o sumarizador final sintetiza todas as respostas em uma resposta coerente. Este método modular permite que o sistema enfrente tarefas complexas de maneira mais eficiente.

def solver(task: str): define a função principal do controlador para executar o fluxo de trabalho completo do ReWOO.

subquestions = planner(task): usa o planejador para dividir a tarefa de entrada em subperguntas focadas.

ans = expert(q): para cada subpergunta, chama a função expert para buscar evidências baseadas na web e gerar uma resposta relevante. Cada subpergunta gerada pelo planejador é passada ao especialista como uma entrada da ferramenta. O módulo especialista processa a entrada usando um modelo de linguagem. Isso pode ser visto como a execução de uma ferramenta para uma subtarefa específica.

answers[q] = ans: armazena cada resposta codificada por sua pergunta correspondente para sumarização posterior.

final_summary = final_summarizer(task, answers): alimenta todas as respostas coletadas no final_summarizer para gerar um resumo limpo e coerente.

print(final_summary) and return final_summary: exibe e retorna o resumo concluído da tarefa original.

Observação: o tempo total gasto pela função solver() pode variar entre os sistemas devido às diferenças na velocidade da CPU, na RAM disponível e na eficiência com que o modelo é executado em diferentes configurações de hardware. Como o código usa uma estratégia de geração em ciclo com um modelo de linguagem, sistemas com menor poder de processamento ou memória podem demorar significativamente mais. A recuperação baseada em rede e grandes tamanhos de prompt também podem contribuir para atrasos. Para melhorar o desempenho, considere reduzir o max_loops usando um modelo menor ou quantizado, otimizando o pipeline do tokenizador e do gerador ou executando o código em um ambiente habilitado para GPU, como o Google Colab ou o Kaggle Notebooks.

def solver(task: str):
    print(f"Planner: Breaking down '{task}' into sub-questions...\n")
    subquestions = planner(task)
    answers = {}
    for q in subquestions:
        print(f"🔎 Expert answering: {q}")
        ans = expert(q)
        print(f"➡ Answer: {ans}\n")
        answers[q] = ans
    print("=== Final Summary ===\n")
    final_summary = final_summarizer(task, answers)
    print(final_summary)
    return final_summary

Etapa 10: Execute o pipeline do ReWOO para gerar o resumo final

Nesta etapa final, executamos o pipeline completo do ReWOO chamando a função solver com uma tarefa específica.

solver("Resuma a novela The Metamorphology"): Aciona todo o processo do ReWOO; planejamento, recuperação de evidências e geração de um resumo para a tarefa de entrada: sumarização do conjunto de dados The Metamorphsis.

Esta etapa produz o resumo final e demonstra como os componentes do ReWOO trabalham juntos de ponta a ponta para um caso de uso real.

solver("Summarize the novella The Metamorphosis")

Principais conclusões

  1. O agente do ReWOO decompôs com sucesso a tarefa (“Resuma a novela The Metamorphsis”) em subperguntas significativas sobre enredo, personagens e temas, permitindo a recuperação de informações focadas.
  2. Cada subpergunta foi respondida usando uma pesquisa na web em tempo real (Serper.dev) e o IBM Granite, produzindo respostas relevantes e bem estruturadas que capturaram os elementos centrais do texto.
  3. A resposta final foi coerente, escrita recentemente e precisa, demonstrando como a geração aumentada de recuperação pode produzir resumos de alta qualidade e semelhantes aos humanos para tarefas de análise literária.

Observação: para melhorar o desempenho e a confiabilidade do pipeline do ReWOO, é importante melhorar as métricas de avaliação, como qualidade de sumarização, coerência e latência de geração. Essas métricas ajudam a avaliar o desempenho do sistema em diferentes tarefas e configurações de hardware. A arquitetura pode ser ampliada integrando algoritmos inteligentes para dividir grandes perguntas em perguntas menores e classificar as respostas mais úteis. Essas melhorias permitiriam um raciocínio mais preciso e eficiente, reduziriam o tempo de geração e melhorariam a qualidade geral das saídas finais.

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