Projetando ferramentas de agentes reutilizáveis
Padrões de esquemas de ferramentas, requisitos de documentação e empacotamento para reutilização.
Projetando ferramentas de agentes reutilizáveis é uma aula grátis de AI Agents no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Agents, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Agents inclui 4 aulas no total.
O que torna uma ferramenta compartilhável
Uma ferramenta de agente compartilhável é aquela que outros desenvolvedores podem integrar aos sistemas de seus agentes sem ler o código-fonte. Ela tem um esquema claro e legível por máquina, um README legível por humanos, códigos de erro bem definidos e comportamento previsível. Pense nela como uma biblioteca, não como um script.
Padrões de esquema de ferramentas
Toda ferramenta compartilhável deve ter um esquema que descreva suas entradas, saídas e metadados. O esquema é o contrato entre o autor da ferramenta e o agente que a utiliza. Baseie-o no JSON Schema para obter a máxima compatibilidade com todas as principais estruturas de agentes.
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'])
Códigos de erro
Defina um formato padrão para as respostas de erro. Toda ferramenta deve retornar a mesma estrutura de erro: código, mensagem e detalhes opcionais. Isso permite que o agente trate os erros de forma programática sem conhecer os detalhes internos da ferramenta.
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())Validação de entradas
Valide as entradas em relação ao esquema antes da execução. Utilize jsonschema para realizar a validação automática. Interrompa imediatamente com um erro descritivo, em vez de permitir que entradas inválidas causem falhas enigmáticas no interior da lógica da ferramenta.
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())Exemplos de uso no esquema
Adicione exemplos concretos ao esquema da ferramenta. Os exemplos têm duas finalidades: ajudam as pessoas a entender rapidamente a ferramenta e podem ser inseridos no contexto do agente como demonstrações com poucos exemplos para melhorar a precisão das chamadas de ferramentas.
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']}")
Limitação de taxa nas ferramentas
As ferramentas que chamam APIs externas devem respeitar os limites de taxa. Implemente um limitador de taxa por ferramenta usando um balde de tokens ou uma janela deslizante. Retorne um erro padrão RATE_LIMITED com a quantidade de segundos até uma nova tentativa quando o limite for excedido.
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})Empacotamento como pacote Python
Estruture sua ferramenta como um pacote Python instalável para que outros desenvolvedores possam adicioná-la aos agentes com um único comando pip install. O pacote expõe uma função get_tool_definition() e uma função execute(params) como API pública.
# 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()Escrevendo o README da ferramenta
Um README claro é essencial para a adoção. Inclua: o que a ferramenta faz, o comando de instalação, as chaves de API ou credenciais necessárias, todos os parâmetros com seus tipos e valores padrão, todos os códigos de erro e pelo menos um exemplo completo de uso.
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])Testando uma ferramenta compartilhável
Uma ferramenta compartilhável deve ter testes automatizados que cubram: o fluxo bem-sucedido, cada código de erro, casos-limite (strings vazias, valores máximos) e o comportamento da limitação de taxa. Os testes são documentação: mostram exatamente como a ferramenta se comporta.
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 allowedFormato compatível com chamadas de funções da OpenAI
Para garantir compatibilidade com as APIs nativas de uso de ferramentas da OpenAI e do Claude, certifique-se de que o esquema da ferramenta esteja no formato exato esperado por essas APIs. O método get_openai_schema() converte seu esquema interno para o formato compatível com a 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'])Versionando sua ferramenta
Utilize o versionamento semântico: MAJOR.MINOR.PATCH. Incremente MAJOR quando houver alterações incompatíveis no esquema, MINOR ao adicionar parâmetros opcionais e PATCH para correções de erros. Armazene a versão no esquema e exponha-a por meio 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.1Verificação de conhecimentos
Qual parte do esquema de uma ferramenta compartilhável permite que a estrutura do agente valide automaticamente as entradas antes de chamar a função de execução da ferramenta?
Recapitulação: projetando ferramentas de agente compartilháveis
Principais aprendizados desta lição:
- Esquema: nome, descrição, versão, parâmetros (JSON Schema), retornos, rate_limit
- Códigos de erro: ToolError padrão com código, mensagem e detalhes
- Validação de entradas: jsonschema valida as entradas em relação ao esquema de parâmetros antes da execução
- Exemplos: incluídos no esquema como contexto com poucos exemplos
- Limitação de taxa: janela deslizante com erro RATE_LIMITED e retry_after
- Empacotamento: pacote instalável com pip, com README, testes e versionamento
Próximo tópico: descoberta de plugins e carregamento dinâmico de ferramentas.
Perguntas Frequentes
A aula “Projetando ferramentas de agentes reutilizáveis” é grátis?
Sim — o texto completo de “Projetando ferramentas de agentes reutilizáveis” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Agents, atualize para CoddyKit PRO. O curso de AI Agents inclui 4 aulas no total.
O que vou aprender em “Projetando ferramentas de agentes reutilizáveis”?
Padrões de esquemas de ferramentas, requisitos de documentação e empacotamento para reutilização. Você pratica AI Agents com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar AI Agents?
Nenhuma experiência prévia é necessária. AI Agents no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.
Quanto tempo leva a aula “Projetando ferramentas de agentes reutilizáveis”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de AI Agents?
Sim. Cada aula de AI Agents inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Projetando ferramentas de agentes reutilizáveis
- Descoberta e registro de plug-ins
- Versionamento e compatibilidade de ferramentas
- Construindo um marketplace de plug-ins para agentes