Versionamento e compatibilità degli strumenti
Versionamento semantico degli strumenti, compatibilità con le versioni precedenti e pattern di deprecazione.
Versionamento e compatibilità degli strumenti è una lezione AI Agents gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento AI Agents, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso AI Agents include 4 lezioni in totale.
Perché il versionamento degli strumenti è importante
Quando l'interfaccia di uno strumento cambia, ad esempio viene rinominato un parametro, viene aggiunto un campo obbligatorio oppure cambia la struttura di un valore restituito, gli agenti che dipendono dalla vecchia interfaccia si interrompono senza segnalarlo. Il versionamento secondo regole semantiche e gli avvisi di deprecazione impediscono questo problema.
Versionamento semantico degli strumenti
Segua il versionamento semantico: MAJOR.MINOR.PATCH. Incrementi MAJOR in caso di modifiche incompatibili (parametri rimossi, tipi di parametro modificati, struttura dei valori restituiti modificata), MINOR per le aggiunte compatibili con le versioni precedenti e PATCH per le correzioni di bug che non modificano l'interfaccia.
VERSIONING_RULES = {
'major_bump': [
'Removed a required or optional parameter',
'Renamed an existing parameter',
'Changed parameter type (e.g., string -> object)',
'Changed response field names or types',
'Removed a response field',
'Changed error code values'
],
'minor_bump': [
'Added an optional parameter',
'Added a new response field',
'Added a new tool to the plugin'
],
'patch_bump': [
'Fixed a bug without interface change',
'Improved error messages',
'Performance improvement',
'Updated documentation'
]
}
for bump_type, examples in VERSIONING_RULES.items():
print(f'{bump_type}:')
for ex in examples[:2]:
print(f' - {ex}')Analisi e confronto delle versioni
Implementi utilità per confrontare le versioni e verificarne la compatibilità. Un agente può dichiarare nella propria configurazione la versione minima richiesta di uno strumento e il registro rifiuta gli strumenti che non soddisfano tale requisito.
from functools import total_ordering
@total_ordering
class Version:
def __init__(self, version_str: str):
parts = version_str.strip().split('.')
if len(parts) != 3 or not all(p.isdigit() for p in parts):
raise ValueError(f'Invalid version: {version_str}')
self.major, self.minor, self.patch = map(int, parts)
def __str__(self):
return f'{self.major}.{self.minor}.{self.patch}'
def __eq__(self, other):
return (self.major, self.minor, self.patch) == (other.major, other.minor, other.patch)
def __lt__(self, other):
return (self.major, self.minor, self.patch) < (other.major, other.minor, other.patch)
def is_compatible_with(self, required: 'Version') -> bool:
"""Compatible if same major version and >= required minor.patch"""
return self.major == required.major and self >= required
v = Version('2.3.1')
required = Version('2.1.0')
print(f'{v} compatible with {required}: {v.is_compatible_with(required)}')
print(f'Is newer: {v > required}')Blocco delle versioni nella configurazione dell'agente
Le configurazioni degli agenti dovrebbero specificare la versione minima richiesta per ogni dipendenza da uno strumento. In questo modo si impedisce che un agente utilizzi accidentalmente una versione più recente e incompatibile dello strumento quando il plugin viene aggiornato.
AGENT_TOOL_REQUIREMENTS = {
'get_weather': '>=1.2.0',
'search_knowledge_base': '>=3.0.0',
'send_email': '>=2.1.0,<3.0.0' # exclude major-version bump
}
def parse_version_constraint(constraint: str) -> list:
"""
Parses constraints like '>=1.2.0,<3.0.0'
Returns list of (operator, Version) tuples
"""
ops = {'>=': lambda a, b: a >= b, '>': lambda a, b: a > b,
'<=': lambda a, b: a <= b, '<': lambda a, b: a < b,
'==': lambda a, b: a == b}
parts = [p.strip() for p in constraint.split(',')]
parsed = []
for part in parts:
for op_str, op_fn in ops.items():
if part.startswith(op_str):
parsed.append((op_fn, Version(part[len(op_str):])))
break
return parsed
def satisfies_constraint(tool_version: str, constraint: str) -> bool:
v = Version(tool_version)
rules = parse_version_constraint(constraint)
return all(op(v, required) for op, required in rules)
print(satisfies_constraint('2.3.0', '>=2.1.0,<3.0.0')) # True
print(satisfies_constraint('3.0.0', '>=2.1.0,<3.0.0')) # FalseAvvisi di deprecazione
Quando rimuove o rinomina un parametro, lo renda obsoleto innanzitutto in una versione MINOR: continui a supportarlo, ma emetta un avviso di deprecazione nella risposta. Lo rimuova solo nella versione MAJOR successiva. In questo modo gli sviluppatori degli agenti hanno il tempo di aggiornare il codice.
import warnings
def execute_get_weather(params: dict) -> dict:
# Handle deprecated parameter 'temp_unit' -> replaced by 'units'
if 'temp_unit' in params:
warnings.warn(
'Parameter temp_unit is deprecated since v1.3.0. '
'Use units instead. Will be removed in v2.0.0.',
DeprecationWarning,
stacklevel=2
)
params = dict(params)
params['units'] = params.pop('temp_unit')
# Include deprecation notice in response
result = _fetch_weather(params['city'], params.get('units', 'celsius'))
if 'temp_unit' in params:
result['_deprecation_warnings'] = [
'temp_unit deprecated; use units'
]
return result
# When calling deprecated param:
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
# result = execute_get_weather({'city': 'London', 'temp_unit': 'celsius'})
print('Deprecation warnings would be captured here')Guide alla migrazione
Per ogni incremento della versione MAJOR, pubblichi una guida alla migrazione che mostri esattamente che cosa è cambiato e fornisca esempi di codice prima e dopo. Senza una guida alla migrazione, gli sviluppatori non possono eseguire l'aggiornamento in sicurezza.
MIGRATION_GUIDES = {
'1.x_to_2.0': {
'summary': 'Response structure changed: temperature is now nested under data{}',
'breaking_changes': [
{
'description': 'temperature field moved',
'before': 'result["temperature"]',
'after': 'result["data"]["temperature"]'
},
{
'description': 'temp_unit parameter removed',
'before': 'execute({"city": "London", "temp_unit": "celsius"})',
'after': 'execute({"city": "London", "units": "celsius"})'
}
],
'migration_steps': [
'1. Update parameter name: temp_unit -> units',
'2. Update response access: result["temperature"] -> result["data"]["temperature"]',
'3. Run your test suite against v2.0.0'
]
}
}
for guide_key, guide in MIGRATION_GUIDES.items():
print(f'Migration guide {guide_key}:')
print(f' {guide["summary"]}')
print(f' Steps: {len(guide["migration_steps"])}')Matrice di compatibilità
Una matrice di compatibilità documenta quali versioni dello strumento sono compatibili con quali versioni del framework dell'agente. La pubblichi e la mantenga come parte della documentazione del plugin.
COMPATIBILITY_MATRIX = {
'weather-tools': {
'1.x': {'framework_min': '0.8.0', 'framework_max': '0.x.x', 'status': 'EOL'},
'2.x': {'framework_min': '1.0.0', 'framework_max': '1.x.x', 'status': 'supported'},
'3.x': {'framework_min': '2.0.0', 'framework_max': None, 'status': 'latest'}
}
}
def check_compatibility(
plugin_name: str,
tool_version: str,
framework_version: str
) -> dict:
matrix = COMPATIBILITY_MATRIX.get(plugin_name, {})
major = tool_version.split('.')[0] + '.x'
row = matrix.get(major)
if not row:
return {'compatible': False, 'reason': 'Version not in matrix'}
fw = Version(framework_version)
min_fw = Version(row['framework_min'])
compatible = fw >= min_fw
return {'compatible': compatible, 'status': row['status'],
'min_framework': row['framework_min']}
result = check_compatibility('weather-tools', '2.3.0', '1.2.0')
print(result)Registro delle versioni
Il registro degli strumenti dovrebbe memorizzare le informazioni sulla versione di ogni strumento caricato e avvisare quando due plugin forniscono lo stesso nome di strumento con versioni diverse. Preferisca le versioni più recenti, a meno che un vincolo non specifichi diversamente.
class VersionedToolRegistry(ToolRegistry):
def register_tool(self, name, schema, execute_fn, plugin_name):
if name in self._tools:
existing_v = Version(self._tools[name]['schema'].get('version', '0.0.0'))
new_v = Version(schema.get('version', '0.0.0'))
if new_v > existing_v:
print(f'Upgrading tool {name}: {existing_v} -> {new_v}')
else:
print(f'Keeping tool {name} v{existing_v} '
f'(skipping older v{new_v} from {plugin_name})')
return
super().register_tool(name, schema, execute_fn, plugin_name)
def get_version(self, tool_name: str) -> str:
tool = self._tools.get(tool_name)
if not tool:
return None
return tool['schema'].get('version', 'unknown')
def check_requirement(self, tool_name: str, constraint: str) -> bool:
v = self.get_version(tool_name)
if not v:
return False
return satisfies_constraint(v, constraint)Gestione corretta delle incompatibilità di versione
Quando un agente viene caricato e uno strumento richiesto non soddisfa il vincolo di versione, non lo ignori senza segnalarlo. Le opzioni sono: interrompere subito l'esecuzione (la scelta più sicura), operare in modalità degradata (senza lo strumento) oppure mostrare un avviso e continuare.
class VersionCheckResult:
def __init__(self):
self.satisfied = []
self.unsatisfied = []
self.missing = []
def check_all_requirements(
requirements: dict,
registry
) -> VersionCheckResult:
result = VersionCheckResult()
for tool_name, constraint in requirements.items():
installed_v = registry.get_version(tool_name)
if installed_v is None:
result.missing.append(tool_name)
elif not satisfies_constraint(installed_v, constraint):
result.unsatisfied.append({
'tool': tool_name,
'required': constraint,
'installed': installed_v
})
else:
result.satisfied.append(tool_name)
return result
def start_agent_with_version_check(requirements, registry):
check = check_all_requirements(requirements, registry)
if check.missing:
raise RuntimeError(f'Missing tools: {check.missing}')
if check.unsatisfied:
for item in check.unsatisfied:
print(f'VERSION MISMATCH: {item["tool"]} '
f'requires {item["required"]}, got {item["installed"]}')
raise RuntimeError('Tool version requirements not satisfied')
print('All tool requirements satisfied')Automazione del changelog
Generi automaticamente un changelog dai messaggi dei commit git utilizzando il formato conventional commit. In questo modo, le guide alla migrazione e le note di rilascio sono sempre aggiornate.
# Conventional commit format:
# feat!: (major) remove temp_unit parameter
# feat: (minor) add 'humidity_pct' to response
# fix: (patch) handle API timeout correctly
# docs: update README
import subprocess
def generate_changelog_from_git(
from_tag: str = 'v1.2.0',
to_tag: str = 'HEAD'
) -> dict:
try:
log = subprocess.check_output(
['git', 'log', f'{from_tag}..{to_tag}',
'--oneline', '--pretty=format:%s'],
text=True
).strip().split('\n')
except subprocess.CalledProcessError:
return {'error': 'git log failed'}
changelog = {'breaking': [], 'features': [], 'fixes': [], 'docs': []}
for msg in log:
if msg.startswith('feat!'):
changelog['breaking'].append(msg[5:].strip())
elif msg.startswith('feat:'):
changelog['features'].append(msg[5:].strip())
elif msg.startswith('fix:'):
changelog['fixes'].append(msg[4:].strip())
elif msg.startswith('docs:'):
changelog['docs'].append(msg[5:].strip())
return changelog
if __name__ == '__main__':
subprocess.check_output = lambda *a, **k: (
"feat!: remove temp_unit parameter\n"
"feat: add humidity_pct to response\n"
"fix: handle API timeout correctly\n"
"docs: update README"
)
changelog = generate_changelog_from_git()
print('Changelog:')
for section, items in changelog.items():
print(f' {section}: {items}')
File di lock per la riproducibilità
Come package-lock.json in npm, mantenga un file di lock dello strumento che registri la versione esatta di ogni plugin installato. Quando l'agente si avvia, verifichi che le versioni installate corrispondano a quelle nel file di lock, garantendo deployment riproducibili e prevedibili in ambienti diversi.
import json
import os
LOCK_FILE = '.tool-lock.json'
def generate_lock_file(registry) -> dict:
lock = {
'generated_at': __import__('datetime').datetime.utcnow().isoformat(),
'tools': {}
}
for tool_name, tool_info in registry._tools.items():
lock['tools'][tool_name] = {
'version': tool_info['schema'].get('version', 'unknown'),
'plugin': tool_info['plugin']
}
with open(LOCK_FILE, 'w') as f:
json.dump(lock, f, indent=2)
print(f'Lock file written: {len(lock["tools"])} tools')
return lock
def verify_lock_file(registry) -> bool:
if not os.path.exists(LOCK_FILE):
print('No lock file found — run generate_lock_file() first')
return False
with open(LOCK_FILE) as f:
lock = json.load(f)
for tool_name, locked_info in lock['tools'].items():
installed_v = registry.get_version(tool_name)
if installed_v != locked_info['version']:
print(f'VERSION MISMATCH: {tool_name} locked={locked_info["version"]} installed={installed_v}')
return False
print('Lock file verified: all versions match')
return True
if __name__ == '__main__':
import tempfile
os.chdir(tempfile.gettempdir())
class MockRegistry:
def __init__(self):
self._tools = {'get_weather': {'schema': {'version': '1.2.0'}, 'plugin': 'weather-tools'}}
def get_version(self, name):
return self._tools[name]['schema']['version']
registry = MockRegistry()
generate_lock_file(registry)
verify_lock_file(registry)
Verifica delle conoscenze
Aggiunge un parametro format opzionale a uno strumento esistente. I chiamanti esistenti non lo utilizzano. Quale componente della versione dovrebbe incrementare?
Riepilogo: versionamento e compatibilità degli strumenti
Concetti chiave di questa lezione:
- Versionamento semantico: MAJOR=breaking, MINOR=additive, PATCH=fix
- Deprecazione: avviso in MINOR, rimozione in MAJOR; includere la deprecazione nella risposta
- Guide alla migrazione: esempi di codice prima/dopo per ogni incremento MAJOR
- Matrice di compatibilità: quali versioni dello strumento funzionano con quali versioni del framework
- Vincolo delle versioni: la configurazione dell'agente specifica vincoli come
>=1.2.0,<2.0.0 - Fallimento immediato: rifiutare il caricamento degli strumenti che non rispettano i vincoli
Prossimo argomento: creare un marketplace di plugin per agenti con funzionalità di pubblicazione, ricerca e installazione.
Impara AI Agents con un tutor IA — gratis
Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.
- Corsi
- 60
- Lezioni
- 239
Domande Frequenti
La lezione «Versionamento e compatibilità degli strumenti» è gratuita?
Sì — il testo completo di «Versionamento e compatibilità degli strumenti» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso AI Agents, passa a CoddyKit PRO. Il corso AI Agents include 4 lezioni in totale.
Cosa imparerò in «Versionamento e compatibilità degli strumenti»?
Versionamento semantico degli strumenti, compatibilità con le versioni precedenti e pattern di deprecazione. Eserciti AI Agents con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare AI Agents?
Non è richiesta alcuna esperienza precedente. AI Agents su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.
Quanto tempo richiede la lezione «Versionamento e compatibilità degli strumenti»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione AI Agents?
Sì. Ogni lezione AI Agents include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Progettazione di strumenti condivisibili per agenti
- Individuazione e registrazione dei plugin
- Versionamento e compatibilità degli strumenti
- Creazione di un marketplace di plugin per agenti