Décorateur @tool de LangChain — Définition des outils

Un outil est le pont permettant à un agent d'interagir avec le monde extérieur.

En utilisant le décorateur@tool, vous pouvez rapidement convertir n'importe quelle fonction Python en un outil appelable par un Agent.


Syntaxe de base de @tool

@tool est un décorateur fourni par LangChain. Son utilisation est extrêmement simple : ajoutez le décorateur @tool à une fonction, et la fonction devient un outil.

Exemple

from langchain.tools import tool

# L'outil le plus simple : une fonction ordinaire + décorateur @tool
@tool
def hello_tool(name: str) -> str:
    """Dites bonjour à la personne spécifiée.

    Arguments :
name: le nom de la personne à saluer
    """

    return f"Bonjour, {name} ! Bienvenue sur EXAMPLE Tutorial."

# Un outil est aussi une fonction Python ordinaire et peut être appelé directement
result = hello_tool.invoke({"name": "Xiao Ming"})
print(result)

# L'outil contient des informations de description générées automatiquement
print(f"\nNom de l'outil : {hello_tool.name}")
print(f"Description de l'outil : {hello_tool.description}")

Sortie :

你好,小明!欢迎来到Example.

Tool name: hello_tool
Tool description: 向指定的人打招呼。

    Args:
        name: 要打招呼的人的名字

La docstring de la fonction devient automatiquement la description de l'outil. L'Agent s'appuie sur cette description pour déterminer "ce que cet outil peut faire" et "quand il doit être appelé". Plus la docstring est claire, plus l'Agent utilise l'outil avec précision. Dans la description, expliquez la signification des paramètres, le comportement de la fonction et les scénarios d'utilisation.


Utilisation de différents types de paramètres

@tool prend en charge plusieurs types de paramètres, notamment int, float, bool et des valeurs d'énumération :

Exemple

from langchain.tools import tool
from typing import Literal


@tool
def search_courses(
    keyword: str,
    level: Literal["Beginner", "Intermediate", "Advanced"],
    max_results: int = 5,
    free_only: bool = True,
) -> str:
    """Rechercher des cours sur EXAMPLE Tutorial.

    Arguments :
keyword: mot-clé de recherche
level: niveau de difficulté du cours
max_results: nombre maximal de résultats à renvoyer
free_only: indique s'il faut afficher uniquement les cours gratuits
    """

    # Simuler les résultats de recherche
    courses = {
        ("python", "Débutant"): "Tutoriel de base Python3 (Gratuit)",
        ("python", "Intermédiaire"): "Pratique de l'analyse de données Python (Gratuit)",
        ("python", "Avancé"): "Apprentissage automatique avancé Python (Réservé aux membres)",
        ("html", "Débutant"): "Tutoriel de base HTML (Gratuit)",
    }
    key = (keyword.lower(), level)
    course = courses.get(key, f"Aucun cours {keyword} trouvé au niveau {level}")
    if free_only and "Réservé aux membres" in course:
        return f"Résultat de recherche : {course} — ce cours nécessite une adhésion et a été filtré pour vous"
    return f"Résultat de recherche : {course}"


# Appels de test avec différents paramètres
print(search_course.invoke({
    "keyword": "python",
    "level": "Débutant",
}))
# Sortie : Résultat de recherche : Tutoriel des bases Python3 (Gratuit)

print(search_course.invoke({
    "keyword": "python",
    "level": "Avancé",
    "free_only": False,
}))
# Sortie : Résultat de recherche : Apprentissage automatique Python avancé (Réservé aux membres)

Enregistrement des outils auprès de l'Agent

Transmettez l'outil défini au paramètre tools de create_agent(), et l'Agent pourra l'utiliser :

Exemple

from dotenv import load_dotenv
load_dotenv()

from langchain.tools import tool
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage


@tool
def search_courses(keyword: str) -> str:
    """Rechercher des cours sur EXAMPLE Tutorial. Passez un mot-clé et obtenez une liste de cours associés.

    Arguments :
keyword: mot-clé de recherche, par ex., python, html, java
    """

    courses = {
        "python": "Tutoriel des bases Python3, Analyse de données avec Python, Introduction au Web Crawler Python",
        "html": "Tutoriel des bases HTML, Nouvelles fonctionnalités HTML5, Exercices sur les formulaires HTML",
        "java": "Tutoriel des bases Java, Java orienté objet, Framework Spring Java",
    }
    return courses.get(keyword.lower(), f"Aucun cours lié à {keyword} n'a été trouvé")


@tool
def get_course_detail(course_name: str) -> str:
    """Obtenir des informations détaillées sur le cours spécifié, y compris le nombre de chapitres et la durée d'étude.

    Arguments :
course_name: nom du cours, par ex., "Python3 Basics Tutorial"
    """

    details = {
        "python3 basics tutorial": "Un total de 30 chapitres, durée d'étude estimée à 20 heures, adapté aux débutants complets",
        "html basics tutorial": "Un total de 25 chapitres, durée d'étude estimée à 15 heures, adapté aux débutants complets",
    }
    return details.get(
        course_name.lower(),
        f"Détails de {course_name} : adapté aux débutants, riche en contenu, avec des cas pratiques"
    )


# Créer l'Agent
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
agent = create_agent(
    model=model,
    tools=[search_courses, get_course_detail],
    system_prompt="Vous êtes un conseiller pédagogique pour EXAMPLE Tutorial, aidant les utilisateurs à trouver des cours adaptés.",
)


# Exécuter l'Agent
def ask(question: str):
    result = agent.invoke({"messages": [HumanMessage(content=question)]})
    print(f"Utilisateur : {question}")
    print(f"Consultant : {result['messages'][-1].content}")
    print("-" * 60)


ask("Je veux apprendre Python. Quels cours me recommandez-vous ?")
ask("Combien de temps faut-il pour terminer le tutoriel Python3 Basics ?")

Sortie :

User: 我想学 Python,有什么课程推荐?
Advisor: 在Example 中有以下 Python 相关课程:
Python3 基础教程、Python 数据分析、Python 爬虫入门。
这些课程很适合 Python 初学者和进阶学习者,您可以根据兴趣选择!
------------------------------------------------------------
User: Python3 基础教程学完需要多久?
Advisor: Python3 基础教程共 30 章,预计学习时长 20 小时,非常适合零基础入门学习。
------------------------------------------------------------

Plusieurs outils travaillant ensemble

Un agent peut enregistrer plusieurs outils, et le modèle décidera automatiquement quand utiliser quel outil :

Exemple

from langchain.tools import tool
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage


@tool
def get_stock_price(symbol: str) -> str:
    """Interroge le prix actuel d'une action.

    Arguments :
symbol: symbole boursier, par ex., AAPL, GOOGL, TSLA
    """

    # Simuler des données boursières
    prices = {"AAPL": 185.50, "GOOGL": 142.30, "TSLA": 245.80}
    price = prices.get(symbol.upper())
    if price is None:
        return f"Symbole boursier {symbol} introuvable"
    return f"{symbol.upper()} prix actuel : ${price}"


@tool
def convert_currency(amount: float, from_currency: str, to_currency: str) -> str:
    """Conversion de devises.

    Arguments :
amount: montant d'argent
from_currency: code de devise d'origine, par ex., USD, CNY
to_currency: code de devise cible, par ex., CNY, USD
    """

    # Simuler les taux de change
    rates = {
        ("USD", "CNY"): 7.25,
        ("CNY", "USD"): 0.138,
    }
    rate = rates.get((from_currency.upper(), to_currency.upper()))
    if rate is None:
        return f"La conversion de {from_currency} vers {to_currency} n'est pas prise en charge"
    result = round(amount * rate, 2)
    return f"{amount} {from_currency} = {result} {to_currency}"


model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
agent = create_agent(
    model=model,
    tools=[get_stock_price, convert_currency],
    system_prompt="Vous êtes un assistant financier qui aide les utilisateurs à consulter les cours des actions et à convertir des devises.",
)

# L'agent décidera automatiquement quel outil appeler
result = agent.invoke({
    "messages": [HumanMessage(content="Quel est le cours de l'action Apple ? Combien cela fait-il en RMB ?")]
})

for msg in result["messages"]:
    if msg.type == "tool":
        print(f"[Appel de l'outil {msg.name}] {msg.content}")
    elif msg.type == "ai" and msg.content:
        print(f"\nRéponse finale : {msg.content}")

Sortie :

[调用工具 get_stock_price] AAPL 当前价格:$185.5
[调用工具 convert_currency] 185.5 USD = 1344.88 CNY

Final answer: 苹果(AAPL)当前股价为 $185.50,按当前汇率换算约为 1344.88 人民币。

Paramètres optionnels et valeurs par défaut pour les outils

Définir des valeurs par défaut pour les paramètres d'outil rend les outils plus flexibles à utiliser :

Exemple

from langchain.tools import tool


@tool
def recommend_tutorial(
    language: str,
    level: str = "Beginner",
    count: int = 3,
) -> str:
    """Recommander des cours de EXAMPLE Tutorial en fonction du langage de programmation et de la difficulté.

    Arguments :
language: langage de programmation, par exemple, Python, Java, HTML
level: niveau de difficulté, options "Beginner", "Intermediate", "Advanced". Par défaut "Beginner"
count: nombre de cours à recommander, par défaut 3
    """

    tutorials = {
        "python": ["Python3 Basics", "Python Object-Oriented", "Python Web Crawler", "Analyse de données avec Python"],
        "java": ["Bases de Java", "Java orienté objet", "Framework des collections Java", "Multithreading Java"],
    }
    all_tutorials = tutorials.get(language.lower(), [f"Tutoriel de base {language}"])

    selected = all_tutorials[:count]
    return f"Cours {language} {level} recommandés : {'、'.join(selected)}"


# Il suffit de passer les paramètres requis lors de l'appel
print(recommend_tutorial.invoke({"language": "Python"}))
# Sortie : Cours Python Débutant recommandés : Bases de Python3, Python orienté objet, Crawler web Python

# Vous pouvez également remplacer les paramètres par défaut
print(recommend_tutorial.invoke({
    "language": "Java",
    "level": "Intermédiaire",
    "count": 2,
}))
# Sortie : Cours Java intermédiaires recommandés : Java Basics, Java Object-Oriented

Les valeurs par défaut permettent à l'Agent d'éviter de spécifier tous les paramètres à chaque fois qu'il appelle des outils. Mais attention : si un paramètre n'a pas de valeur par défaut et que l'Agent ne la fournit pas, l'appel échouera. Ne définissez pas de valeurs par défaut pour les paramètres clés.


L'args_schema de l'outil — Validation personnalisée des paramètres

Pour des exigences complexes de validation des paramètres, un modèle Pydantic peut être utilisé comme args_schema :

Exemple

from pydantic import BaseModel, Field
from langchain.tools import tool


# Définir le modèle de paramètres (permet un contrôle plus fin des paramètres)
class CourseSearchInput(BaseModel):
    """Paramètres de recherche de cours"""
    keyword: str = Field(
        description="Mot-clé de recherche, prend en charge la correspondance floue",
        min_length=1,            # Au moins 1 caractère
        max_length=50,           # Au maximum 50 caractères
    )
    category: str = Field(
        default="all",
        description="Catégorie de cours : all (all), frontend (frontend), backend (backend), data (science des données)",
        pattern=r"^(all|frontend|backend|data)$",  # Restreindre les valeurs autorisées
    )
    page: int = Field(
        default=1,
        description="Numéro de page, à partir de 1",
        ge=1,                    # Supérieur ou égal à 1
        le=100,                  # Inférieur ou égal à 100
    )


@tool(args_schema=CourseSearchInput)
def search_course(keyword: str, category: str = "all", page: int = 1) -> str:
    """Rechercher des cours sur le site de tutoriels EXAMPLE"""
    return f"Recherche de '{keyword}' (catégorie : {category}, page {page}) : 15 résultats trouvés au total"


# Appel valide
print(search_course.invoke({"keyword": "Python", "category": "backend", "page": 1}))

# Appel non valide (catégorie absente des valeurs autorisées)
try:
    search_course.invoke({"keyword": "Python", "category": "invalid"})
except Exception as e:
    print(f"Échec de la validation des paramètres : {e}")

Résultats de l'exécution :

搜索 'Python' (分类: backend, 第 1 页):共找到 15 条结果
参数校验失败: ...

Comparaison des méthodes de définition d'outils

MéthodeQuantité de codeScénarios applicablesExemple
Décorateur @toolMinimumOutils simples à modérément complexesLa plupart des scénarios
@tool + args_schemaMoyenneOutils nécessitant une validation fine des paramètresEncapsulation d’API, opérations de base de données
Classe Pydantic comme outilPlusOutils avec une logique métier complexeOutils contenant un état interne
Format dictionnaireLe moins (mais non recommandé)Description des outils distants/intégrésOutils MCP, outils côté serveur
Autres extensions