500;">import Anthropic 500;">from '@anthropic-ai/sdk'
500;">import { z } 500;">from 'zod'
500;">import { Langfuse } 500;">from 'langfuse'
500;">const client = 500;">new Anthropic()
500;">const langfuse = 500;">new Langfuse({ secretKey: process.env.LANGFUSE_SECRET })
"color:#6b7280;font-style:italic;">// 1. Tool-use : agent qui exécute vraiment, ne se contente pas de répondre
500;">const tools = [
{
name: 'fetch_customer_orders',
description: 'Récupère les commandes d\'un client depuis la DB Postgres.',
input_schema: {
500;">type: 'object',
properties: {
customer_id: { 500;">type: 'string', description: 'UUID du client' },
limit: { 500;">type: 'integer', description: 'Max 50', 500;">default: 10 },
},
required: ['customer_id'],
},
},
]
// 2. Structured output via Zod sur la réponse finale
500;">const AnswerSchema = z.object({
answer: z.string().max(500),
citations: z.array(z.string()).max(5),
confidence: z.number().min(0).max(1),
})
// 3. Trace Langfuse pour observabilité cost + latency + drift
500;">const trace = langfuse.trace({ name: 'support-agent', userId })
// 4. Appel Claude 4.7 avec adaptive thinking + tool-use
500;">const response = 500;">await client.messages.create({
model: 'claude-opus-4-7',
thinking: { 500;">type: 'adaptive' },
max_tokens: 2048,
tools,
system: 'Tu réponds aux questions clients avec citations sources.',
messages: [{ role: 'user', content: userMessage }],
})
// 5. Boucle tool-use : exécute les tools côté serveur, renvoie résultats
500;">if (response.stop_reason === 'tool_use') {
500;">const toolResults = 500;">await executeTools(response.content, tools)
// ... loop jusqu'à stop_reason === 'end_turn'
}
"color:#6b7280;font-style:italic;">// 6. Validation stricte avant injection
500;">const final = AnswerSchema.parse(JSON.parse(extractText(response)))
"color:#6b7280;font-style:italic;">// 7. Trace fin : cost réel, p95, drift detection
trace.update({
output: final,
metadata: { costEur: computeCost(response.usage), model: 'claude-opus-4-7' },
})