Pilote Orléans · configuration, pas un fork · aucun lieu inventé

Livrable 16

Reco et planificateur

17 — Planificateur (IA)

Reco MVP — pas de ML

Score = combinaison linéaire des termes de la recherche, restreinte par des hard filters :

  • même ville ;
  • non expiré ;
  • si le contexte est « maintenant » : ouvert ou event actif ou offre active ;
  • si budget fourni : écarter les prix connus au-dessus ; ne pas écarter price_unknown (les garder en fin de liste, label « prix non communiqué ») ;
  • si distance max : écarter au-delà, seulement si un point d'origine existe.

Explainabilité, une raison vraie max trois puces :

  • « Ouvert maintenant » (si le calcul d'horaire le dit)
  • « À X min à pied » uniquement si un routeur a répondu ; sinon « à environ N m » si haversine, libellé « distance directe »
  • « Dans votre budget » si prix connu et sous le seuil
  • « Concert ce soir » si event lié publié
  • « Déclaré par l'établissement il y a … »

Interdit : « recommandé pour vous » sans préférence stockée. Si pas de personnalisation : « correspond à la recherche ».

Personnalisation (P2) : favoris, follows, clics — opt-in personalization_enabled, désactivable, sans âge exact, sans catégorie sensible.

Embeddings / collaboratif : P2, et seulement après volume réel. pgvector pas au schéma MVP.

Planificateur

Pipeline obligatoire :

requête
 → intent (règles ou LLM)
 → contraintes
 → retrieval SQL
 → ranking
 → enchaînement glouton (pas un TSP prétendu optimal)
 → phrases à partir des champs réels

Interdit : prompt « invente une soirée à Orléans ».

Séquence

Types d'étapes demandés (sequence: restaurant, bar, event, club) ou défaut configurable par DNA si l'utilisateur dit « une soirée » sans détail : ne pas appliquer un défaut silencieux. Demander le créneau ou proposer les filtres vides.

Pour chaque étape, créneau estimé :

  • durée par défaut affichée comme hypothèse de planification (« créneau proposé : 1 h 30 »), paramètre, pas une vérité sur le service ;
  • next start = fin + déplacement ;
  • le lieu doit être ouvert sur tout le créneau ou l'event doit couvrir le créneau ;
  • déplacement = routeur si un fournisseur répond ; sinon distance directe sans temps inventé. Pas d'estimation « 5 km/h » présentée comme une durée de marche. THIRD-PARTY si API routing.

Chaque étape : primary + jusqu'à 2 alternatives réelles. S'il en manque : « pas d'autre option vérifiée ».

Changement (annulation, closed_until) : recalcul de cette étape.

Mode nuit : le plan stocké, prochaine étape en tête, lien itinéraire, alternative. Pas de tracking de position en fond. La géoloc est redemandée au moment de l'itinéraire.

Groupe

Tables prévues (08). Pas d'UI MVP. Pas de chat de groupe.

Météo

Si un fournisseur est branché plus tard : infléchir terrasse vs intérieur si l'attribut terrasse est sourcé. Si météo down : ignorer. Ne pas bloquer. Aucun fournisseur choisi. THIRD-PARTY. Ne pas inventer la météo du jour.

Coût IA

  • Cache d'intent par hash de requête normalisée, TTL court.
  • Petit modèle pour l'intent ; pas d'appel pour le ranking.
  • Rate limit par session.
  • Si pas de clé : règles seules, fonction identique en aval.
  • XAI_API_KEY serveur uniquement, jamais dans le client.

Sécurité IA

Le modèle ne renvoie que des slots. Les noms de lieux dans sa sortie sont ignorés. Injection dans le champ recherche : traité comme du texte de requête, pas comme une instruction système (le prompt système est fixe ; la requête est data).

Décisions

D1 — Explainable linear, hard constraints

  • Alternatives : boîte noire ; tri par popularité (interdite sans signal, et le signal n'est pas de la foule).
  • Risque : résultats « plats ». Acceptable.
  • Multi-ville : poids et durées de créneau overridables dans la DNA, filtres identiques.

D2 — LLM optionnel et tardif dans le pipeline

  • Choix : la base est la vérité opérationnelle.
  • Risque : texte fluide qui sur-promet. Le template de rendu ne peut imprimer que des champs (name, starts_at, provenance). Pas de phrase libre du modèle sur l'ambiance si l'ambiance n'est pas un attribut sourcé.