การกำหนดรุ่นและความเข้ากันได้ของเครื่องมือ
การกำหนดรุ่นเชิงความหมายสำหรับเครื่องมือ ความเข้ากันได้แบบย้อนหลัง และรูปแบบการเลิกใช้
การกำหนดรุ่นและความเข้ากันได้ของเครื่องมือ เป็นบทเรียน AI Agents ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Agents และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดการจัดการเวอร์ชันเครื่องมือจึงสำคัญ
เมื่ออินเทอร์เฟซของเครื่องมือเปลี่ยนแปลง เช่น เปลี่ยนชื่อพารามิเตอร์ เพิ่มฟิลด์ที่จำเป็น หรือเปลี่ยนโครงสร้างค่าที่ส่งคืน เอเจนต์ที่พึ่งพาอินเทอร์เฟซเดิมอาจหยุดทำงานโดยไม่มีการแจ้งเตือน การจัดการเวอร์ชันตามกฎเชิงความหมายและประกาศการเลิกใช้งานช่วยป้องกันปัญหานี้
การกำหนดเวอร์ชันเครื่องมือตามหลักความหมาย
ปฏิบัติตามการกำหนดเวอร์ชันตามหลักความหมาย: MAJOR.MINOR.PATCH เพิ่มค่า MAJOR เมื่อมีการเปลี่ยนแปลงที่ทำให้เข้ากันไม่ได้ (ลบพารามิเตอร์ เปลี่ยนชนิดพารามิเตอร์ หรือเปลี่ยนโครงสร้างค่าที่ส่งคืน) เพิ่มค่า MINOR เมื่อเพิ่มสิ่งที่ยังเข้ากันได้กับเวอร์ชันก่อนหน้า และเพิ่มค่า PATCH เมื่อแก้ไขข้อบกพร่องที่ไม่ส่งผลต่ออินเทอร์เฟซ
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}')การแยกวิเคราะห์และเปรียบเทียบเวอร์ชัน
สร้างเครื่องมืออรรถประโยชน์สำหรับเปรียบเทียบเวอร์ชันเพื่อตรวจสอบความเข้ากันได้ เอเจนต์สามารถประกาศเวอร์ชันเครื่องมือขั้นต่ำที่ต้องใช้ไว้ในการตั้งค่า และรีจิสทรีจะปฏิเสธเครื่องมือที่ไม่เป็นไปตามข้อกำหนด
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}')การกำหนดเวอร์ชันตายตัวในการตั้งค่าเอเจนต์
การตั้งค่าเอเจนต์ควรกำหนดเวอร์ชันขั้นต่ำที่จำเป็นสำหรับการพึ่งพาเครื่องมือแต่ละรายการไว้ตายตัว วิธีนี้ป้องกันไม่ให้เอเจนต์เผลอใช้เครื่องมือเวอร์ชันใหม่กว่าที่เข้ากันไม่ได้เมื่อมีการอัปเดตปลั๊กอิน
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')) # Falseคำเตือนการเลิกใช้งาน
เมื่อต้องลบหรือเปลี่ยนชื่อพารามิเตอร์ ให้ประกาศเลิกใช้งานในเวอร์ชัน MINOR ก่อน โดยยังคงให้ใช้งานได้แต่ส่งคำเตือนการเลิกใช้งานกลับมา จากนั้นจึงลบออกในเวอร์ชัน MAJOR ถัดไป วิธีนี้เปิดโอกาสให้นักพัฒนาเอเจนต์มีเวลาอัปเดต
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')คู่มือการย้ายระบบ
สำหรับการเพิ่มเวอร์ชัน MAJOR ทุกครั้ง ให้เผยแพร่คู่มือการย้ายระบบที่แสดงอย่างชัดเจนว่ามีการเปลี่ยนแปลงอะไรบ้าง พร้อมตัวอย่างโค้ดก่อนและหลัง หากไม่มีคู่มือการย้ายระบบ นักพัฒนาจะไม่สามารถอัปเกรดได้อย่างปลอดภัย
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"])}')ตารางความเข้ากันได้
ตารางความเข้ากันได้จะบันทึกว่าเครื่องมือแต่ละเวอร์ชันเข้ากันได้กับเฟรมเวิร์กเอเจนต์เวอร์ชันใดบ้าง ให้เผยแพร่และดูแลตารางนี้เป็นส่วนหนึ่งของเอกสารประกอบปลั๊กอิน
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)รีจิสทรีเวอร์ชัน
รีจิสทรีเครื่องมือควรเก็บข้อมูลเวอร์ชันของเครื่องมือที่โหลดไว้แต่ละรายการ และแจ้งเตือนเมื่อปลั๊กอินสองตัวมีชื่อเครื่องมือเดียวกันแต่ใช้คนละเวอร์ชัน ให้เลือกเวอร์ชันที่ใหม่กว่า เว้นแต่จะมีข้อจำกัดระบุไว้เป็นอย่างอื่น
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)การจัดการเวอร์ชันไม่ตรงกันอย่างเหมาะสม
เมื่อเอเจนต์เริ่มทำงานแล้วพบว่าเครื่องมือที่จำเป็นไม่เป็นไปตามข้อกำหนดเวอร์ชัน อย่ามองข้ามปัญหาโดยไม่แจ้งเตือน ทางเลือกได้แก่ ล้มเหลวโดยเร็ว (ปลอดภัยที่สุด) ทำงานในโหมดลดความสามารถ (โดยไม่ใช้เครื่องมือนั้น) หรือแจ้งเตือนแล้วทำงานต่อ
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')การสร้างบันทึกการเปลี่ยนแปลงโดยอัตโนมัติ
สร้างบันทึกการเปลี่ยนแปลงจากข้อความคอมมิตใน Git ตามรูปแบบคอมมิตมาตรฐานโดยอัตโนมัติ วิธีนี้ช่วยให้คู่มือการย้ายระบบและบันทึกประจำรุ่นของคุณเป็นปัจจุบันอยู่เสมอ
# 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}')
ไฟล์ล็อกเพื่อการทำซ้ำได้
เช่นเดียวกับ package-lock.json ใน npm ให้ดูแลไฟล์ล็อกเครื่องมือที่บันทึกรุ่นที่แน่นอนของปลั๊กอินแต่ละรายการที่ติดตั้งไว้ เมื่อเอเจนต์เริ่มทำงาน ให้ตรวจสอบว่ารุ่นที่ติดตั้งตรงกับไฟล์ล็อก เพื่อให้การนำไปใช้งานในสภาพแวดล้อมต่าง ๆ สามารถทำซ้ำได้และมีผลลัพธ์ที่คาดการณ์ได้
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)
ตรวจสอบความเข้าใจ
คุณเพิ่มพารามิเตอร์ format ที่ไม่บังคับให้กับเครื่องมือที่มีอยู่ ผู้เรียกใช้งานเดิมไม่ได้ใช้พารามิเตอร์นี้ คุณควรเพิ่มส่วนประกอบของรุ่นใด
สรุป: การกำหนดรุ่นเครื่องมือและความเข้ากันได้
ประเด็นสำคัญจากบทเรียนนี้:
- การกำหนดรุ่นเชิงความหมาย: MAJOR=ทำลายความเข้ากันได้, MINOR=เพิ่มความสามารถ, PATCH=แก้ไขข้อบกพร่อง
- การเลิกใช้งาน: แจ้งเตือนใน MINOR และนำออกใน MAJOR พร้อมระบุการเลิกใช้งานไว้ในผลลัพธ์
- คู่มือการย้ายระบบ: มีตัวอย่างโค้ดก่อนและหลังสำหรับการเพิ่มรุ่น MAJOR ทุกครั้ง
- ตารางความเข้ากันได้: ระบุว่ารุ่นเครื่องมือใดทำงานร่วมกับรุ่นกรอบงานใดได้
- การตรึงรุ่น: การกำหนดค่าของเอเจนต์ระบุข้อจำกัด เช่น
>=1.2.0,<2.0.0 - ปฏิเสธทันที: ปฏิเสธการโหลดเครื่องมือที่ไม่ตรงตามข้อจำกัด
ถัดไป: การสร้างตลาดกลางปลั๊กอินของเอเจนต์สำหรับเผยแพร่ ค้นหา และติดตั้ง
คำถามที่พบบ่อย
บทเรียน “การกำหนดรุ่นและความเข้ากันได้ของเครื่องมือ” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การกำหนดรุ่นและความเข้ากันได้ของเครื่องมือ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Agents ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การกำหนดรุ่นและความเข้ากันได้ของเครื่องมือ”
การกำหนดรุ่นเชิงความหมายสำหรับเครื่องมือ ความเข้ากันได้แบบย้อนหลัง และรูปแบบการเลิกใช้ คุณปฏิบัติ AI Agents ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Agents หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Agents บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “การกำหนดรุ่นและความเข้ากันได้ของเครื่องมือ” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Agents นี้ได้ไหม
ได้ บทเรียน AI Agents ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การออกแบบเครื่องมือเอเจนต์ที่แบ่งปันได้
- การค้นพบและลงทะเบียนปลั๊กอิน
- การกำหนดรุ่นและความเข้ากันได้ของเครื่องมือ
- การสร้างตลาดปลั๊กอินเอเจนต์