feat(chatbot): mode profondeur côté serveur (rapide / approfondi) sur les 4 routes
Contrat unique `profondeur` ('rapide' | 'approfondi', défaut rapide) dans
utils/chatProfondeur.ts (libellés partagés). Les 3 routes Bifrost lisent
body.profondeur ?? body.mode, choisissent le tier (20b / 120b + replis), un
prompt système « réflexion » (Entraide, Réseaux, Taff) au même format JSON, et un
budget max_tokens adapté. Pensées lit body.profondeur (jamais body.mode, réservé à
LightRAG) : posture réflexion ajoutée au user_prompt + max_total_tokens 40000.
Modèle servi journalisé, et champ debug exposé uniquement en dev.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015vcVGz8i4WpZm2dixKUiSD
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
75d8440601
commit
80f69565aa
@@ -7,7 +7,7 @@
|
||||
// @ts-ignore — JSON import résolu par Vite/Rollup
|
||||
import taffData from '../../public/data/plateformes-taff.json'
|
||||
import { checkRateLimitJson } from '~/server/utils/rateLimitJson'
|
||||
import { pickBifrostTier, bifrostContent, REASONING_MARGIN_TOKENS, type BifrostChatResponse } from '~/server/utils/bifrost'
|
||||
import { pickBifrostTier, profondeurDuBody, bifrostMaxTokens, bifrostDebug, bifrostContent, REGLE_GUILLEMETS, type BifrostChatResponse } from '~/server/utils/bifrost'
|
||||
|
||||
interface PlateformeMinimal {
|
||||
id: string
|
||||
@@ -49,6 +49,29 @@ FORMAT :
|
||||
PLATEFORMES DISPONIBLES :
|
||||
{{PLATEFORMES_JSON}}`
|
||||
|
||||
// Prompt « réflexion » (mode approfondi, v1 — prompts définitifs par onglet : B7/B9). Même format JSON.
|
||||
const SYSTEM_PROMPT_REFLEXION = `Tu es un conseiller pour les architectes indépendants français qui cherchent des missions. Tu connais toutes les plateformes de mise en relation architecte↔particulier et les agrégateurs d'appels d'offres publics référencés par AEP (Architecture d'Écologie Politique).
|
||||
|
||||
POSTURE : avant de recommander une plateforme, tu aides l'architecte à clarifier ce qu'il cherche et qui il est : type de missions visées (particuliers, public, réno, neuf), volume et rythme, statut et assurances, ce qu'il accepte de céder (commission, abonnement, temps de réponse), ses valeurs. Tu reformules son profil tel que tu le comprends, tu nommes un arbitrage que sa demande laisse ouvert, tu poses 2 ou 3 questions qui l'aident à se situer, PUIS tu orientes vers LA ou LES plateformes du contexte qui correspondent, avec leurs limites.
|
||||
|
||||
RÈGLES :
|
||||
1. Ne recommande QUE des plateformes présentes dans le contexte ci-dessous. Si l'une est « À éviter », signale-le clairement.
|
||||
2. ${REGLE_GUILLEMETS}
|
||||
3. Sois direct et opinionné — c'est la valeur d'AEP — mais ne présume pas de ce que tu ignores de son profil : demande.
|
||||
4. Réponse de 300 mots maximum, en français, en prose, ton conseiller pair, tutoiement.
|
||||
5. Retourne UNIQUEMENT un JSON valide, sans texte avant ou après.
|
||||
|
||||
FORMAT :
|
||||
{
|
||||
"reponse_texte": "Ta réponse en prose, max 300 mots : reformulation, arbitrage, questions, puis plateformes",
|
||||
"plateformes_recommandees": [
|
||||
{ "id": "slug-kebab", "nom": "Nom plateforme", "raison": "Pourquoi cette plateforme en 1 phrase" }
|
||||
]
|
||||
}
|
||||
|
||||
PLATEFORMES DISPONIBLES :
|
||||
{{PLATEFORMES_JSON}}`
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const config = useRuntimeConfig()
|
||||
|
||||
@@ -67,7 +90,8 @@ export default defineEventHandler(async (event) => {
|
||||
if (!question || question.length < 5) {
|
||||
throw createError({ statusCode: 400, statusMessage: 'Question trop courte.' })
|
||||
}
|
||||
const tier = pickBifrostTier(body?.mode)
|
||||
const profondeur = profondeurDuBody(body)
|
||||
const tier = pickBifrostTier(profondeur)
|
||||
|
||||
// Données bundlées statiquement à la compilation (import JSON)
|
||||
const plateformes: PlateformeMinimal[] = ((taffData as any).plateformes ?? []).map((p: any) => ({
|
||||
@@ -91,7 +115,7 @@ export default defineEventHandler(async (event) => {
|
||||
justification: p.scoring.justification_tag,
|
||||
}))
|
||||
|
||||
const systemPrompt = SYSTEM_PROMPT.replace('{{PLATEFORMES_JSON}}', JSON.stringify(context, null, 0))
|
||||
const systemPrompt = (profondeur === 'approfondi' ? SYSTEM_PROMPT_REFLEXION : SYSTEM_PROMPT).replace('{{PLATEFORMES_JSON}}', JSON.stringify(context, null, 0))
|
||||
|
||||
const bifrostUrl = config.bifrostUrl as string
|
||||
const bifrostVk = config.bifrostVk as string
|
||||
@@ -100,6 +124,7 @@ export default defineEventHandler(async (event) => {
|
||||
}
|
||||
|
||||
let mistralRaw: string
|
||||
let debugExtra: Record<string, unknown> = {}
|
||||
try {
|
||||
const res = await $fetch<BifrostChatResponse>(
|
||||
`${bifrostUrl}/v1/chat/completions`,
|
||||
@@ -110,7 +135,7 @@ export default defineEventHandler(async (event) => {
|
||||
model: tier.model,
|
||||
fallbacks: tier.fallbacks,
|
||||
temperature: 0.3,
|
||||
max_tokens: 700 + REASONING_MARGIN_TOKENS,
|
||||
max_tokens: bifrostMaxTokens(700, profondeur),
|
||||
response_format: { type: 'json_object' },
|
||||
messages: [
|
||||
{ role: 'system', content: systemPrompt },
|
||||
@@ -120,6 +145,7 @@ export default defineEventHandler(async (event) => {
|
||||
}
|
||||
)
|
||||
mistralRaw = bifrostContent(res, 'chatbot-taff')
|
||||
debugExtra = bifrostDebug(res, 'chatbot-taff', profondeur)
|
||||
} catch {
|
||||
throw createError({ statusCode: 502, statusMessage: 'Erreur IA — réessaie dans quelques instants.' })
|
||||
}
|
||||
@@ -133,6 +159,7 @@ export default defineEventHandler(async (event) => {
|
||||
nom: r.nom ?? plateformes.find(p => p.id === r.id)?.nom ?? r.id,
|
||||
raison: r.raison ?? '',
|
||||
})),
|
||||
...debugExtra,
|
||||
}
|
||||
} catch {
|
||||
return { reponse_texte: "Je n'ai pas pu analyser ta demande.", plateformes_recommandees: [] }
|
||||
|
||||
Reference in New Issue
Block a user