Voltar as noticias
Um agente jogou Slay the Spire 2 sozinho — e o que desbloqueou foi o jogo dizendo 'não'
Casos de UsoMediaEN

Um agente jogou Slay the Spire 2 sozinho — e o que desbloqueou foi o jogo dizendo 'não'

Dev.to - MCP·9 de setembro de 2026

Eu fiz um agente jogar Slay the Spire 2 sozinho — e o que desbloqueou foi o jogo dizendo 'não'

Em 08/09/2026, um agente jogou um combate solo inteiro de Slay the Spire 2 sem intervenção humana: 7 turnos, 35 ações, 0 rejeições. Antes de qualquer entusiasmo, o escopo honesto: este é um registro de sessão, não um benchmark auditado — eu não tenho o log bruto daquela luta arquivado, e a reprodução passa por um suporte sintético + artefatos versionados com md5 (detalhes na seção QA).

E o detalhe que impulsiona este texto: nenhuma das 35 ações foi decidida por um LLM. Cada decisão de jogo foi uma política gananciosa local baseada em pontuação rodando dentro da ponte Python. O LLM (Hermes, que opera o sistema) estava fora do caminho crítico. E os dois problemas mais difíceis neste projeto não foram resolvidos com "IA mais inteligente" — eles foram resolvidos quando o jogo disse "não" e o agente aprendeu com isso.

O que você levará

  • O padrão de feedback de rejeição (o framework): como um erro de ambiente se torna um estado persistente que filtra as próximas ações do agente — sem re-treinamento, sem LLM, sem re-prompt. Copiável para qualquer agente ↔ integração de sistema síncrona (jogo, motor, hardware).
  • A regra "onde colocar a decisão": determinística, local passo a passo para o que é repetível; LLM para o que precisa de contexto aberto. Saber onde o LLM não deve estar é uma decisão de engenharia, não uma falta de ousadia.
  • As duas falhas instrutivas: um deadlock de thread principal (task.Wait() no Godot → Task.WhenAny com timeout) e patches que quebram em cada atualização de Acesso Antecipado (saída: reflexão defensiva).

A cena de abertura: o jogo já sabia como jogar sozinho

Tudo começou com engenharia reversa. StS2 roda em um fork do Godot com a lógica em C#/.NET — a DLL principal é sts2.dll (9,3 MB). Decompilando com ilspycmd no meu PC, encontrei um sistema interno AutoSlay (MegaCrit.Sts2.Core.AutoSlay): um AutoSlayer que orquestra toda a execução (mapa, combate, recompensa, loja) apenas para testes, com um seletor de cartas aleatório — e não está exposto na UI do jogador.

Sem reivindicação de novidade: um mod de autoslay público já existe na comunidade (STS2AutoSlayMod no Nexus, desde 21/03/2026). O que importa para este projeto é outra coisa: se o jogo tem um autoslayer, então um gancho de seleção de cartas oficial existe em algum lugar. Eu o encontrei: ICardSelector, em MegaCrit.Sts2.Core.TestSupport (namespace de teste, mas público), com GetSelectedCards(options, minSelect, maxSelect) e GetSelectedCardReward(...). O mesmo gancho que o jogo usa para descartar, recompensar, atualizar e remover — um seletor lida com tudo (detalhe na seção EA).

A tese: isso não é um problema de LLM

Todo mundo assume que "um agente de IA jogando um jogo" = LLM chamando LLM em cada ação. A parte contraintuitiva deste projeto:

Fazer um agente jogar um jogo real não é um problema de LLM — é um problema de canal de comando e um problema de feedback. O jogo precisa receber a ação e precisa dizer quando falhou.

Decisões de combate vivem em uma política local determinística — _autopilot_decide(gate, trigger), inline na ponte desde a v0.1.3, presente na v0.2.7 na linha 396 de server/sts2_bridge.py. É gananciosa por pontuação: dano/custo com bônus de morte, bloqueio preventivo e de desespero, poderes escalonados jogados cedo em lutas longas, veneno quando a mão não pode matar, alvo escolhido pela intenção do inimigo. Zero chamadas de LLM no loop (verificado por grep no zip).

A regra que usei, e que se aplica a qualquer projeto de agente:

Tipo de decisão Onde vive Por quê
Passo a passo repetível (qual carta, qual alvo) Política local determinística (pontuação) Determinismo, latência, custo zero por decisão
Contexto aberto (o que está acontecendo, o que mudou) LLM como operador/observador Julgamento, linguagem natural, explicação

O LLM opera o sistema: liga/desliga o piloto automático, lê o estado, vê rejeições, ajusta a política. Ele não é o cérebro da jogada — e vender "um agente LLM jogando" seria a mentira por omissão que mata a credibilidade na hora.

Arquitetura: o canal de comando

O pipeline completo (código verificado nos artefatos com md5, seção QA):

Slay the Spire 2 (EA, C#/Godot)
   └─ mod (BaseLib + Harmony, MainFile.cs)          ← compila e patcha o repositório público
        │  POST http://127.0.0.1:5000/update_state  ← loopback, fire-and-forget
        ▼
   bridge Python/FastMCP (sts2_bridge.py v0.2.7)
        │  Resposta HTTP a CADA push = canal de comando
        │  {"Type":"PlayCard","HandIndex":N,"TargetIndex":M} | {"Type":"EndTurn"} | OK
        ▼
   MCP (10 ferramentas) → Hermes (operador/observador)

Três pontos que valem a pena destacar:

  1. Somente loopback. O mod só fala com 127.0.0.1:5000 (MainFile.cs v0.3.2, linha 404: _aiServerUrl = "http://127.0.0.1:5000/update_state"; _rejectionUrl na linha 27). A ponte rejeita qualquer origem que não seja localhost (route_update_state, linha 645; route_rejection, linha 704). O jogo nunca abre uma porta — ele apenas POSTa.
  2. A resposta HTTP é o comando. Cada push de estado do jogo recebe uma resposta; se o corpo for JSON de comando, o mod o executa (TryManualPlay, linha 74; combatManager.SetReadyToEndTurn, linha 131). Se for OK, ele não faz nada. Um único canal, síncrono por construção — sem fila, sem polling.
  3. 10 ferramentas MCP (sts2_bridge.py, linhas 761–908): sts2_status, sts2_get_state, sts2_get_combat, sts2_history, sts2_rejections, sts2_autopilot, sts2_set_hold, sts2_play_card, sts2_end_turn, sts2_clear_pending.

O mod base é público: Manuelbbl/Communication_Mod_STS2 — "Um poderoso mod de API que exporta o estado completo do jogo ao vivo de Slay the Spire 2 para um servidor local para treinamento de IA e desenvolvimento de bots", com BaseLib como um requisito estrito. É a base que compilo e patcho; o que é meu (ponte, piloto automático, suporte) é público em github.com/brmarcosbr/sts2-mcp-bridge; o que permanece apenas nos zips versionados são os patches em cima do mod (seletor v3, canal de rejeição), porque o repositório base não tem licença que permita redistribuí-los (veja Limites).

O padrão de feedback de rejeição (o cerne deste texto)

O mod é fire-and-forget: quando o jogo recusa uma jogada, o comando falhou silenciosamente — o jogo não trava, ele simplesmente não executa. Sem feedback, o agente tentaria a mesma carta para sempre. A solução foi um canal de erro dedicado:

1. Fire-and-forget com um sep

Contexto Triplo Up

O artigo ilustra como a interação entre agentes de IA e jogos pode ser otimizada, o que pode ser aplicado em empresas que desenvolvem jogos ou sistemas interativos. A compreensão do feedback e da tomada de decisão local pode melhorar a eficiência de agentes em ambientes complexos.

Noticias relacionadas

Gostou do conteudo?

Receba toda semana as principais novidades sobre WebMCP.