pgberlureau's picture
feat: enrich LLM context with location history and per-location action tracking
cd3605f

A newer version of the Gradio SDK is available: 6.13.0

Upgrade
metadata
title: Text Adventure Agent Submission
emoji: 🗺
colorFrom: green
colorTo: blue
sdk: gradio
sdk_version: 5.12.0
app_file: app.py
pinned: false
license: mit

Text Adventure MCP Agent

Architecture

L'agent suit le pattern MCP : agent.py (client) envoie des actions à mcp_server.py (serveur) qui wrappe le moteur Jericho.

L'idée principale c'est d'enrichir le contexte du LLM plutôt que d'essayer de contrôler ses décisions par programme.

Côté serveur (mcp_server.py)

On utilise l'API Jericho pour ajouter des métadonnées à chaque réponse de play_action :

  • [Location: ...] : le lieu actuel (via get_player_location())
  • [Untried valid actions: ...] : les actions valides pas encore essayées (via get_valid_actions())
  • [Already tried here: ...] : ce qui a déjà été tenté à cet endroit, avec le résultat
  • [WARNING: ...] : un avertissement quand l'agent reste trop longtemps au même endroit

Tout est tracké par lieu (dataclass LocationLog), donc même quand l'agent revient quelque part, il sait ce qu'il a déjà essayé.

Côté agent (agent.py)

On force tous les appels à passer par play_action (les tools memory, get_map, inventory sont redirigés vers look) puisque toute l'info utile est déjà dans les réponses enrichies.

On montre au LLM les 10 derniers lieux visités sous forme de chaîne (ex: Outside → Hole → Fountain Room → Cave With Stream → Fountain Room → ...). Ça lui permet de voir quand il oscille entre deux endroits. Si les 6 derniers lieux contiennent 2 endroits ou moins, on ajoute un WARNING dans le prompt.

On corrige aussi les verbes que le LLM invente (checkexamine, grabtake, etc.) avant de les envoyer au jeu.

Ce qui n'a pas marché

On a d'abord essayé de détecter programmatiquement quand l'agent était bloqué pour forcer une action différente. Ça a été une catastrophe : la détection se déclenchait trop tôt (rester au même lieu ≠ osciller), et ça bloquait des bonnes actions que le LLM aurait prises tout seul (par ex. northeast qui était la bonne sortie). Au final le forçage faisait cycler l'agent dans des directions inutiles pendant 100 steps.

La conclusion c'est que le LLM prend de meilleures décisions que des heuristiques codées en dur, il faut juste lui donner la bonne information.

Améliorations possibles

  • Utiliser un historique multi-turn au lieu de prompts single-turn, pour donner au LLM une vraie mémoire de la session
  • Demander au LLM de formuler un plan de haut niveau de temps en temps (ex: "trouver une clé pour le coffre") au lieu de réagir step by step
  • Détecter le pattern "drop items before climbing" : l'agent reste bloqué au Hole parce qu'il ne peut pas monter les escaliers en portant des objets