LangChain Tools : Guide complet pour la création et l'utilisation d'outils LLM personnalisés + exemples de code (2025)
Apprenez à créer et à utiliser les outils LangChain pour améliorer l'intégration de l'IA avec les systèmes externes, et ainsi optimiser l'automatisation et les fonctionnalités.

LangChaîne Les outils sont des solutions basées sur Python qui permettent une interaction fluide entre les grands modèles de langage (LLM) et des systèmes externes tels que les API et les bases de données. En facilitant les appels de fonctions structurés, ces outils permettent aux LLM d'effectuer des tâches telles que la récupération de données en temps réel, l'exécution de requêtes ou l'automatisation de workflows. Cette approche comble le fossé entre le raisonnement de l'IA et les résultats exploitables, ce qui la rend idéale pour les scénarios nécessitant des mises à jour en temps réel ou l'intégration système.
Les outils LangChain sont particulièrement efficaces pour les applications telles que les robots de service client, les systèmes d'assistance technique et les assistants financiers. Les développeurs ont le choix entre deux méthodes de création : @tool décorateur pour la simplicité ou la BaseTool Sous-classe pour une personnalisation avancée. Les deux approches privilégient des signatures de fonctions claires, une gestion robuste des erreurs et une validation précise des entrées pour garantir la fiabilité.
Pour les équipes recherchant une alternative au développement personnalisé, des plateformes comme Laténode Simplifiez l'automatisation grâce à des connecteurs pré-intégrés et des workflows visuels. Par exemple, en intégrant des outils comme Notion, WhatsApp, ou Google Sheets devient simple sans nécessiter de codage approfondi. Cela réduit le temps de développement et les frais de maintenance, permettant aux équipes de se concentrer sur la création de solutions performantes.
Création d'une coutume Langchain outil
Architecture de l'outil LangChain et composants principaux
Les outils LangChain reposent sur un framework structuré qui transforme les fonctions Python en interfaces appelables par de grands modèles de langage (LLM). Cette configuration permet une interaction fluide entre les modèles d'IA et les systèmes externes. Nous explorerons ci-dessous les composants clés qui assurent le bon fonctionnement de ces outils.
Composants clés des outils LangChain
Les fonctionnalités des outils LangChain reposent sur cinq composants essentiels. Chacun joue un rôle spécifique pour garantir un fonctionnement fluide et une communication fiable entre les outils et les LLM :
- Signature de fonction
La signature de la fonction sert de modèle à l'interface de l'outil. Elle définit les paramètres acceptés par l'outil et ses résultats. Les indications de type Python jouent un rôle essentiel dans la définition de cette signature, aidant les LLM à identifier l'outil adapté à des tâches spécifiques. Le nom de la fonction sert d'identifiant unique, guidant le LLM dans la sélection de l'outil approprié lors de l'exécution. - Descriptions des outils
Les descriptions d'outils permettent aux étudiants de master de comprendre clairement leur fonction. Rédigées dans un langage simple et naturel, elles expliquent quand et comment utiliser l'outil, ainsi que les types de résultats qu'il produit. Des descriptions claires et concises sont essentielles pour éviter les malentendus ou une mauvaise utilisation de l'outil. - Schéma des paramètres
Le schéma de paramètres définit les règles et la structure des entrées de l'outil. Grâce aux indications de type Python, les développeurs peuvent créer des schémas spécifiant des contraintes, des valeurs par défaut et des règles de validation personnalisées. Cela garantit un formatage correct des données d'entrée, réduisant ainsi le risque d'erreurs d'exécution et améliorant la fiabilité globale. - Traitement des retours
Ce composant détermine le traitement des résultats d'un outil et leur retour au LLM. Les outils peuvent produire des résultats sous diverses formes, telles que du texte brut, des données structurées ou des objets complexes. Le format de retour est essentiel pour que le LLM puisse exploiter efficacement les résultats dans son flux de travail global. - Gestion des erreurs
La gestion des erreurs est un aspect crucial, mais souvent négligé. Les outils doivent être capables de gérer des problèmes tels que les pannes de réseau, les limites de débit ou les entrées non valides. Une gestion efficace des erreurs garantit qu'une seule panne ne perturbe pas le fonctionnement d'un agent, ce qui est particulièrement important dans les environnements de production.
Méthodes de sous-classe Decorator vs. BaseTool
LangChain propose deux approches principales pour la création d'outils, chacune adaptée à différents niveaux de complexité et cas d'utilisation. Ces méthodes sont les suivantes : @tool décorateur et le BaseTool sous-classe.
- L'espace
@toolDécorateur
Cette approche est conçue pour la simplicité. Elle permet aux développeurs de convertir rapidement des fonctions Python en outils compatibles avec LangChain, avec un minimum d'effort. Le décorateur gère automatiquement des tâches telles que la génération de schémas, la validation des paramètres et le traitement des erreurs de base. Il est idéal pour les opérations simples telles que les appels d'API, les calculs simples ou les transformations de données, où la gestion d'état ou l'initialisation complexe ne sont pas nécessaires. - L'espace
BaseToolSous-classe
Pour des besoins plus avancés, leBaseToolLa méthode de sous-classe offre une personnalisation étendue. Elle est adaptée aux outils nécessitant une logique complexe, des opérations avec état ou une gestion avancée des erreurs. Les développeurs peuvent implémenter une initialisation personnalisée, des opérations asynchrones et des types de retour plus complexes. Bien que cette méthode implique davantage de codage, elle offre la flexibilité nécessaire aux outils de production, notamment ceux impliquant l'authentification, les connexions persistantes ou une logique métier détaillée.
Choisir la bonne approche
Le choix entre ces méthodes dépend de la complexité de l'outil et de son utilisation prévue. Les outils simples commencent souvent par l'approche décoratrice et peuvent évoluer vers des implémentations basées sur des sous-classes à mesure que les besoins augmentent. Cependant, pour les outils nécessitant une gestion robuste des erreurs ou une intégration avec des systèmes complexes, il est préférable de commencer par l'approche décoratrice. BaseTool la sous-classe peut faire gagner du temps et éviter les défis architecturaux ultérieurs.
Créer des outils personnalisés avec une validation appropriée
Lors de la création d'outils personnalisés, il est essentiel de privilégier une validation rigoureuse des entrées, une gestion efficace des erreurs et une documentation claire. Ces éléments garantissent la fiabilité des outils et leur intégration transparente aux grands modèles linguistiques (LLM).
Comment créer un outil de base
L'espace @tool Decorator propose une méthode simple pour créer des outils LangChain. Il génère automatiquement des schémas et gère les validations de base, ce qui le rend idéal pour les opérations simples.
Voici un exemple d’outil de recherche météo :
<span class="hljs-keyword">from</span> langchain.tools <span class="hljs-keyword">import</span> tool
<span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> <span class="hljs-type">Optional</span>
<span class="hljs-keyword">import</span> requests
<span class="hljs-meta">@tool</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">get_weather_data</span>(<span class="hljs-params">city: <span class="hljs-built_in">str</span>, country_code: <span class="hljs-type">Optional</span>[<span class="hljs-built_in">str</span>] = <span class="hljs-string">"US"</span></span>) -> <span class="hljs-built_in">str</span>:
<span class="hljs-string">"""
Fetch current weather information for a specified city.
Args:
city: The name of the city to get weather for.
country_code: Two-letter country code (default: US).
Returns:
Weather information as a formatted string.
"""</span>
<span class="hljs-keyword">try</span>:
api_key = <span class="hljs-string">"your_api_key_here"</span>
url = <span class="hljs-string">"http://api.openweathermap.org/data/2.5/weather"</span>
params = {
<span class="hljs-string">"q"</span>: <span class="hljs-string">f"<span class="hljs-subst">{city}</span>,<span class="hljs-subst">{country_code}</span>"</span>,
<span class="hljs-string">"appid"</span>: api_key,
<span class="hljs-string">"units"</span>: <span class="hljs-string">"imperial"</span>
}
response = requests.get(url, params=params, timeout=<span class="hljs-number">10</span>)
response.raise_for_status()
data = response.json()
temp = data[<span class="hljs-string">"main"</span>][<span class="hljs-string">"temp"</span>]
description = data[<span class="hljs-string">"weather"</span>][<span class="hljs-number">0</span>][<span class="hljs-string">"description"</span>]
<span class="hljs-keyword">return</span> <span class="hljs-string">f"Current weather in <span class="hljs-subst">{city}</span>: <span class="hljs-subst">{temp}</span>°F, <span class="hljs-subst">{description}</span>"</span>
<span class="hljs-keyword">except</span> requests.exceptions.RequestException <span class="hljs-keyword">as</span> e:
<span class="hljs-keyword">return</span> <span class="hljs-string">f"Error fetching weather data: <span class="hljs-subst">{<span class="hljs-built_in">str</span>(e)}</span>"</span>
<span class="hljs-keyword">except</span> KeyError <span class="hljs-keyword">as</span> e:
<span class="hljs-keyword">return</span> <span class="hljs-string">f"Invalid response format: missing <span class="hljs-subst">{<span class="hljs-built_in">str</span>(e)}</span>"</span>
Pour les scénarios plus avancés, tels que ceux nécessitant une initialisation personnalisée ou la gestion des états internes, le BaseTool la sous-classe offre une plus grande flexibilité :
<span class="hljs-keyword">from</span> langchain.tools <span class="hljs-keyword">import</span> BaseTool
<span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> <span class="hljs-type">Type</span>
<span class="hljs-keyword">from</span> pydantic <span class="hljs-keyword">import</span> BaseModel, Field
<span class="hljs-keyword">class</span> <span class="hljs-title class_">DatabaseQueryInput</span>(<span class="hljs-title class_ inherited__">BaseModel</span>):
query: <span class="hljs-built_in">str</span> = Field(description=<span class="hljs-string">"SQL query to execute"</span>)
table: <span class="hljs-built_in">str</span> = Field(description=<span class="hljs-string">"Target table name"</span>)
<span class="hljs-keyword">class</span> <span class="hljs-title class_">DatabaseQueryTool</span>(<span class="hljs-title class_ inherited__">BaseTool</span>):
name = <span class="hljs-string">"database_query"</span>
description = <span class="hljs-string">"Execute SQL queries against the company database"</span>
args_schema: <span class="hljs-type">Type</span>[BaseModel] = DatabaseQueryInput
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, connection_string: <span class="hljs-built_in">str</span></span>):
<span class="hljs-built_in">super</span>().__init__()
<span class="hljs-variable language_">self</span>.connection_string = connection_string
<span class="hljs-variable language_">self</span>.connection = <span class="hljs-literal">None</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">_run</span>(<span class="hljs-params">self, query: <span class="hljs-built_in">str</span>, table: <span class="hljs-built_in">str</span></span>) -> <span class="hljs-built_in">str</span>:
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-variable language_">self</span>.connection:
<span class="hljs-variable language_">self</span>.connection = <span class="hljs-variable language_">self</span>._establish_connection()
<span class="hljs-comment"># Execute query with proper validation</span>
<span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>._execute_safe_query(query, table)
Meilleures pratiques pour les noms et descriptions d'outils
Choisir des noms clairs et descriptifs pour les outils aide les étudiants en master à comprendre leur objectif et leur utilisation. Utilisez des verbes d'action dans les noms d'outils (par exemple, search_documents au lieu de docs) et éviter les abréviations qui pourraient prêter à confusion pour le LLM. La cohérence entre les outils connexes est tout aussi importante ; par exemple, nommer plusieurs outils API comme api_get_user, api_create_user et api_delete_user crée un regroupement logique.
Les descriptions doivent être concises et rédigées à la voix active, décrivant clairement l'objectif de l'outil, les données requises et les résultats attendus. Comparez ces deux exemples :
<span class="hljs-comment"># Poor description</span>
<span class="hljs-meta">@tool</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">calc</span>(<span class="hljs-params">x: <span class="hljs-built_in">float</span>, y: <span class="hljs-built_in">float</span></span>) -> <span class="hljs-built_in">float</span>:
<span class="hljs-string">"""Does math stuff"""</span>
<span class="hljs-keyword">return</span> x + y
<span class="hljs-comment"># Effective description</span>
<span class="hljs-meta">@tool</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">add_numbers</span>(<span class="hljs-params">first_number: <span class="hljs-built_in">float</span>, second_number: <span class="hljs-built_in">float</span></span>) -> <span class="hljs-built_in">float</span>:
<span class="hljs-string">"""
Add two numbers together and return the sum.
Use this tool when you need to perform basic addition of numeric values.
Both inputs must be numbers (integers or decimals).
Args:
first_number: The first number to add.
second_number: The second number to add.
Returns:
The sum of the two input numbers.
"""</span>
<span class="hljs-keyword">return</span> first_number + second_number
Saisie des paramètres et validation des entrées
Un typage précis des paramètres est essentiel pour prévenir les problèmes d'exécution et guider les interactions LLM. Les indices de type Python et les modèles Pydantic fonctionnent bien ensemble pour renforcer la validation.
Validation de type de base Exemple:
<span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> <span class="hljs-type">List</span>, <span class="hljs-type">Dict</span>, <span class="hljs-type">Optional</span>, <span class="hljs-type">Union</span>
<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime
<span class="hljs-keyword">from</span> enum <span class="hljs-keyword">import</span> Enum
<span class="hljs-keyword">class</span> <span class="hljs-title class_">Priority</span>(<span class="hljs-built_in">str</span>, Enum):
LOW = <span class="hljs-string">"low"</span>
MEDIUM = <span class="hljs-string">"medium"</span>
HIGH = <span class="hljs-string">"high"</span>
<span class="hljs-meta">@tool</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">create_task</span>(<span class="hljs-params">
title: <span class="hljs-built_in">str</span>,
description: <span class="hljs-type">Optional</span>[<span class="hljs-built_in">str</span>] = <span class="hljs-literal">None</span>,
priority: Priority = Priority.MEDIUM,
due_date: <span class="hljs-type">Optional</span>[datetime] = <span class="hljs-literal">None</span>,
tags: <span class="hljs-type">List</span>[<span class="hljs-built_in">str</span>] = []
</span>) -> <span class="hljs-type">Dict</span>[<span class="hljs-built_in">str</span>, <span class="hljs-type">Union</span>[<span class="hljs-built_in">str</span>, <span class="hljs-built_in">int</span>]]:
<span class="hljs-string">"""
Create a new task in the project management system.
Args:
title: Task title (required, max 100 characters).
description: Detailed task description (optional).
priority: Task priority level (low, medium, high).
due_date: When the task should be completed (ISO format).
tags: List of tags to categorize the task.
Returns:
Dictionary containing a task ID and a confirmation message.
"""</span>
<span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(title) > <span class="hljs-number">100</span>:
<span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">"Title must be 100 characters or less"</span>)
<span class="hljs-keyword">if</span> due_date <span class="hljs-keyword">and</span> due_date < datetime.now():
<span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">"Due date cannot be in the past"</span>)
task_id = generate_task_id()
<span class="hljs-keyword">return</span> {
<span class="hljs-string">"task_id"</span>: task_id,
<span class="hljs-string">"message"</span>: <span class="hljs-string">f"Task '<span class="hljs-subst">{title}</span>' created successfully"</span>
}
Validation avancée en utilisant les modèles Pydantiques :
<span class="hljs-keyword">from</span> pydantic <span class="hljs-keyword">import</span> BaseModel, Field, validator
<span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> <span class="hljs-type">List</span>
<span class="hljs-keyword">import</span> re
<span class="hljs-keyword">class</span> <span class="hljs-title class_">EmailInput</span>(<span class="hljs-title class_ inherited__">BaseModel</span>):
recipients: <span class="hljs-type">List</span>[<span class="hljs-built_in">str</span>] = Field(description=<span class="hljs-string">"List of email addresses"</span>)
subject: <span class="hljs-built_in">str</span> = Field(description=<span class="hljs-string">"Email subject line"</span>, max_length=<span class="hljs-number">200</span>)
body: <span class="hljs-built_in">str</span> = Field(description=<span class="hljs-string">"Email body content"</span>)
<span class="hljs-meta"> @validator(<span class="hljs-params"><span class="hljs-string">'recipients'</span></span>)</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">validate_emails</span>(<span class="hljs-params">cls, v</span>):
email_pattern = <span class="hljs-string">r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'</span>
<span class="hljs-keyword">for</span> email <span class="hljs-keyword">in</span> v:
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> re.<span class="hljs-keyword">match</span>(email_pattern, email):
<span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">f"Invalid email address: <span class="hljs-subst">{email}</span>"</span>)
<span class="hljs-keyword">return</span> v
<span class="hljs-meta"> @validator(<span class="hljs-params"><span class="hljs-string">'subject'</span></span>)</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">validate_subject</span>(<span class="hljs-params">cls, v</span>):
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> v.strip():
<span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">"Subject cannot be empty"</span>)
<span class="hljs-keyword">return</span> v.strip()
<span class="hljs-meta">@tool</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">send_email</span>(<span class="hljs-params">email_data: EmailInput</span>) -> <span class="hljs-built_in">str</span>:
<span class="hljs-string">"""
Send an email to specified recipients with validation.
All email addresses are validated before sending.
The subject line is required and cannot be empty.
"""</span>
<span class="hljs-comment"># Send validated email</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">f"Email sent to <span class="hljs-subst">{<span class="hljs-built_in">len</span>(email_data.recipients)}</span> recipients"</span>
Gestion des erreurs et gestion des exceptions
Une fois les entrées validées, une gestion rigoureuse des erreurs devient essentielle pour garantir la continuité des flux de travail, même en cas de problème. Une gestion des erreurs bien conçue empêche qu'une seule défaillance ne perturbe l'ensemble du processus et fournit des retours utiles pour le débogage.
Voici un exemple de décorateur permettant de standardiser la gestion des erreurs entre les outils :
<span class="hljs-keyword">import</span> logging
<span class="hljs-keyword">from</span> functools <span class="hljs-keyword">import</span> wraps
<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">def</span> <span class="hljs-title function_">handle_tool_errors</span>(<span class="hljs-params">func</span>):
<span class="hljs-string">"""Decorator to standardize error handling across tools."""</span>
<span class="hljs-meta"> @wraps(<span class="hljs-params">func</span>)</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">wrapper</span>(<span class="hljs-params">*args, **kwargs</span>):
<span class="hljs-keyword">try</span>:
<span class="hljs-keyword">return</span> func(*args, **kwargs)
<span class="hljs-keyword">except</span> requests.exceptions.Timeout <span class="hljs-keyword">as</span> e:
logging.error(<span class="hljs-string">f"Timeout occurred: <span class="hljs-subst">{e}</span>"</span>)
<span class="hljs-keyword">return</span> <span class="hljs-string">"Request timed out"</span>
<span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
logging.error(<span class="hljs-string">f"An error occurred: <span class="hljs-subst">{e}</span>"</span>)
<span class="hljs-keyword">return</span> <span class="hljs-string">f"Error: <span class="hljs-subst">{e}</span>"</span>
<span class="hljs-keyword">return</span> wrapper
sbb-itb-23997f1
Intégration d'outils avec des agents et des flux de travail
L'intégration des outils LangChain avec les agents implique de sélectionner les bons outils et de garantir une exécution fluide des tâches.
Connecter les outils aux agents
Voici un exemple de configuration d'un agent avec plusieurs outils adaptés à un scénario de service client :
<span class="hljs-keyword">from</span> langchain.agents <span class="hljs-keyword">import</span> initialize_agent, AgentType
<span class="hljs-keyword">from</span> langchain.llms <span class="hljs-keyword">import</span> OpenAI
<span class="hljs-keyword">from</span> langchain.tools <span class="hljs-keyword">import</span> tool
<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime
<span class="hljs-meta">@tool</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">lookup_order_status</span>(<span class="hljs-params">order_id: <span class="hljs-built_in">str</span></span>) -> <span class="hljs-built_in">str</span>:
<span class="hljs-string">"""
Retrieve the current status of a customer order using its ID.
Args:
order_id: The unique identifier for the order (e.g., ORD-12345).
Returns:
Information about the order status, including shipping details.
"""</span>
<span class="hljs-comment"># Simulated API call</span>
api_response = requests.get(<span class="hljs-string">f"https://api.company.com/orders/<span class="hljs-subst">{order_id}</span>"</span>)
<span class="hljs-keyword">if</span> api_response.status_code == <span class="hljs-number">200</span>:
data = api_response.json()
<span class="hljs-keyword">return</span> <span class="hljs-string">f"Order <span class="hljs-subst">{order_id}</span>: <span class="hljs-subst">{data[<span class="hljs-string">'status'</span>]}</span> - Expected delivery: <span class="hljs-subst">{data[<span class="hljs-string">'delivery_date'</span>]}</span>"</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">f"Order <span class="hljs-subst">{order_id}</span> not found in system"</span>
<span class="hljs-meta">@tool</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">process_refund_request</span>(<span class="hljs-params">order_id: <span class="hljs-built_in">str</span>, reason: <span class="hljs-built_in">str</span></span>) -> <span class="hljs-built_in">str</span>:
<span class="hljs-string">"""
Handle a customer refund request.
Args:
order_id: The order ID for which the refund is requested.
reason: The reason provided by the customer for requesting the refund.
Returns:
Confirmation of the refund request along with a reference number.
"""</span>
refund_id = <span class="hljs-string">f"REF-<span class="hljs-subst">{datetime.now().strftime(<span class="hljs-string">'%Y%m%d'</span>)}</span>-<span class="hljs-subst">{order_id[-<span class="hljs-number">5</span>:]}</span>"</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">f"Refund initiated for <span class="hljs-subst">{order_id}</span>. Reference: <span class="hljs-subst">{refund_id}</span>. Processing time: 3-5 business days."</span>
<span class="hljs-comment"># Initialize the agent with tools</span>
llm = OpenAI(temperature=<span class="hljs-number">0</span>)
tools = [lookup_order_status, process_refund_request]
agent = initialize_agent(
tools=tools,
llm=llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=<span class="hljs-literal">True</span>,
max_iterations=<span class="hljs-number">3</span>
)
<span class="hljs-comment"># The agent selects the appropriate tool based on user input</span>
response = agent.run(<span class="hljs-string">"I need to check order ORD-67890 and request a refund because the item arrived damaged"</span>)
Dans cet exemple, l'agent utilise la requête d'entrée pour déterminer les outils à activer. Lorsque plusieurs outils sont disponibles, les regrouper en groupes spécialisés peut améliorer la précision et l'efficacité. Par exemple, les outils peuvent être regroupés selon leur fonction, par exemple en fonction des tâches liées aux commandes ou aux produits :
<span class="hljs-keyword">from</span> langchain.agents <span class="hljs-keyword">import</span> AgentExecutor
<span class="hljs-keyword">from</span> langchain.tools <span class="hljs-keyword">import</span> BaseTool
<span class="hljs-keyword">class</span> <span class="hljs-title class_">CustomerServiceAgent</span>:
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):
<span class="hljs-variable language_">self</span>.order_tools = [lookup_order_status, process_refund_request, additional_order_tool]
<span class="hljs-variable language_">self</span>.product_tools = [additional_product_tool, additional_product_tool_2]
<span class="hljs-keyword">def</span> <span class="hljs-title function_">route_to_specialist</span>(<span class="hljs-params">self, query: <span class="hljs-built_in">str</span></span>) -> AgentExecutor:
<span class="hljs-keyword">if</span> <span class="hljs-string">"order"</span> <span class="hljs-keyword">in</span> query.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">"refund"</span> <span class="hljs-keyword">in</span> query.lower():
<span class="hljs-keyword">return</span> initialize_agent(<span class="hljs-variable language_">self</span>.order_tools, llm, AgentType.ZERO_SHOT_REACT_DESCRIPTION)
<span class="hljs-keyword">elif</span> <span class="hljs-string">"product"</span> <span class="hljs-keyword">in</span> query.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">"inventory"</span> <span class="hljs-keyword">in</span> query.lower():
<span class="hljs-keyword">return</span> initialize_agent(<span class="hljs-variable language_">self</span>.product_tools, llm, AgentType.ZERO_SHOT_REACT_DESCRIPTION)
<span class="hljs-keyword">else</span>:
<span class="hljs-comment"># Default to general tools</span>
<span class="hljs-keyword">return</span> initialize_agent(<span class="hljs-variable language_">self</span>.order_tools[:<span class="hljs-number">2</span>], llm, AgentType.ZERO_SHOT_REACT_DESCRIPTION)
Cette méthode garantit que les requêtes sont acheminées vers les outils les plus pertinents, créant ainsi une expérience utilisateur plus rationalisée.
Modèles d'outils avancés pour flux de travail complexes
Pour les workflows nécessitant plusieurs appels d'API ou requêtes de base de données indépendants, l'exécution asynchrone peut considérablement améliorer l'efficacité. Au lieu de traiter les tâches les unes après les autres, les modèles asynchrones permettent leur exécution en parallèle :
<span class="hljs-keyword">import</span> asyncio
<span class="hljs-keyword">from</span> langchain.tools <span class="hljs-keyword">import</span> tool
<span class="hljs-keyword">import</span> aiohttp
<span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> <span class="hljs-type">List</span>
<span class="hljs-meta">@tool</span>
<span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">fetch_user_data_async</span>(<span class="hljs-params">user_id: <span class="hljs-built_in">str</span></span>) -> <span class="hljs-built_in">str</span>:
<span class="hljs-string">"""
Retrieve a user's profile asynchronously.
Args:
user_id: The unique identifier for the user.
Returns:
Profile details as a JSON string.
"""</span>
<span class="hljs-keyword">async</span> <span class="hljs-keyword">with</span> aiohttp.ClientSession() <span class="hljs-keyword">as</span> session:
<span class="hljs-keyword">async</span> <span class="hljs-keyword">with</span> session.get(<span class="hljs-string">f"https://api.userservice.com/users/<span class="hljs-subst">{user_id}</span>"</span>) <span class="hljs-keyword">as</span> response:
<span class="hljs-keyword">if</span> response.status == <span class="hljs-number">200</span>:
data = <span class="hljs-keyword">await</span> response.json()
<span class="hljs-keyword">return</span> <span class="hljs-string">f"User <span class="hljs-subst">{user_id}</span>: <span class="hljs-subst">{data[<span class="hljs-string">'name'</span>]}</span>, <span class="hljs-subst">{data[<span class="hljs-string">'email'</span>]}</span>, <span class="hljs-subst">{data[<span class="hljs-string">'subscription_tier'</span>]}</span>"</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">f"User <span class="hljs-subst">{user_id}</span> not found"</span>
<span class="hljs-meta">@tool</span>
<span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">fetch_usage_metrics_async</span>(<span class="hljs-params">user_id: <span class="hljs-built_in">str</span></span>) -> <span class="hljs-built_in">str</span>:
<span class="hljs-string">"""
Obtain usage statistics for a user asynchronously.
Args:
user_id: The identifier for the user.
Returns:
Usage details, including API call count and storage usage.
"""</span>
<span class="hljs-keyword">async</span> <span class="hljs-keyword">with</span> aiohttp.ClientSession() <span class="hljs-keyword">as</span> session:
<span class="hljs-keyword">async</span> <span class="hljs-keyword">with</span> session.get(<span class="hljs-string">f"https://api.analytics.com/usage/<span class="hljs-subst">{user_id}</span>"</span>) <span class="hljs-keyword">as</span> response:
<span class="hljs-keyword">if</span> response.status == <span class="hljs-number">200</span>:
data = <span class="hljs-keyword">await</span> response.json()
<span class="hljs-keyword">return</span> <span class="hljs-string">f"Usage for <span class="hljs-subst">{user_id}</span>: <span class="hljs-subst">{data[<span class="hljs-string">'api_calls'</span>]}</span> calls, <span class="hljs-subst">{data[<span class="hljs-string">'storage_gb'</span>]}</span>GB storage"</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">f"No usage data for <span class="hljs-subst">{user_id}</span>"</span>
<span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">parallel_user_analysis</span>(<span class="hljs-params">user_ids: <span class="hljs-type">List</span>[<span class="hljs-built_in">str</span>]</span>) -> <span class="hljs-type">List</span>[<span class="hljs-built_in">str</span>]:
<span class="hljs-string">"""Execute multiple asynchronous tasks for user data retrieval."""</span>
tasks = []
<span class="hljs-keyword">for</span> user_id <span class="hljs-keyword">in</span> user_ids:
tasks.append(fetch_user_data_async(user_id))
tasks.append(fetch_usage_metrics_async(user_id))
results = <span class="hljs-keyword">await</span> asyncio.gather(*tasks)
<span class="hljs-keyword">return</span> results
Cette approche permet non seulement de gagner du temps, mais garantit également que le système peut gérer efficacement des flux de travail complexes.
Pour les tâches nécessitant un contexte sur plusieurs interactions, des outils avec état peuvent être utilisés. Ces outils conservent les informations, permettant une analyse cumulative et un meilleur suivi :
<span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> <span class="hljs-type">Dict</span>, <span class="hljs-type">Any</span>
<span class="hljs-keyword">import</span> json
<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime
<span class="hljs-keyword">from</span> langchain.tools <span class="hljs-keyword">import</span> BaseTool
<span class="hljs-keyword">class</span> <span class="hljs-title class_">StatefulAnalyticsTool</span>(<span class="hljs-title class_ inherited__">BaseTool</span>):
name = <span class="hljs-string">"analytics_tracker"</span>
description = <span class="hljs-string">"Track and analyze user behavior patterns across multiple interactions"</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):
<span class="hljs-built_in">super</span>().__init__()
<span class="hljs-variable language_">self</span>.session_data: <span class="hljs-type">Dict</span>[<span class="hljs-built_in">str</span>, <span class="hljs-type">Any</span>] = {}
<span class="hljs-variable language_">self</span>.interaction_count = <span class="hljs-number">0</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">_run</span>(<span class="hljs-params">self, action: <span class="hljs-built_in">str</span>, data: <span class="hljs-built_in">str</span></span>) -> <span class="hljs-built_in">str</span>:
<span class="hljs-variable language_">self</span>.interaction_count += <span class="hljs-number">1</span>
<span class="hljs-keyword">if</span> action == <span class="hljs-string">"track_event"</span>:
event_data = json.loads(data)
event_type = event_data.get(<span class="hljs-string">"type"</span>)
<span class="hljs-keyword">if</span> event_type <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> <span class="hljs-variable language_">self</span>.session_data:
<span class="hljs-variable language_">self</span>.session_data[event_type] = []
<span class="hljs-variable language_">self</span>.session_data[event_type].append({
<span class="hljs-string">"timestamp"</span>: datetime.now().isoformat(),
<span class="hljs-string">"data"</span>: event_data,
<span class="hljs-string">"interaction_number"</span>: <span class="hljs-variable language_">self</span>.interaction_count
})
<span class="hljs-keyword">return</span> <span class="hljs-string">f"Tracked <span class="hljs-subst">{event_type}</span> event. Total interactions: <span class="hljs-subst">{self.interaction_count}</span>"</span>
<span class="hljs-keyword">elif</span> action == <span class="hljs-string">"analyze_patterns"</span>:
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-variable language_">self</span>.session_data:
<span class="hljs-keyword">return</span> <span class="hljs-string">"No data collected yet for analysis"</span>
patterns = {}
<span class="hljs-keyword">for</span> event_type, events <span class="hljs-keyword">in</span> <span class="hljs-variable language_">self</span>.session_data.items():
patterns[event_type] = {
<span class="hljs-string">"count"</span>: <span class="hljs-built_in">len</span>(events),
<span class="hljs-string">"frequency"</span>: <span class="hljs-built_in">len</span>(events) / <span class="hljs-variable language_">self</span>.interaction_count
}
<span class="hljs-keyword">return</span> <span class="hljs-string">f"Behavior patterns: <span class="hljs-subst">{json.dumps(patterns, indent=<span class="hljs-number">2</span>)}</span>"</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"Unknown action. Use 'track_event' or 'analyze_patterns'"</span>
Considérations de production pour les outils LangChain
La transition des outils LangChain du développement à la production nécessite une approche réfléchie pour relever les défis de performance, de sécurité et de maintenance. Ces considérations sont cruciales pour garantir un fonctionnement efficace et sécurisé des outils dans des environnements réels.
Optimisation des performances des outils
Les goulots d'étranglement des performances dans les environnements de production proviennent souvent de réponses API externes lentes, d'une logique inefficace ou d'opérations synchrones excessives [1][2]Ces problèmes sont particulièrement prononcés lorsque les outils gèrent des volumes élevés de requêtes simultanées ou interagissent avec des API qui appliquent des limites de débit.
Une façon d’améliorer les performances est de : modèles d'exécution asynchrones, qui permettent aux outils de gérer plusieurs requêtes simultanément. Cette approche est particulièrement efficace pour les opérations d'E/S, comme le montre l'exemple suivant :
<span class="hljs-keyword">import</span> asyncio
<span class="hljs-keyword">import</span> aiohttp
<span class="hljs-keyword">from</span> langchain.tools <span class="hljs-keyword">import</span> StructuredTool
<span class="hljs-keyword">from</span> pydantic <span class="hljs-keyword">import</span> BaseModel
<span class="hljs-keyword">class</span> <span class="hljs-title class_">BatchAPITool</span>(<span class="hljs-title class_ inherited__">BaseModel</span>):
<span class="hljs-string">"""Optimized tool for handling multiple API requests concurrently."""</span>
<span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">fetch_data_batch</span>(<span class="hljs-params">self, endpoints: <span class="hljs-built_in">list</span>[<span class="hljs-built_in">str</span>]</span>) -> <span class="hljs-built_in">dict</span>:
<span class="hljs-string">"""Process multiple API endpoints concurrently with error handling."""</span>
<span class="hljs-keyword">async</span> <span class="hljs-keyword">with</span> aiohttp.ClientSession(
timeout=aiohttp.ClientTimeout(total=<span class="hljs-number">10</span>),
connector=aiohttp.TCPConnector(limit=<span class="hljs-number">20</span>)
) <span class="hljs-keyword">as</span> session:
tasks = [<span class="hljs-variable language_">self</span>._fetch_single(session, url) <span class="hljs-keyword">for</span> url <span class="hljs-keyword">in</span> endpoints]
results = <span class="hljs-keyword">await</span> asyncio.gather(*tasks, return_exceptions=<span class="hljs-literal">True</span>)
<span class="hljs-keyword">return</span> {
<span class="hljs-string">"successful"</span>: [r <span class="hljs-keyword">for</span> r <span class="hljs-keyword">in</span> results <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-built_in">isinstance</span>(r, Exception)],
<span class="hljs-string">"failed"</span>: [<span class="hljs-built_in">str</span>(r) <span class="hljs-keyword">for</span> r <span class="hljs-keyword">in</span> results <span class="hljs-keyword">if</span> <span class="hljs-built_in">isinstance</span>(r, Exception)],
<span class="hljs-string">"total_processed"</span>: <span class="hljs-built_in">len</span>(results)
}
<span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">_fetch_single</span>(<span class="hljs-params">self, session: aiohttp.ClientSession, url: <span class="hljs-built_in">str</span></span>) -> <span class="hljs-built_in">dict</span>:
<span class="hljs-keyword">try</span>:
<span class="hljs-keyword">async</span> <span class="hljs-keyword">with</span> session.get(url) <span class="hljs-keyword">as</span> response:
<span class="hljs-keyword">if</span> response.status == <span class="hljs-number">200</span>:
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> response.json()
<span class="hljs-keyword">return</span> {<span class="hljs-string">"error"</span>: <span class="hljs-string">f"HTTP <span class="hljs-subst">{response.status}</span>"</span>}
<span class="hljs-keyword">except</span> asyncio.TimeoutError:
<span class="hljs-keyword">return</span> {<span class="hljs-string">"error"</span>: <span class="hljs-string">"Request timeout"</span>}
<span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
<span class="hljs-keyword">return</span> {<span class="hljs-string">"error"</span>: <span class="hljs-string">f"Request failed: <span class="hljs-subst">{<span class="hljs-built_in">str</span>(e)}</span>"</span>}
<span class="hljs-comment"># Create the structured tool with async support</span>
batch_tool = StructuredTool.from_function(
func=BatchAPITool().fetch_data_batch,
name=<span class="hljs-string">"batch_api_processor"</span>,
description=<span class="hljs-string">"Process multiple API endpoints concurrently for improved performance"</span>
)
En plus de l'exécution asynchrone, limitation de débit et mise en cache sont des éléments essentiels d'une stratégie de production robuste. La limitation du débit empêche les outils de dépasser les quotas d'API, tandis que la mise en cache réduit la fréquence des appels d'API en stockant les réponses pendant une durée déterminée.
Limitation de débit avec recul exponentiel
Pour gérer efficacement les API à débit limité, il est important de mettre en œuvre des stratégies de backoff exponentiel. L'exemple suivant illustre un décorateur qui relance les requêtes avec des délais croissants :
<span class="hljs-keyword">import</span> random
<span class="hljs-keyword">from</span> functools <span class="hljs-keyword">import</span> wraps
<span class="hljs-keyword">import</span> asyncio
<span class="hljs-keyword">def</span> <span class="hljs-title function_">rate_limited_retry</span>(<span class="hljs-params">max_retries=<span class="hljs-number">3</span>, base_delay=<span class="hljs-number">1.0</span></span>):
<span class="hljs-string">"""Decorator for handling rate limits with exponential backoff."""</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">decorator</span>(<span class="hljs-params">func</span>):
<span class="hljs-meta"> @wraps(<span class="hljs-params">func</span>)</span>
<span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">wrapper</span>(<span class="hljs-params">*args, **kwargs</span>):
<span class="hljs-keyword">for</span> attempt <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(max_retries + <span class="hljs-number">1</span>):
<span class="hljs-keyword">try</span>:
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> func(*args, **kwargs)
<span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
<span class="hljs-keyword">if</span> <span class="hljs-string">"rate limit"</span> <span class="hljs-keyword">in</span> <span class="hljs-built_in">str</span>(e).lower() <span class="hljs-keyword">and</span> attempt < max_retries:
delay = base_delay * (<span class="hljs-number">2</span> ** attempt) + random.uniform(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>)
<span class="hljs-keyword">await</span> asyncio.sleep(delay)
<span class="hljs-keyword">continue</span>
<span class="hljs-keyword">raise</span> e
<span class="hljs-keyword">return</span> {<span class="hljs-string">"error"</span>: <span class="hljs-string">"Max retries exceeded"</span>}
<span class="hljs-keyword">return</span> wrapper
<span class="hljs-keyword">return</span> decorator
Stratégies de mise en cache
La mise en cache peut améliorer considérablement la réactivité et réduire les appels d'API en stockant les données fréquemment consultées. Voici un exemple de système de mise en cache simple :
<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime, timedelta
<span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> <span class="hljs-type">Dict</span>, <span class="hljs-type">Any</span>, <span class="hljs-type">Optional</span>
<span class="hljs-keyword">class</span> <span class="hljs-title class_">ToolCache</span>:
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, default_ttl_minutes: <span class="hljs-built_in">int</span> = <span class="hljs-number">15</span></span>):
<span class="hljs-variable language_">self</span>.cache: <span class="hljs-type">Dict</span>[<span class="hljs-built_in">str</span>, <span class="hljs-type">Dict</span>[<span class="hljs-built_in">str</span>, <span class="hljs-type">Any</span>]] = {}
<span class="hljs-variable language_">self</span>.default_ttl = timedelta(minutes=default_ttl_minutes)
<span class="hljs-keyword">def</span> <span class="hljs-title function_">get</span>(<span class="hljs-params">self, key: <span class="hljs-built_in">str</span></span>) -> <span class="hljs-type">Optional</span>[<span class="hljs-type">Any</span>]:
<span class="hljs-keyword">if</span> key <span class="hljs-keyword">in</span> <span class="hljs-variable language_">self</span>.cache:
entry = <span class="hljs-variable language_">self</span>.cache[key]
<span class="hljs-keyword">if</span> datetime.now() < entry[<span class="hljs-string">"expires"</span>]:
<span class="hljs-keyword">return</span> entry[<span class="hljs-string">"data"</span>]
<span class="hljs-keyword">else</span>:
<span class="hljs-keyword">del</span> <span class="hljs-variable language_">self</span>.cache[key]
<span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">set</span>(<span class="hljs-params">self, key: <span class="hljs-built_in">str</span>, data: <span class="hljs-type">Any</span>, ttl_minutes: <span class="hljs-type">Optional</span>[<span class="hljs-built_in">int</span>] = <span class="hljs-literal">None</span></span>) -> <span class="hljs-literal">None</span>:
ttl = timedelta(minutes=ttl_minutes) <span class="hljs-keyword">if</span> ttl_minutes <span class="hljs-keyword">else</span> <span class="hljs-variable language_">self</span>.default_ttl
<span class="hljs-variable language_">self</span>.cache[key] = {
<span class="hljs-string">"data"</span>: data,
<span class="hljs-string">"expires"</span>: datetime.now() + ttl
}
<span class="hljs-comment"># Global cache instance</span>
tool_cache = ToolCache()
En combinant ces techniques (exécution asynchrone, limitation de débit et mise en cache), les outils LangChain peuvent obtenir des performances plus fluides et plus fiables dans les environnements de production.
Sécurité dans le développement d'outils
Si les performances sont primordiales, la sécurité est tout aussi cruciale lors du déploiement des outils LangChain en production. Ces outils accèdent souvent à des systèmes externes avec des autorisations élevées, ce qui les rend vulnérables à des risques tels qu'une validation insuffisante des entrées et un accès trop permissif.
Validation des entrées avec Pydantique Modèles
Les modèles Pydantic constituent une base solide pour la validation des entrées. En appliquant des règles strictes, ils empêchent les données malveillantes ou invalides de compromettre le système. Voici un exemple de modèle d'entrée sécurisé :
<span class="hljs-keyword">from</span> pydantic <span class="hljs-keyword">import</span> BaseModel, Field
<span class="hljs-keyword">class</span> <span class="hljs-title class_">SecureAPIRequest</span>(<span class="hljs-title class_ inherited__">BaseModel</span>):
<span class="hljs-string">"""Secure input model with comprehensive validation."""</span>
endpoint: <span class="hljs-built_in">str</span> = Field(..., regex=<span class="hljs-string">r'^[a-zA-Z0-9/_-]+$'</span>, max_length=<span class="hljs-number">200</span>)
user_id: <span class="hljs-built_in">str</span> = Field(..., regex=<span class="hljs-string">r'^[a-zA-Z0-9-]+$'</span>)
<span class="hljs-comment"># Additional fields and validators can be added here to further secure inputs</span>
Sécurisation des outils API
L'exemple suivant illustre un outil API sécurisé qui intègre la validation des entrées et des contrôles de sécurité supplémentaires :
<span class="hljs-keyword">def</span> <span class="hljs-title function_">create_secure_api_tool</span>():
<span class="hljs-string">"""Create API tool with built-in security validation."""</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">secure_api_call</span>(<span class="hljs-params">request: SecureAPIRequest</span>) -> <span class="hljs-built_in">str</span>:
<span class="hljs-comment"># Additional security checks</span>
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> _is_authorized_user(request.user_id):
<span class="hljs-keyword">return</span> <span class="hljs-string">"Error: Unauthorized access attempt"</span>
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> _is_allowed_endpoint(request.endpoint):
<span class="hljs-keyword">return</span> <span class="hljs-string">"Error: Endpoint not permitted"</span>
<span class="hljs-keyword">try</span>:
<span class="hljs-comment"># Perform the actual API call with validated inputs</span>
result = _execute_api_request(request)
<span class="hljs-keyword">return</span> _sanitize_response(result)
<span class="hljs-keyword">except</span> Exception:
<span class="hljs-comment"># Never expose internal error details</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"Error: Request processing failed"</span>
<span class="hljs-keyword">return</span> StructuredTool.from_function(
func=secure_api_call,
name=<span class="hljs-string">"secure_api_tool"</span>,
description=<span class="hljs-string">"Execute API requests with comprehensive security validation"</span>
)
Nettoyage des réponses API
Pour éviter que des informations sensibles ne soient exposées, les réponses doivent être nettoyées avant d'être renvoyées :
<span class="hljs-keyword">def</span> <span class="hljs-title function_">_sanitize_response</span>(<span class="hljs-params">response: <span class="hljs-built_in">dict</span></span>) -> <span class="hljs-built_in">str</span>:
<span class="hljs-string">"""Remove sensitive information from API responses."""</span>
sensitive_keys = [<span class="hljs-string">'password'</span>, <span class="hljs-string">'token'</span>, <span class="hljs-string">'secret'</span>, <span class="hljs-string">'key'</span>, <span class="hljs-string">'credential'</span>]
<span class="hljs-keyword">def</span> <span class="hljs-title function_">clean_dict</span>(<span class="hljs-params">obj</span>):
<span class="hljs-keyword">if</span> <span class="hljs-built_in">isinstance</span>(obj, <span class="hljs-built_in">dict</span>):
<span class="hljs-keyword">return</span> {k: clean_dict(v) <span class="hljs-keyword">for</span> k, v <span class="hljs-keyword">in</span> obj.items()
<span class="hljs-keyword">if</span> k.lower() <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> sensitive_keys}
<span class="hljs-keyword">elif</span> <span class="hljs-built_in">isinstance</span>(obj, <span class="hljs-built_in">list</span>):
<span class="hljs-keyword">return</span> [clean_dict(item) <span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> obj]
<span class="hljs-keyword">return</span> obj
cleaned = clean_dict(response)
<span class="hljs-keyword">return</span> <span class="hljs-built_in">str</span>(cleaned)[:<span class="hljs-number">1000</span>] <span class="hljs-comment"># Limit response size</span>
Gestion des autorisations
La gestion des autorisations doit respecter le principe du moindre privilège, garantissant que les outils n'accèdent qu'aux ressources nécessaires à leurs tâches. Les contrôles d'accès basés sur les rôles peuvent limiter davantage les actions non autorisées, renforçant ainsi la sécurité globale. [1][3].
LaténodeL'approche d'intégration visuelle de
Les outils LangChain nécessitent souvent un codage manuel et une maintenance continue, ce qui peut être chronophage et gourmand en ressources. Latenode, quant à lui, simplifie ce processus grâce à ses connecteurs pré-intégrés à des centaines de services, éliminant ainsi le besoin de codage personnalisé dans la plupart des intégrations courantes.
Développement Latenode vs. LangChain manuel
Le contraste entre la création d'outils LangChain personnalisés et l'utilisation du workflow visuel de Latenode est saisissant, notamment en termes de temps de développement et de complexité. Par exemple, la création d'un outil personnalisé pour Google Sheets implique généralement un codage important pour des tâches telles que la gestion des erreurs, l'authentification et la validation des données. Avec Latenode, les mêmes fonctionnalités sont accessibles via une interface intuitive par glisser-déposer.
Imaginez un workflow conçu pour traiter les commentaires clients et mettre à jour une feuille de calcul. Normalement, cela nécessiterait des outils distincts pour le traitement des données, l'authentification API et la manipulation de la feuille de calcul. Latenode simplifie cela en une séquence visuelle du type : Webhook → OpenAI GPT-4 → Google Sheets. Chaque connecteur de cette chaîne intègre une authentification et une gestion des erreurs, éliminant ainsi une grande partie des tâches manuelles.
Latenode prend en charge l'intégration avec plus de 300 applications et plus de 200 modèles d'IA, couvrant ainsi un large éventail de besoins d'automatisation métier sans nécessiter de code personnalisé. Cette approche est particulièrement avantageuse pour les équipes à la recherche de solutions fiables sans la charge supplémentaire d'une maintenance continue. En simplifiant les processus de développement et de maintenance, Latenode facilite la transition vers une gestion système efficace.
En plus d’accélérer le développement, cette plateforme réduit considérablement les défis liés à la maintenance d’outils sur mesure.
Réduire les frais généraux et améliorer la maintenabilité
Le développement d'outils programmatiques implique souvent le débogage d'appels de fonctions complexes et la gestion de l'analyse des paramètres, un processus fastidieux et source d'erreurs. Latenode élimine ces obstacles en permettant les interactions entre LLM et le système grâce à son workflow visuel, rendant les intégrations accessibles même aux non-développeurs.
Des fonctionnalités telles que l'historique d'exécution intégré et la réexécution de scénarios permettent aux équipes de diagnostiquer et de corriger rapidement les problèmes, sans avoir à reconstruire des workflows entiers. Cela élimine une grande partie des incertitudes généralement associées au débogage d'outils personnalisés.
De plus, AI Code Copilot de Latenode améliore la flexibilité en permettant aux équipes de générer et de modifier du JavaScript directement dans les workflows. Cette fonctionnalité comble le fossé entre conception visuelle et logique personnalisée, permettant aux équipes d'ajouter des fonctionnalités sur mesure sans avoir à jongler entre différents environnements de développement. Cette intégration transparente permet aux équipes de se concentrer sur la création de solutions d'automatisation simples et efficaces.
La maintenance est encore simplifiée, car Latenode gère automatiquement les modifications d'API, les mises à jour d'authentification et la fiabilité des connecteurs. Cela évite aux équipes la surveillance continue des mises à jour d'API externes et la révision des implémentations personnalisées, réduisant ainsi les coûts à long terme.
Connecteurs pré-construits pour des intégrations plus rapides
Les connecteurs pré-configurés de Latenode offrent aux équipes un moyen plus rapide et plus efficace d'intégrer des systèmes externes, tout en minimisant les besoins de maintenance. Ces intégrations sont conçues pour gérer automatiquement la gestion des erreurs et les mises à jour des API, ce qui permet de gagner un temps précieux.
La bibliothèque de connecteurs de la plateforme comprend des outils commerciaux populaires tels que Notion, Stripe, WhatsApp, Telegramet LinkedIn. Chaque connecteur est doté d'une authentification préconfigurée et prend en charge les cas d'utilisation courants, garantissant un fonctionnement fluide même avec l'évolution des API.
Pour l'automatisation des messageries personnelles, Latenode va au-delà des intégrations d'API standard. Il permet l'automatisation de plateformes comme WhatsApp, LinkedIn et Telegram, permettant une communication personnalisée et des workflows de type CRM. La mise en œuvre de fonctionnalités telles que des outils LangChain personnalisés serait extrêmement complexe en raison des défis liés à l'authentification et à la conformité.
De plus, la base de données intégrée de Latenode permet une gestion structurée des données directement dans les workflows. Associée à l'automatisation des navigateurs headless, elle prend en charge des scénarios d'automatisation complexes qui nécessiteraient autrement plusieurs outils personnalisés et services externes.
Pour les équipes qui hésitent entre développer ou acheter, le modèle de tarification de Latenode, basé sur le temps d'exécution plutôt que sur des frais par tâche, s'avère souvent plus rentable. Il peut générer des économies significatives par rapport aux coûts de développement et de maintenance des outils LangChain personnalisés.
Questions Fréquentes Posées
Quelle est la différence entre l'utilisation du décorateur @tool et la sous-classe de BaseTool pour créer des outils LangChain ?
L'espace @tool Decorator offre un moyen simple de transformer des fonctions Python en outils LangChain. En enveloppant simplement une fonction, il attribue automatiquement des attributs clés, comme le nom et la description de l'outil, en extrayant ces informations du nom et de la docstring de la fonction. C'est donc un excellent choix pour créer des outils simples ou tester rapidement des idées.
Pour les scénarios qui exigent plus de complexité, sous-classement BaseTool est la meilleure option. Cette méthode offre une plus grande flexibilité, vous permettant de définir des attributs personnalisés, d'implémenter une validation avancée, de gérer les erreurs et de concevoir des comportements plus complexes. Elle est particulièrement adaptée aux outils devant répondre à des exigences de production ou gérer des flux de travail complexes.
En substance, le @tool Le décorateur est parfait pour des installations rapides et faciles, tandis que BaseTool est le choix incontournable pour créer des outils plus avancés et plus fiables.
Comment Latenode facilite-t-il l'intégration de systèmes externes par rapport à la création d'outils personnalisés dans LangChain ?
Latenode rationalise le processus d'intégration de systèmes externes grâce à son conception de flux de travail visuel, éliminant ainsi le besoin de codage manuel. Son interface intuitive par glisser-déposer permet des connexions fluides entre les agents d'IA, les API et les services externes, évitant ainsi les tâches souvent complexes de validation des paramètres et de gestion des erreurs inhérentes au développement d'outils LangChain personnalisés.
En automatisant des tâches critiques telles que la gestion des erreurs et la configuration du système, Latenode réduit non seulement le temps de configuration, mais aussi le risque d'erreurs de codage. C'est donc un choix idéal pour ceux qui recherchent des intégrations rapides et fiables, surtout s'ils ne possèdent pas d'expertise avancée en programmation. Avec Latenode, les utilisateurs peuvent se consacrer pleinement à la création. Solutions basées sur l'IA plutôt que de dépanner le code.
Quelles sont les meilleures pratiques pour déployer de manière sécurisée et efficace les outils LangChain en production ?
Pour déployer les outils LangChain de manière sécurisée et efficace dans un environnement de production, commencez par vous concentrer sur validation des entrées et des sortiesCela contribue à la protection contre les attaques par injection et autres vulnérabilités de sécurité. Assurez-vous que les autorisations sont configurées pour fournir uniquement l'accès minimal nécessaire aux fonctionnalités, réduisant ainsi les risques potentiels. journalisation et surveillance est tout aussi crucial, car il vous permet d’identifier et de résoudre rapidement tout problème pouvant survenir.
Une autre étape clé consiste à se préparer à une éventuelle utilisation abusive en mettant en œuvre filtrage et validation de sortie pour maintenir l'exactitude et l'intégrité des données. Pour améliorer la fiabilité du système, intégrez limitation de débit pour contrôler la circulation et mécanismes de gestion des erreurs Pour gérer les problèmes inattendus sans perturber l'activité. En suivant ces mesures, vous pouvez créer un environnement sécurisé et stable pour vos outils LangChain tout en maintenant des performances optimales.
À lire également



