0Pricing
AI Agents · 강의

에이전트 단계 추적 로깅

사후 분석을 위해 각 추론 단계, 도구 호출, 결과를 기록합니다.

에이전트 단계 추적 로깅은(는) CoddyKit의 무료 AI Agents 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Agents 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.

에이전트에 추적 로그 기록이 필수적인 이유

일반 애플리케이션 로그는 오류와 이벤트를 기록합니다. 에이전트 추적 로그는 추론을 기록합니다. 각 단계에서 에이전트가 무엇을 생각했는지, 어떤 도구를 선택했는지, 어떤 인수를 사용했는지, 도구가 무엇을 반환했는지를 기록하는 것입니다.

추적 로그 기록이 없으면 에이전트의 실패를 디버깅하는 일은 계기판이 전혀 없는 자동차의 문제를 진단하는 것과 같습니다. 추측만 할 수 있을 뿐입니다.

Python 로그 기록 모듈 설정하기

Python에 내장된 logging 모듈은 표준 도구입니다. 에이전트 시작 시 타임스탬프, 수준, 메시지를 포함하는 형식으로 구성합니다. 추적 데이터에는 DEBUG 수준을 사용합니다. 운영 환경에서는 이 수준을 끌 수 있습니다.

import logging
import sys

logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s [%(levelname)s] %(name)s: %(message)s',
    datefmt='%H:%M:%S',
    stream=sys.stdout
)

logger = logging.getLogger('myagent')

# Usage:
logger.debug('Step 1: reasoning started')
logger.info('Agent task completed in 5 steps')
logger.warning('Tool returned empty result')
logger.error('Failed to parse tool arguments')

# Output:
# 14:32:01 [DEBUG] myagent: Step 1: reasoning started
# 14:32:03 [INFO] myagent: Agent task completed in 5 steps

각 추론 단계 기록하기

모든 단계의 시작 부분에 핵심 사실을 기록합니다. 단계 번호, LLM이 생성한 추론, 선택한 도구, 전달한 인수를 기록하는 것입니다. 이렇게 하면 에이전트의 의사 결정 과정을 완전히 기록할 수 있습니다.

import logging
import json

logger = logging.getLogger('myagent')

def log_step(step: int, thought: str, tool_name: str, tool_args: dict):
    logger.debug(
        f'Step {step}: '
        f'reasoning="{thought[:100]}" '
        f'tool={tool_name} '
        f'args={json.dumps(tool_args, ensure_ascii=False)[:200]}'
    )

# Example usage in the agent loop:
# log_step(
#     step=1,
#     thought='I need to find the current weather in Tokyo',
#     tool_name='get_weather',
#     tool_args={'city': 'Tokyo', 'unit': 'celsius'}
# )

if __name__ == '__main__':
    import sys
    logging.basicConfig(level=logging.DEBUG, format='%(message)s', stream=sys.stdout)
    log_step(
        step=1,
        thought='I need to find the current weather in Tokyo',
        tool_name='get_weather',
        tool_args={'city': 'Tokyo', 'unit': 'celsius'}
    )

도구 결과 기록하기

각 도구 호출 후 성공 여부와 결과 미리 보기를 기록합니다. 전체 결과를 기록하면 너무 장황할 수 있으므로, 읽기 쉽도록 처음 200자로 잘라 내십시오.

import logging

logger = logging.getLogger('myagent')

def log_tool_result(step: int, tool_name: str, result: str, success: bool):
    status = 'OK' if success else 'ERROR'
    preview = str(result)[:200].replace('\n', ' ')
    logger.debug(
        f'Step {step} result [{status}]: tool={tool_name} '
        f'result_preview="{preview}"'
    )

    if not success:
        logger.warning(f'Tool {tool_name} failed at step {step}')

# Log at the start of the step:
# log_step(step, thought, tool_name, tool_args)
# result = execute_tool(tool_name, tool_args)
# log_tool_result(step, tool_name, result, success=True)

if __name__ == '__main__':
    import sys
    logging.basicConfig(level=logging.DEBUG, format='%(message)s', stream=sys.stdout)
    log_tool_result(1, 'get_weather', '{"temp_c": 18, "condition": "cloudy"}', success=True)
    log_tool_result(2, 'get_weather', 'Connection timed out', success=False)

JSON 형식으로 구조화된 로그 기록하기

일반 텍스트 로그는 읽기 쉽지만 질의하기는 어렵습니다. 구조화된 JSON 로그는 로그 집계 시스템(Datadog, Splunk, CloudWatch)에 수집하여 필터링, 대시보드, 경고에 활용할 수 있습니다.

import logging
import json
import sys

class JSONFormatter(logging.Formatter):
    def format(self, record: logging.LogRecord) -> str:
        log_obj = {
            'timestamp': self.formatTime(record),
            'level': record.levelname,
            'logger': record.name,
            'message': record.getMessage()
        }
        # Add any extra fields attached to the log record
        if hasattr(record, 'step'):
            log_obj['step'] = record.step
        if hasattr(record, 'tool'):
            log_obj['tool'] = record.tool
        return json.dumps(log_obj)

handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(JSONFormatter())
logger = logging.getLogger('agent_trace')
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)

logger.setLevel(logging.DEBUG)
logger.debug('Step 3: tool=search_web', extra={'step': 3, 'tool': 'search_web'})

추가 필드와 함께 로그 기록하기

로그 호출에 extra={}를 전달하면 구조화된 필드를 추가할 수 있습니다. 이러한 필드는 JSON 형식 지정기나 로그 집계 시스템에서 필터링과 분석에 사용할 수 있습니다.

import logging

logger = logging.getLogger('agent_trace')

def log_step_structured(step: int, tool: str, thought: str, args: dict):
    logger.debug(
        f'Step {step}: tool={tool}',
        extra={
            'step': step,
            'tool': tool,
            'thought': thought[:200],
            'tool_args': args
        }
    )

# If using a JSON formatter, this produces:
# {
#   'timestamp': '14:32:01',
#   'level': 'DEBUG',
#   'message': 'Step 3: tool=search_web',
#   'step': 3,
#   'tool': 'search_web',
#   'thought': 'I need to find recent news about...',
#   'args': {'query': 'AI news 2025'}
# }

if __name__ == '__main__':
    import sys
    handler = logging.StreamHandler(sys.stdout)
    handler.setFormatter(logging.Formatter('%(message)s | step=%(step)s tool=%(tool)s'))
    logger.addHandler(handler)
    logger.setLevel(logging.DEBUG)
    log_step_structured(3, 'search_web', 'I need to find recent news about...', {'query': 'AI news 2025'})

파일에 로그 기록하기

운영 환경용 에이전트에서는 나중에 분석할 수 있도록 파일에 로그를 기록합니다. RotatingFileHandler를 사용하여 로그 파일 크기에 상한을 설정하고 디스크가 모두 소진되는 것을 방지합니다.

import logging
from logging.handlers import RotatingFileHandler
import sys

logger = logging.getLogger('myagent')
logger.setLevel(logging.DEBUG)

# Console handler — INFO and above
console = logging.StreamHandler(sys.stdout)
console.setLevel(logging.INFO)
console.setFormatter(logging.Formatter('%(message)s'))

# File handler — DEBUG and above, rotates at 10MB
file_handler = RotatingFileHandler(
    'agent_trace.log',
    maxBytes=10 * 1024 * 1024,  # 10 MB
    backupCount=3
)
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(logging.Formatter(
    '%(asctime)s [%(levelname)s] %(message)s'
))

logger.addHandler(console)
logger.addHandler(file_handler)

logger.info('Agent task completed in 5 steps')
logger.debug('Step 1: reasoning started')

다중 사용자 에이전트의 세션 ID 기록하기

여러 사용자나 작업이 동시에 실행되면 로그가 서로 섞일 수 있습니다. 특정 실행의 로그를 필터링할 수 있도록 모든 로그 메시지에 세션 ID나 작업 ID를 추가합니다.

import logging
import uuid

class SessionLogger:
    def __init__(self, name: str):
        self.logger = logging.getLogger(name)
        self.session_id = str(uuid.uuid4())[:8]

    def debug(self, msg: str, **kwargs):
        self.logger.debug(f'[session={self.session_id}] {msg}', **kwargs)

    def info(self, msg: str, **kwargs):
        self.logger.info(f'[session={self.session_id}] {msg}', **kwargs)

    def error(self, msg: str, **kwargs):
        self.logger.error(f'[session={self.session_id}] {msg}', **kwargs)

# Each agent run gets its own logger with a unique session ID
# log = SessionLogger('myagent')
# log.info(f'Starting task: {query}')  # [session=a3f1b290] Starting task: ...

if __name__ == '__main__':
    import sys
    logging.basicConfig(level=logging.INFO, format='%(message)s', stream=sys.stdout)
    log = SessionLogger('myagent')
    log.info(f'Starting task: summarize the quarterly report')

각 단계의 실행 시간 측정하기

병목을 식별할 수 있도록 각 단계 로그에 시간 정보를 추가합니다. 어떤 도구가 가장 느린가요? LLM이 추론하는 데 얼마나 걸리나요? 이 데이터가 최적화의 방향을 제시합니다.

import time
import logging

logger = logging.getLogger('myagent')

def timed_tool_call(tool_name: str, tool_fn, args: dict) -> str:
    start = time.perf_counter()
    try:
        result = tool_fn(**args)
        elapsed = time.perf_counter() - start
        logger.debug(f'Tool {tool_name} completed in {elapsed:.2f}s')
        return result
    except Exception as e:
        elapsed = time.perf_counter() - start
        logger.error(f'Tool {tool_name} failed in {elapsed:.2f}s: {e}')
        raise

# In the agent loop:
# result = timed_tool_call('search_web', search_web, {'query': 'Python'})
# Logs: Tool search_web completed in 1.34s

if __name__ == '__main__':
    import sys
    logging.basicConfig(level=logging.DEBUG, format='%(message)s', stream=sys.stdout)
    def search_web(query):
        return f'3 results for {query}'
    result = timed_tool_call('search_web', search_web, {'query': 'Python'})
    print('Tool result:', result)

완전한 단계 추적 패턴

다음은 에이전트 단계에 사용할 수 있는 완전한 운영 환경용 추적 로그 기록 패턴입니다. 모든 단계에서 단계 번호, 추론, 도구 선택, 인수, 결과 미리 보기, 실행 시간을 기록하므로 에이전트 실행을 전체적으로 파악할 수 있습니다.

import time
import logging
import json

logger = logging.getLogger('myagent')

def trace_step(step_num: int, thought: str, tool: str, args: dict, execute_fn):
    # Log decision
    logger.debug(
        f'Step {step_num}: thought="{thought[:80]}" tool={tool} '
        f'args={json.dumps(args)[:100]}'
    )

    # Execute with timing
    t0 = time.perf_counter()
    try:
        result = execute_fn(tool, args)
        elapsed = time.perf_counter() - t0
        preview = str(result)[:100].replace('\n', ' ')
        logger.debug(f'Step {step_num} done in {elapsed:.2f}s: "{preview}"')
        return result
    except Exception as e:
        elapsed = time.perf_counter() - t0
        logger.error(f'Step {step_num} failed in {elapsed:.2f}s: {e}')
        return f'ERROR: {e}'

if __name__ == '__main__':
    import sys
    logging.basicConfig(level=logging.DEBUG, format='%(message)s', stream=sys.stdout)
    def execute_fn(tool, args):
        return f'42 (from {tool})'
    trace_step(1, 'I should compute the answer', 'calculator', {'expr': '6*7'}, execute_fn)

운영 환경에서 로그 끄기

debug 추적 로그에는 민감한 데이터(질의, API 응답)가 포함되며 매우 장황할 수 있습니다. 운영 환경에서는 로그 수준을 INFO 또는 WARNING으로 설정하여 디버그 추적을 억제합니다. 환경 변수를 사용하여 수준을 제어하십시오.

import os
import logging
import sys

# Read log level from environment variable
log_level_str = os.environ.get('LOG_LEVEL', 'INFO').upper()
log_level = getattr(logging, log_level_str, logging.INFO)

logging.basicConfig(level=log_level, stream=sys.stdout)
logger = logging.getLogger('myagent')

# Development: LOG_LEVEL=DEBUG python agent.py     -> full traces
# Production:  LOG_LEVEL=WARNING python agent.py  -> only warnings/errors
# Default:     LOG_LEVEL not set                  -> INFO level

logger.debug('This only appears in DEBUG mode')
logger.info('This appears in INFO and DEBUG modes')
logger.warning('This always appears')

지식 확인: 추적 로그 기록

에이전트 단계의 추적 로그 기록에 대한 이해도를 확인합니다.

복습: 에이전트 단계의 추적 로그 기록

이제 에이전트를 위한 완전한 추적 로그 기록 전략을 갖추었습니다.

  • logging.basicConfig(level=DEBUG)를 사용하여 추적 수준 로그를 활성화합니다
  • 각 단계에서 단계 번호, 추론, 도구 이름, 인수를 기록합니다
  • 미리 보기와 성공 또는 실패 상태를 함께 도구 결과를 기록합니다
  • 구조화되고 질의 가능한 로그에는 JSON 형식을 사용합니다
  • 다중 사용자 또는 동시 실행 에이전트에는 세션 ID를 추가합니다
  • 느린 단계를 식별할 수 있도록 실행 시간을 추가합니다
  • LOG_LEVEL 환경 변수로 로그의 상세 수준을 제어합니다

자주 묻는 질문

“에이전트 단계 추적 로깅” 강의는 무료인가요?

네 — “에이전트 단계 추적 로깅” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Agents 강의 전체를 잠금 해제할 수 있습니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.

“에이전트 단계 추적 로깅”에서 뭘 배우나요?

사후 분석을 위해 각 추론 단계, 도구 호출, 결과를 기록합니다. 브라우저에서 직접 실행하는 실습 코드로 AI Agents을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

AI Agents을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 AI Agents은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“에이전트 단계 추적 로깅” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 AI Agents 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 AI Agents 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 일반적인 에이전트 반복 과정 실패
  2. 에이전트 단계 추적 로깅
  3. 무한 반복 감지 및 중단
  4. 단계별 디버깅 기법
← AI Agents(으)로 돌아가기