Pular para o conteúdo principal
Inteligência Artificial
Agentes de IA

Tutorial GLM-5-Turbo: crie um agente de navegador em tempo real

Aprenda a criar um agente de IA no navegador que pesquisa na web, extrai dados de voos em tempo real e retorna recomendações claras usando o GLM-5-Turbo.
Aashi Dutt's photo
Aashi Dutt
Actualizado · 9 min leer

Explore com IA

ChatGPTClaudePerplexity

Crie sua conta gratuita

Pratique e programa seu progresso.

Continuar Com O Google
Ao continuar, você aceita nossos Termos de Uso, nossa Política de Privacidade e que seus dados serão armazenados nos EUA.

O GLM-5-Turbo foi projetado especificamente para fluxos de trabalho em estilo agente, em que o modelo coordena execuções em múltiplas etapas. Ele é otimizado para entender instruções complexas, acionar ferramentas com confiabilidade e produzir saídas estruturadas que podem ser consumidas por sistemas. 

Neste tutorial, vamos criar um agente de navegador em tempo real que navega ativamente pela web, extrai informações relevantes e gera um resumo claro para o usuário. Ao final, você terá uma arquitetura reutilizável que pode ser estendida além de voos para qualquer tarefa real de busca e extração.

Você pode ver nosso projeto com GLM-5-Turbo em ação no vídeo abaixo:

O que é o GLM-5-Turbo?

O GLM-5-Turbo foi criado para dar suporte a fluxos de trabalho de agentes no mundo real. Ele oferece múltiplos modos de raciocínio, permitindo equilibrar respostas mais rápidas e análises mais profundas conforme a tarefa. 

Para aplicações interativas, ele também suporta saída em streaming, entregando respostas token a token para uma experiência mais responsiva.

Uma de suas principais forças é o function calling, que permite ao modelo invocar ferramentas externas com confiabilidade. O modelo também suporta saídas estruturadas como JSON, facilitando a integração com sistemas e camadas de UI a jusante.

Para fluxos mais longos, o GLM-5-Turbo inclui cache de contexto, o que ajuda a manter a performance em interações estendidas sem reprocessar as mesmas informações repetidamente. Ele também suporta integração com sistemas externos via MCP (Model Context Protocol), permitindo a conexão com ferramentas e fontes de dados adicionais.

Feito para fluxos de trabalho com agentes

O GLM-5-Turbo é profundamente otimizado para ambientes em estilo agente, especialmente cenários como OpenClaw, em que as tarefas envolvem várias etapas, ferramentas e longas cadeias de execução.

Essa otimização melhora várias áreas críticas:

  • Confiabilidade na invocação de ferramentas: garante que o modelo chame as funções certas de forma consistente.
  • Decomposição de instruções: permite que o modelo quebre tarefas complexas em etapas menores.
  • Estabilidade em execuções longas: essencial para agentes com várias etapas.

Na prática, o GLM-5-Turbo é rápido o suficiente para sistemas interativos e, ao mesmo tempo, confiável em cenários de múltiplas etapas com chamadas de ferramentas — exatamente o que precisamos para criar agentes de navegador.

Projeto de exemplo com GLM-5-Turbo: crie um agente de navegador em tempo real

Neste tutorial, vamos criar um aplicativo em Streamlit que funciona como um assistente de viagem leve. O usuário fornece uma consulta como “Encontre os voos mais baratos de SFO para JFK de sexta a segunda”. O sistema então:

  • Pesquisa na web por páginas de voos relevantes
  • Abre e inspeciona essas páginas
  • Extrai informações úteis como preço, duração e conexões
  • Resume as melhores opções em um formato fácil de entender

Em alto nível, o sistema tem quatro componentes que trabalham juntos.

  • A primeira é a camada de LLM (llm_client.py), que envia requisições de chat-completion para Z.AI ou OpenRouter. 
  • A segunda é a camada de ferramentas de navegador (browser_tools.py), que expõe ações como pesquisar, abrir páginas e extrair conteúdo. 
  • A terceira é o loop do agente (agent.py), que conecta o modelo e as ferramentas em um fluxo de trabalho multi-etapas. 
  • Por fim, a interface do Streamlit (app.py) oferece uma UI para interação e visualização.

Código-fonte completo: https://github.com/AashiDutt/GLM5_TURBO

Passo 1: pré-requisitos

Antes de construir o aplicativo, garanta que você tem:

  • Python 3.9+
  • Uma chave de API do GLM-5-Turbo (Z.AI ou OpenRouter)
  • Playwright instalado para automação de navegador

Instale as bibliotecas necessárias:

pip install streamlit pandas python-dotenv requests playwright
playwright install chromium

O arquivo app.py usa Streamlit, pandas, dotenv e módulos personalizados. Já o browser_tools.py usa requests e Playwright. As chamadas de API são feitas em llm_client.py usando requests.

Agora, execute o comando abaixo para criar um arquivo .env onde ficarão nossas chaves de API:

cp .env.example .env

Selecione seu endpoint de API preferido e informe a chave de API:

.env
PROVIDER=zai
# API direta da Z.AI
ZAI_API_KEY=Your Z.AI API key
ZAI_BASE_URL=https://api.z.ai/api/paas/v4/chat/completions
ZAI_MODEL=glm-5-turbo
# OpenRouter
OPENROUTER_API_KEY=Your OpenRouter API key
OPENROUTER_BASE_URL=https://openrouter.ai/api/v1/chat/completions
OPENROUTER_MODEL=z-ai/glm-5-turbo
# Navegador
HEADLESS=true
MAX_STEPS=10

Da mesma forma, o Playwright é iniciado por este construtor em browser_tools.py:

class BrowserTools:
    def __init__(self, headless: bool = True) -> None:
        self.playwright = sync_playwright().start()
        self.browser = self.playwright.chromium.launch(headless=headless)
        self.context = self.browser.new_context(viewport={"width": 1440, "height": 1100})
        self.page = self.context.new_page()

Esse bloco inicializa um ambiente de navegador totalmente controlado usando Playwright, que o agente utiliza para interagir com a web. 

Ele inicia o mecanismo do Playwright, abre um navegador Chromium, cria uma sessão isolada e abre uma nova página onde todas as ações acontecem. 

Essa configuração permite que o agente navegue em sites reais, observe conteúdo ao vivo e tome decisões com base no que vê.

Passo 2: configurando o cliente de LLM

Em seguida, vamos configurar nosso LLMClient, que suporta tanto o uso direto da Z.AI quanto do OpenRouter com a mesma interface. O endpoint específico do provedor é selecionado no construtor. Como os preços são comparáveis, você pode usar qualquer uma das APIs neste demo, conforme sua preferência.

Veja a configuração principal:

class LLMClient:
    def __init__(
        self,
        provider: str,
        api_key: str,
        model: str,
        app_name: str = "GLM-5 Browser Agent Demo",
        app_url: str = "http://localhost:8501",
    ) -> None:
        self.provider = provider.lower().strip()
        self.api_key = api_key
        self.model = model
        if self.provider == "zai":
            self.url = os.getenv("ZAI_BASE_URL", "https://api.z.ai/api/paas/v4/chat/completions")
        elif self.provider == "openrouter":
            self.url = os.getenv("OPENROUTER_BASE_URL", "https://openrouter.ai/api/v1/chat/completions")

Esse inicializador configura o cliente de LLM selecionando o endpoint de API apropriado (Z.AI ou OpenRouter) e mantendo a interface consistente. 

Ele armazena a chave de API, o modelo e a URL do endpoint, permitindo que o restante do sistema chame o modelo sem se preocupar com diferenças específicas do provedor.

Em seguida, create_chat_completion() monta o payload, anexa ferramentas quando necessário e interpreta quaisquer chamadas de ferramenta retornadas. 

payload: Dict[str, Any] = {
    "model": self.model,
    "messages": messages,
    "temperature": temperature,
    "max_tokens": max_tokens,
    "stream": False,
}
if tools:
    payload["tools"] = tools
    payload["tool_choice"] = "auto"

O payload acima define a requisição enviada ao modelo, incluindo o contexto da conversa e parâmetros de geração. Ao anexar tools e ativar tool_choice="auto", o modelo pode decidir quando invocar funções externas.

Passo 3: definindo as ferramentas do navegador

Em agent.py, definimos um esquema de ferramentas que o modelo pode chamar. Incluem search_web, open_url, open_search_result, extract_page, extract_flight_cards, click, type_text e wait_for_text.

Aqui está um exemplo de definição de ferramenta:

{
    "type": "function",
    "function": {
        "name": "search_web",
        "description": "Search the public web for flight result pages or travel aggregators.",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {"type": "string"},
                "max_results": {"type": "integer", "default": 8},
            },
            "required": ["query"],
        },
    },
}

Esse esquema informa ao modelo o que a ferramenta faz, quais entradas espera e como chamá-la. Ao definir ferramentas assim, permitimos que o modelo decida dinamicamente quando pesquisar na web, em vez de codificar o fluxo manualmente.

No lado da execução, essas ferramentas são implementadas em browser_tools.py. Para este demo, usamos o endpoint HTML do DuckDuckGo para armazenar os links atuais de resultados para navegação posterior.

def search_web(self, query: str, max_results: int = 8) -> Dict[str, Any]:
    url = f"https://html.duckduckgo.com/html/?q={quote_plus(query)}"
    headers = {"User-Agent": "Mozilla/5.0"}
    resp = requests.get(url, headers=headers, timeout=30)
    resp.raise_for_status()
    html = resp.text

A função search_web() acima faz uma busca leve na web buscando o HTML bruto dos resultados e fazendo o parsing, evitando a necessidade de uma API paga de busca. Ela também armazena os resultados internamente para que o agente possa navegá-los nas etapas seguintes.

Agora que definimos como o agente pode interagir com a web, o próximo passo é ver como ele usa essas ferramentas para extrair informações de voos via pesquisa.

Passo 4: extraindo informações de voos

Quando o modelo encontra uma fonte promissora, ele precisa inspecioná-la. Podemos usar as ferramentas de navegador (do passo 3) para extrair snapshots brutos da página.

Passo 4.1: abrindo e extraindo páginas

Vamos usar a ferramenta open_url() para carregar a página e retornar um snapshot com título, URL e texto visível.

def open_url(self, url: str) -> Dict[str, Any]:
    self.page.goto(url, wait_until="domcontentloaded", timeout=45000)
    self.page.wait_for_timeout(1200)
    return self._page_snapshot()

Para uma extração mais ampla, usaremos a ferramenta extract_page() abaixo, que retorna o snapshot da página e um conjunto de links coletados da página atual.

def extract_page(self, max_chars: int = 7000, link_limit: int = 20) -> Dict[str, Any]:
    snapshot = self._page_snapshot(max_chars=max_chars)
    snapshot["links"] = self._collect_links(limit=link_limit)
    self.current_links = snapshot["links"]
    return snapshot

Isso é útil porque o modelo nem sempre precisa clicar às cegas. Às vezes, ele pode primeiro inspecionar o texto e os links disponíveis e, então, decidir o próximo passo.

Passo 4.2: extração heurística de voos

Uma parte-chave do demo é a função extract_flight_cards(), que recebe o texto visível da página e usa regex para detectar preços, horários, duração e conexões.

Aqui está o núcleo dessa lógica:

money_pattern = re.compile(r"(?:\$|USD\s?)(\d{2,5})")
time_pattern = re.compile(r"\b\d{1,2}:\d{2}\s?(?:AM|PM|am|pm)?\b")
duration_pattern = re.compile(r"\b\d{1,2}\s?h\s?\d{0,2}\s?m?\b|\b\d{1,2}\s?hr\s?\d{0,2}\s?min?\b", re.I)
stop_pattern = re.compile(r"nonstop|1 stop|2 stops|3 stops", re.I)

Esses padrões de regex funcionam como detectores para sinais comuns relacionados a voos. O money_pattern captura preços em formatos como $299 ou USD 299, enquanto o time_pattern identifica horários de partida e chegada. 

Da mesma forma, o duration_pattern extrai a duração da viagem e o stop_pattern detecta se o voo é direto ou tem escalas. Você pode criar padrões semelhantes para qualquer caso de uso.

Com esses sinais definidos, a função varre pequenos trechos de texto e busca combinações significativas. Quando encontra uma correspondência, constrói um cartão de voo estruturado:

card = {
    "snippet": joined[:350],
    "price_usd": int(price_match.group(1)),
    "times": times[:2],
    "duration": duration.group(0) if duration else None,
    "stops": stops.group(0) if stops else None,
}

O bloco acima converte texto bruto em uma representação estruturada de uma opção de voo. Ele extrai o preço, limita os horários aos mais relevantes e trata campos ausentes. Isso preserva o contexto original, útil para depuração.

Com a extração pronta, o agente agora consegue transformar conteúdo não estruturado da página em dados utilizáveis. Em seguida, veremos como esses dados fluem pelo loop do agente para orientar decisões em várias etapas.

Passo 5: loop do agente

O comportamento do agente está na classe BrowserAgent (dentro de agent.py). Essa classe envia o prompt e o esquema de ferramentas para o modelo, verifica se o modelo quer chamar alguma ferramenta, executa a ferramenta, adiciona o resultado de volta na conversa e continua até produzir uma resposta final.

Aqui está o loop principal:

for step in range(1, self.max_steps + 1):
    assistant = self.llm.create_chat_completion(
        messages=messages,
        tools=TOOLS,
        temperature=0.2,
        max_tokens=2200,
        enable_thinking=False,
    )
    if assistant.tool_calls:
        ...
        result = self.tool_runner(tc.name, tc.arguments)
        ...
        continue
    final_content = assistant.content.strip()
    if final_content:
        yield {"type": "final", "step": step, "content": final_content}
        return

Esse loop é o coração do demo. 

A cada passo, o modelo recebe o estado atual da conversa e decide o que fazer. Se ele retornar chamadas de ferramentas, elas são executadas com tool_runner, e os resultados são realimentados no loop para a próxima iteração. 

Esse processo continua até o modelo produzir uma resposta final em vez de chamar uma ferramenta.

O loop também impõe um limite máximo de etapas para evitar execução infinita e manter tudo sob controle e eficiente.

Passo 6: conectando as ferramentas ao app

Em app.py, mapeamos os nomes das ferramentas solicitadas pelo modelo para os métodos reais do navegador. Esse mapeamento é implementado com a função make_tool_runner():

def make_tool_runner(browser: BrowserTools):
    def run(name: str, args: Dict[str, Any]):
        if name == "search_web":
            return browser.search_web(**args)
        if name == "open_url":
            return browser.open_url(**args)
        if name == "open_search_result":
            return browser.open_search_result(**args)
        if name == "extract_page":
            return browser.extract_page(**args)
        if name == "extract_flight_cards":
            return browser.extract_flight_cards(**args)

Essa função atua como um despachante entre o modelo e o navegador. O modelo retorna apenas o nome da ferramenta e os argumentos, e run() traduz isso em uma chamada de função na instância de BrowserTools. 

Agora que o agente consegue chamar e executar ferramentas com sucesso, o próximo passo é construir a interface que une tudo.

Passo 7: construindo a UI no Streamlit

A interface em Streamlit transforma o agente de navegador em um aplicativo interativo. Ela coleta os detalhes da viagem do usuário, inicia o agente, transmite as etapas intermediárias e, por fim, exibe um resumo junto com uma tabela estruturada das principais opções de voo. Todo esse fluxo de UI está em app.py.

st.set_page_config(page_title="GLM-5 Browser Agent", page_icon="", layout="wide")
st.title("GLM-5-Turbo Real-Time Browser Agent")
st.subheader("Trip Request")
origin = st.text_input("Origin", value="SFO")
destination = st.text_input("Destination", value="JFK")
depart_date = st.date_input("Depart date")
return_date = st.date_input("Return date")
adults = st.number_input("Adults", min_value=1, max_value=9, value=1)
natural_request = st.text_area(
    "Optional natural language request",
    value="Find the cheapest reasonable flight options and summarize the best ones.",
    height=120,
)
user_query = (
    f"Find flight options from {origin} to {destination} for {adults} adult(s). "
    f"Departure date: {depart_date}. Return date: {return_date}. "
    f"User preference: {natural_request}"
)
run = st.button("Run browser agent", type="primary", use_container_width=True)
if run:
    if not api_key:
        st.error("Please enter an API key in the sidebar.")
        st.stop()
    llm = LLMClient(provider=provider, api_key=api_key, model=model)
    event_box = st.container(border=True)
    result_box = st.container(border=True)
    all_events = []
    with managed_browser(headless=headless) as browser:
        agent = BrowserAgent(llm=llm, tool_runner=make_tool_runner(browser), max_steps=max_steps)
for event in agent.stream(user_query):
    all_events.append(event)
    with event_box:
        if event["type"] == "status":
            st.write(f"**Step {event['step']}** — {event['content']}")
        elif event["type"] == "tool_call":
            with st.expander(f"Step {event['step']} • Tool call: {event['tool']}", expanded=False):
                st.json(event["arguments"])
        elif event["type"] == "tool_result":
            with st.expander(f"Step {event['step']} • Tool result: {event['tool']}", expanded=False):
                st.json(event["result"])
        elif event["type"] == "final":
            st.success("Agent finished.")
final_event = next((e for e in reversed(all_events) if e["type"] == "final"), None)
final_text = final_event["content"] if final_event else ""
with result_box:
    st.subheader("Final Answer")
    parsed = parse_final_json(final_text)
    if parsed:
        st.markdown(render_final_markdown(parsed))
        options_df = build_options_dataframe(parsed)
        if not options_df.empty:
            st.subheader("Top options table")
            st.dataframe(
                options_df,
                use_container_width=True,
                column_config={
                    "Link": st.column_config.LinkColumn("Link", display_text="Open source"),
                },
            )
    else:
        st.markdown(final_text)

Veja como a UI do Streamlit integra todos os componentes:

  • As chamadas st.set_page_config() e st.title() definem o layout e o título do app, enquanto widgets como st.text_input(), st.date_input(), st.number_input() e st.text_area() coletam os detalhes da viagem. 
  • Quando o usuário clica no botão Run browser agent, o app primeiro verifica se há uma chave de API, depois inicializa o LLMClient. Em seguida, cria contêineres separados para logs intermediários do agente e resultados finais e abre uma sessão do Playwright gerenciada. Dentro dessa sessão, o BrowserAgent começa a transmitir eventos, e a UI exibe cada atualização de status, chamada de ferramenta e resultado de ferramenta.
  • Quando o agente termina, o app extrai o evento final, faz o parsing do JSON retornado e o renderiza. O resumo é mostrado por render_final_markdown(), enquanto build_options_dataframe() converte as opções de voo estruturadas em uma tabela com links clicáveis para as fontes.

Com este passo concluído, você pode salvar tudo como app.py e iniciar o app com:

streamlit run app.py

Este projeto funciona bem como um demo real porque usa resultados de busca de navegador e chamadas de ferramentas de verdade. Ao mesmo tempo, ainda é um protótipo. Sites de passagens são dinâmicos, as páginas podem ter ruído e algumas plataformas usam proteções anti-bot. 

A lógica de extração atual é propositalmente heurística, o que mantém o sistema simples e fácil de entender.

Mais importante: essa configuração não se limita a voos. Com alguns ajustes — principalmente nos prompts e na lógica de extração — você pode reutilizar a mesma arquitetura para criar agentes de compras, pesquisa, agregação de notícias ou qualquer tarefa que exija navegar e resumir informações ao vivo.

Conclusão

Neste tutorial, construímos um agente de navegador em tempo real com GLM-5-Turbo, Playwright e Streamlit. O modelo atua como planejador, as ferramentas de navegador como camada de execução e a UI transforma os resultados estruturados em um formato amigável.

A principal lição é que o valor não vem só do modelo. Ele surge da combinação do modelo com uma camada de ferramentas controlada e um loop de agente. 

Há várias extensões possíveis: melhorar a extração com parsers específicos por site, estender o sistema para hotéis ou roteiros, ou integrar preferências do usuário como voos diretos ou companhias aéreas favoritas. Isso pode ajudar você a transformar este demo em uma extensão de navegador completa.

Perguntas frequentes sobre o GLM-5-Turbo

Preciso de uma GPU para executar este projeto com GLM-5-Turbo?

Não. Este projeto não requer GPU porque o modelo é acessado via API (Z.AI ou OpenRouter). Todo o processamento pesado acontece na infraestrutura do provedor; sua máquina local só cuida da UI e da automação do navegador.

Por que usar um agente de navegador em vez de uma API de voos?

APIs são mais confiáveis e estruturadas, mas se limitam a dados predefinidos e muitas vezes exigem acesso pago. Já um agente de navegador pode:

  • explorar várias fontes de forma dinâmica
  • se adaptar a diferentes consultas
  • funcionar sem APIs pré-integradas

No entanto, para produção, a melhor escolha geralmente é uma abordagem híbrida (agente e APIs).

Por que o agente às vezes falha em alguns sites?

Muitos sites de viagens usam:

  • renderização dinâmica em JavaScript
  • proteções anti-bot
  • layouts que mudam com frequência

Como este demo depende de automação genérica de navegador e extração heurística, ele pode não funcionar de forma consistente em todos os sites.

Por que evitamos retornar JSON como saída final?

JSON é útil internamente para depuração, processamento estruturado, ranqueamento e filtragem. Porém, usuários finais preferem resumos legíveis. Por isso o sistema converte saídas estruturadas em um formato amigável.


Aashi Dutt's photo
Author
Aashi Dutt
LinkedIn
Twitter

Sou Especialista Google Developers em ML (Gen AI), tricampeã no Kaggle e Embaixadora Women Techmakers, com mais de três anos de experiência na área de tecnologia. Cofundei uma startup de saúde em 2020 e atualmente faço um mestrado em ciência da computação na Georgia Tech, com foco em aprendizado de máquina.

Temas
Inteligência Artificial
Agentes de IA

Principais cursos da DataCamp

Curso

Sistemas Multiagentes com LangGraph

2 h 45 min
9K
Crie sistemas multiagentes poderosos aplicando padrões emergentes de design de agentes na estrutura LangGraph.
Ver detalhesComeçar Curso

Crie sua conta gratuita

Pratique e programa seu progresso.

Continuar Com O Google
Ao continuar, você aceita nossos Termos de Uso, nossa Política de Privacidade e que seus dados serão armazenados nos EUA.
Ver mais
Relacionado

blog

A OpenAI anuncia o GPT-4 Turbo com visão: O que sabemos até o momento

Descubra a atualização mais recente da OpenAI, GPT-4 Turbo com visão, e seus principais recursos, incluindo o corte de conhecimento aprimorado, uma janela de contexto expandida, preço acessível e muito mais.
Richie Cotton's photo

Richie Cotton

7 min

blog

Como aprender IA do zero em 2026: Um guia completo feito por especialistas

Descubra tudo o que você precisa saber sobre aprender IA em 2026, desde dicas para começar, recursos úteis e insights de especialistas do setor.
Adel Nehme's photo

Adel Nehme

15 min

blog

Os 7 melhores geradores de vídeo com IA para 2026, com vídeos de exemplo

Conheça os melhores geradores de vídeo com IA disponíveis hoje, incluindo RunwayML, Synthesia, Colossyan, Pictory, DeepBrain AI, Invideo e os super esperados Sora e Veo da DeepMind.
Dr Ana Rojo-Echeburúa's photo

Dr Ana Rojo-Echeburúa

9 min

Tutorial

Criando agentes LangChain para automatizar tarefas em Python

Um tutorial abrangente sobre a criação de agentes LangChain com várias ferramentas para automatizar tarefas em Python usando LLMs e modelos de bate-papo usando OpenAI.
cursor ai code editor

Tutorial

AI do cursor: Um guia com 10 exemplos práticos

Saiba como instalar o Cursor AI no Windows, macOS e Linux e descubra como usá-lo em 10 casos de uso diferentes.

Tutorial

Um guia para iniciantes na engenharia de prompts do ChatGPT

Descubra como fazer com que o ChatGPT forneça os resultados que você deseja, fornecendo a ele as entradas necessárias.
Matt Crabtree's photo

Matt Crabtree

6 min

Ver mais