25분
Tool 테스트 전략: 현장 배포 전 필수 검증
Day 2: Tool 정의 & Function Calling
Tool 테스트 전략: 현장 배포 전 필수 검증
AI Agent 기초 > Day 2: Tool 정의 & Function Calling
학습 목표
Tool을 현장 배포 전 체계적으로 테스트하는 방법을 안다 엣지 케이스와 에러 시나리오를 미리 식별한다 실제 MES/ERP 연동 시 주의사항을 이해한다
"데모에서는 됐는데..."
Agent를 만들고 데모를 한다. "CNC-001 상태 알려줘" - 잘 된다. "매뉴얼에서 E-4072 찾아줘" - 잘 된다.
박수를 받고 배포한다.
현장 반장: "cnc-001 알려줘" -> Tool: "cnc-001을 찾을 수 없습니다" (대소문자!)
현장 반장: " CNC-001 " -> Tool: " CNC-001 을 찾을 수 없습니다" (공백!)
현장 반장: "CNC-999 상태" -> Tool: KeyError (존재하지 않는 설비!)
현장 반장: "전체 설비 상태 보여줘" -> Tool: 어떤 Tool을 써야 할지 모름
데모에서 되는 것과 현장에서 되는 것은 다르다.
테스트 레벨 3단계
Level 1: 단위 테스트 (Tool 개별)
def test_get_equipment_status():
"""각 Tool의 기본 동작을 테스트합니다."""
# 정상 케이스
result = get_equipment_status("CNC-001")
assert "CNC-001" in result
assert "가동" in result
# 대소문자 처리
result = get_equipment_status("cnc-001")
assert "CNC-001" in result # 대문자로 변환되어야 함
# 공백 처리
result = get_equipment_status(" CNC-001 ")
assert "CNC-001" in result # 앞뒤 공백 제거되어야 함
# 존재하지 않는 설비
result = get_equipment_status("CNC-999")
assert "찾을 수 없습니다" in result
assert "CNC-001" in result # 등록된 설비 목록 안내
# 빈 문자열
result = get_equipment_status("")
assert "찾을 수 없습니다" in result
print("모든 단위 테스트 통과!")
Level 2: 통합 테스트 (Agent + Tool)
def test_agent_integration():
"""Agent가 Tool을 올바르게 호출하는지 테스트합니다."""
test_cases = [
# (입력, 기대 호출 Tool, 기대 파라미터)
("CNC-001 상태 알려줘", "get_equipment_status", {"equipment_id": "CNC-001"}),
("E-4072 알람 원인이 뭐야?", "search_manual", {"query": "E-4072"}),
("PRESS-005 알람 이력 조회", "get_alarm_history", {"equipment_id": "PRESS-005"}),
("베어링 BRG-002 재고", "check_inventory", {"item_code": "BRG-002"}),
("오늘 생산 실적", "get_production_data", {}),
]
for user_input, expected_tool, expected_args in test_cases:
# Agent 호출 후 어떤 Tool이 호출되었는지 확인
# (실제로는 mock을 사용하거나 로그를 분석)
print(f"입력: {user_input}")
print(f"기대: {expected_tool}({expected_args})")
print()
Level 3: 현장 시나리오 테스트
# 현장 엔지니어들의 실제 질문 패턴
real_world_questions = [
# 자연어 변형
"CNC-003 어때?", # 구어체
"003번 설비 확인해봐", # 번호만 사용
"A라인 전체 괜찮아?", # 라인 단위 질문
# 복합 질문
"CNC-003에 알람 떴는데 부품 재고 있어?", # 2개 Tool 필요
"어제 생산량이랑 불량률 비교해줘", # 분석 요구
# 모호한 질문
"문제 있는 설비?", # 어떤 기준?
"긴급한 거 있어?", # 무엇이 긴급?
"아까 그거 다시 알려줘", # 문맥 의존
# 엣지 케이스
"", # 빈 입력
"ㅋㅋㅋ", # 의미 없는 입력
"삭제해줘", # 위험한 요청
]
실제 MES/ERP 연동 시 주의사항
┌─────────────────────────────────────────┐
│ 실제 연동 체크리스트 │
├─────────────────────────────────────────┤
│ [ ] 인증: API 키 / OAuth 토큰 관리 │
│ [ ] 타임아웃: 3-5초 제한 (MES 느릴 수 있음) │
│ [ ] 재시도: 실패 시 1-2회 재시도 │
│ [ ] 캐싱: 동일 조회 5분간 캐시 │
│ [ ] 로깅: 모든 Tool 호출/결과 기록 │
│ [ ] 권한: 읽기 전용 계정 사용 │
│ [ ] 속도제한: API 호출 횟수 제한 │
│ [ ] 데이터 형식: 날짜/숫자 변환 처리 │
│ [ ] 개인정보: 작업자 이름 등 마스킹 │
│ [ ] 모니터링: 에러율, 응답시간 추적 │
└─────────────────────────────────────────┘
# 실제 연동 패턴 (프로덕션 수준)
import time
import logging
from functools import lru_cache
logger = logging.getLogger("agent_tools")
@lru_cache(maxsize=100)
def _cached_equipment_status(equipment_id: str, _cache_key: int) -> dict:
"""5분 캐시되는 설비 상태 조회 (내부용)"""
return mes_api.get_status(equipment_id)
def get_equipment_status(equipment_id: str) -> str:
"""설비 상태 조회 (프로덕션 버전)"""
equipment_id = equipment_id.upper().strip()
cache_key = int(time.time() // 300) # 5분 단위 캐시
try:
start = time.time()
data = _cached_equipment_status(equipment_id, cache_key)
elapsed = time.time() - start
logger.info(f"Tool called: get_equipment_status({equipment_id}) - {elapsed:.2f}s")
if not data:
return f"설비 '{equipment_id}'를 찾을 수 없습니다."
return format_equipment_status(data)
except ConnectionError:
logger.error(f"MES connection failed for {equipment_id}")
return "MES 시스템에 연결할 수 없습니다. 네트워크를 확인해주세요."
except TimeoutError:
logger.error(f"MES timeout for {equipment_id}")
return "MES 응답 시간이 초과되었습니다. 잠시 후 다시 시도해주세요."
except Exception as e:
logger.error(f"Unexpected error for {equipment_id}: {e}")
return "설비 상태 조회 중 오류가 발생했습니다. 관리자에게 문의해주세요."
핵심: 에러 메시지는 사용자가 이해할 수 있는 한국어로 반환한다. 스택 트레이스나 영어 에러 메시지를 절대 노출하지 않는다.
AI로 학습하기 — 꿀팁
🤖Tool 테스트 체크리스트 자동 생성AI 학습 팁
제조 현장 배포 전 Tool 검증 체크리스트를 구조화하면 팀 전체가 재사용 가능한 QA 템플릿이 됩니다.
제조 현장에 배포할 설비 제어 Tool(예: set_equipment_speed, trigger_maintenance_request)의 현장 배포 전 테스트 체크리스트를 만들어줘. 정상 입력, 경계값, 잘못된 타입, 권한 없는 명령, 설비 오프라인 상태, 동시 호출 충돌 등 엣지 케이스를 포함하고, 각 테스트 케이스에 입력값·예상 출력·판정 기준을 표로 정리해줘.
이 팁이 도움이 됐나요?