프로덕션 환경에서 에이전트 워크플로 실행을 시작할 때 가장 두려워하는 것은 무엇입니까? 답이 틀렸다는 것이 아니라, 왜 틀렸는지 전혀 모르는 것입니다. 감사 로그가 없으면 에이전트는 조정하는 도구, 전달하는 매개변수, 중간 상태 및 최종 결정의 기반이 되는 블랙박스와 같습니다. 모든 것이 불투명합니다.
감사 로그(Audit Log)는 이러한 블랙박스 문제를 해결하기 위해 고안되었습니다. 도구 호출, LLM 입력 및 출력, 상태 전환, 비정상적인 이벤트 등을 포함하여 에이전트 워크플로의 모든 주요 작업을 기록합니다. 이를 통해 사후 검토를 수행하고, 예외를 디버깅하고, 규정 준수 감사 요구 사항을 충족할 수 있습니다.
감사 로그에는 무엇을 기록해야 하나요?
모든 데이터가 기억할 가치가 있는 것은 아닙니다. 핵심 기록 항목은 다섯 가지 범주로 나뉩니다.
- 요청 및 응답: 온도, max_tokens 및 기타 매개변수를 포함하여 각 LLM 호출의 전체 프롬프트 및 완료입니다. 이것을 잃으면 어떤 추론도 재현할 수 없습니다.
- 도구 호출 추적: 에이전트가 호출한 함수 이름, 전달된 매개변수, 반환된 결과 및 소요된 시간입니다. 도구에서 반환된 데이터가 예상 형식이 아닐 때 많은 오류가 발생합니다.
- 상태 변경: 사용자 의도, 수집된 정보, 중간 의사결정 결과 등 워크플로의 주요 변수 값이 변경됩니다.
- 예외 및 재시도: 네트워크 시간 초과, LLM 반환 형식 오류, 예외를 발생시키는 도구 등은 디버깅의 주요 내용입니다.
- 메타데이터: 요청 ID, 타임스탬프, 버전 번호, 에이전트 인스턴스 ID. 여러 상호 작용과 수평적 조사를 상호 연결하는 데 사용됩니다.
실제 프로젝트에서는 LLM 대화만 녹음하고 도구 호출은 완전히 무시하는 팀을 보았습니다. 결과적으로 API 제한으로 인해 전체 워크플로가 중단되었습니다. 알아내는 데 이틀이 걸렸습니다. 도구 호출 기록이 누락되었기 때문입니다.

구축 단계: 로그 구조에서 검색까지
1. 로그 구조 정의
플랫 JSON 형식을 사용하여 이벤트당 하나의 레코드를 사용합니다. 주요 필드: event_id, trace_id(동일한 작업 흐름을 연결하는 데 사용됨), agent_id, event_type(예: llm_call, tool_call, state_change, error), timestamp, payload.
너무 깊게 중첩하지 마십시오. 그렇지 않으면 쿼리 성능이 급격히 떨어집니다. 컬럼형 스토리지(ClickHouse 등)나 구조화된 로그 서비스(Seq, Loki 등)를 사용하는 것이 좋습니다.
2. 숨기기 전략
모든 변수를 기록하려고 하지 마십시오. 이렇게 하면 저장 비용이 낮아지고 분석이 어려워집니다. 우선순위 기록:
- 각 LLM 호출의 입력 및 출력(큰 텍스트를 제한하기 위해 잘림 기능을 켤 수 있음)
- 각 도구 호출의 매개변수 및 반환 결과
- 워크플로우 시작 및 종료(최종 출력 및 소요 시간 기록)
- 모든 예외 또는 재시도 이벤트
숨겨진 코드는 일반적으로 데코레이터 패턴 또는 AOP를 사용하여 에이전트 프레임워크에 삽입됩니다. LangChain을 예로 들면, CallbackHandler, on_llm_start, on_tool_start 및 기타 후크에 로그를 작성할 수 있습니다.
3. 보관 및 보유 정책
감사 로그는 메모리에만 저장할 수 없으며, 그렇지 않으면 종료 시 손실됩니다. 최소한 로컬 디스크에 쓰기(압축은 매일 순환), 선택적으로 S3 또는 ES에 동기화합니다. 보존 기간은 규정 준수 요구 사항(일반적으로 90~180일)을 기준으로 하며, 오래된 데이터는 콜드 스토리지에 보관됩니다.
4. 검색 및 시각화
로그는 확인할 수 있는 경우에만 의미가 있습니다. Trace_id, 시간 범위, 이벤트 유형 및 Agent_id별 필터링을 지원하는 간단한 쿼리 인터페이스를 구축합니다. "지난 수요일에 워크플로 X가 왜 실패했나요?"와 같은 자연어 쿼리를 사용할 수 있다면 더욱 좋을 것입니다.

가장 들어가기 쉬운 함정
제가 가장 많이 보는 문제는 로그 차단 워크플로입니다. 많은 사람들이 원격 데이터베이스에 동기적으로 씁니다. 네트워크가 혼잡하면 에이전트 응답이 느려지거나 시간 초과가 발생합니다. 해결책은 비동기적으로 작성하는 것입니다. 즉, 로컬 메모리 버퍼 큐가 먼저 작성되고 백그라운드 스레드가 일괄적으로 플러시됩니다. 대기열이 가득 찬 경우 기본 프로세스에 영향을 미치기보다는 로그를 잃는 것이 더 낫습니다. 최소한 로그가 손실되어도 여전히 실행될 수 있으며 작업 흐름이 중단되면 아무것도 찾을 수 없습니다.
두 번째 함정은 로그가 너무 많아 스토리지 폭발로 이어진다는 것입니다. 특히 각 LLM 호출은 하루에 GB에 달하는 전체 대화를 녹음합니다. 해결 방법: 지난 X일의 원본 로그만 보관하고, 집계 및 요약 후에 이전 데이터를 삭제합니다. 또한 키 페이로드만 기록되고 긴 시스템 프롬프트가 제거됩니다.
세 번째 함정은 로그에 추적 ID가 없다는 것입니다. 연관된 컨텍스트가 없으면 수천 개의 로그가 파일에 흩어져 있으며 어떤 로그가 동일한 워크플로우에 속하는지 알 수 없습니다. 추적 ID는 워크플로가 시작되고 모든 하위 호출을 통해 전달될 때 생성되어야 합니다.
실제 시나리오: 실패한 도구 호출
사용자 주문 쿼리를 담당하는 에이전트가 있다고 가정해 보겠습니다. get_order(id) 도구를 호출하지만 서버가 500 오류를 반환합니다. 감사 로그에는 다음이 기록되어야 합니다.
- 이벤트 종류 :
tool_call_start, 파라미터 :{order_id: "123"} - 이벤트 유형:
tool_call_error, 반환:{status: 500, error: "Internal Server Error"} - 이후 Agent는 재시도(또는 전략 변경) 후
tool_call_retry,tool_call_end을 기록합니다.
감사 로그가 없으면 이 500 오류는 LLM에 의해 조용히 무시됩니다. 사용자에게는 "쿼리 실패"라는 메시지가 표시되며 개발자는 이것이 에이전트 코드 문제인지 백엔드 인터페이스 문제인지 알 수 없습니다.
대체 계획: 표준 계획이 실패하는 경우
팀의 리소스가 제한되어 있고 독립적인 로그 시스템을 구축할 수 없는 경우 다운그레이드하여 LLM 자체를 "감사"에 사용할 수 있습니다. 구체적인 방법은 각 작업 단계 후에 에이전트가 현재 상태를 자연어로 요약하고 이를 임시 변수에 쓰도록 하는 것입니다. 워크플로가 끝나면 에이전트는 전체 로그를 출력해야 합니다. 신뢰할 수는 없지만(상담원이 뭔가를 생략하거나 구성할 수 있음) 아무것도 없는 것보다는 낫습니다.
또 다른 보다 성숙한 다운그레이드 솔루션은 기존 비즈니스 로그 + 요청 ID를 재사용하는 것입니다. 즉, 각 에이전트 상호작용의 Trace_id를 비즈니스 데이터베이스의 요청 로그 테이블에 기록하고 백엔드 서비스가 호출 링크 자체를 기록하도록 하는 것입니다. 단점은 침입성이 높지만 추가 인프라가 필요하지 않다는 것입니다.
##드디어
감사 로깅은 선택 사항이 아닙니다. 에이전트 워크플로가 실제 사용자 요청 처리를 시작하는 것이 유일한 문제 해결 창입니다. 먼저 로그를 설정한 다음 온라인에 접속하세요. 그렇지 않으면 조만간 재작업하는 데 몇 배의 시간이 걸릴 것입니다.

아직 댓글이 없습니다