Skip to content

Correção: Seleção de Guia em Experiências Exclusivas

🐛 Problema Identificado

Para reservas de experiências exclusivas (exclusive=true, shelfExperience=false), o campo ifriend.id (ID do guia) é OBRIGATÓRIO na API, mas o agente não estava solicitando essa informação ao usuário antes de tentar emitir a reserva.

Cenários afetados:

  1. Experiência exclusiva SEM variação (ID 174 no stage)
  2. Problema: Não pediu para escolher o guia
  3. Consequência: Reserva criada com sucesso (mas deveria ter pedido escolha mesmo com 1 guia apenas)

  4. Experiência exclusiva COM variação (ID 900 no stage)

  5. Problema: Não pediu para selecionar o guia
  6. Erro retornado: HTTP 500 - "Call to a member function getPrice() on null"
  7. Causa: API tentou processar reserva sem ifriend.id

Por que acontecia:

O agente não tinha: 1. ❌ Ferramenta para listar guias disponíveis de uma experiência 2. ❌ Instruções no prompt para identificar experiências exclusivas 3. ❌ Lógica para solicitar seleção de guia antes de emitir reserva


✅ Solução Implementada

1. Nova Ferramenta: listar_guias_experience_tool

Criada ferramenta que: - Verifica se experiência é exclusiva (exclusive=true, shelfExperience=false) - Busca lista de guias disponíveis da experiência via API - Retorna detalhes de cada guia (nome, cidade, rating, idiomas, foto)

Arquivo: listar_guias_experience_tool.py

async def listar_guias_experience_tool(experience_id: int) -> dict:
    """
    Lista os guias (iFriends) disponíveis para atender uma experiência exclusiva.

    Returns:
        dict: {
            "experience_id": int,
            "exclusive": bool,
            "shelf_experience": bool,
            "ifriends": [  # Lista de guias disponíveis
                {
                    "id": int,
                    "name": str,
                    "city": str,
                    "rating": float,
                    "price": str,
                    "bio": str,
                    "languages": [str],
                    "photo": str
                }
            ],
            "error": None ou mensagem de erro
        }
    }
    """

Como funciona:

  1. Busca detalhes da experiência via GET /experiences/{id}
  2. Verifica campos exclusive e shelfExperience
  3. Se não for exclusiva ou for de prateleira → retorna lista vazia
  4. Extrai IDs dos guias do campo experienceIfriends
  5. Para cada guia, busca detalhes completos via GET /ifriends/{id}
  6. Retorna lista formatada com informações relevantes

2. Instruções no Prompt do Sistema

Adicionadas instruções no estado QUOTE do system_prompt.py:

⚠️ EXPERIÊNCIAS EXCLUSIVAS - SELEÇÃO DE GUIA:
Quando detalhes_experience retornar exclusive=true e shelfExperience=false:
- SEMPRE chamar listar_guias_experience_tool(experience_id)
- Se retornar MAIS DE 1 guia:
  * Apresentar lista numerada dos guias disponíveis
  * Parar e aguardar usuário escolher o guia
- Se retornar APENAS 1 guia:
  * Usar automaticamente esse guia (não precisa perguntar)
- Após escolha, usar ifriend_id na reserva (campo OBRIGATÓRIO para exclusivas)

3. Instruções no Booking Agent

Atualizado booking_agent.py com fluxo detalhado:

⚠️ PARA EXPERIÊNCIAS EXCLUSIVAS (exclusive=true, shelfExperience=false):
  → SEMPRE chamar listar_guias_experience_tool(product_id)
  → Se retornar MAIS DE 1 guia disponível:
    * Apresentar lista numerada: "Guias disponíveis:
      1. [Nome] - [Cidade] - Rating: [X] - [Idiomas]
      2. ...
      Qual guia você prefere?"
    * Aguardar escolha do usuário
  → Se retornar APENAS 1 guia:
    * Usar automaticamente (informar ao usuário): "O guia [Nome] irá atendê-lo."
  → CRÍTICO: ifriend_id é OBRIGATÓRIO para experiências exclusivas!
  → Aplicar MESMO fluxo se experiência exclusiva TEM variação

4. Integração com Root Agent

Ferramenta registrada em agent.py:

from ifriend_agent.tools.listar_guias_experience_tool import listar_guias_experience_tool

root_agent = LlmAgent(
    ...
    tools=[
        ...
        listar_guias_experience_tool,
        ...
    ]
)

🔄 Fluxo Corrigido

Cenário 1: Experiência Exclusiva SEM Variação

sequenceDiagram
    participant User
    participant Agent
    participant detalhes_experience
    participant listar_guias_experience_tool

    User->>Agent: Quero reservar experiência ID 174
    Agent->>detalhes_experience: Buscar detalhes
    detalhes_experience-->>Agent: exclusive=true, shelfExperience=false

    Note over Agent: Identificou: EXCLUSIVA!<br/>Precisa selecionar guia

    Agent->>listar_guias_experience_tool: Listar guias (174)
    listar_guias_experience_tool-->>Agent: [Guia 1: Maria (Rio)]

    Note over Agent: Apenas 1 guia disponível<br/>Usar automaticamente

    Agent-->>User: O guia Maria irá atendê-lo.<br/>Vamos prosseguir com a reserva?

Cenário 2: Experiência Exclusiva COM Variação E Múltiplos Guias

sequenceDiagram
    participant User
    participant Agent
    participant detalhes_experience
    participant listar_guias_experience_tool
    participant listar_variacoes_tool

    User->>Agent: Quero reservar experiência ID 900
    Agent->>detalhes_experience: Buscar detalhes
    detalhes_experience-->>Agent: exclusive=true, shelfExperience=false, has variations

    Note over Agent: EXCLUSIVA + VARIAÇÃO<br/>Precisa: guia + variação

    Agent->>listar_guias_experience_tool: Listar guias
    listar_guias_experience_tool-->>Agent: [Guia 1: João, Guia 2: Ana, Guia 3: Pedro]

    Agent-->>User: Guias disponíveis:<br/>1. João - SP - 4.8★ - [PT, EN]<br/>2. Ana - RJ - 5.0★ - [PT, ES, EN]<br/>3. Pedro - MG - 4.5★ - [PT]<br/><br/>Qual guia você prefere?

    User->>Agent: Quero a Ana (opção 2)

    Agent->>listar_variacoes_tool: Listar variações
    listar_variacoes_tool-->>Agent: [Variação A, Variação B]

    Agent-->>User: Variações disponíveis:<br/>1. Variação A...<br/>2. Variação B...<br/><br/>Qual você gostaria?

📦 Estrutura de Payloads Atualizada

Experiência Exclusiva SEM Variação

{
  "type": "experience",
  "experience": {"id": 174},
  "ifriend": {"id": 11},  // ✅ OBRIGATÓRIO - obtido via listar_guias_experience_tool
  "customer": {"id": 7},
  "dates": [{
    "day": "2026-03-10",
    "period": "10:00",
    "numAdult": 3,
    "numChild": 0
  }],
  "pax": [...]
}

Experiência Exclusiva COM Variação

{
  "type": "experience",
  "experience": {"id": 900},
  "ifriend": {"id": 25},  // ✅ OBRIGATÓRIO - escolhido pelo usuário
  "customer": {"id": 7},
  "dates": [{
    "day": "2026-03-20",
    "period": "08:00",
    "numAdult": 2,
    "numChild": 1
  }],
  "providerData": {
    "provider": "platform",
    "variations": [{
      "id": 13,
      "quantity": 1,
      "agePolicies": [
        {"id": 34, "name": "Adulto", "quantity": 2},
        {"id": 35, "name": "Criança", "quantity": 1}
      ]
    }]
  },
  "pax": [...]  // 3 passageiros
}

Nota importante: Experiências exclusivas COM variação precisam de: 1. ✅ ifriend.id (guia escolhido) 2. ✅ providerData (variação escolhida com age policies corretas)


🎯 Regras de Identificação

Quando é Experiência Exclusiva?

is_exclusive = experience_data.get("exclusive") == True
is_shelf = experience_data.get("shelfExperience") == False

needs_guide_selection = is_exclusive and not is_shelf

Quando NÃO precisa selecionar guia?

Experiências de Prateleira (shelfExperience=true) - Mesmo que exclusive=true, se for "shelf" não precisa selecionar guia

Experiências Não Exclusivas (exclusive=false) - Não requerem seleção de guia específico - Se tiverem variação, usar apenas providerData

Experiências Exclusivas (exclusive=true, shelfExperience=false) - SEMPRE requerem ifriend.id - Aplicável tanto para sem variação quanto com variação


🧪 Como Testar

Teste 1: Experiência Exclusiva com 1 Guia

Usuário: "Quero reservar a experiência ID 174 para amanhã"

Esperado:
1. Agent chama detalhes_experience(174)
2. Identifica: exclusive=true, shelfExperience=false
3. Agent chama listar_guias_experience_tool(174)
4. Retorna: [Guia único]
5. Agent informa: "O guia [Nome] irá atendê-lo."
6. Prossegue com coleta de dados

Teste 2: Experiência Exclusiva com Múltiplos Guias

Usuário: "Quero reservar a experiência ID 900"

Esperado:
1. Agent chama detalhes_experience(900)
2. Identifica: exclusive=true, shelfExperience=false
3. Agent chama listar_guias_experience_tool(900)
4. Retorna: [Guia 1, Guia 2, Guia 3]
5. Agent apresenta lista numerada com detalhes
6. Aguarda escolha do usuário
7. Após escolha, se tiver variação, lista variações
8. Após escolher variação, prossegue com reserva

Teste 3: Experiência NÃO Exclusiva com Variação

Usuário: "Quero reservar a experiência ID 1929"

Esperado:
1. Agent chama detalhes_experience(1929)
2. Identifica: exclusive=false (ou shelfExperience=true)
3. Agent NÃO chama listar_guias_experience_tool
4. Agent chama listar_variacoes_tool diretamente
5. Prossegue com seleção de variação
6. NÃO inclui ifriend.id na reserva

📋 Checklist de Validação

Para experiências exclusivas, garantir que:

  • [ ] detalhes_experience retorna exclusive e shelfExperience
  • [ ] Se exclusive=true e shelfExperience=false → chamar listar_guias_experience_tool
  • [ ] Se múltiplos guias → apresentar lista e aguardar escolha
  • [ ] Se 1 guia → usar automaticamente e informar usuário
  • [ ] ifriend.id está presente no payload de reserva
  • [ ] Fluxo funciona tanto para experiências SEM quanto COM variação
  • [ ] Não solicitar guia quando shelfExperience=true ou exclusive=false

🔗 Arquivos Modificados

  1. listar_guias_experience_tool.py - Nova ferramenta
  2. system_prompt.py - Instruções no estado QUOTE
  3. booking_agent.py - Fluxo detalhado
  4. agent.py - Registro da ferramenta
  5. cenarios-teste.md - Documentação dos bugs corrigidos

🚀 Próximos Passos

  1. ✅ Testar em stage com produto ID 174 (exclusiva sem variação, 1 guia)
  2. ✅ Testar em stage com produto ID 900 (exclusiva com variação, múltiplos guias)
  3. ⚠️ Validar que experiências de prateleira não solicitam guia indevidamente
  4. ⚠️ Confirmar que experiências não-exclusivas funcionam normalmente

Data da correção: 06/01/2026
Problema original: cenarios-teste.md
Status: ✅ Implementado e documentado