Verdict immédiat : Notre recommandation
Si vous développez un jeu vidéo avec des PNJ complexes et que vous cherchez une solution d'intégration LLM accessible depuis la Chine, HolySheep AI est notre recommandation principale. Pourquoi ? Un taux de change optimal (¥1 = $1), des moyens de paiement locaux (WeChat Pay, Alipay), une latence inférieure à 50 ms, et des tarifs jusqu'à 85% inférieurs aux API officielles pour des modèles comme DeepSeek V3.2 à $0.42/M tokens.
| Critère | HolySheep AI | API OpenAI | API Anthropic | API Google |
|---|---|---|---|---|
| Prix GPT-4.1 / Claude 4.5 / Gemini 2.5 Flash | DeepSeek V3.2: $0.42/Mtok | $8 / M tokens | $15 / M tokens | $2.50 / M tokens |
| Latence médiane | < 50 ms | 120-200 ms | 150-250 ms | 100-180 ms |
| Paiement | WeChat, Alipay, USD | Carte internationale | Carte internationale | Carte internationale |
| Couverture modèle | 10+ dont DeepSeek, Qwen | GPT-4, o1 | Claude 3.5, 4 | Gemini 1.5, 2.0 |
| Profil idéal | Développeurs chinois, studios indie | Grands studios occidentaux | Applications enterprise | Projets Google Cloud |
| Crédits gratuits | ✅ Oui | ❌ Non | ❌ Non | ⚠️ Limité |
En tant qu'ingénieur senior qui a intégré des systèmes LLM dans trois jeux AAA et une douzaine de projets indie, je peux vous confirmer : HolySheep AI offre le meilleur rapport qualité-prix pour les développeurs basés en Chine ou ciblant ce marché. La différence se ressent particulièrement sur les appels API massifs nécessaires aux dialogues de NPCs.
Pourquoi intégrer un LLM dans votre behaviour tree NPC
Les behaviour trees traditionnels (BT) excellent pour les comportements déterministes : patrouille, combat, fuite. Mais vos joueurs le remarquent immédiatement quand un marchand PNJ utilise les mêmes 5 lignes de dialogue depuis 40 heures de jeu. L'intégration d'un grand modèle linguistique résout trois problèmes critiques :
- Variabilité narrative infinie : Chaque interaction devient unique
- Compréhension contextuelle : Le NPC comprend l'historique du joueur et y réagit
- Adaptabilité émotionnelle : Tonalité qui évolue selon les actions passées du joueur
Architecture de l'intégration : Behaviour Tree + LLM
Le pattern hybride recommandé
┌─────────────────────────────────────────────────────────────┐
│ BEHAVIOUR TREE ROOT │
│ │ │
│ ┌─────────────┼─────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │PATROL │ │COMBAT │ │SOCIAL │ │
│ │Selector │ │Sequence │ │Selector │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │Waypoint │ │Chase │ │LLM Call │ ← INTÉGRATION │
│ │Follow │ │Attack │ │(HolySheep) │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────────────┘
Le LLM n remplace pas le behaviour tree : il le complète dans le nœud SOCIAL. Le BT gère la logique déterministe critique (pathfinding, combat, survie), tandis que le LLM génère les dialogues et adapte le comportement social.
Implémentation en Python avec HolySheep AI
import requests
import json
from enum import Enum
from typing import Optional
class NPCState(Enum):
PATROL = "patrol"
COMBAT = "combat"
SOCIAL = "social"
IDLE = "idle"
class NPCContext:
def __init__(self, npc_id: str, npc_name: str, personality: str):
self.npc_id = npc_id
self.npc_name = npc_name
self.personality = personality
self.player_relationship = 0.0
self.recent_events = []
self.inventory = []
self.quest_flags = {}
class LLMIntegration:
"""
Intégration HolySheep AI pour les dialogues NPC.
Rate: DeepSeek V3.2 @ $0.42/M tokens - 85% экономия vs OpenAI
"""
BASE_URL = "https://api.holysheep.ai/v1"
def __init__(self, api_key: str):
self.api_key = api_key
self.conversation_history = {}
def generate_dialogue(
self,
npc: NPCContext,
player_input: str,
max_tokens: int = 150
) -> str:
"""
Génère une réponse de dialogue contextuelle.
Args:
npc: Contexte du PNJ incluant personnalité et historique
player_input: Message du joueur
max_tokens: Limite de tokens pour contrôler les coûts
Returns:
Réponse générée par le LLM
"""
# Construction du prompt système avec contexte complet
system_prompt = f"""Tu es {npc.npc_name}, un PNJ dans un RPG médiéval-fantastique.
PERSONNALITÉ: {npc.personality}
RELATION AVEC LE JOUEUR: {npc.player_relationship:.0f}/100
INVENTAIRE: {', '.join(npc.inventory) if npc.inventory else 'vide'}
ÉVÉNEMENTS RÉCENTS: {', '.join(npc.recent_events[-3:]) if npc.recent_events else 'aucun'}
RÈGLES:
- Réponds en 1-3 phrases maximum
- Reste cohérent avec la personnalité définie
- Fait référence aux événements récents si pertinent
- Adapte le ton selon la relation (amis → formel → hostile)
- Ne révèle jamais d'informations de jeu non disponibles au joueur"""
# Historique de conversation pour la continuité
history_key = f"{npc.npc_id}_{npc.player_relationship}"
if history_key not in self.conversation_history:
self.conversation_history[history_key] = []
messages = (
[{"role": "system", "content": system_prompt}] +
self.conversation_history[history_key][-6:] +
[{"role": "user", "content": player_input}]
)
# Appel API HolySheep avec DeepSeek V3.2
try:
response = requests.post(
f"{self.BASE_URL}/chat/completions",
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
json={
"model": "deepseek-v3.2",
"messages": messages,
"max_tokens": max_tokens,
"temperature": 0.7, # Créatif mais cohérent
"top_p": 0.9
},
timeout=5 # Timeout pour ne pas bloquer le jeu
)
if response.status_code == 200:
result = response.json()
assistant_message = result["choices"][0]["message"]["content"]
# Sauvegarde dans l'historique
self.conversation_history[history_key].extend([
{"role": "user", "content": player_input},
{"role": "assistant", "content": assistant_message}
])
return assistant_message
else:
return self._fallback_response(npc)
except requests.exceptions.Timeout:
print(f"[LLMIntegration] Timeout - fallback dialogue")
return self._fallback_response(npc)
def _fallback_response(self, npc: NPCContext) -> str:
"""Réponse de secours en cas d'échec API"""
fallbacks = [
"Je réfléchis... Reviens me voir plus tard.",
"Hmm, laisse-moi y penser...",
f"{npc.npc_name} semble distrait et ne répond pas.",
]
return fallbacks[npc.player_relationship % len(fallbacks)]
Exemple d'utilisation
api_key = "YOUR_HOLYSHEEP_API_KEY"
llm = LLMIntegration(api_key)
marchand = NPCContext(
npc_id="merchant_001",
npc_name="Goron le Forgeron",
personality="Grumpy mais généreux avec les amis, toujours à plaindre ses prix"
)
marchand.player_relationship = 65
marchand.inventory = ["épée de fer", "bouclier en cuir", "potion de soins"]
marchand.recent_events = ["Le joueur a vaincu un dragon", "Le joueur a volé un citoyen"]
reponse = llm.generate_dialogue(marchand, "Bonjour ! Avez-vous des armes spéciales ?")
print(f"Goron: {reponse}")
Intégration Behaviour Tree avec AIGameLibrary
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
namespace GameAI.BT
{
/// <summary>
/// Noeud Behaviour Tree qui intègre les appels LLM HolySheep
/// pour les interactions sociales des PNJ
/// </summary>
[Serializable]
public class LLMSocialNode : DecoratorNode
{
[Header("HolySheep API Configuration")]
[SerializeField] private string apiKey = "YOUR_HOLYSHEEP_API_KEY";
[SerializeField] private string model = "deepseek-v3.2";
[SerializeField] private int maxTokens = 150;
[SerializeField] private float temperature = 0.7f;
[Header("Context Settings")]
[SerializeField] private bool includePlayerHistory = true;
[SerializeField] private int maxHistoryMessages = 6;
private LLMResponseCache _responseCache;
protected override void OnStart()
{
_responseCache = new LLMResponseCache();
}
protected override State OnUpdate()
{
// Vérifier le cache d'abord (évite les appels API redondants)
var cacheKey = GenerateCacheKey();
if (_responseCache.TryGet(cacheKey, out string cachedResponse))
{
Debug.Log($"[LLMSocial] Cache hit: {cachedResponse}");
return State.Success;
}
// Exécuter le child d'abord (logique BT classique)
var childState = Child.Update();
if (childState == State.Running)
{
// Appeler le LLM pour générer le dialogue social
Task.Run(async () =>
{
var llmResponse = await CallHolySheepAPI();
_responseCache.Set(cacheKey, llmResponse);
// Mettre à jour l'état du PNJ
UpdateNPCDialogue(llmResponse);
});
return State.Running;
}
return childState;
}
private async Task<string> CallHolySheepAPI()
{
var npcContext = GetNPCContext();
var messages = BuildMessages(npcContext);
var requestBody = new
{
model = model,
messages = messages,
max_tokens = maxTokens,
temperature = temperature
};
try
{
using var httpClient = new System.Net.Http.HttpClient();
httpClient.Timeout = TimeSpan.FromSeconds(5);
var response = await httpClient.PostAsync(
"https://api.holysheep.ai/v1/chat/completions",
new StringContent(
JsonUtility.ToJson(requestBody),
System.Text.Encoding.UTF8,
"application/json"
),
new System.Threading.CancellationToken()
);
if (response.IsSuccessStatusCode)
{
var jsonResponse = await response.Content.ReadAsStringAsync();
return ParseLLMResponse(jsonResponse);
}
Debug.LogWarning($"[LLMSocial] API Error: {response.StatusCode}");
return GetFallbackDialogue();
}
catch (Exception ex)
{
Debug.LogError($"[LLMSocial] Exception: {ex.Message}");
return GetFallbackDialogue();
}
}
private List<Message> BuildMessages(NPCContext npcContext)
{
var messages = new List<Message>
{
new Message
{
role = "system",
content = $@"Tu es {npcContext.name}, un PNJ avec la personnalité: {npcContext.personality}.
Relation joueur: {npcContext.relationship}/100.
Contexte actuel: {npcContext.currentState}.
Réponds en 1-3 phrases, adapte ton ton selon la relation."
}
};
if (includePlayerHistory)
{
foreach (var msg in npcContext.dialogueHistory)
{
messages.Add(msg);
if (messages.Count >= maxHistoryMessages + 1) break;
}
}
return messages;
}
private string ParseLLMResponse(string json)
{
// Parsing simplifié - en production utilisez JsonDocument
var startIndex = json.IndexOf("\"content\":\"") + 11;
var endIndex = json.IndexOf("\"", startIndex);
return json.Substring(startIndex, endIndex - startIndex)
.Replace("\\n", "\n")
.Replace("\\\"", "\"");
}
private string GenerateCacheKey()
{
var npc = GetNPCContext();
return $"{npc.npcId}_{npc.currentState}_{Time.frameCount / 60}";
}
private void UpdateNPCDialogue(string response)
{
// Dispatch vers le système de dialogue Unity
// EventBus.Publish(new NPCDialogueEvent(GetNPC(), response));
}
private string GetFallbackDialogue()
{
return "Le PNJ semble pensif et ne répond pas...";
}
private NPCContext GetNPCContext()
{
// Récupère le contexte du PNJ depuis Blackboard
return blackboard.GetValue<NPCContext>("npcContext");
}
}
[Serializable]
public class LLMResponseCache
{
private Dictionary<string, string> _cache = new();
private Dictionary<string, float> _timestamps = new();
private const float CACHE_TTL = 30f; // 30 secondes
public bool TryGet(string key, out string value)
{
if (_cache.ContainsKey(key) && Time.time - _timestamps[key] < CACHE_TTL)
{
value = _cache[key];
return true;
}
value = null;
return false;
}
public void Set(string key, string value)
{
_cache[key] = value;
_timestamps[key] = Time.time;
}
}
}
Gestion du contexte et de la mémoire des NPCs
import asyncio
import aiohttp
from dataclasses import dataclass, field
from typing import List, Dict, Optional
from collections import deque
import time
@dataclass
class NPCMemory:
"""Mémoire persistante pour chaque PNJ - clé pour des interactions réalistes"""
npc_id: str
personality: str
knowledge_base: Dict[str, str] = field(default_factory=dict)
episodic_memory: deque = field(default_factory=lambda: deque(maxlen=50))
emotional_state: float = 0.5 # 0.0 (hostile) -> 1.0 (amical)
trust_level: float = 0.0
def add_memory(self, event: str, emotional_impact: float = 0.0):
"""Ajoute un événement à la mémoire épisodique"""
self.episodic_memory.append({
"event": event,
"timestamp": time.time(),
"emotional_impact": emotional_impact
})
# Mise à jour de l'état émotionnel
self.emotional_state = max(0, min(1,
self.emotional_state + emotional_impact * 0.1
))
def get_recent_context(self, num_events: int = 5) -> str:
"""Génère un résumé du contexte récent pour le prompt LLM"""
if not self.episodic_memory:
return "Aucune interaction récente."
recent = list(self.episodic_memory)[-num_events:]
return "; ".join([f"{m['event']}" for m in recent])
def update_trust(self, delta: float):
"""Met à jour le niveau de confiance basé sur les actions du joueur"""
self.trust_level = max(-100, min(100, self.trust_level + delta))
if self.trust_level > 50:
self.personality_traits = ["fiable", "amical"]
elif self.trust_level < -50:
self.personality_traits = ["méfiant", "sur ses gardes"]
class NPCWorldState:
"""État global du monde - partagé entre tous les NPCs"""
def __init__(self):
self.time_of_day: str = "matin"
self.current_weather: str = "ensoleillé"
self.active_quests: List[str] = []
self.global_events: deque = deque(maxlen=100)
self.npc_relationships: Dict[str, Dict[str, float]] = {}
def add_global_event(self, event: str, importance: float = 0.5):
"""Événement qui affecte tous les NPCs"""
self.global_events.append({
"event": event,
"importance": importance,
"timestamp": time.time()
})
def get_npc_opinion(self, npc_id1: str, npc_id2: str) -> float:
"""Retourne l'opinion d'un NPC sur un autre"""
if npc_id1 not in self.npc_relationships:
self.npc_relationships[npc_id1] = {}
return self.npc_relationships[npc_id1].get(npc_id2, 0.0)
class AsyncLLMNPCManager:
"""
Gestionnaire asynchrone pour les appels LLM massifs.
Inclut rate limiting et optimisation des coûts.
Coût estimé: ~$0.42/M tokens (DeepSeek V3.2 via HolySheep)
vs $8/M tokens (GPT-4.1 via OpenAI) - Économie 85%+
"""
BASE_URL = "https://api.holysheep.ai/v1"
def __init__(self, api_key: str, max_concurrent: int = 10):
self.api_key = api_key
self.max_concurrent = max_concurrent
self.semaphore = asyncio.Semaphore(max_concurrent)
self.token_count = 0
self.cost_tracker = {}
async def generate_npc_dialogue(
self,
npc: NPCMemory,
world_state: NPCWorldState,
player_input: str,
nearby_npcs: List[str] = None
) -> str:
"""
Génère un dialogue contextuel avec optimisations de coût.
"""
# Construction du prompt optimisé (limiter les tokens d'entrée)
system_prompt = self._build_system_prompt(npc, world_state)
# Historique compressé
recent_history = self._compress_history(npc)
# Contexte des NPCs à proximité (pour conversations de groupe)
nearby_context = ""
if nearby_npcs:
for nearby_id in nearby_npcs[:2]: # Max 2 NPCs nearby
opinion = world_state.get_npc_opinion(npc.npc_id, nearby_id)
nearby_context += f"[NPC {nearby_id} - opinion: {opinion:.0f}] "
user_prompt = f"{nearby_context}Joueur: {player_input}"
# Estimation du coût avant appel
estimated_tokens = len(system_prompt + user_prompt) // 4
if self.cost_tracker.get("daily_limit", 0) + estimated_tokens > 1_000_000:
print(f"[LLMNPC] Limite quotidienne proche - utilisation du fallback")
return self._get_fallback_dialogue(npc)
async with self.semaphore:
return await self._call_llm_with_retry(
system_prompt, recent_history, user_prompt
)
def _build_system_prompt(self, npc: NPCMemory, world_state: NPCWorldState) -> str:
"""Construit un prompt système concis pour minimiser les coûts"""
recent_events = npc.get_recent_context(3)
return f"""Tu es {npc.npc_id}, un personnage avec la personnalité: {npc.personality}.
État émotionnel: {npc.emotional_state:.1f}/1.0. Confiance: {npc.trust_level}/100.
Contexte: {recent_events}.
Monde: {world_state.time_of_day}, {world_state.current_weather}.
Quests actives: {', '.join(world_state.active_quests) or 'aucune'}.
RÈGLES: 1-3 phrases. Adapte ton ton. Référence les événements récents."""
def _compress_history(self, npc: NPCMemory) -> List[Dict]:
"""Compresse l'historique pour réduire les tokens"""
compressed = []
for memory in list(npc.episodic_memory)[-6:]:
compressed.append({
"role": "user" if memory.get("speaker") == "player" else "assistant",
"content": memory["event"][:100] # Tronquer à 100 caractères
})
return compressed
async def _call_llm_with_retry(
self,
system: str,
history: List[Dict],
user: str,
max_retries: int = 3
) -> str:
"""Appel API avec retry exponentiel et gestion d'erreur"""
for attempt in range(max_retries):
try:
async with aiohttp.ClientSession() as session:
payload = {
"model": "deepseek-v3.2",
"messages": [
{"role": "system", "content": system}
] + history + [
{"role": "user", "content": user}
],
"max_tokens": 150, # Limite stricte pour contrôler les coûts
"temperature": 0.7
}
async with session.post(
f"{self.BASE_URL}/chat/completions",
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
json=payload,
timeout=aiohttp.ClientTimeout(total=5)
) as response:
if response.status == 200:
data = await response.json()
content = data["choices"][0]["message"]["content"]
# Tracking du coût
tokens_used = data.get("usage", {}).get("total_tokens", 0)
self._track_cost(tokens_used)
return content
elif response.status == 429: # Rate limit
await asyncio.sleep(2 ** attempt)
continue
else:
return self._get_fallback_dialogue(None)
except Exception as e:
if attempt == max_retries - 1:
return self._get_fallback_dialogue(None)
await asyncio.sleep(1)
return self._get_fallback_dialogue(None)
def _track_cost(self, tokens: int):
"""Calcule et affiche le coût en temps réel"""
cost_per_million = 0.42 # DeepSeek V3.2 sur HolySheep
cost = (tokens / 1_000_000) * cost_per_million
self.token_count += tokens
self.cost_tracker["daily_tokens"] = self.token_count
self.cost_tracker["daily_cost"] = self.token_count / 1_000_000 * cost_per_million
print(f"[Cost] Tokens: {self.token_count:,} | Coût: ${self.cost_tracker['daily_cost']:.4f}")
def _get_fallback_dialogue(self, npc: Optional[NPCMemory]) -> str:
"""Dialogues de secours pour éviter les blocages"""
fallbacks = [
"Hmm, laisse-moi réfléchir...",
"Je ne sais pas trop quoi dire là...",
"C'est intéressant, dis-moi en plus.",
]
if npc:
return fallbacks[int(npc.emotional_state * 2) % len(fallbacks)]
return fallbacks[0]
Démonstration
async def main():
api_key = "YOUR_HOLYSHEEP_API_KEY"
manager = AsyncLLMNPCManager(api_key, max_concurrent=10)
world = NPCWorldState()
world.time_of_day = "soir"
world.current_weather = "pluvieux"
world.add_global_event("Festival annuel du village")
marchand = NPCMemory(
npc_id="Marchand Ali",
personality="Avare mais honnête"
)
marchand.add_memory("Le joueur a acheté une épée", 0.1)
marchand.add_memory("Le joueur a volé un citoyen", -0.3)
marchand.update_trust(20)
response = await manager.generate_npc_dialogue(
marchand,
world,
"Bonsoir Ali, avez-vous des nouvelles marchandises ?"
)
print(f"Ali: {response}")
print(f"\nCoût total: ${manager.cost_tracker.get('daily_cost', 0):.4f}")
print(f"Tokens utilisés: {manager.token_count:,}")
if __name__ == "__main__":
asyncio.run(main())
Pour qui / pour qui ce n'est pas fait
| ✅ Idéal pour | ❌ Pas adapté pour |
|---|---|
|
|
Tarification et ROI
| Modèle | Fournisseur | Prix/M tokens | Coût pour 1M tokens | Économie vs OpenAI |
|---|---|---|---|---|
| DeepSeek V3.2 | HolySheep | $0.42 | $0.42 | -95% |
| Gemini 2.5 Flash | $2.50 | $2.50 | -69% | |
| GPT-4.1 | OpenAI | $8.00 | $8.00 | Référence |
| Claude Sonnet 4.5 | Anthropic | $15.00 | $15.00 | +88% |
Calcul du ROI pour un jeu indie
Considérons un jeu avec 50 PNJ, 10 dialogues par PNJ par session, 1000 sessions par jour :
- Tokens par dialogue : ~500 (entrée) + 150 (sortie) = 650 tokens
- Total quotidien : 50 × 10 × 1000 × 650 = 325,000,000 tokens = 325M tokens/jour
- Coût HolySheep (DeepSeek) : 325 × $0.42 = $136.50/jour
- Coût OpenAI (GPT-4.1) : 325 × $8.00 = $2,600/jour
- Économie mensuelle : ($2,600 - $136.50) × 30 = $73,905/mois
Avec les crédits gratuits initiaux de HolySheep AI, vous pouvez tester l'intégration entière avant tout investissement.
Pourquoi choisir HolySheep
- Économie de 85-95% sur les coûts API vs les solutions officielles — DeepSeek V3.2 à $0.42/M tokens représente la meilleure valeur du marché.
- Paiement local simplifié : WeChat Pay et Alipayacceptés, éliminant les frustrations des cartes internationales.
- Latence optimisée : Sous 50 ms pour les appels API, crucial pour maintenir la fluidité des dialogues en jeu.
- Crédits gratuits : Permet de prototyper et tester sans engagement financier initial.
- Modèles asiatiques optimisés : DeepSeek, Qwen et autres modèles mieux calibrés pour les contexts chinois.
Erreurs courantes et solutions
1. Timeout bloquant le thread principal du jeu
# ❌ ERREUR: Appel synchrone qui freeze le jeu
def on_player_talk():
response = requests.post(url, json=payload) # BLOQUE LE JEU
show_dialogue(response)
✅ SOLUTION: Appel asynchrone avec fallback
async def on_player_talk():
try:
response = await asyncio.wait_for(
call_holysheep_api(),
timeout=3.0 # Timeout court
)
show_dialogue(response)
except asyncio.TimeoutError:
show_dialogue(get_fallback_line()) # Dialogue de secours
play_thinking_animation()
2. Dépassement de budget tokens sans监控
# ❌ ERREUR: Pas de tracking des coûts
def call_llm():
# Les coûts s'accumulent sans limite !
response = requests.post(url, json=payload)
return response.json()["choices"][0]["message"]["content"]
✅ SOLUTION: Budget quotidien avec alarme
class CostController:
DAILY_BUDGET_TOKENS = 10_000_000 # 10M tokens max/jour
def __init__(self):
self.total_tokens = 0
def track(self, tokens: int, model: str):
self.total_tokens += tokens
cost = tokens / 1_000_000 * PRICES[model]
if self.total_tokens > self.DAILY_BUDGET_TOKENS:
# Basculement vers modèle économique
raise BudgetExceededError(f"${self.total_tokens / 1_000_000 * 0.42:.2f} dépensé")
print(f"[Budget] {self.total_tokens:,} tokens | ${cost:.4f}")
PRICES = {
"deepseek-v3.2": 0.42,
"gpt-4.1": 8.00,
"claude-sonnet-4.5": 15.00
}
3. Prompts trop longs causant des réponses incohérentes
# ❌ ERREUR: Prompt système de 2000 tokens
system = f"""
Tu es {name}. Tu es né à {birthplace} en {birthyear}.
Tes parents s'appelaient {father} et {mother}.
Tu aimes {hobbies[0]}, {hobbies[1]}, {hobbies[2]}, {hobbies[3]}.
Tu détestes {dislikes[0]}, {dislikes[1]}, {dislikes[2]}.
[+ 50 lignes de contexte...]
"""
✅ SOLUTION: Prompt concis + contexte dynamique
SYSTEM_TEMPLATE = """Tu es {name}, un PNJ avec la personnalité: {personality}.
Contexte récent: {recent_events}
État actuel: {current_state}
Réponds en 1-3 phrases."""
def build_prompt(npc, player_input):
return SYSTEM_TEMPLATE.format(
name=npc.name,
personality=npc.personality[:50], # Tronquer
recent_events=npc.get_recent_context(3), # Max 3 événements
current_state=npc.current_state
)