Agents IA et function calling : créer des outils pour LLM
Vous construisez un agent IA qui doit récupérer des données en temps réel, effectuer des calculs ou interagir avec des API externes. Mais comment combler le fossé entre la génération de texte du LLM et l'exécution réelle de code ? Le function calling (aussi appelé tool use ou utilisation d'outils) est la réponse. Il permet aux LLM de demander des actions spécifiques, et votre code les exécute. Ce guide vous accompagne dans la conception, l'implémentation et le débogage du function calling pour les agents IA.
Qu'est-ce que le function calling ?
Le function calling est un mécanisme par lequel un LLM peut produire une requête structurée pour appeler une fonction que vous avez définie. Au lieu de générer du texte libre, le modèle renvoie un objet JSON contenant le nom de la fonction et ses arguments. Votre application exécute ensuite la fonction et renvoie le résultat au modèle. Cela permet aux agents d'effectuer des actions au-delà de la génération de texte, comme interroger des bases de données, envoyer des e-mails ou appeler des API.
Les principaux fournisseurs de LLM comme OpenAI, Anthropic et Google prennent en charge le function calling. L'idée centrale est cohérente : vous décrivez les outils disponibles, le modèle décide quand les utiliser, et vous gérez l'exécution.
Concevoir des outils pour les LLM
Des outils bien conçus sont essentiels pour un comportement fiable de l'agent. Suivez ces principes :
- Noms et descriptions clairs : Utilisez des noms de fonctions descriptifs et des descriptions détaillées. Le LLM s'appuie sur ces éléments pour choisir le bon outil.
- Paramètres simples : Limitez les paramètres et utilisez des types standard (string, number, boolean, array, object). Évitez les structures imbriquées complexes lorsque c'est possible.
- Idempotence : Dans la mesure du possible, concevez des outils idempotents (sûrs à réessayer) pour gérer les échecs avec élégance.
- Gestion des erreurs : Renvoyez des messages d'erreur informatifs pour que le LLM puisse ajuster son approche.
Exemple : outil météo
Voici une définition simple d'outil au format JSON schema, couramment utilisée avec l'API d'OpenAI :
{
"name": "get_weather",
"description": "Get the current weather for a given city",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "The city name, e.g., San Francisco"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit"
}
},
"required": ["city"]
}
}
Implémenter le function calling : étape par étape
Construisons une boucle d'agent minimale avec l'API d'OpenAI (le modèle s'applique à d'autres fournisseurs).
1. Définir vos outils
Créez une liste de schémas d'outils et une correspondance entre les noms de fonctions et les fonctions Python réelles.
import json
import openai
# Tool schemas
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a city",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
},
"required": ["city"]
}
}
}
]
# Actual functions
def get_weather(city: str, unit: str = "celsius") -> dict:
# In reality, call a weather API
return {"city": city, "temperature": 22, "unit": unit, "condition": "sunny"}
# Map names to functions
function_map = {
"get_weather": get_weather
}
2. Créer la boucle de l'agent
La boucle de l'agent envoie des messages au LLM, vérifie les appels d'outils, les exécute et répète jusqu'à ce que le modèle renvoie une réponse finale.
def run_agent(user_message: str):
messages = [{"role": "user", "content": user_message}]
while True:
response = openai.ChatCompletion.create(
model="gpt-4",
messages=messages,
tools=tools,
tool_choice="auto"
)
message = response.choices[0].message
messages.append(message)
# If no tool calls, return the content
if not message.get("tool_calls"):
return message["content"]
# Execute each tool call
for tool_call in message.tool_calls:
function_name = tool_call.function.name
arguments = json.loads(tool_call.function.arguments)
if function_name in function_map:
result = function_map[function_name](**arguments)
else:
result = {"error": f"Unknown function: {function_name}"}
# Append tool result to messages
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result)
})
Cette boucle continue jusqu'à ce que le LLM produise une réponse sans appel d'outil, indiquant qu'il dispose de suffisamment d'informations.
3. Gérer les erreurs et les cas limites
Les agents en conditions réelles doivent gérer :
- Arguments invalides : Interceptez les exceptions lors de l'analyse des arguments ou de l'appel des fonctions.
- Outils inconnus : Renvoyez un message d'erreur au LLM pour qu'il puisse se corriger.
- Timeouts : Définissez des délais d'attente pour les appels d'API externes afin d'éviter les blocages.
- Limites de débit : Implémentez des tentatives avec backoff exponentiel.
Bonnes pratiques pour des agents fiables
- Limitez le nombre d'outils : Trop d'outils perturbent le modèle. Regroupez les fonctions apparentées ou utilisez un routeur.
- Validez les entrées : Assainissez et validez tous les arguments avant exécution.
- Journalisez tout : Enregistrez les appels d'outils et les résultats pour le débogage et l'audit.
- Testez avec des prompts variés : Assurez-vous que l'agent sélectionne les bons outils dans différents scénarios.
- Prévoyez des solutions de repli : Si un outil échoue, l'agent doit essayer des alternatives ou demander des clarifications.
Comparaison du support du function calling
| Fournisseur | Nom de la fonctionnalité | Format |
|---|---|---|
| OpenAI | Function Calling | JSON Schema |
| Anthropic | Tool Use | JSON Schema |
| Function Calling | OpenAPI Schema |
Patrons avancés
À mesure que votre agent se développe, envisagez ces patrons :
- Appels d'outils parallèles : Certains modèles peuvent demander plusieurs outils à la fois. Exécutez-les simultanément pour gagner en rapidité.
- Human-in-the-loop : Pour les actions sensibles (par exemple, envoyer de l'argent), exigez une approbation humaine avant exécution.
- Mémoire : Stockez l'historique des conversations et les résultats d'outils pour fournir du contexte lors de longues sessions.
- Routage d'outils : Utilisez un classifieur léger pour sélectionner les outils pertinents avant d'appeler le LLM principal.
Déboguer le function calling
Quand les choses tournent mal, vérifiez :
- Les descriptions d'outils sont-elles claires et sans ambiguïté ?
- Les noms et types des paramètres sont-ils corrects ?
- Le modèle dispose-t-il de suffisamment de contexte pour choisir le bon outil ?
- Gérez-vous correctement les résultats d'outils (par exemple, la sérialisation JSON) ?
Utilisez la journalisation pour capturer l'historique complet des messages et les appels d'outils. Souvent, le problème vient d'une inadéquation entre les arguments attendus et réels.
FAQ
Quelle est la différence entre function calling et tool use ?
Ils désignent le même concept. OpenAI l'appelle « function calling », tandis qu'Anthropic utilise « tool use ». Les deux permettent aux LLM de demander l'exécution de fonctions externes.
Puis-je utiliser le function calling avec des modèles open source ?
Oui, certains modèles open source comme Llama 3.1 prennent en charge le function calling, et des frameworks comme LangChain fournissent des abstractions. Cependant, le support varie, et vous devrez peut-être affiner le modèle ou utiliser des formats de prompt spécifiques.
Comment empêcher le LLM d'appeler des fonctions dangereuses ?
N'exposez jamais directement des fonctions dangereuses. Utilisez des listes d'autorisation, validez les entrées et implémentez des contrôles de permissions. Pour les opérations sensibles, exigez une confirmation humaine avant exécution.
Prêt à construire votre propre agent IA ? Commencez par définir un outil simple et tester la boucle de l'agent. Pour plus d'outils de développement, consultez notre JSON Formatter pour déboguer les payloads d'appels d'outils.