Outils

Un outil permet au modèle d'appeler votre code Python, par exemple pour effectuer un appel API, une requête de base de données ou un calcul. Le SDK décrit l'outil au modèle, exécute la fonction lorsque le modèle l'appelle et renvoie le résultat.

Écrire un outil

Écrire un outil

Décorez une fonction avec @agents.tool et passez-la dans tools=. Dans cet exemple, l'agent l'utilise pour consulter une commande :

import asyncio

from mistralai import agents


@agents.tool
async def get_order(order_id: str) -> dict[str, str]:
    """Get the status of an order."""
    return {"order_id": order_id, "status": "shipped on Monday"}  # read from your database


agent = agents.Agent(
    model="mistral-large-4",
    instructions="Answer questions about orders in one plain sentence.",
    tools=[get_order],
)


async def main() -> None:
    state = await agent.run("Has order 1042 shipped?")
    if isinstance(state, agents.Completed):
        print(state.text)
        print(state.tool_calls)


if __name__ == "__main__":
    asyncio.run(main())
Yes, order 1042 has shipped — its status is "shipped on Monday."
(ToolCall(name='client.get_order', arguments={'order_id': '1042'}),)

Le modèle a appelé get_order une fois. L'enregistrement du tour répertorie cet appel sous l'identifiant de l'outil, client.get_order : client est l'espace de noms par défaut de vos propres outils.

Le SDK construit les informations que le modèle lit à partir de la fonction elle-même. Il tire le nom du nom de la fonction, la description de sa docstring et le schéma d'entrée de ses paramètres typés. Annotez aussi le type de retour : il devient le schéma de sortie.

La fonction décorée reste appelable. Vous pouvez donc la tester comme n'importe quelle autre fonction avec await get_order("1042"). Définissez les outils au niveau du module, car le décorateur lève ValueError pour une fonction imbriquée ou une lambda.

N'utilisez pas d'appel bloquant dans un outil async def, par exemple avec time.sleep. Écrivez un outil bloquant sous la forme d'une simple fonction def, qui s'exécute dans son propre thread.

Décrire les arguments

Décrire les arguments

Décrivez un argument au modèle avec Annotated et un Field Pydantic :

from typing import Annotated

from pydantic import Field

from mistralai import agents


@agents.tool
async def search_issues(
    query: Annotated[str, Field(description="Full-text query, such as 'login timeout'.")],
    limit: int = 10,
) -> list[str]:
    """Search the issue tracker."""
    return [f"#{n}: {query}" for n in range(limit)]  # call your tracker here

Chaque paramètre doit avoir une annotation de type. Passez name=, description= ou input_schema= pour remplacer les informations fournies par la fonction.

Signaler un échec au modèle

Signaler un échec au modèle

Un échec attendu, comme une facture inconnue, fait partie de la réponse de l'outil. Levez agents.ToolError avec un message destiné au modèle. Le modèle lit ce message tel quel et peut agir en conséquence :

import asyncio

from mistralai import agents

INVOICES = {"A-1": {"id": "A-1", "status": "paid"}}


@agents.tool
async def get_invoice(invoice_id: str) -> dict[str, str]:
    """Fetch an invoice."""
    if invoice_id not in INVOICES:
        raise agents.ToolError(f"No invoice {invoice_id}. Ask the user to check the number.")
    return INVOICES[invoice_id]


agent = agents.Agent(model="mistral-large-4", instructions="Answer in one plain sentence.", tools=[get_invoice])


async def main() -> None:
    state = await agent.run("What is the status of invoice B-7?")
    if isinstance(state, agents.Completed):
        print(state.text)


asyncio.run(main())
I wasn't able to find invoice **B-7** in the system — the lookup returned "No invoice B-7" for that ID and several common variations (B7, B-007, INV-B-7, etc.). Could you double-check the invoice number? It may have a different format (e.g., a different prefix, more digits, or a typo).

Le modèle a demandé à l'utilisateur de vérifier le numéro, comme le message le lui indiquait.

Une erreur inattendue, c'est-à-dire toute autre exception, correspond à un bug ou à une panne. Le SDK la consigne avec sa traceback (dans les logs de votre déploiement si l'agent est déployé). Par défaut, le modèle lit uniquement The tool failed with an unexpected error., car une traceback peut contenir des noms internes ou des données client. Définissez tool_errors="show" sur l'agent pendant le développement pour montrer l'exception au modèle, ou tool_errors="raise" pour faire échouer le tour à la place.

Avec "raise", votre code gère l'échec à la place du modèle :

import asyncio

from mistralai import agents


@agents.tool
async def get_region_price(region: str) -> int:
    """Price of the plan in a region."""
    return {"us-east": 10}[region]  # raises KeyError for any other region


agent = agents.Agent(model="mistral-large-4", tools=[get_region_price], tool_errors="raise")


async def main() -> None:
    match await agent.run("What does the plan cost in eu-west?"):
        case agents.Failed(error=error):
            print(error.code, error.message)
            #> tool_raised Tool 'get_region_price' raised KeyError
        case agents.Completed(text=text):
            print(text)


asyncio.run(main())

error.message fournit le nom de l'outil et la classe de l'exception, ici KeyError. Il omet le texte de l'exception elle-même, 'eu-west', car ce texte peut contenir des noms internes ou des données client. L'exception complète et sa traceback figurent dans le log du SDK.

Un résultat qui ne correspond pas au output_schema= de l'outil n'est pas une erreur inattendue. Le SDK consigne un avertissement. Avec "hide" et "show", le modèle lit quel champ est incorrect. Avec "raise", le tour se termine avec le statut Failed et le code d'erreur tool_output_schema_mismatch.

Comment le modèle appelle un outil

Comment le modèle appelle un outil

Par défaut, le modèle appelle vos outils depuis le code qu'il écrit dans l'outil intégré run_typescript, sous la forme tools.client.<name>(...). Il peut ainsi enchaîner plusieurs appels en une seule étape. Définissez model_access="direct" pour placer plutôt un outil dans la liste d'outils du modèle :

from mistralai import agents


@agents.tool(model_access="direct")
async def get_weather(city: str) -> str:
    """Weather for a city."""
    return f"Sunny in {city}."
Comment un outil s'exécute une fois déployé

Comment un outil s'exécute une fois déployé

Lorsqu'il est déployé avec Studio (auto-hébergé ou géré par Mistral), un outil s'exécute au plus une fois. Si un appel est perdu, par exemple à la suite d'un crash, le modèle lit que l'appel peut avoir eu un effet ou non. Un outil qui produit des effets de bord doit donc pouvoir être appelé deux fois sans risque. Passez au service qu'il appelle une clé d'idempotence construite à partir de la requête, pour qu'un second appel utilise la même clé :

@agents.tool
async def refund_order(order_id: str, amount_cents: int) -> str:
    """Refund an order."""
    refund = await payments.refunds.create(  # your payment service's client
        order_id=order_id,
        amount_cents=amount_cents,
        idempotency_key=f"refund-{order_id}",  # the same key when the model calls again
    )
    return f"Refund {refund.id} for order {order_id}: {refund.status}."

Si le service n'accepte pas de clé, vérifiez d'abord : consultez les remboursements de la commande et renvoyez celui que vous trouvez au lieu de procéder à un nouveau remboursement. Un outil qui ne fait que lire n'a besoin ni de clé ni de vérification.

Outils client

Outils client

Un outil client est un outil auquel votre programme répond, et non l'agent. Utilisez-en un lorsque la réponse n'est disponible que là où l'agent est utilisé, par exemple sur l'appareil de l'utilisateur ou dans votre interface ; sinon, utilisez votre propre outil, car un outil client met le tour en attente d'une réponse de votre programme. Déclarez-le sur une fonction sans implémentation et passez-le à l'agent comme n'importe quel outil :

from mistralai import agents


@agents.client_tool
def get_location() -> str:
    """The user's current city."""
    raise NotImplementedError  # your program answers it

Lorsque le modèle l'appelle, l'exécution s'arrête et renvoie agents.Blocked ; envoyez le résultat pour la reprendre. La documentation de référence explique comment procéder.

Outil, connecteur ou skill

Outil, connecteur ou skill

Vous avezUtilisez
Une fonction PythonUn outil (@agents.tool)
Un service hébergé ou un serveur MCPUn connecteur ou un serveur MCP
Une procédure écriteUn skill
Problèmes courants

Problèmes courants

SymptômeSolution
ValueError: Decorated tools must be defined at module scopeDéplacez la fonction au niveau du module.
agents.SdkError lors de la définition de l'outilAnnotez chaque paramètre et ajoutez une docstring ou description=.
Le modèle lit The tool failed with an unexpected error.Votre outil a levé une exception. Consultez la traceback dans vos logs ou définissez tool_errors="show" pendant le développement.
L'agent n'a ni bash ni outils de gestion de fichiersIls proviennent de la sandbox. Attribuez-en une à l'agent avec environment= ; consultez Environnement.

Connecteurs et MCP : donnez à l'agent des outils provenant de services externes.