การประมวลผลการเรียกใช้เครื่องมือในแอปพลิเคชัน
ตรวจจับ finish_reason tool_calls ในการตอบกลับจาก API แยกชื่อฟังก์ชันและอาร์กิวเมนต์ เรียกใช้ฟังก์ชัน Python ที่เกี่ยวข้อง และส่งผลลัพธ์กลับไปยังโมเดล
การประมวลผลการเรียกใช้เครื่องมือในแอปพลิเคชัน เป็นบทเรียน AI Engineering Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Engineering Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน
ออบเจ็กต์การตอบกลับการเรียกเครื่องมือ
เมื่อโมเดลตัดสินใจเรียกฟังก์ชัน การตอบกลับจาก API จะมีรายการ tool_calls อยู่ในออบเจ็กต์ข้อความ การเรียกเครื่องมือแต่ละครั้งมี id ที่ไม่ซ้ำกัน ชื่อฟังก์ชัน function.name ที่จะเรียก และ function.arguments ซึ่งเป็นสตริง JSON ของอาร์กิวเมนต์ที่โมเดลต้องการส่ง โค้ดของแอปพลิเคชันของคุณมีหน้าที่แยกวิเคราะห์ข้อมูลนี้และเรียกใช้ฟังก์ชัน
from openai import OpenAI
import json
client = OpenAI()
response = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': 'What is the weather in Paris?'}],
tools=tools # defined previously
)
message = response.choices[0].message
if response.choices[0].finish_reason == 'tool_calls':
for tool_call in message.tool_calls:
print('Call ID:', tool_call.id)
print('Function name:', tool_call.function.name)
print('Arguments (JSON string):', tool_call.function.arguments)การแยกวิเคราะห์อาร์กิวเมนต์ของฟังก์ชัน
ฟิลด์ function.arguments เป็นสตริงที่เข้ารหัสเป็น JSON ไม่ใช่ dict ของ Python คุณต้องแยกวิเคราะห์ด้วย json.loads() ควรครอบการทำงานนี้ด้วย try/except เสมอ — บางครั้งโมเดลสร้าง JSON ที่มีรูปแบบไม่ถูกต้องแม้จะมีคำแนะนำจากสคีมา และคุณต้องจัดการกรณีนี้อย่างเหมาะสม
import json
def parse_tool_call(tool_call) -> dict:
'''Parse a tool call's arguments from JSON string to dict.'''
try:
args = json.loads(tool_call.function.arguments)
return args
except json.JSONDecodeError as e:
print(f'Failed to parse arguments for {tool_call.function.name}: {e}')
print(f'Raw arguments: {tool_call.function.arguments}')
return {}
# Usage
tool_call = message.tool_calls[0]
args = parse_tool_call(tool_call)
print('Parsed args:', args) # {'location': 'Paris', 'unit': 'celsius'}การส่งต่อไปยังฟังก์ชันที่ถูกต้อง
ใช้ function.name เพื่อส่งต่อไปยังฟังก์ชัน Python ที่ถูกต้อง รูปแบบที่เป็นระเบียบคือเก็บฟังก์ชันไว้ในพจนานุกรมที่แมปชื่อกับฟังก์ชันที่เรียกใช้ได้ วิธีนี้หลีกเลี่ยงสายโซ่ if/elif ที่เปราะบาง และทำให้เพิ่มเครื่องมือใหม่ในภายหลังได้ง่าย
def get_current_weather(location: str, unit: str = 'celsius') -> str:
# Real implementation calls a weather API
return f'{location}: 18{chr(176)}C, partly cloudy'
def create_calendar_event(title: str, start_time: str, duration_minutes: int, **kwargs) -> str:
return f'Event created: {title} at {start_time} for {duration_minutes} minutes'
# Tool registry: maps function names to callables
TOOL_REGISTRY = {
'get_current_weather': get_current_weather,
'create_calendar_event': create_calendar_event
}
def execute_tool_call(tool_call) -> str:
name = tool_call.function.name
args = parse_tool_call(tool_call)
if name not in TOOL_REGISTRY:
return f'Unknown function: {name}'
try:
result = TOOL_REGISTRY[name](**args)
return str(result)
except Exception as e:
return f'Function {name} raised an error: {str(e)}'การส่งผลลัพธ์กลับไปยังโมเดล
หลังจากเรียกใช้ฟังก์ชันแล้ว คุณต้องส่งผลลัพธ์กลับไปยังโมเดลด้วยการเรียก API ติดตามผล เพิ่มข้อความของผู้ช่วย ซึ่งมี tool_calls อยู่ในบทสนทนา จากนั้นเพิ่มข้อความใหม่ที่มี role='tool' ค่า tool_call_id และผลลัพธ์ของฟังก์ชันเป็นเนื้อหา แล้วจึงเรียก API อีกครั้ง
def run_tool_call_loop(messages: list, tools: list) -> str:
response = client.chat.completions.create(
model='gpt-4o',
messages=messages,
tools=tools
)
message = response.choices[0].message
messages.append(message) # Add assistant's tool_calls message
# Execute all tool calls and collect results
for tool_call in (message.tool_calls or []):
result = execute_tool_call(tool_call)
# Add each tool result as a 'tool' role message
messages.append({
'role': 'tool',
'tool_call_id': tool_call.id,
'content': result
})
# Second API call with results appended
final_response = client.chat.completions.create(
model='gpt-4o',
messages=messages,
tools=tools
)
return final_response.choices[0].message.contentรอบการสนทนาแบบสมบูรณ์
การโต้ตอบด้วยการเรียกเครื่องมือที่สมบูรณ์ประกอบด้วยข้อความสี่รายการในประวัติบทสนทนา ได้แก่ ข้อความของผู้ใช้ ข้อความของผู้ช่วยที่ขอเรียกเครื่องมือ ข้อความผลลัพธ์ของเครื่องมือ และคำตอบสุดท้ายของผู้ช่วยที่นำผลลัพธ์มาประกอบ ความเข้าใจโครงสร้างนี้จำเป็นอย่างยิ่งสำหรับการสร้างผู้ช่วยที่ใช้เครื่องมือและสนทนาได้หลายรอบ
# The full message history for a tool-calling conversation:
conversation = [
{'role': 'user', 'content': 'What is the weather in Tokyo?'},
# Model requests a tool call (added by run_tool_call_loop)
# {'role': 'assistant', 'content': None, 'tool_calls': [...]},
# Application sends tool result back
# {'role': 'tool', 'tool_call_id': 'call_abc123', 'content': 'Tokyo: 22C, sunny'},
# Model produces final human-readable response
# {'role': 'assistant', 'content': 'The weather in Tokyo is 22 degrees Celsius and sunny.'}
]
final_answer = run_tool_call_loop(
[{'role': 'user', 'content': 'What is the weather in Tokyo?'}],
tools
)
print(final_answer)การจัดการกรณีที่ไม่มีการเรียกเครื่องมือ
บางครั้งโมเดลตอบโดยตรงโดยไม่เรียกเครื่องมือใด ๆ — finish_reason จะเป็น 'stop' แทนที่จะเป็น 'tool_calls' ตรวจสอบกรณีนี้เสมอก่อนพยายามประมวลผลการเรียกเครื่องมือ การใช้งานที่มีความทนทานควรจัดการทั้งสองเส้นทางได้อย่างเป็นระเบียบ
def smart_complete(user_message: str) -> str:
messages = [{'role': 'user', 'content': user_message}]
response = client.chat.completions.create(
model='gpt-4o',
messages=messages,
tools=tools
)
choice = response.choices[0]
if choice.finish_reason == 'stop':
# Model answered directly without calling a tool
return choice.message.content
elif choice.finish_reason == 'tool_calls':
# Process tool calls
messages.append(choice.message)
for tc in choice.message.tool_calls:
result = execute_tool_call(tc)
messages.append({'role': 'tool', 'tool_call_id': tc.id, 'content': result})
# Get final answer
final = client.chat.completions.create(model='gpt-4o', messages=messages)
return final.choices[0].message.content
return 'Unexpected finish reason: ' + choice.finish_reasonการตรวจสอบอาร์กิวเมนต์ก่อนเรียกใช้
บางครั้งโมเดลอาจส่งอาร์กิวเมนต์ที่ไม่ผ่านการตรวจสอบตามตรรกะทางธุรกิจ เช่น ระยะเวลาติดลบ อีเมลไม่ถูกต้อง หรือวันที่ในอดีต ให้ตรวจสอบอาร์กิวเมนต์ก่อนเรียกใช้ฟังก์ชันจริง และส่งคืนสตริงข้อผิดพลาดที่อธิบายชัดเจนหากการตรวจสอบไม่ผ่าน จากนั้นโมเดลจะสามารถแก้ไขอาร์กิวเมนต์ในการสนทนารอบถัดไปได้
from pydantic import BaseModel, ValidationError
from datetime import datetime
class CreateEventArgs(BaseModel):
title: str
start_time: str # ISO 8601
duration_minutes: int
def safe_create_event(tool_call) -> str:
try:
raw_args = json.loads(tool_call.function.arguments)
validated = CreateEventArgs(**raw_args)
# Additional business rule
event_time = datetime.fromisoformat(validated.start_time)
if event_time < datetime.now():
return 'Error: start_time must be in the future.'
return create_calendar_event(**validated.dict())
except ValidationError as e:
return f'Invalid arguments: {e}'การบันทึกการโต้ตอบจากการเรียกเครื่องมือ
บันทึกการโต้ตอบจากการเรียกเครื่องมือเสมอเพื่อใช้ในการแก้ไขข้อบกพร่องและวิเคราะห์ข้อมูล ให้บันทึกชื่อฟังก์ชัน อาร์กิวเมนต์ ผลลัพธ์ และเวลาที่ใช้เรียกใช้ ข้อมูลนี้ช่วยให้คุณระบุได้ว่าเครื่องมือใดถูกเรียกบ่อยที่สุด เครื่องมือใดล้มเหลว และโมเดลสร้างรูปแบบอาร์กิวเมนต์แบบใด ซึ่งมีคุณค่าอย่างยิ่งต่อการปรับปรุงสคีมาและการใช้งานฟังก์ชันของคุณ
import time
import logging
logger = logging.getLogger('tool_calls')
def logged_execute(tool_call) -> str:
name = tool_call.function.name
args_str = tool_call.function.arguments
start = time.time()
result = execute_tool_call(tool_call)
elapsed = time.time() - start
logger.info(
'Tool call executed',
extra={
'function': name,
'arguments': args_str,
'result_length': len(result),
'elapsed_ms': round(elapsed * 1000)
}
)
return resultข้อควรพิจารณาด้านความปลอดภัยของการเรียกเครื่องมือ
อย่าเรียกใช้ฟังก์ชันใด ๆ โดยพลการจากผลลัพธ์ของโมเดลโดยไม่ตรวจสอบความถูกต้อง ตรวจสอบให้แน่ใจว่าอนุญาตเฉพาะชื่อฟังก์ชันที่ระบุไว้อย่างชัดเจนใน TOOL_REGISTRY ตรวจสอบอาร์กิวเมนต์ทั้งหมด และตรวจสอบสิทธิ์ก่อนดำเนินการ โมเดลเป็นผู้เรียกที่ไม่น่าเชื่อถือ — คำสั่งอันตรายอาจพยายามเรียกใช้ฟังก์ชันที่ทำลายข้อมูล หากตรรกะการส่งต่อของคุณอนุญาตกว้างเกินไป
- อนุญาตเฉพาะฟังก์ชันที่ระบุไว้อย่างชัดเจนในทะเบียนเครื่องมือ
- ตรวจสอบอินพุตด้วย Pydantic ก่อนเรียกใช้
- กำหนดให้ต้องมีสิทธิ์สำหรับการดำเนินการเขียนหรือลบ
การส่งคืนผลลัพธ์ที่มีโครงสร้างและรายละเอียด
ผลลัพธ์ของเครื่องมือไม่จำเป็นต้องเป็นสตริงธรรมดา คุณสามารถส่งคืนข้อมูลในรูปแบบ JSON ตาราง หรือสรุปได้ การส่งคืนข้อมูลที่มีโครงสร้างเป็น JSON ช่วยให้โมเดลแยกวิเคราะห์และอ้างอิงฟิลด์เฉพาะในคำตอบสุดท้ายได้ สำหรับผลลัพธ์ขนาดใหญ่ ให้ส่งคืนสรุปพร้อมข้อเท็จจริงสำคัญ แทนการใส่ข้อมูลดิบทั้งหมดลงในบริบท
def get_order_status(order_id: str) -> str:
# Fetch from real database
order = {'id': order_id, 'status': 'shipped', 'estimated_delivery': '2024-03-15', 'carrier': 'FedEx', 'tracking': 'FX123456'}
# Return concise summary, not raw DB record
return (
f'Order {order_id}: Status={order["status"]}, '
f'Estimated delivery: {order["estimated_delivery"]}, '
f'Carrier: {order["carrier"]}, Tracking: {order["tracking"]}'
)บทสนทนาหลายรอบที่ใช้เครื่องมือ
รูปแบบที่มีประสิทธิภาพคือบทสนทนาหลายรอบที่โมเดลเรียกใช้เครื่องมือผ่านข้อความของผู้ใช้หลายรายการเพื่อสะสมบริบท ควรรักษาประวัติบทสนทนาเต็มรูปแบบไว้เสมอ รวมถึงการเรียกเครื่องมือและผลลัพธ์ที่ผ่านมา เพื่อให้โมเดลอ้างอิงคำตอบก่อนหน้าได้โดยไม่ต้องเรียกเครื่องมือซ้ำโดยไม่จำเป็น
ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจของคุณเกี่ยวกับการประมวลผลการเรียกเครื่องมือในแอปพลิเคชันของคุณ
สรุปบทเรียน
ในบทเรียนนี้ คุณได้เรียนรู้ว่า อาร์กิวเมนต์ของการเรียกเครื่องมือมาในรูปสตริง JSON ที่ต้องแยกวิเคราะห์ด้วย json.loads() พจนานุกรม TOOL_REGISTRY แมปชื่อฟังก์ชันกับฟังก์ชันที่เรียกใช้ได้เพื่อการส่งต่อที่เป็นระเบียบ และ ผลลัพธ์จะถูกส่งกลับไปยังโมเดลเป็นข้อความที่มี role='tool' พร้อม tool_call_id ที่ตรงกัน บทถัดไป เราจะจัดการกรณีที่โมเดลเรียกใช้หลายฟังก์ชันพร้อมกันด้วยการเรียกฟังก์ชันแบบขนาน
คำถามที่พบบ่อย
บทเรียน “การประมวลผลการเรียกใช้เครื่องมือในแอปพลิเคชัน” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การประมวลผลการเรียกใช้เครื่องมือในแอปพลิเคชัน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Engineering Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การประมวลผลการเรียกใช้เครื่องมือในแอปพลิเคชัน”
ตรวจจับ finish_reason tool_calls ในการตอบกลับจาก API แยกชื่อฟังก์ชันและอาร์กิวเมนต์ เรียกใช้ฟังก์ชัน Python ที่เกี่ยวข้อง และส่งผลลัพธ์กลับไปยังโมเดล คุณปฏิบัติ AI Engineering Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Engineering Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Engineering Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “การประมวลผลการเรียกใช้เครื่องมือในแอปพลิเคชัน” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Engineering Academy นี้ได้ไหม
ได้ บทเรียน AI Engineering Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การกำหนดโครงสร้างฟังก์ชันสำหรับ API
- การประมวลผลการเรียกใช้เครื่องมือในแอปพลิเคชัน
- การเรียกใช้ฟังก์ชันแบบขนาน
- การสร้างส่วนติดต่อฐานข้อมูลด้วยภาษาธรรมชาติ