Agent Architecture Audit(에이전트 아키텍처 감사)
래퍼 계층, 오래된 메모리, 재시도 루프, 전송/렌더링 변형 뒤에 숨은 장애를 찾아내는 에이전트 시스템 진단 워크플로입니다.
활성화 시점
필수 사용:
- 모든 에이전트 또는 LLM 기반 애플리케이션을 프로덕션에 출시할 때
- 도구 호출, 메모리, 다단계 워크플로가 있는 기능을 출시할 때
- 래퍼 계층 추가 후 에이전트 동작이 저하될 때
- 사용자가 "에이전트가 점점 나빠지고 있어요" 또는 "도구가 불안정해요"라고 보고할 때
- 동일 모델이 플레이그라운드에서는 잘 작동하지만 래퍼 안에서는 문제가 발생할 때
- 15분 이상 에이전트 동작을 디버깅했지만 근본 원인을 찾지 못했을 때
특히 중요한 경우:
- 새 프롬프트 계층, 도구 정의, 메모리 시스템을 추가한 경우
- 시스템 내 서로 다른 에이전트가 일관성 없이 동작하는 경우
- 어제까지 잘 작동하던 모델이 오늘 환각(hallucination)을 일으키는 경우
- 응답을 조용히 변형시키는 숨은 복구/재시도 루프가 의심되는 경우
사용하지 말아야 할 경우:
- 일반 코드 디버깅 —
agent-introspection-debugging사용 - 코드 리뷰 — 언어별 리뷰어 에이전트 사용
- 보안 검사 —
security-review또는security-review/scan사용 - 에이전트 성능 벤치마킹 —
agent-eval사용 - 새 기능 작성 — 적절한 워크플로 스킬 사용
12계층 스택
모든 에이전트 시스템에는 이러한 계층이 있으며, 각 계층에서 문제가 발생할 수 있습니다.
| # | 계층 | 문제점 |
|---|---|---|
| 1 | 시스템 프롬프트 | 상충되는 지침, 지침 과다 |
| 2 | 세션 기록 | 이전 회차의 오래된 컨텍스트 주입 |
| 3 | 장기 메모리 | 세션 간 오염, 새 대화에 이전 주제 등장 |
| 4 | 증류(distillation) | 압축된 아티팩트가 의사-사실로 재유입 |
| 5 | 능동적 회상(recall) | 중복 요약 계층이 컨텍스트 낭비 |
| 6 | 도구 선택 | 잘못된 도구 라우팅, 모델이 필수 도구를 건너뜀 |
| 7 | 도구 실행 | 환각 실행 — 호출했다고 주장하지만 실제로 수행하지 않음 |
| 8 | 도구 결과 해석 | 도구 출력을 잘못 읽거나 무시 |
| 9 | 응답 정형화 | 최종 응답의 형식 손상 |
| 10 | 플랫폼 렌더링 | 전송 계층 변형(UI, API, CLI가 유효한 응답을 변형) |
| 11 | 숨은 복구 루프 | 두 번째 LLM 패스를 실행하는 자동 폴백/재시도 에이전트 |
| 12 | 지속성 | 만료된 상태나 캐시된 아티팩트를 최신 증거로 재사용 |
일반적인 장애 패턴
1. 래퍼 회귀(Wrapper Regression)
기본 모델이 올바른 답을 생성하지만, 래퍼 계층이 오히려 성능을 저하시킵니다.
증상:
- 플레이그라운드나 직접 API 호출에서는 잘 작동하지만, 에이전트 안에서는 문제가 발생
- 새로운 프롬프트 계층을 추가했더니 기존 동작이 저하됨
- 에이전트가 확신에 차 보이지만 틀린 답을 자신있게 말함
- "마지막 업데이트 전까지는 잘 작동했어요"
2. 메모리 오염(Memory Contamination)
오래된 주제가 기록, 메모리 검색, 증류를 통해 새 대화로 유출됩니다.
증상:
- 에이전트가 관련 없는 과거 주제를 꺼냄
- 사용자 수정 사항이 반영되지 않음(오래된 메모리가 새 정보를 덮어씀)
- 동일 세션의 아티팩트가 의사-사실로 재유입
- 메모리가 무한히 증가하여 시간이 지남에 따라 응답 품질 저하
3. 도구 규율 실패(Tool Discipline Failure)
프롬프트에는 도구가 선언되어 있지만 코드로 강제되지 않습니다. 모델이 도구를 건너뛰거나 실행을 환각합니다.
증상:
- 프롬프트에 "반드시 도구 X를 사용"이라고 명시했지만, 모델이 호출 없이 답변
- 도구 결과가 올바른 것처럼 보이지만 실제로 실행된 적이 없음
- 서로 다른 도구가 동일한 책임을 두고 경쟁
- 모델이 필요하지 않을 때 도구를 사용하거나, 반드시 사용해야 할 때 건너뜀
4. 렌더링/전송 손상(Rendering/Transport Corruption)
에이전트의 내부 응답은 정확하지만, 플랫폼 계층이 전달 중에 변형시킵니다.
증상:
- 로그에는 정확한 응답이 있지만, 사용자는 깨진 출력을 봄
- 마크다운 렌더링, JSON 파싱, 스트리밍 조각이 유효한 응답을 손상
- 숨은 폴백 에이전트가 전달 전에 응답을 조용히 대체
- 터미널과 UI 간 출력 차이 발생
5. 숨은 에이전트 계층(Hidden Agent Layers)
명시적 계약 없이 자동 복구, 재시도, 요약, 회상 에이전트가 실행됩니다.
증상:
- 내부 생성과 사용자 전달 간 출력 차이 발생
- 사용자가 모르는 두 번째 LLM 패스를 실행하는 "자동 수정" 루프
- 여러 에이전트가 조정 없이 동일한 출력을 수정
- 보이지 않는 계층이 응답을 "다듬거나" "수정"
감사 워크플로
1단계: 범위 설정
감사할 대상을 정의합니다.
- 대상 시스템 — 어떤 에이전트 애플리케이션?
- 진입점 — 사용자가 어떻게 상호작용합니까?
- 모델 스택 — 어떤 LLM과 공급자?
- 증상 — 사용자가 무엇을 보고합니까?
- 시간 범위 — 언제부터 시작되었습니까?
- 감사할 계층 — 12개 중 어떤 계층이 해당됩니까?
2단계: 증거 수집
코드베이스에서 증거를 수집합니다.
- 소스 코드 — 에이전트 루프, 도구 라우터, 메모리 수용, 프롬프트 조립
- 로그 — 과거 세션 추적, 도구 호출 기록
- 설정 — 프롬프트 템플릿, 도구 스키마, 공급자 설정
- 메모리 파일 — SOP, 지식베이스, 세션 아카이브
rg를 사용하여 안티 패턴을 검색합니다.
# 프롬프트 텍스트에만 표현된 도구 요구 사항(코드에는 없음)
rg "must.*tool|必须.*工具|required.*call" --type md
# 검증 없는 도구 실행
rg "tool_call|toolCall|tool_use" --type py --type ts
# 주 에이전트 루프 외부의 숨은 LLM 호출
rg "completion|chat\.create|messages\.create|llm\.invoke"
# 사용자 수정 우선순위 없이 메모리 수용
rg "memory.*admit|long.*term.*update|persist.*memory" --type py --type ts
# 추가 LLM 호출을 실행하는 폴백 루프
rg "fallback|retry.*llm|repair.*prompt|re-?prompt" --type py --type ts
# 자동 출력 변형
rg "mutate|rewrite.*response|transform.*output|shap" --type py --type ts
3단계: 장애 매핑
각 발견 사항에 대해 다음을 문서화합니다.
- 증상 — 사용자가 보는 현상
- 메커니즘 — 래퍼가 어떻게 이를 유발하는지
- 소스 계층 — 12개 중 어떤 계층인지
- 근본 원인 — 가장 깊은 원인
- 증거 — 파일:줄 또는 로그:행 참조
- 신뢰도 — 0.0 ~ 1.0
4단계: 수정 전략
기본 수정 순서(코드 우선, 프롬프트 우선 아님):
- 도구 요구 사항 코드 게이트 — 프롬프트 텍스트가 아닌 코드로 강제
- 숨은 복구 에이전트 제거 또는 축소 — 계약과 함께 명시적으로 폴백 설정
- 컨텍스트 중복 줄이기 — 프롬프트 + 히스토리 + 메모리 + 증류를 통해 동일 정보 제공 방지
- 메모리 수용 조건 강화 — 에이전트 주장보다 사용자 수정 우선
- 증류 트리거 조건 강화 — 압축해서는 안 될 것을 압축하지 않음
- 렌더링 변형 줄이기 — 변형하지 말고 통과(pass-through)
- 타입이 있는 JSON 인벨롭으로 전환 — 자유 형식 산문 대신 구조화된 내부 흐름
심각도 모델
| 수준 | 의미 | 조치 |
|---|---|---|
critical | 에이전트가 잘못된 운영 동작을 확신하며 생성 가능 | 다음 릴리스 전에 수정 |
high | 에이전트가 정확성이나 안정성을 자주 저하시킴 | 이번 스프린트에 수정 |
medium | 정확성은 대체로 유지되나 출력이 취약하거나 낭비적임 | 다음 주기로 계획 |
low | 주로 미관상 또는 유지보수 문제 | 백로그 |
출력 형식
다음 순서로 결과를 사용자에게 제시합니다.
- 심각도 순으로 정렬된 결과(가장 심각한 것부터)
- 아키텍처 진단(어떤 계층이 무엇을 어떻게 손상시켰는지)
- 정렬된 수정 계획(코드 우선, 프롬프트 우선 아님)
칭찬이나 요약으로 시작하지 마십시오. 시스템이 망가졌다면 직설적으로 말하십시오.
빠른 진단 질문
에이전트 시스템을 감사할 때 다음 질문에 답하십시오.
| # | 질문 | '예'인 경우 → |
|---|---|---|
| 1 | 모델이 필수 도구를 건너뛰고도 응답할 수 있습니까? | 도구가 코드로 게이트되지 않음 |
| 2 | 오래된 대화 내용이 새 대화에 나타납니까? | 메모리 오염 |
| 3 | 동일한 정보가 시스템 프롬프트와 메모리와 히스토리에 모두 있습니까? | 컨텍스트 중복 |
| 4 | 플랫폼이 전달 전에 두 번째 LLM 패스를 실행합니까? | 숨은 복구 루프 |
| 5 | 내부 생성과 사용자 전달 간 출력이 다릅니까? | 렌더링 손상 |
| 6 | "반드시 도구 X를 사용" 규칙이 프롬프트 텍스트에만 있습니까? | 도구 규율 실패 |
| 7 | 에이전트 자신의 독백이 지속적인 메모리가 될 수 있습니까? | 메모리 중독 |
피해야 할 안티 패턴
- 래퍼 계층 회귀를 반증하기 전에 모델을 탓하지 마십시오.
- 오염 경로를 제시하지 않고 메모리를 탓하지 마십시오.
- 깨끗한 현재 상태가 더러운 과거 사건을 지우도록 허용하지 마십시오.
- 마크다운 산문을 신뢰할 수 있는 내부 프로토콜로 취급하지 마십시오.
- 코드가 절대 강제하지 않는 프롬프트 텍스트의 "반드시 사용"을 받아들이지 마십시오.
- 결과는 직접적이고 증거에 기반하며 심각도 순으로 정렬하십시오.
보고서 스키마
감사는 다음 형식을 따르는 구조화된 보고서를 생성해야 합니다.
{
"schema_version": "ecc.agent-architecture-audit.report.v1",
"executive_verdict": {
"overall_health": "high_risk",
"primary_failure_mode": "string",
"most_urgent_fix": "string"
},
"scope": {
"target_name": "string",
"model_stack": ["string"],
"layers_to_audit": ["string"]
},
"findings": [
{
"severity": "critical|high|medium|low",
"title": "string",
"mechanism": "string",
"source_layer": "string",
"root_cause": "string",
"evidence_refs": ["file:line"],
"confidence": 0.0,
"recommended_fix": "string"
}
],
"ordered_fix_plan": [
{ "order": 1, "goal": "string", "why_now": "string", "expected_effect": "string" }
]
}
관련 스킬
agent-introspection-debugging— 에이전트 런타임 오류(루프, 시간 초과, 상태 오류) 디버그agent-eval— 에이전트 성능을 직접 비교 벤치마킹security-review— 코드 및 설정에 대한 보안 감사autonomous-agent-harness— 자율 에이전트 운영 설정agent-harness-construction— 에이전트 하네스를 처음부터 구축