การทดสอบตัวแทนโดยอิงการยืนยัน
ตรวจสอบการเรียกใช้เครื่องมือ ขั้นตอนระหว่างทาง และโครงสร้างข้อมูลส่งออกสุดท้าย
การทดสอบตัวแทนโดยอิงการยืนยัน เป็นบทเรียน AI Agents ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Agents และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน
ก้าวพ้นการจับคู่สตริงแบบตรงทั้งหมด
เนื่องจากผลลัพธ์ของ LLM ไม่กำหนดแน่นอน การทดสอบด้วย assert response == 'exact text' จึงเปราะบาง แต่ให้เขียนการตรวจยืนยันที่ตรวจสอบโครงสร้างและเจตนาของการตอบกลับ โดยไม่ขึ้นอยู่กับถ้อยคำที่ตรงกันทุกประการ
การตรวจยืนยันว่ามีการเรียกใช้เครื่องมือ
สำหรับเอเจนต์ที่เรียกใช้ฟังก์ชัน การตรวจยืนยันที่เชื่อถือได้มากที่สุดคือการตรวจสอบว่าเอเจนต์เลือกเรียกใช้เครื่องมือที่ถูกต้องหรือไม่ นี่เป็นการตรวจสอบด้านโครงสร้าง จึงไม่ขึ้นอยู่กับถ้อยคำที่แน่นอนในกระบวนการคิดของ LLM
import json
from unittest.mock import patch, MagicMock
@patch('myagent.client.chat.completions.create')
def test_agent_calls_search_tool(mock_create):
# Mock: agent decides to call search_web
tool_call = MagicMock()
tool_call.function.name = 'search_web'
tool_call.function.arguments = json.dumps({'query': 'Python tutorials'})
mock_create.return_value = MagicMock(
choices=[MagicMock(message=MagicMock(tool_calls=[tool_call]))]
)
response = mock_create() # simulating the agent call
tc = response.choices[0].message.tool_calls
assert tc is not None
assert len(tc) > 0
assert tc[0].function.name == 'search_web'
# --- demo: give unittest.mock.patch a real dotted path to patch ---
import sys
import types
_myagent = types.ModuleType('myagent')
_myagent.client = types.SimpleNamespace(
chat=types.SimpleNamespace(completions=types.SimpleNamespace(create=lambda *a, **k: None))
)
sys.modules['myagent'] = _myagent
test_agent_calls_search_tool()
print('test_agent_calls_search_tool: PASS')
การตรวจยืนยันชื่อเครื่องมือที่ถูกต้อง
นอกจากตรวจสอบว่ามีการเรียกใช้เครื่องมือแล้ว ให้ตรวจสอบว่าชื่อเครื่องมือเฉพาะตรงตามที่คาดไว้ด้วย วิธีนี้ช่วยตรวจจับกรณีที่เอเจนต์เลือกเครื่องมือผิดสำหรับคำค้นหาที่กำหนด
import json
from unittest.mock import MagicMock
def extract_tool_calls(response) -> list:
message = response.choices[0].message
if not message.tool_calls:
return []
return [
{
'name': tc.function.name,
'args': json.loads(tc.function.arguments)
}
for tc in message.tool_calls
]
# In a test:
# calls = extract_tool_calls(mock_response)
# assert calls[0]['name'] == 'get_weather'
# assert calls[0]['args']['city'] == 'Paris'
print('Tool name and argument assertions are the most reliable agent tests')การตรวจยืนยันอาร์กิวเมนต์ของเครื่องมือ
หลังจากตรวจสอบชื่อเครื่องมือแล้ว ให้ตรวจสอบว่าอาร์กิวเมนต์ถูกต้อง เอเจนต์ต้องไม่เพียงเลือกเครื่องมือที่ถูกต้องเท่านั้น แต่ยังต้องใส่พารามิเตอร์ที่ถูกต้องจากคำขอของผู้ใช้ด้วย
import json
from unittest.mock import patch, MagicMock
@patch('myagent.client.chat.completions.create')
def test_weather_tool_gets_correct_city(mock_create):
tool_call = MagicMock()
tool_call.function.name = 'get_weather'
tool_call.function.arguments = json.dumps({'city': 'Tokyo', 'unit': 'celsius'})
mock_create.return_value = MagicMock(
choices=[MagicMock(message=MagicMock(tool_calls=[tool_call]))]
)
response = mock_create()
args = json.loads(response.choices[0].message.tool_calls[0].function.arguments)
assert args['city'] == 'Tokyo'
assert args.get('unit') in ['celsius', 'fahrenheit', None] # flexible
# --- demo: give unittest.mock.patch a real dotted path to patch ---
import sys
import types
_myagent = types.ModuleType('myagent')
_myagent.client = types.SimpleNamespace(
chat=types.SimpleNamespace(completions=types.SimpleNamespace(create=lambda *a, **k: None))
)
sys.modules['myagent'] = _myagent
test_weather_tool_gets_correct_city()
print('test_weather_tool_gets_correct_city: PASS')
การตรวจสอบเอาต์พุตด้วย JSON Schema
เมื่อเอเจนต์ส่งคืน JSON ที่มีโครงสร้าง ให้ตรวจสอบผลลัพธ์เทียบกับ JSON Schema เพื่อให้แน่ใจว่าฟิลด์ที่จำเป็นมีอยู่ครบและมีชนิดข้อมูลถูกต้อง ไลบรารี jsonschema ช่วยให้ทำเช่นนี้ได้ง่าย
# pip install jsonschema
import jsonschema
AGENT_RESPONSE_SCHEMA = {
'type': 'object',
'required': ['answer', 'sources', 'confidence'],
'properties': {
'answer': {'type': 'string', 'minLength': 1},
'sources': {
'type': 'array',
'items': {'type': 'string', 'format': 'uri'}
},
'confidence': {'type': 'number', 'minimum': 0, 'maximum': 1}
}
}
def test_agent_output_schema(agent_output: dict):
try:
jsonschema.validate(instance=agent_output, schema=AGENT_RESPONSE_SCHEMA)
print('Schema validation passed')
except jsonschema.ValidationError as e:
raise AssertionError(f'Invalid agent output: {e.message}')การตรวจยืนยันการมีอยู่ของคีย์เวิร์ด
สำหรับการตอบกลับที่เป็นข้อความและมีถ้อยคำแตกต่างกันได้ ให้ตรวจสอบว่าแนวคิดหรือคำสำคัญปรากฏอยู่ในผลลัพธ์ วิธีนี้ยืดหยุ่นแต่ยังมีความหมาย — อย่างน้อยคำตอบของเอเจนต์ต้องกล่าวถึงคำที่เกี่ยวข้อง
def assert_keywords_present(text: str, keywords: list, require_all: bool = True):
lower_text = text.lower()
found = [kw.lower() in lower_text for kw in keywords]
if require_all:
missing = [kw for kw, f in zip(keywords, found) if not f]
assert not missing, f'Missing keywords: {missing}'
else:
assert any(found), f'None of {keywords} found in: {text[:100]}'
# Tests
response = 'The capital city of France is Paris, located in western Europe.'
assert_keywords_present(response, ['paris', 'france', 'capital'])
print('All keywords present!') # passes
assert_keywords_present(response, ['spain', 'france'], require_all=False)
print('At least one keyword present!') # passesการตรวจยืนยันรูปแบบการตอบกลับ: การตรวจสอบชนิดข้อมูล
การตรวจยืนยันชนิดข้อมูลทำงานรวดเร็วและเชื่อถือได้ ให้ตรวจสอบว่าเอเจนต์ส่งคืน dict ไม่ใช่ None ฟิลด์ประเภทลิสต์เป็นลิสต์ และฟิลด์ตัวเลขอยู่ในช่วงที่ถูกต้อง
def test_agent_returns_valid_structure(agent_result):
# Type checks
assert isinstance(agent_result, dict), 'Result must be a dict'
assert isinstance(agent_result.get('answer'), str), 'answer must be a string'
assert isinstance(agent_result.get('steps'), list), 'steps must be a list'
# Non-empty checks
assert len(agent_result['answer']) > 0, 'answer must not be empty'
assert len(agent_result['steps']) >= 1, 'must have at least one step'
# Range checks
confidence = agent_result.get('confidence', 0)
assert 0.0 <= confidence <= 1.0, 'confidence must be 0-1'
print('Structural assertions are fast and reliable')การตรวจยืนยัน finish_reason
ฟิลด์ finish_reason บอกเหตุผลที่โมเดลหยุดสร้างผลลัพธ์ การตรวจยืนยันฟิลด์นี้ช่วยตรวจจับปัญหาได้: 'stop' หมายถึงคำตอบเสร็จสมบูรณ์ 'tool_calls' หมายถึงเอเจนต์ต้องการเรียกใช้เครื่องมือ และ 'length' หมายถึงผลลัพธ์ถูกตัดทอน
from unittest.mock import MagicMock
def test_agent_stops_cleanly(mock_response):
finish_reason = mock_response.choices[0].finish_reason
assert finish_reason in ('stop', 'tool_calls'), \
f'Unexpected finish_reason: {finish_reason}'
def test_no_truncation(mock_response):
finish_reason = mock_response.choices[0].finish_reason
assert finish_reason != 'length', \
'Response was truncated — increase max_tokens'
# Example mock for a clean stop
mock = MagicMock()
mock.choices = [MagicMock(finish_reason='stop')]
test_agent_stops_cleanly(mock)
print('finish_reason: stop — clean termination')การตรวจยืนยันจำนวนขั้นตอนในลูป
เอเจนต์ที่ทำงานในลูปควรทำงานเสร็จภายในจำนวนขั้นตอนที่เหมาะสม ให้ตรวจยืนยันว่าเอเจนต์เสร็จสิ้นภายในจำนวนรอบสูงสุดที่กำหนด — วิธีนี้ช่วยตรวจจับลูปไม่สิ้นสุดที่ตัวป้องกัน max_iterations มีไว้เพื่อป้องกัน
def test_agent_completes_in_bounded_steps(mock_agent):
result = mock_agent.run('Search for the weather in Paris')
# Agent should complete within 5 steps
assert result['steps_taken'] <= 5, \
f'Agent took too many steps: {result["steps_taken"]}'
# Agent should produce a final answer, not exit on timeout
assert result['status'] == 'completed', \
f'Agent did not complete: {result["status"]}'
assert result['answer'] is not None
print('Bounding step count prevents runaway agents from passing tests')การทำพารามิเตอร์การทดสอบสำหรับข้อมูลเข้าหลายรูปแบบ
@pytest.mark.parametrize ของ pytest ช่วยให้คุณเรียกใช้การทดสอบเดียวกันกับข้อมูลเข้าหลายรูปแบบ วิธีนี้เหมาะอย่างยิ่งสำหรับการทดสอบว่าเอเจนต์ส่งคำค้นหาประเภทต่าง ๆ ไปยังเครื่องมือที่ถูกต้อง
import pytest
from unittest.mock import patch, MagicMock
import json
@pytest.mark.parametrize('query,expected_tool', [
('What is the weather in Tokyo?', 'get_weather'),
('Calculate 15% of 200', 'calculator'),
('Search for Python books', 'web_search'),
('What time is it in Berlin?', 'get_time'),
])
@patch('myagent.client.chat.completions.create')
def test_agent_tool_routing(mock_create, query, expected_tool):
tool_call = MagicMock()
tool_call.function.name = expected_tool
tool_call.function.arguments = json.dumps({'input': query})
mock_create.return_value = MagicMock(
choices=[MagicMock(message=MagicMock(tool_calls=[tool_call]))]
)
response = mock_create()
actual = response.choices[0].message.tool_calls[0].function.name
assert actual == expected_toolการเขียนตัวช่วยการตรวจยืนยันแบบกำหนดเอง
เมื่อชุดการทดสอบเอเจนต์มีขนาดใหญ่ขึ้น ให้แยกรูปแบบการตรวจยืนยันที่ใช้บ่อยออกมาเป็นตัวช่วย วิธีนี้ทำให้การทดสอบสั้นลง อ่านง่ายขึ้น และดูแลรักษาได้ง่ายขึ้นเมื่อรูปแบบการตอบกลับของเอเจนต์เปลี่ยนแปลง
import json
def assert_tool_called(response, tool_name: str, required_args: dict = None):
message = response.choices[0].message
assert message.tool_calls, 'Expected tool call but got plain text'
names = [tc.function.name for tc in message.tool_calls]
assert tool_name in names, f'Expected {tool_name}, got {names}'
if required_args:
for tc in message.tool_calls:
if tc.function.name == tool_name:
args = json.loads(tc.function.arguments)
for key, val in required_args.items():
assert args.get(key) == val, \
f'Arg {key}: expected {val}, got {args.get(key)}'
# Clean test using the helper:
# assert_tool_called(response, 'get_weather', {'city': 'Paris'})
# --- demo ---
from unittest.mock import MagicMock
tool_call = MagicMock()
tool_call.function.name = 'get_weather'
tool_call.function.arguments = json.dumps({'city': 'Paris'})
response = MagicMock(choices=[MagicMock(message=MagicMock(tool_calls=[tool_call]))])
assert_tool_called(response, 'get_weather', {'city': 'Paris'})
print('assert_tool_called passed: agent called get_weather with city=Paris')
ตรวจสอบความรู้: การทดสอบเอเจนต์โดยใช้การตรวจยืนยัน
ทดสอบความเข้าใจเกี่ยวกับกลยุทธ์การตรวจยืนยันสำหรับการทดสอบเอเจนต์
ทบทวน: การทดสอบเอเจนต์โดยใช้การตรวจยืนยัน
ขณะนี้คุณมีชุดเครื่องมือการตรวจยืนยันที่ครบถ้วนสำหรับการทดสอบเอเจนต์แล้ว:
- ตรวจสอบว่า
tool_callsไม่ว่างเปล่าเมื่อเอเจนต์ควรใช้เครื่องมือ - ตรวจยืนยันชื่อเครื่องมือที่ถูกต้องด้วย
tc.function.name == 'expected_tool' - ตรวจสอบอาร์กิวเมนต์ของเครื่องมือโดยแยกวิเคราะห์
tc.function.argumentsเป็น JSON - ใช้
jsonschema.validate()เพื่อตรวจสอบเอาต์พุตที่มีโครงสร้าง - ใช้การตรวจสอบการมีอยู่ของคีย์เวิร์ดสำหรับการตรวจยืนยันข้อความที่ยืดหยุ่น
- ตรวจสอบ
finish_reasonและจำนวนขั้นตอนสำหรับเอเจนต์ที่ทำงานในลูป - ใช้
@pytest.mark.parametrizeสำหรับสถานการณ์ข้อมูลเข้าหลายรูปแบบ
คำถามที่พบบ่อย
บทเรียน “การทดสอบตัวแทนโดยอิงการยืนยัน” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การทดสอบตัวแทนโดยอิงการยืนยัน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เหตุใดการทดสอบตัวแทนจึงแตกต่าง
- การจำลองการเรียก LLM ในการทดสอบ
- การทดสอบตัวแทนโดยอิงการยืนยัน
- การทดสอบการผสานรวมสำหรับไปป์ไลน์ตัวแทน