Agente ReAct no watsonx Orchestrate — API REST real + RAG, construído com IBM Bob

Pedi para o agente “me reserva nesse voo” e ele não reservou. Em vez de preencher a chamada com um user_id qualquer para satisfazer o schema, ele percebeu que faltava cadastro e me perguntou nome e e-mail. Quando respondi, executou duas ferramentas em sequência sozinho: registrou o passageiro, pegou o ID que voltou na resposta e só então fez a reserva.

Esse é o comportamento que separa um agente de verdade de um chatbot com acesso a API. O modelo não tinha o user_id, e a alternativa fácil — inventar um número — é exatamente o que quebra sistemas em produção. Este lab monta esse cenário: um agente ReAct no IBM watsonx Orchestrate ligado a uma API REST real e a uma base de conhecimento (RAG) com documentos corporativos.

O cenário e a API de reservas vêm do projeto IBM/galaxium-travels, uma aplicação de demonstração publicada pela IBM sob Apache-2.0 — o backend em FastAPI já vinha pronto. O que construí em cima disso foi a camada de agente: ferramentas, base de conhecimento e o YAML do agente, usando o ADK do watsonx Orchestrate. Essa parte foi feita com o IBM Bob, o assistente de código da IBM — das specs OpenAPI aos YAMLs de agente e knowledge base.

Objetivo do Lab

Construir um agente único que age sobre um sistema real (sistema de reservas de viagens espaciais, via FastAPI + SQLite) e consulta documentos internos (catálogo de pacotes, FAQ, guia de preparação) para responder dúvidas de política — decidindo sozinho qual dos dois caminhos usar em cada pergunta.

O ponto central é a orquestração de fluxos de múltiplas etapas: a API exige que o passageiro exista antes de reservar, e é o agente que descobre e resolve essa dependência.

Antes de Começar — O Que Você Precisa

Este lab é reproduzível em casa, e tudo que ele usa tem versão gratuita. São quatro coisas para preparar antes de escrever qualquer YAML.

1. Conta no watsonx Orchestrate (trial de 30 dias)

O Orchestrate é um produto pago, mas oferece trial gratuito de 30 dias — suficiente com folga para este lab. Cadastre-se pela página do produto usando um IBMid (que também é grátis e serve para o Bob depois).

Com o ambiente provisionado, pegue as duas credenciais que o ADK vai pedir:

  1. Faça login na sua instância do watsonx Orchestrate
  2. Clique no ícone de usuário no canto superior direito e vá em Settings
  3. Abra a aba API details
  4. Copie a service instance URL
  5. Clique em Generate API key e guarde a chave

Guarde a API key com cuidado: dependendo do provedor ela não é recuperável depois — se perder, é preciso gerar outra.

2. Python 3.11+ e o ADK

O ADK (Agent Development Kit) é o orchestrate CLI, e exige Python 3.11 ou superior:

python3 --version                              # precisa ser >= 3.11
pip install --upgrade ibm-watsonx-orchestrate
orchestrate --help                             # confirma a instalação

Agora conecte o CLI ao seu ambiente, usando as credenciais do passo anterior:

# registra o ambiente (a URL da aba API details)
orchestrate env add -n meu-wxo -u <service-instance-url>

# ativa (vai pedir a API key; ou passe com --api-key)
orchestrate env activate meu-wxo

Confira se está tudo certo:

orchestrate env list
orchestrate agents list

A autenticação remota expira a cada ~2 horas. Quando os comandos começarem a falhar com erro de token, rode o orchestrate env activate de novo — é o motivo mais comum de “parou de funcionar do nada” no meio do lab.

3. O IBM Bob (opcional, mas foi como fiz)

O Bob é o assistente de código da IBM — um fork do VS Code com um agente integrado. Tem trial de 30 dias com 40 Bobcoins; depois é assinatura paga. Baixe em bob.ibm.com/download:

Requer 4 GB de RAM (8 GB recomendado), 500 MB de disco e login com IBMid no primeiro início.

O lab funciona sem o Bob — os YAMLs estão todos neste post. Ele entra como acelerador para escrever spec, YAMLs e instruções.

4. O repositório da Galaxium Travels

O cenário e a API vêm do projeto da IBM:

git clone https://github.com/IBM/galaxium-travels.git
cd galaxium-travels

O repositório completo traz um frontend React e um serviço Java de holds, mas para este lab só o backend Python importa — é ele que vira as ferramentas do agente. Você pode ignorar o resto.

Tecnologias Utilizadas

Antes do código, vale entender cada peça — inclusive porque algumas são específicas do ecossistema IBM.

IBM watsonx Orchestrate

Plataforma da IBM para criar e executar agentes de IA que integram sistemas corporativos. Em vez de você escrever o laço de raciocínio do agente na mão (chamar o modelo, interpretar a resposta, executar a ferramenta, devolver o resultado, repetir), o Orchestrate cuida disso. Você declara o agente em YAML: qual modelo usar, quais ferramentas ele tem, qual base de conhecimento consultar e quais instruções seguir.

O trabalho é feito pelo orchestrate CLI, o ADK (Agent Development Kit), que importa ferramentas, bases de conhecimento e agentes para o ambiente.

Agente ReAct

ReAct significa Reasoning + Acting — raciocinar e agir. É um padrão em que o modelo alterna entre pensar e executar: analisa o pedido, decide qual ferramenta chamar, observa o resultado, pensa de novo com essa informação nova e decide o próximo passo.

A diferença prática em relação a um modelo que só responde texto: o agente ReAct pode encadear chamadas, usando a saída de uma como entrada da próxima. É o que permite resolver “registrar → reservar” sem que ninguém tenha programado essa sequência.

O laço ReAct — pensa, age, observa e repete até conseguir responder

OpenAPI Specification

Formato padrão (JSON ou YAML) que descreve uma API REST: quais endpoints existem, que parâmetros aceitam, o que retornam. É a forma como o Orchestrate transforma uma API em ferramentas do agente — sem escrever uma linha de código de integração.

Cada endpoint da spec vira uma ferramenta, e a descrição de cada campo é o que o modelo lê para decidir quando e como usá-la. Descrição ruim na spec significa ferramenta usada errado pelo agente.

RAG (Retrieval-Augmented Generation)

Geração aumentada por recuperação. O modelo responde a partir dos seus documentos, não apenas do que aprendeu no treinamento. Os documentos são quebrados em pedaços (chunks), convertidos em vetores numéricos (embeddings) e indexados. Na hora da pergunta, o sistema busca os trechos mais parecidos semanticamente e injeta no contexto antes de gerar a resposta.

O ganho é direto: preço de pacote e política de cancelamento saem do catálogo real da empresa, não da imaginação do modelo.

FastAPI + SQLite

FastAPI é o framework Python que expõe o sistema de reservas como API REST. Ele gera a spec OpenAPI automaticamente a partir do código — o que economiza justamente o passo mais chato deste lab. SQLite é o banco em arquivo único que guarda voos, usuários e reservas, sem exigir servidor de banco.

IBM Bob

Assistente de código da IBM, usado aqui para construir a camada de agente sobre a aplicação existente: ajustar a spec OpenAPI para o formato que o Orchestrate aceita, escrever os YAMLs do agente e da base de conhecimento, redigir as instruções de roteamento e montar o script de subida da API.

Arquitetura

                    [ Usuário via chat ]
                            │
                            ▼
              [ galaxium_travel_agent  (ReAct) ]
                   granite-3-8b-instruct
                     │               │
          ┌──────────┘               └──────────┐
          ▼                                     ▼
 [ Ferramentas OpenAPI ]              [ Base de conhecimento ]
   FastAPI + SQLite :8001                RAG · 3 documentos
   flights / register / user             pacotes · FAQ ·
   book / bookings / cancel              preparação
Componente Função
galaxium_travel_agent Agente ReAct que decide entre agir (API) e consultar (RAG)
granite-3-8b-instruct Modelo IBM Granite que faz o raciocínio do agente
Ferramentas OpenAPI 6 endpoints da API de reservas, importados via spec
galaxium-travels-kb Base vetorial com os 3 documentos corporativos
FastAPI + SQLite Sistema de reservas real, na porta 8001
orchestrate CLI Importa ferramentas, KB e agente para o ambiente

O diagrama abaixo percorre o processo inteiro, etapa por etapa: o Bob preparando os documentos da base de conhecimento, a ingestão no RAG (chunking, embeddings, índice), a API virando ferramentas via OpenAPI, a montagem do agente e — no final — a conversa real em que ele registra o passageiro e efetiva a reserva.

Diagrama animado — do preparo da base de conhecimento até a reserva efetivada pelo agente

As cinco etapas que o diagrama percorre são exatamente as deste post:

Etapa O que acontece Comando
1. Documentos Catálogo, FAQ e guia (do repositório da IBM) viram a matéria-prima do RAG
2. RAG Chunking, embeddings e índice vetorial orchestrate knowledge-bases import
3. API A spec OpenAPI vira 6 ferramentas do agente orchestrate tools import
4. Agente ReAct ligando ferramentas + base de conhecimento orchestrate agents import
5. Reserva O agente encadeia registerbook sozinho orchestrate chat start

Há também uma versão interativa do diagrama, com as mesmas cinco etapas em HTML.

Como as Partes se Conectam

O fluxo começa no chat. O agente recebe a mensagem e o modelo Granite decide o caminho com base nas instruções do YAML:

Se a pergunta depende do estado atual do sistema — quais voos existem, quantos assentos sobraram, quais reservas o cliente tem — ele chama uma ferramenta. Os dados vêm do SQLite via FastAPI, sempre atuais.

Se a pergunta é sobre política ou catálogo — quanto custa o pacote lunar, qual a regra de cancelamento, o que pode levar na bagagem — ele consulta o RAG. A resposta sai dos documentos indexados.

E quando o pedido exige as duas coisas, ou várias etapas encadeadas, o laço ReAct entra em ação: age, observa o retorno, raciocina de novo e decide o próximo passo.

Estrutura do Projeto

Organizei o lab assim — os itens marcados com [IBM] vêm do repositório original, os demais são a camada de agente que construí:

wxo-galaxium-travels-agent/
├── start_api.sh                    # atalho meu: venv + seed + uvicorn
├── galaxium-openapi.json           # OpenAPI spec ajustado p/ o Orchestrate
├── galaxium-knowledge-base.yaml    # definição da base RAG
├── galaxium-travel-agent.yaml      # definição do agente ReAct
├── knowledge-bases/                # [IBM] documentos indexados no RAG
│   ├── travel_packages_catalog.md  # pacotes e preços
│   ├── passenger_faq.md            # perguntas frequentes
│   └── passenger_preparation_guide.md
├── booking_system_backend/         # [IBM] a API REST
│   ├── server.py                   # endpoints FastAPI
│   ├── models.py                   # tabelas (User, Flight, Booking)
│   ├── schemas.py                  # contratos de entrada/saída
│   ├── seed.py                     # dados de demonstração
│   └── services/                   # regras de negócio
└── diagrama/                       # diagrama animado do fluxo
    ├── gerar_gif.py                # gera o GIF das 5 etapas (Pillow)
    ├── wxo-galaxium-travels-agent.gif
    └── wxo-galaxium-travels-agent.html

A API de Reservas

O agente só é interessante se tiver um sistema real para controlar. O backend define três tabelas — usuários, voos e reservas — com o detalhe que gera a dependência interessante: Booking tem uma foreign key para User.

class Booking(Base):
    __tablename__ = 'bookings'
    booking_id = Column(Integer, primary_key=True, autoincrement=True)
    user_id = Column(Integer, ForeignKey('users.user_id'), nullable=False)
    flight_id = Column(Integer, ForeignKey('flights.flight_id'), nullable=False)
    status = Column(String, nullable=False)
    seat_class = Column(String, nullable=False, default='economy')
    price_paid = Column(Integer, nullable=False)

user_id é obrigatório e referencia um usuário existente. Reservar sem cadastro é impossível — e o sistema não inventa passageiro. Essa restrição de banco é o que força o agente a planejar.

Para subir a API, direto do repositório clonado:

cd galaxium-travels/booking_system_backend
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python server.py                 # sobe na porta 8001

Na primeira execução o banco é populado com dados de demonstração — 10 voos (Terra → Marte, Terra → Lua, Júpiter → Europa…) e 10 usuários. A semeadura é idempotente: só roda se o banco estiver vazio, então reiniciar não apaga o que você cadastrou.

Deixe este terminal aberto — a API precisa continuar no ar durante todo o lab.

Confirme que subiu abrindo o Swagger no navegador:

curl -s http://localhost:8001/flights | head -c 200

Sobre o endereço do Swagger, atenção a uma pegadinha: depende de como o backend foi configurado. No repositório oficial ele responde em http://localhost:8001/docs. Nesta cópia do lab o server.py define root_path="/api" (um ajuste para roteamento por load balancer), o que empurra tudo para baixo de /api — e aí o Swagger fica em http://localhost:8001/api/docs.

Se /docs der 404, tente /api/docs, e vice-versa. Isso importa além do Swagger: é o mesmo prefixo que precisa entrar no servers.url da spec OpenAPI — se errar aqui, o agente importa as ferramentas mas toda chamada volta 404.

Testando a dependência à mão

Vale reproduzir no Swagger o problema que o agente vai ter que resolver. Tente reservar sem cadastro:

POST /book
{ "user_id": 99, "name": "Felipe", "flight_id": 1, "seat_class": "economy" }

Retorna erro — o usuário 99 não existe. Agora cadastre:

POST /register
{ "name": "Felipe", "email": "felipe@email.com" }

Guarde o user_id retornado e refaça o POST /book com ele: funciona. Essa sequência manual é exatamente o que o agente vai fazer sozinho.

O OpenAPI Spec

O FastAPI gera a spec automaticamente, mas ela precisa de dois ajustes para o Orchestrate:

Ajuste O que muda Por quê
Versão 3.1.03.0.3 O Orchestrate aceita apenas OpenAPI 3.0.x
servers URL base = http://localhost:8001/api O Orchestrate precisa saber para onde chamar

Os seis endpoints que viram ferramentas:

Método Endpoint operationId O que faz
GET /flights get_flights_flights_get Listar voos disponíveis
POST /register register_user_endpoint_register_post Cadastrar passageiro
GET /user get_user_endpoint_user_get Buscar usuário por nome + e-mail
POST /book book_flight_endpoint_book_post Reservar voo
GET /bookings/{user_id} get_user_bookings_bookings__user_id__get Ver reservas
POST /cancel/{booking_id} cancel_booking_endpoint_cancel__booking_id__post Cancelar reserva

O operationId é o nome pelo qual o agente referencia a ferramenta no YAML — por isso ele aparece nessa forma verbosa gerada pelo FastAPI.

De endpoint a ferramenta — a spec vira uma tool com parâmetros tipados

orchestrate tools import -k openapi -f galaxium-openapi.json
orchestrate tools list

Se o seu Orchestrate roda em SaaS, ele não enxerga localhost. Nesse caso é preciso expor a API com um túnel HTTPS público (ngrok http 8001) e trocar o servers.url da spec pela URL pública — incluindo o /api no final — antes de reimportar.

A Base de Conhecimento (RAG)

A KB referencia os três documentos Markdown. O Orchestrate faz chunking, gera embeddings e indexa:

spec_version: v1
kind: knowledge_base
name: galaxium-travels-kb
description: >
  Documentos internos da Galaxium Travels usados para responder dúvidas de
  clientes via RAG: catálogo de pacotes e preços, políticas de cancelamento,
  FAQ do passageiro e o guia de preparação para o voo.

documents:
  - "knowledge-bases/travel_packages_catalog.md"
  - "knowledge-bases/passenger_faq.md"
  - "knowledge-bases/passenger_preparation_guide.md"

vector_index:
  chunk_size: 500
  chunk_overlap: 50
  embeddings_model_name: "default"

chunk_size: 500 define o tamanho de cada pedaço indexado, e chunk_overlap: 50 faz pedaços vizinhos compartilharem 50 caracteres. Esse overlap existe para evitar que uma informação seja cortada bem na fronteira entre dois chunks e acabe recuperada pela metade.

Como o RAG responde — busca semântica, contexto e resposta ancorada no documento

Os caminhos em documents são relativos ao diretório de onde você roda o comando, não ao arquivo YAML. Rodando de outra pasta, o import falha dizendo que não encontrou os documentos — é o erro mais bobo e mais comum aqui.

Dois pontos onde este YAML difere do exemplo da documentação, e que valem atenção se algo não funcionar no seu ambiente:

embeddings_model_name: "default" — a documentação oficial usa o nome explícito do modelo, ibm/slate-125m-english-rtrvr-v2. Se o "default" for rejeitado na sua versão do ADK, troque pelo nome completo.

Documentos em Markdown — a documentação lista PDF, DOCX, PPTX, XLSX, CSV, HTML e TXT, sem citar .md explicitamente. Funcionou aqui, mas se o seu import reclamar do formato, renomear para .txt resolve sem alterar o conteúdo — os documentos são texto puro de qualquer forma.

Feito isso, importe:

orchestrate knowledge-bases import -f galaxium-knowledge-base.yaml
orchestrate knowledge-bases list          # confirma que apareceu

A indexação não é instantânea: o Orchestrate precisa quebrar os documentos, gerar os embeddings e subir tudo para o índice vetorial. Se testar o agente imediatamente e ele responder que não sabe, espere um pouco e pergunte de novo antes de sair mexendo nas instruções.

O Agente

Aqui está o núcleo do lab. O YAML declara modelo, estilo, ferramentas, base de conhecimento e — o mais importante — as instruções que ensinam o agente a escolher entre agir e consultar:

spec_version: v1
kind: native
name: galaxium_travel_agent
title: Galaxium Travel Agent
llm: watsonx/ibm/granite-3-8b-instruct
style: react
hide_reasoning: false

style: react é o que ativa o laço raciocinar-agir-observar. hide_reasoning: false deixa o raciocínio visível na interface — essencial para conferir se o agente usou a ferramenta certa.

O bloco de instruções faz o roteamento:

instructions: |
  ## Quando usar as FERRAMENTAS (API) vs. a BASE DE CONHECIMENTO
  - Use as **ferramentas** (API) sempre que a pergunta envolver dados vivos do
    sistema: listar voos, registrar passageiro, buscar usuário, reservar,
    ver reservas ou cancelar.
  - Use a **base de conhecimento** (RAG) para perguntas gerais sobre políticas,
    pacotes de viagem, preços de catálogo, regras de cancelamento e preparação.
  - Na dúvida, prefira a ferramenta quando a resposta depender do estado atual
    do sistema (assentos, IDs, reservas do cliente).

  ## Fluxo de reserva (planeje antes de agir)
  Para reservar um voo, a API exige um `user_id`. Portanto:
  1. Se o cliente ainda não tem cadastro, registre-o primeiro (nome + e-mail).
  2. Se o cliente diz que já tem conta, busque o usuário para recuperar o `user_id`.
  3. Só então reserve o voo, usando o `user_id` obtido no passo anterior.
  Nunca invente um `user_id` — obtenha-o sempre de uma ferramenta.

  ## Recuperação de erro
  Se uma chamada retornar erro, não repita a mesma chamada. Investigue:
  confirme nome e e-mail, busque o usuário, ou ofereça um novo cadastro.

A frase “nunca invente um user_id” parece óbvia, mas é ela que evita o comportamento mais comum de um modelo pressionado a preencher um schema: chutar um valor plausível. Escrita assim, a instrução transforma o campo faltante em pergunta ao usuário.

As ferramentas e a KB são referenciadas por nome:

tools:
  - get_flights_flights_get
  - register_user_endpoint_register_post
  - get_user_endpoint_user_get
  - book_flight_endpoint_book_post
  - get_user_bookings_bookings__user_id__get
  - cancel_booking_endpoint_cancel__booking_id__post

knowledge_base:
  - galaxium-travels-kb
orchestrate agents import -f galaxium-travel-agent.yaml

A ordem importa: o YAML do agente referencia ferramentas e KB pelo nome, então importe os dois antes do agente — caso contrário a importação falha.

Executando — O Roteiro Completo

Juntando tudo, do zero até o agente respondendo. Você vai precisar de dois terminais: um para a API, outro para o orchestrate.

Terminal 1 — a API no ar

git clone https://github.com/IBM/galaxium-travels.git
cd galaxium-travels/booking_system_backend
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python server.py                 # deixe rodando

Terminal 2 — expor a API (só se o Orchestrate for SaaS)

Se o seu Orchestrate é o da nuvem — o caso de quem usa o trial — ele não enxerga o seu localhost. É preciso um túnel público antes de importar as ferramentas:

ngrok http 8001

Copie a URL https:// que o ngrok mostrar e use no servers.url da spec (com o mesmo sufixo de path do seu Swagger — /api ou nada):

"servers": [
  { "url": "https://xxxx-xxxx.ngrok-free.dev/api" }
]

Pulei esse passo na primeira tentativa e as ferramentas importaram normalmente — só para dar timeout em toda chamada depois. O erro não aparece na importação, só no uso.

Terminal 2 — importar e testar

A ordem aqui não é opcional: o YAML do agente referencia ferramentas e base de conhecimento pelo nome. Se elas ainda não existirem, a importação do agente falha.

# 0. ambiente ativo? (o token expira a cada ~2h)
orchestrate env activate meu-wxo

# 1. ferramentas a partir da spec OpenAPI
orchestrate tools import -k openapi -f galaxium-openapi.json

# 2. base de conhecimento (chunking + embeddings + índice)
orchestrate knowledge-bases import -f galaxium-knowledge-base.yaml

# 3. o agente, que referencia os dois acima
orchestrate agents import -f galaxium-travel-agent.yaml

# 4. conferir que os três existem
orchestrate tools list
orchestrate knowledge-bases list
orchestrate agents list

# 5. abrir o chat
orchestrate chat start

No chat, selecione galaxium_travel_agent e siga para os testes abaixo.

Refazendo do zero

Se quiser recomeçar limpo — útil ao ajustar instruções e comparar comportamento:

orchestrate agents remove          -n galaxium_travel_agent
orchestrate knowledge-bases remove -n galaxium-travels-kb

Para zerar também os dados de reserva, apague o arquivo SQLite do backend e suba a API de novo; a semeadura roda outra vez por encontrar o banco vazio.

Testando o Agente

Pergunta de política (RAG)

Prompt: Quais pacotes vocês oferecem para ir à Lua?

O agente consulta a base de conhecimento e responde com os pacotes lunares do catálogo — Lunar Escape (250.000 GXC), Lunar Royale (490.000 GXC) e Honeymoon on the Moon — com os preços que estão nos documentos. Abrindo o raciocínio dá para confirmar que ele usou o RAG, e não a API.

Consulta à API

Prompt: Quais são os próximos voos disponíveis?

Aqui ele chama GET /flights, recebe o JSON com origem, destino, preço e assentos por classe, e formata numa lista legível. Dado vivo, vindo do banco.

Fluxo de múltiplas etapas

Este é o teste que importa.

Prompt: Me reserva nesse voo, por favor.

O agente não executa nada. Ele vê que a ferramenta de reserva exige user_id, não tem esse dado e pede o que falta. Isso é planejamento — ele inspecionou o schema da ferramenta antes de tentar usá-la.

Prompt: Não tenho user ID.

Ele entende que precisa registrar primeiro e pede nome e e-mail.

Prompt: Meu nome é Felipe, email felipe@email.com

Agora ele executa duas ferramentas em sequência, sozinho:

  1. POST /register → recebe o user_id na resposta
  2. POST /book → usa esse user_id como parâmetro

Uma etapa alimentando a outra, sem ninguém ter programado a sequência. A dependência estava no banco de dados; o agente a descobriu pelo schema e pelas instruções.

Fluxo de múltiplas etapas — o agente pergunta o que falta e encadeia register → book

Recuperação de erro

Tente reservar com um nome que não bate com o cadastro. A API retorna erro, e o comportamento interessante é o que o agente não faz: repetir a mesma chamada esperando resultado diferente. Ele busca o usuário, confere os dados e sugere o recadastro.

RAG de preparação

Prompt: O que preciso levar numa viagem para Marte? Posso levar plantas?

Resposta ancorada no guia de preparação e no FAQ: limite de bagagem, itens proibidos (organismos vivos, solo lunar) e requisitos médicos específicos de Marte.

Monitoramento e Troubleshooting

Sintoma Causa provável Solução
Address already in use na 8001 API já rodando lsof -ti:8001 | xargs kill -9 e suba de novo
Swagger não abre em /docs O backend usa root_path="/api" Tente http://localhost:8001/api/docs (ou o inverso)
orchestrate: command not found ADK não instalado ou fora do PATH pip install --upgrade ibm-watsonx-orchestrate no venv ativo
ADK falha ao instalar Python abaixo de 3.11 python3 --version — o ADK exige 3.11+
Import do agente falha KB ou ferramentas ainda não existem Importe tools e KB antes do agente
Import da KB não acha os arquivos Caminhos são relativos ao diretório atual Rode o comando da raiz do lab, onde está knowledge-bases/
Ferramentas importam mas dão timeout Orchestrate SaaS não alcança localhost Exponha via ngrok e atualize servers.url na spec
Toda chamada de ferramenta volta 404 servers.url sem o prefixo certo Inclua (ou remova) o /api conforme o seu Swagger
Erro de token / 401 no meio do lab Autenticação remota expira (~2h) orchestrate env activate <ambiente> de novo
Agente diz não saber sobre pacotes Índice ainda processando Aguarde a indexação terminar e pergunte de novo
Agente responde política pela API Instrução de roteamento fraca Reforce no YAML: ferramenta = dado vivo, RAG = política
Agente inventa um user_id Falta a instrução explícita Adicione “nunca invente um user_id” nas instruções

Com hide_reasoning: false, a própria interface é a melhor ferramenta de diagnóstico: dá para ver qual ferramenta o agente escolheu, com quais parâmetros e o que voltou.

Para Que Serve no Mercado

O padrão deste lab — agente com ferramentas de API real mais RAG sobre documentos internos — é a forma mais direta de aplicar IA agêntica em cenário corporativo.

Atendimento que resolve, não só responde. A maioria dos assistentes consulta FAQ e encaminha para um humano quando é preciso agir. Aqui o agente executa a ação no sistema — abre chamado, agenda, cancela — usando a API que a empresa já tem.

Integração sem projeto de integração. A API vira ferramenta pela spec OpenAPI. Se a empresa já expõe REST documentado, o caminho até o agente é importar a spec, não escrever camada de integração.

Resposta ancorada em documento. Preço, política e prazo saem do documento oficial via RAG. Isso muda a conversa sobre risco: a resposta é rastreável até a fonte, em vez de depender do que o modelo memorizou.

Fluxos com pré-requisito. Cadastro antes de pedido, aprovação antes de provisionamento, validação antes de emissão — o agente descobre a dependência pelo schema e resolve, em vez de falhar ou inventar dados.

Conclusão

O que ficou mais claro rodando este lab não foi o poder do modelo, mas o peso das instruções e do schema. O mesmo Granite, com as mesmas seis ferramentas, se comporta de forma completamente diferente conforme o YAML diz “nunca invente um user_id” ou fica calado sobre isso.

A restrição de foreign key no SQLite, a descrição de cada campo na spec OpenAPI e três parágrafos de instrução em português foram o que produziu o comportamento correto — pedir o dado que falta em vez de chutar um valor. Isso é engenharia de contrato, não mágica de IA. Vale lembrar disso antes de culpar o modelo quando um agente age errado: normalmente o que faltou foi descrição na ferramenta ou instrução no agente.

E a parte que mais me surpreendeu foi o quanto o IBM Bob acelerou o caminho até aqui — ajustar a spec, escrever os YAMLs e montar o script de subida foi tudo conversa com ele.

Créditos

O cenário da Galaxium Travels e o sistema de reservas não são meus: vêm do projeto IBM/galaxium-travels, publicado pela IBM sob licença Apache-2.0. A API em FastAPI, o modelo de dados e os documentos da agência já vinham prontos no repositório — é uma aplicação de demonstração criada justamente para exercitar agentes de IA sobre uma base de código realista.

O que fiz aqui foi a camada de agente em cima disso: importar a API como ferramentas via OpenAPI spec, montar a base de conhecimento (RAG) a partir dos documentos, escrever o YAML do agente ReAct com as instruções de roteamento e testar o fluxo de múltiplas etapas usando o ADK do watsonx Orchestrate.

Essa parte foi construída com o IBM Bob, que escreveu os YAMLs do agente e da knowledge base, ajustou o OpenAPI spec para o formato aceito pelo Orchestrate e redigiu as instruções de roteamento — coube a mim revisar e executar.

Referências