Conversations multi-tours (follow-ups) — `thread_id` + bloc `SUIVI`
`thread_id` + bloc `SUIVI` + résolution des follow-ups (apps externes)
Objectif
Permettre des échanges “naturels” sur des documents, sans réinjecter l’historique brut dans chaque prompt :
- “détaille S2”
- “détaille le point B” (compat legacy)
- “détaille le 2e point”
Tout en restant enterprise safe :
- les faits proviennent toujours des documents (RAG strict + citations),
- aucune “culture générale” automatique si le retrieval ne retrouve pas de sources,
- l’état conversationnel stocké ne contient pas de texte de document.
Contrat côté client (application externe via API Nexus)
1) Envoyer un thread_id stable
Sur chaque POST /api/query, envoyer :
caller_app(recommandé)thread_id(recommandé, stable par conversation)
Exemple (payload JSON) :
{
"query": "Résume le rapport 2024 du CERN",
"caller_app": "external_app",
"thread_id": "thread-123",
"source_app": "operations",
"workspace": "projets",
"language": "fr"
}2) Follow-ups recommandés
Après un livrable, envoyer préférentiellement des références explicites :
Détaille S2Détaille le point B(compat legacy → S2)Détaille le 2e point(→ S2)
Éviter les anaphores “pures” (“détaille ça”) : Nexus demandera alors de choisir une section (S1..S8).
Contrat côté service (prompts)
Quand un service produit un livrable (résumé/synthèse/rapport), il doit terminer en dernière position par un bloc machine‑parsable :
SUIVI
[S1] <titre court>
[S2] <titre court>
[S3] <titre court>
[S4] <titre court>Règles :
- le mot‑clé doit être exactement
SUIVI(ne jamais le traduire), - 4 à 8 sections maximum,
- titres descriptifs et basés sur le
CONTEXT(ne pas inventer), - aucun texte après le bloc.
Implémentation côté Nexus (résumé)
1) thread_state (Postgres)
Nexus stocke un état minimal (outline + docs utilisés) dans public.thread_state :
- clé :
(tenant_id, caller_app, thread_id) last_outline(jsonb) : sections S1..Snlast_doc_ids/last_titles(jsonb)
Cet état n’est pas une source : il sert uniquement à comprendre ce que l’utilisateur désigne dans un follow‑up.
2) Résolution déterministe (sans LLM)
Quand un follow‑up est détecté et qu’un thread_state est disponible :
S2→ S2point B→ S22e point→ S2
Nexus construit alors une requête de retrieval robuste (ex. "<titre S2> — <question>") et injecte au modèle un indicateur FOLLOWUP_REFERENCE.
3) Fallback best-effort
Si SUIVI n’est pas disponible (service non migré) :
- le resolver ne bloque pas,
- Nexus retombe sur la condensation best‑effort + retry retrieval + no_context safe.
Debug (SQL)
Vérifier si un outline existe pour un thread :
SELECT updated_at, last_outline
FROM thread_state
WHERE caller_app = '<caller_app>' AND thread_id = '<thread_id>'
ORDER BY updated_at DESC
LIMIT 1;Vérifier la résolution d’un follow‑up :
SELECT created_at, question, followup_resolved, followup_section_id, followup_ref_type
FROM queries_log
WHERE caller_app = '<caller_app>' AND thread_id = '<thread_id>'
ORDER BY created_at DESC
LIMIT 20;