3

Agent 모니터링: 블랙박스를 투명하게

Day 4: 설비 조회 Agent

학습 목표
  • Agent의 동작을 모니터링하는 방법을 안다
  • 핵심 지표(호출 횟수, 응답 시간, 정확도)를 추적할 수 있다
  • LangSmith를 활용한 Agent 추적을 이해한다

Agent는 블랙박스다

Agent를 배포하면 이런 질문이 온다.

"Agent가 왜 그렇게 답했어?" "어제보다 느려진 것 같은데?" "API 비용이 얼마나 나오는 거야?"

답하려면 모니터링이 필요하다.


핵심 지표 (KPI)

지표설명목표
응답 시간질문~최종 응답< 15초
Tool 호출 수질문당 평균< 5회
궤적 일치율기대한 Tool을 다 불렀고 군더더기가 없었나아래 참조
결과 일치율답에 담긴 값이 데이터와 맞나아래 참조
에러율Tool 실패율< 5%
Token 비용질문당 비용재서 기준을 정한다

캐시 히트율은 지표에서 뺐다. 같은 설비를 몇 번 묻느냐에 따라 달라지는 값이라 Agent의 품질을 재지 못한다. 캐시는 "동일 조회가 API를 부르지 않는가"로 확인한다.


"정확도"를 무엇으로 재나

"정확도 90%"라고 쓰려면 무엇을 정답으로 놓았는지 먼저 정해야 한다. 둘로 나눈다.

무엇을 보나어떻게 채점하나
궤적 평가어떤 Tool을 어떤 인자로 불렀나질문마다 기대 Tool 목록을 미리 적고, 누락과 군더더기를 센다
결과 평가최종 답에 담긴 값답에서 숫자·부품 코드·상태를 뽑아 데이터와 대조한다

두 값은 따로 움직인다. 도구를 다 부르고도 답을 틀리게 쓸 수 있고, 엉뚱한 순서로 부르고도 운 좋게 맞을 수 있다. 20문항짜리 고정 질문 묶음을 만들어 두고 프롬프트를 고칠 때마다 같은 묶음을 돌리는 것이 최소한의 방법이다. 이 대조표가 없으면 "정확도가 올랐다"는 문장은 근거가 없다.


구조적 로깅

import json
import time
from datetime import datetime

class AgentMonitor:
    """Agent 실행을 모니터링합니다."""

    def __init__(self):
        self.sessions = []

    def start_session(self, user_query: str) -> dict:
        return {
            "query": user_query,
            "start_time": time.time(),
            "tool_calls": [],
            "tokens": {"input": 0, "output": 0},
            "errors": [],
        }

    def log_tool_call(self, session: dict, tool_name: str,
                      args: dict, result: str, duration: float,
                      cached: bool):
        session["tool_calls"].append({
            "tool": tool_name,
            "args": args,
            "result_length": len(result),
            "duration_ms": round(duration * 1000),
            "cached": cached,
            "timestamp": datetime.now().isoformat()
        })

    # token_usage는 LLM 응답에서 그대로 꺼낸다:
    #   u = response.usage
    #   token_usage = {"input": u.prompt_tokens, "output": u.completion_tokens}
    # 루프를 돌면 회차마다 더해야 한 질문의 총량이 된다.
    def end_session(self, session: dict, response: str,
                    token_usage: dict):
        session["end_time"] = time.time()
        session["total_time"] = session["end_time"] - session["start_time"]
        session["response_length"] = len(response)
        session["tokens"] = token_usage
        session["tool_count"] = len(session["tool_calls"])
        session["cache_hits"] = sum(
            1 for tc in session["tool_calls"] if tc["cached"]
        )
        self.sessions.append(session)
        return session

    def get_dashboard(self) -> str:
        if not self.sessions:
            return "아직 데이터가 없습니다."

        avg_time = sum(s["total_time"] for s in self.sessions) / len(self.sessions)
        avg_tools = sum(s["tool_count"] for s in self.sessions) / len(self.sessions)
        in_tokens = sum(s["tokens"].get("input", 0) for s in self.sessions)
        out_tokens = sum(s["tokens"].get("output", 0) for s in self.sessions)
        error_count = sum(len(s["errors"]) for s in self.sessions)

        # 입력과 출력은 단가가 다르므로 따로 곱한다.
        # gpt-4o-mini 공개 단가(2026-07 확인): 100만 토큰당 입력 $0.15 / 출력 $0.60
        # 단가는 바뀐다. 모델을 바꾸거나 분기가 지나면 공급자 가격표를 다시 확인한다.
        cost = in_tokens / 1_000_000 * 0.15 + out_tokens / 1_000_000 * 0.60

        return f"""Agent 대시보드 ({len(self.sessions)}개 세션):
  평균 응답 시간: {avg_time:.1f}초
  평균 Tool 호출: {avg_tools:.1f}회
  Token 사용: 입력 {in_tokens:,} / 출력 {out_tokens:,}
  에러 발생: {error_count}건
  예상 비용: ${cost:.4f}"""

LangSmith 연동 (권장)

LangChain을 사용하면 LangSmith로 자동 추적이 가능하다.

# 환경 변수 설정
export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_API_KEY=your_key
export LANGCHAIN_PROJECT=equipment-agent
# 코드 변경 없이 자동 추적!
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
result = agent_executor.invoke({"input": "CNC-003 상태"})

# LangSmith 대시보드에서 확인:
# - 전체 실행 트레이스
# - 각 Tool 호출 상세
# - Token 사용량
# - 에러 발생 위치
# - 응답 시간 분포

LangSmith는 무료 플랜으로도 시작할 수 있다. 다만 이 주차의 실습은 LangSmith 없이도 전부 돌아간다. 위 AgentMonitor처럼 직접 로그를 남기면 같은 정보를 얻을 수 있고, 사내 데이터를 외부로 보내기 어려운 현장에서는 그 편이 현실적이다.


현장 리포트 자동화

# 매일 아침 자동으로 리포트 생성
def daily_report(monitor: AgentMonitor):
    sessions = monitor.sessions  # 최근 24시간

    slow_queries = [s for s in sessions if s["total_time"] > 15]
    error_sessions = [s for s in sessions if s["errors"]]
    heavy_queries = [s for s in sessions if s["tool_count"] > 8]

    report = f"""일일 Agent 리포트 ({datetime.now().strftime('%Y-%m-%d')})

총 질문: {len(sessions)}건
평균 응답: {sum(s['total_time'] for s in sessions) / len(sessions):.1f}초

주의 항목:
  느린 질문(>15초): {len(slow_queries)}건
  에러 발생: {len(error_sessions)}건
  과도한 Tool 호출(>8회): {len(heavy_queries)}건
"""

    if slow_queries:
        report += "\n느린 질문 TOP 3:\n"
        for s in sorted(slow_queries, key=lambda x: -x["total_time"])[:3]:
            report += f"  - {s['query'][:50]} ({s['total_time']:.1f}초)\n"

    return report
AI로 학습하기 — 꿀팁
Agent 모니터링 대시보드 스키마 생성AI 학습 팁

제조 현장 Agent의 핵심 지표를 추적하는 모니터링 로그 스키마와 대시보드 쿼리를 정의해두세요.

제조 현장 AI Agent 모니터링 시스템을 설계해줘. 수집할 핵심 지표(Tool 호출 횟수, 각 Tool 응답 시간, 루프 반복 횟수, 최종 판단 정확도, 오류율)를 JSONL 로그 형식으로 정의하고, 이 로그를 Pandas로 집계해 '일별 Tool별 평균 응답시간'과 '오류 패턴 Top 5'를 출력하는 Python 코드를 작성해줘.
이 팁이 도움이 됐나요?
용어