Concevoir des outils d’agents partageables
Normes de schéma d’outils, exigences de documentation et empaquetage pour la réutilisation.
Concevoir des outils d’agents partageables est une leçon AI Agents gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Agents, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Agents comprend 4 leçons au total.
Qu’est-ce qui rend un outil partageable ?
Un outil d’agent partageable est un outil que d’autres développeurs peuvent intégrer à leurs systèmes d’agents sans lire le code source. Il dispose d’un schéma clair et lisible par machine, d’un README lisible par un humain, de codes d’erreur bien définis et d’un comportement prévisible. Considérez-le comme une bibliothèque plutôt que comme un script.
Normes des schémas d’outils
Chaque outil partageable doit disposer d’un schéma décrivant ses entrées, ses sorties et ses métadonnées. Le schéma constitue le contrat entre l’auteur de l’outil et l’agent qui l’utilise. Fondez-le sur JSON Schema pour garantir une compatibilité maximale avec tous les principaux cadres d’agents.
TOOL_SCHEMA_TEMPLATE = {
'name': 'get_weather',
'description': 'Returns current weather conditions for a city. '
'Use when the user asks about weather or temperature.',
'version': '1.2.0',
'parameters': {
'type': 'object',
'properties': {
'city': {
'type': 'string',
'description': 'City name (e.g., London, Tokyo)',
'minLength': 1,
'maxLength': 100
},
'units': {
'type': 'string',
'enum': ['celsius', 'fahrenheit'],
'default': 'celsius',
'description': 'Temperature unit'
}
},
'required': ['city']
},
'returns': {
'type': 'object',
'properties': {
'temperature': {'type': 'number'},
'condition': {'type': 'string'},
'humidity_pct': {'type': 'number'}
}
},
'rate_limit': {'calls_per_minute': 60}
}
if __name__ == '__main__':
print(f"Tool: {TOOL_SCHEMA_TEMPLATE['name']} (v{TOOL_SCHEMA_TEMPLATE['version']})")
print('Description:', TOOL_SCHEMA_TEMPLATE['description'])
print('Required params:', TOOL_SCHEMA_TEMPLATE['parameters']['required'])
Codes d’erreur
Définissez un format standard de réponse d’erreur. Chaque outil doit renvoyer la même structure d’erreur : un code, un message et des détails facultatifs. L’agent peut ainsi gérer les erreurs par programmation sans connaître les détails internes de l’outil.
from enum import Enum
class ToolErrorCode(Enum):
INVALID_PARAMS = 'INVALID_PARAMS'
NOT_FOUND = 'NOT_FOUND'
RATE_LIMITED = 'RATE_LIMITED'
UPSTREAM_ERROR = 'UPSTREAM_ERROR'
TIMEOUT = 'TIMEOUT'
UNAUTHORISED = 'UNAUTHORISED'
INTERNAL_ERROR = 'INTERNAL_ERROR'
class ToolError(Exception):
def __init__(self, code: ToolErrorCode, message: str, details: dict = None):
self.code = code
self.message = message
self.details = details or {}
def to_dict(self) -> dict:
return {
'error': True,
'code': self.code.value,
'message': self.message,
'details': self.details
}
try:
raise ToolError(
ToolErrorCode.NOT_FOUND,
'City not found in database',
{'city': 'Atlantis', 'suggestion': 'Did you mean Athens?'}
)
except ToolError as e:
print(e.to_dict())Validation des entrées
Validez les entrées par rapport au schéma avant l’exécution. Utilisez jsonschema pour automatiser la validation. Échouez rapidement avec une erreur descriptive plutôt que de laisser des entrées non valides provoquer des échecs difficiles à comprendre au cœur de la logique de l’outil.
import jsonschema # pip install jsonschema
def validate_tool_input(params: dict, schema: dict) -> dict:
"""
Validate params against schema.
Returns validated (and default-filled) params.
Raises ToolError on validation failure.
"""
try:
# Fill in defaults
filled = dict(params)
for prop, definition in schema['properties'].items():
if prop not in filled and 'default' in definition:
filled[prop] = definition['default']
# Validate against schema
jsonschema.validate(instance=filled, schema=schema)
return filled
except jsonschema.ValidationError as e:
raise ToolError(
ToolErrorCode.INVALID_PARAMS,
f'Validation failed: {e.message}',
{'path': list(e.path), 'schema_path': list(e.schema_path)}
)
# Example usage:
try:
params = validate_tool_input({'city': 'London'}, TOOL_SCHEMA_TEMPLATE['parameters'])
print('Valid params:', params)
except ToolError as e:
print('Error:', e.to_dict())Exemples d’utilisation dans le schéma
Ajoutez des exemples concrets au schéma de votre outil. Les exemples ont deux fonctions : ils aident les humains à comprendre rapidement l’outil et peuvent être injectés dans le contexte de l’agent comme démonstrations fondées sur quelques exemples afin d’améliorer la précision des appels d’outils.
TOOL_WITH_EXAMPLES = {
'name': 'search_knowledge_base',
'description': 'Search the company knowledge base for documentation.',
'parameters': {
'type': 'object',
'properties': {
'query': {'type': 'string'},
'top_k': {'type': 'integer', 'default': 5, 'minimum': 1, 'maximum': 20}
},
'required': ['query']
},
'examples': [
{
'description': 'Search for onboarding docs',
'input': {'query': 'how to onboard new users', 'top_k': 3},
'output': {'results': [{'title': 'User Onboarding Guide', 'score': 0.95}]}
},
{
'description': 'Search with default top_k',
'input': {'query': 'API authentication'},
'output': {'results': [{'title': 'API Auth Docs', 'score': 0.88}]}
}
]
}
if __name__ == '__main__':
print('Tool:', TOOL_WITH_EXAMPLES['name'])
for ex in TOOL_WITH_EXAMPLES['examples']:
print(f" - {ex['description']}: input={ex['input']} -> output={ex['output']}")
Limitation du débit des outils
Les outils qui appellent des API externes doivent respecter les limites de débit. Implémentez un limiteur de débit propre à chaque outil à l’aide d’un seau de jetons ou d’une fenêtre glissante. Renvoyez une erreur standard RATE_LIMITED accompagnée du nombre de secondes avant une nouvelle tentative lorsque la limite est dépassée.
import time
from collections import deque
class SlidingWindowRateLimiter:
def __init__(self, max_calls: int, window_seconds: int):
self.max_calls = max_calls
self.window = window_seconds
self._calls = deque() # timestamps of recent calls
def check(self) -> tuple:
"""
Returns (allowed: bool, retry_after_seconds: float)
"""
now = time.time()
# Remove calls outside the window
while self._calls and self._calls[0] < now - self.window:
self._calls.popleft()
if len(self._calls) >= self.max_calls:
oldest = self._calls[0]
retry_after = (oldest + self.window) - now
return False, round(retry_after, 1)
self._calls.append(now)
return True, 0.0
weather_limiter = SlidingWindowRateLimiter(max_calls=10, window_seconds=60)
allowed, retry = weather_limiter.check()
if not allowed:
raise ToolError(ToolErrorCode.RATE_LIMITED,
f'Rate limit exceeded. Retry in {retry}s',
{'retry_after': retry})Conditionnement sous forme de paquet Python
Structurez votre outil comme un paquet Python installable afin que d’autres développeurs puissent l’ajouter à leurs agents avec une seule commande pip install. Le paquet expose une fonction get_tool_definition() et une fonction execute(params) comme interface publique.
# Directory structure:
# agent_tool_weather/
# __init__.py
# tool.py
# schema.py
# pyproject.toml
# README.md
# agent_tool_weather/tool.py
from .schema import SCHEMA
from .errors import ToolError, ToolErrorCode
def get_tool_definition() -> dict:
return SCHEMA
def execute(params: dict) -> dict:
validated = validate_tool_input(params, SCHEMA['parameters'])
city = validated['city']
units = validated['units']
return _fetch_weather(city, units)
def _fetch_weather(city: str, units: str) -> dict:
import requests
url = f'https://api.weather.example.com/current?city={city}&units={units}'
response = requests.get(url, headers={'X-API-Key': 'YOUR_KEY'}, timeout=5)
if response.status_code == 404:
raise ToolError(ToolErrorCode.NOT_FOUND, f'City not found: {city}')
response.raise_for_status()
return response.json()Rédaction du README de l’outil
Un README clair est essentiel à l’adoption. Incluez : la fonction de l’outil, la commande d’installation, les clés d’API ou identifiants requis, tous les paramètres avec leurs types et valeurs par défaut, tous les codes d’erreur et au moins un exemple complet d’utilisation.
README_TEMPLATE = '''
# agent-tool-weather
Get real-time weather conditions for any city.
## Installation
pip install agent-tool-weather
## Setup
import os
os.environ["WEATHER_API_KEY"] = "your-key-here"
## Usage
from agent_tool_weather import get_tool_definition, execute
# In your agent
tool_def = get_tool_definition()
# Execute
result = execute({"city": "Tokyo", "units": "celsius"})
print(result)
# {"temperature": 22.5, "condition": "Partly cloudy", "humidity_pct": 65}
## Parameters
| Name | Type | Required | Default | Description |
|-------|--------|----------|----------|-----------------|
| city | string | Yes | - | City name |
| units | string | No | celsius | celsius or fahrenheit |
## Error Codes
- INVALID_PARAMS: Parameter validation failed
- NOT_FOUND: City not found
- RATE_LIMITED: 60 calls/minute limit exceeded
- UPSTREAM_ERROR: Weather API unavailable
'''
print(README_TEMPLATE[:300])Test d’un outil partageable
Un outil partageable doit disposer de tests automatisés couvrant : le cas nominal, chaque code d’erreur, les cas limites (chaînes vides, valeurs maximales) et le comportement de limitation du débit. Les tests constituent une documentation : ils montrent exactement comment l’outil se comporte.
import pytest
def test_valid_city_returns_weather(mock_weather_api):
result = execute({'city': 'London'})
assert 'temperature' in result
assert 'condition' in result
assert isinstance(result['temperature'], (int, float))
def test_missing_required_param_raises_error():
with pytest.raises(ToolError) as exc_info:
execute({}) # city is required
assert exc_info.value.code == ToolErrorCode.INVALID_PARAMS
def test_unknown_city_raises_not_found(mock_weather_api_404):
with pytest.raises(ToolError) as exc_info:
execute({'city': 'Atlantis'})
assert exc_info.value.code == ToolErrorCode.NOT_FOUND
def test_default_units_is_celsius():
params = validate_tool_input({'city': 'Paris'}, TOOL_SCHEMA_TEMPLATE['parameters'])
assert params['units'] == 'celsius'
def test_rate_limit_enforced():
limiter = SlidingWindowRateLimiter(max_calls=2, window_seconds=60)
limiter.check() # call 1
limiter.check() # call 2
allowed, _ = limiter.check() # call 3 — should fail
assert not allowedFormat compatible avec les appels de fonctions d’OpenAI
Pour assurer la compatibilité avec les API natives d’utilisation d’outils d’OpenAI et de Claude, vérifiez que le schéma de votre outil respecte exactement le format attendu par ces API. La get_openai_schema() convertit votre schéma interne au format compatible avec OpenAI.
def get_openai_schema(tool_schema: dict) -> dict:
"""Convert internal tool schema to OpenAI function-calling format."""
return {
'type': 'function',
'function': {
'name': tool_schema['name'],
'description': tool_schema['description'],
'parameters': tool_schema['parameters']
}
}
def get_anthropic_schema(tool_schema: dict) -> dict:
"""Convert to Anthropic tool format."""
return {
'name': tool_schema['name'],
'description': tool_schema['description'],
'input_schema': tool_schema['parameters']
}
# Usage in an agent:
openai_tools = [get_openai_schema(t) for t in [TOOL_SCHEMA_TEMPLATE]]
anthropic_tools = [get_anthropic_schema(t) for t in [TOOL_SCHEMA_TEMPLATE]]
print('OpenAI format:', openai_tools[0]['function']['name'])
print('Anthropic format:', anthropic_tools[0]['name'])Gestion des versions de votre outil
Utilisez le versionnage sémantique : MAJOR.MINOR.PATCH. Incrémentez MAJOR lors des modifications incompatibles du schéma, MINOR lors de l’ajout de paramètres facultatifs et PATCH pour les corrections de bogues. Stockez la version dans le schéma et exposez-la au moyen de get_tool_definition().
VERSION = '1.2.0'
def bump_version(current: str, change_type: str) -> str:
parts = list(map(int, current.split('.')))
if change_type == 'major':
return f'{parts[0]+1}.0.0'
if change_type == 'minor':
return f'{parts[0]}.{parts[1]+1}.0'
if change_type == 'patch':
return f'{parts[0]}.{parts[1]}.{parts[2]+1}'
raise ValueError(f'Unknown change_type: {change_type}')
# Breaking change (removed required param) -> major
print(bump_version('1.2.0', 'major')) # 2.0.0
# Added optional param -> minor
print(bump_version('1.2.0', 'minor')) # 1.3.0
# Bug fix -> patch
print(bump_version('1.2.0', 'patch')) # 1.2.1Vérification des connaissances
Quelle partie du schéma d’un outil partageable permet au cadre d’agents de valider automatiquement les entrées avant d’appeler la fonction d’exécution de l’outil ?
Récapitulatif : conception d’outils d’agents partageables
Points clés de cette leçon :
- Schéma : nom, description, version, paramètres (JSON Schema), valeurs renvoyées et limitation du débit
- Codes d’erreur : ToolError standard avec un code, un message et des détails
- Validation des entrées : jsonschema valide les entrées par rapport au schéma des paramètres avant l’exécution
- Exemples : inclus dans le schéma comme contexte fondé sur quelques exemples
- Limitation du débit : fenêtre glissante avec une erreur de limitation du débit et un délai avant nouvelle tentative
- Conditionnement : paquet installable avec pip, comprenant un README, des tests et un versionnage
Ensuite : découverte des extensions et chargement dynamique des outils.
Questions Fréquemment Posées
La leçon « Concevoir des outils d’agents partageables » est-elle gratuite ?
Oui — le texte complet de « Concevoir des outils d’agents partageables » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Agents, passe à CoddyKit PRO. Le cours AI Agents comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Concevoir des outils d’agents partageables » ?
Normes de schéma d’outils, exigences de documentation et empaquetage pour la réutilisation. Tu pratiques AI Agents avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer AI Agents ?
Aucune expérience préalable n'est requise. AI Agents sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.
Combien de temps prend la leçon « Concevoir des outils d’agents partageables » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon AI Agents ?
Oui. Chaque leçon AI Agents inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Concevoir des outils d’agents partageables
- Découverte et enregistrement des plug-ins
- Gestion des versions et de la compatibilité des outils
- Construire une place de marché de plug-ins d’agents