오케스트레이션 디버깅 — AI 여러 개가 엉켰을 때 범인을 찾는 법
RoundPrep 제18화. 시연 날, 슬라이드 다섯 번째에서 행 번호가 안 맞았다. 누가·어떤 입력에·어떤 프롬프트로 갔는지 없으면 멀티에이전트는 범인 찾기 게임이다.
한줄 요약
오케스트레이션 디버깅은 “어느 에이전트가, 어떤 입력을 받아서, 어떤 판단을 내렸는가”를 단계별로 기록해두지 않으면 원인을 찾을 수 없다.
테제
추적 ID 없는 오케스트레이션은, 응급실에서 원인 모르는 쇼크와 같다.
스테이크
장애 나서 재현이 안 되면 박과장은 롤백을 외친다. 서진은 환자 브리핑을 못 받는다.
전환점 — RoundPrep 메모
로그에 프롬프트만 있고 노드 ID가 없어 하루를 태웠다.
본문
원인을 모르는 오진
2016년 IBM Watson이 MD Anderson Cancer Center와의 협업을 종료했을 때, 외부에 알려진 이유 중 하나는 “AI의 치료 권고가 전문가 패널의 의견과 달랐는데, 왜 그런 권고가 나왔는지 설명할 수 없었다”는 것이었다.
AI가 틀린 것도 문제지만, 왜 틀렸는지 모르는 것이 더 큰 문제다.
단일 AI는 틀린 답을 냈어도 “이 프롬프트를 받아서 이 답을 냈다”고 추적할 수 있다. 하지만 멀티 에이전트 시스템은 다르다. 에이전트 A의 출력이 B에게 전달되고, B의 출력이 C에게 가고, C가 최종 답을 냈다. 최종 결과가 잘못됐을 때, 잘못이 A에서 시작된 건지 B에서 시작된 건지, 아니면 C의 판단 자체가 문제인지 알 수 없다.
멀티 에이전트 디버깅이 어려운 이유 3가지
- 비결정론적 동작
같은 입력을 줘도 LLM은 매번 조금씩 다른 출력을 낸다. 버그를 재현하려고 해도 “그때 그 출력”이 다시 나오지 않는다. 개발에서는 버그 재현이 수정의 첫 단계인데, 이것이 원천적으로 어렵다.
- 에러 전파
에이전트 A가 약간 이상한 요약을 냈다. 에이전트 B는 그걸 받아서 그것대로 분석했다. 에이전트 C는 B의 분석을 바탕으로 최종 권고를 냈다. 결과는 크게 틀렸지만 A의 오류는 “약간 이상한 요약” 수준이었다. 원인과 결과 사이의 거리가 멀다.
- 타이밍 문제
병렬로 실행되는 에이전트들 사이에서 순서 문제가 생긴다. 에이전트 A와 B가 동시에 실행되는데, B가 A의 결과를 기다리지 않고 먼저 완료됐다. 이런 타이밍 버그는 로그가 없으면 존재 자체를 인식하기 어렵다.
해결 원칙: 모든 것을 기록한다
오케스트레이션 시스템을 만들 때부터 트레이싱(Tracing) 을 기본으로 설계해야 한다. 나중에 붙이는 것이 아니라 처음부터.
기록해야 할 것들:
| 항목 | 예시 |
|---|---|
| 에이전트 이름 | diagnosis_agent |
| 실행 시각 | 2026-04-02 07:34:21 |
| 입력 | 받은 환자 데이터 요약 |
| 출력 | 생성한 감별진단 목록 |
| 소요 시간 | 3.2초 |
| 사용 모델 | claude-sonnet-4-6 |
| 오류 여부 | 없음 / 오류 메시지 |
이 기록이 있으면 나중에 “7번째 에이전트가 받은 입력이 뭐였나”를 정확히 볼 수 있다.
실전에서 자주 나오는 버그 패턴 4가지
패턴 1 — 컨텍스트 희석
에이전트가 너무 많은 정보를 받아서 중요한 정보를 놓친다.
증상: 초반에 명확히 언급된 중요 정보를 후반 에이전트가 모른다. 원인: 이전 에이전트들의 출력이 쌓이면서 초기 정보가 컨텍스트 후반으로 밀려났다. 대처: 각 에이전트에게는 필요한 정보만 선별해서 전달한다. 전체 히스토리를 통째로 넘기지 않는다.
패턴 2 — 확신의 전파
에이전트 A가 “아마도 X일 것 같다”고 불확실하게 표현했는데, 에이전트 B가 이를 “X이다”로 확정적으로 해석해서 다음 단계에 전달한다.
증상: 최종 결과에서 근거 없는 확신이 들어간다. 원인: 에이전트들이 불확실성 표현을 처리하는 방식이 통일되어 있지 않다. 대처: 에이전트 간 인터페이스에 신뢰도 점수를 명시적으로 포함시킨다.
패턴 3 — 무한 재시도
에이전트가 실패했을 때 재시도를 하는데, 재시도 종료 조건이 없어서 계속 반복한다.
증상: 시스템이 멈추지 않고 비용이 계속 발생한다. 원인: 오류 처리 로직에 최대 재시도 횟수가 없다. 대처: 모든 재시도 로직에 상한선을 설정하고, 상한 도달 시 실패로 처리하는 경로를 만든다.
패턴 4 — 조용한 실패 (Silent Failure)
에이전트가 오류를 내지 않고 빈 결과나 기본값을 반환한다. 시스템은 정상 작동 중이라고 인식한다.
증상: 결과가 나오긴 했는데 내용이 의미없거나 비어있다. 원인: 예외 처리가 오류를 삼키고 빈 값을 반환한다. 대처: 빈 결과나 기본값 반환도 경고로 처리한다. “결과 없음”은 성공이 아니다.
LangSmith: 트레이싱 도구
LangChain/LangGraph 기반 시스템이라면 LangSmith 를 쓰면 된다. 별도 코드 없이 각 에이전트 호출을 자동으로 추적하고 시각화한다.
보여주는 것:
- 전체 실행 흐름 (어느 노드에서 어느 노드로 갔는지)
- 각 노드의 입력과 출력
- 소요 시간과 토큰 사용량
- 오류가 발생한 정확한 위치
단일 페이지에서 “이 실행에서 4번째 에이전트가 받은 입력이 뭔지”를 바로 볼 수 있다.
의료 시스템에서 트레이싱이 특히 중요한 이유
의료 AI에서는 “왜 이런 결론이 나왔는가”를 설명할 수 있어야 한다. 규제 요건이기도 하고, 환자 안전 문제이기도 하다.
AI가 “이 환자에게 A 약물보다 B 약물이 더 적합하다”고 판단했다면:
- 어떤 데이터를 근거로 했는가
- 어느 에이전트가 그 판단을 내렸는가
- 해당 에이전트에게 어떤 입력이 들어갔는가
이 추적이 가능해야 의사가 AI 권고를 신뢰하고 검토할 수 있다. 블랙박스 결과는 의료 현장에서 받아들여지지 않는다.
어떤 에이전트가 어디서 실패했는지 알았다면, 다음은 그 실패를 자동으로 감지하는 모니터링 → 오케스트레이션 모니터링
에이전트 시스템을 처음 만들 때 테스트를 어떻게 설계하는가 → 오케스트레이션 테스팅
다음 회의 한 줄
혜준: “trace_id는 환자·배치·요청 삼각으로 겹칩니다.”
다음 화
디버깅은 일회성이 아니라 상시 관찰로 이어져야 한다 — 오케스트레이션 모니터링
편집 초안(cu2604021138). 프레임워크·API·임상 규정은 발행일 이후 바뀔 수 있으니 공식 문서와 병원 정책을 기준으로 확인한다.
더 알고 싶다면
🔗 관련 글
- 오케스트레이션 모니터링 — 디버깅 이후 상시 모니터링 체계
- 오케스트레이션 테스팅 — 사전 테스트로 버그를 배포 전에 잡는 방법
- 상태 관리 — 상태 추적으로 어느 단계에서 문제가 생겼는지 확인
- ReAct 패턴 — ReAct 루프가 꼬이는 대표 버그 패턴