[논문 리뷰] TRAJDEBUG — long-horizon agent trajectory에서 첫 치명 오류 찾기
TRAJDEBUG는 장기 agent 실패에서 최종 증상이 아니라 실패를 만든 최초 critical error step을 evidence 기반으로 찾는 프레임워크다.
TrajDebug: Tracing Error Lifecycle to Identify Critical Failures in Long-Horizon Agent Trajectories
Yunjia Qi, Zehua Yin, Xintong Shi, Hao Peng, Songyuanyi Lu, Yixian Liu, Richeng Xuan, Yuhong Liu, et al. (2026)- arXiv
한 줄 요약
TRAJDEBUG는 실패한 long-horizon agent trajectory에서 “어디서부터 망가졌나”를 찾는 프레임워크다. 단순히 마지막 에러 메시지나 눈에 띄는 tool failure를 찍는 방식이 아니라, 각 step의 잘못된 commitment를 evidence로 검증하고, 그 오류가 나중에 복구됐는지 또는 최종 실패에 실제 흔적을 남겼는지 추적한다.
내가 보기에 이 논문의 좋은 점은 agent debugging을 최종 실패 분류가 아니라 오류 생애주기 추적 문제로 바꿨다는 데 있다. 장기 실행 agent에서 제일 위험한 오해는 “마지막에 보인 에러가 원인일 것”이라는 착각이다. 실제로는 초반의 작은 잘못된 판단이 중간 복구 시도와 부작용을 거치며 뒤늦게 터지는 경우가 많다.
왜 이 문제가 중요한가
코딩 agent, customer-service agent, research agent가 길게 실행되면 trace는 금방 지저분해진다.
- planning step
- tool call
- observation
- 재계획
- 검증
- 수정
- 다시 tool call
이 과정이 수십~수백 step으로 늘어나면 실패 원인을 사람이 읽기도 어렵고, LLM judge에게 통째로 던져도 정확도가 떨어진다. 논문은 critical error detection을 “실패한 trajectory에서 최종 실패를 책임지는 가장 이른 decisive error step을 찾는 일”로 정의한다.
중요한 건 local error와 critical error가 다르다는 점이다. 어떤 step은 분명히 틀렸지만 뒤에서 복구된다. 어떤 step은 틀린 상태로 남아도 최종 결과에는 영향을 안 줄 수 있다. 반대로 어떤 step은 당시에는 작은 위반처럼 보여도 이후 행동 전체를 틀어진 방향으로 몰고 간다.
논문의 pilot study도 이 지점을 보여준다. 샘플링한 50개 실패 trajectory에서 local error는 총 381개, 평균 7.62개였지만 각 trajectory의 critical error는 하나다. 비-critical local error 중 61.9%는 나중에 복구됐고, 31.4%는 끝까지 남았으며, 6.6%는 남아 있지만 downstream decision에 쓰이지 않는 dormant error였다. 즉 “처음 발견한 오류”를 원인으로 찍으면 자주 틀린다.
TRAJDEBUG의 핵심 구조
TRAJDEBUG는 세 단계로 critical error를 좁힌다.
- Error trigger detection: 각 step에서 evidence-grounded mismatch를 찾는다.
- Error state classification: 같은 reference object를 위반하는 trigger들을 묶고, 복구 여부와 terminal footprint를 분류한다.
- Candidate-set-guided causal attribution: terminal relevance가 있는 후보 중 최종 실패를 가장 잘 설명하는 최초 step을 고른다.
이 구조가 괜찮은 이유는 전체 trace를 한 번에 판정하지 않는다는 점이다. 긴 trajectory를 “대충 읽고 원인 하나 찍기”로 처리하면 judge가 그럴듯한 narrative를 만들어낼 가능성이 높다. TRAJDEBUG는 먼저 작은 단위의 evidence를 만들고, 그 evidence가 실제 실패까지 이어졌는지를 따로 본다.
1단계: multi-granularity compression
장기 trajectory를 그대로 넣으면 context는 길고, 중요한 근거는 흩어져 있다. TRAJDEBUG는 각 step에 대해 세 가지 view를 만든다.
- High-detail view: 원래 instruction, action, observation, local reasoning 등 직접 검증에 필요한 세부 정보
- Medium-detail view: step의 주요 의도, action, state update
- Low-detail view: coarse progress, salient entity, unresolved commitment
판정 단계에서는 현재 step과 가까운 문맥은 자세히 보고, 먼 과거는 압축해서 본다. 이건 실무 agent observability에도 꽤 현실적인 설계다. 모든 tool output을 영구히 full text로 judge prompt에 넣는 건 비싸고 불안정하다. 대신 trace 저장소에는 원본을 남기되, debugging layer는 distance와 목적에 따라 view를 다르게 꺼내야 한다.
2단계: evidence-grounded trigger
TRAJDEBUG의 trigger는 “이 step이 느낌상 이상하다”가 아니다. 논문은 trigger를 대략 다음 요소로 본다.
- 어느 step에서 발생했는가
- 현재 step의 잘못된 commitment는 무엇인가
- 어떤 reference를 위반했는가
- reference category는 무엇인가
- execution phase는 어디인가
Reference category는 네 가지로 나뉜다.
- Task Conflict: task instruction이나 constraint 위반
- History Conflict: 이전 tool output, 관찰, established fact와 충돌
- Intra-Step Conflict: 같은 step 내부의 자기모순
- Environment Anomaly: agent action은 합리적이지만 environment response가 비정상인 경우
여기서 마음에 드는 규칙은 verbatim evidence condition이다. 잘못된 commitment와 위반된 reference가 명시적으로 인용 가능해야 trigger로 인정한다. Agent 디버깅에서 이 조건은 중요하다. “아마 이랬을 것”이라는 진단은 retrospective hallucination이 되기 쉽다.
3단계: error state를 추적한다
같은 오류는 여러 step에서 반복해서 나타날 수 있다. 예를 들어 “core/serialization.py를 수정하지 말라”는 task constraint가 있었는데, agent가 계획 step에서 이를 무시하고, action step에서 실제 수정하고, verification step에서 그 부작용을 합리화할 수 있다. 이걸 세 개의 독립 오류로 세면 root cause가 흐려진다.
TRAJDEBUG는 같은 reference object를 위반하는 trigger들을 error instance로 묶고, 각 instance의 상태를 분류한다.
- Clean Resolution: 복구됐고 terminal footprint가 없음
- Costly Resolution: 복구됐지만 복구 비용이 커서 terminal footprint가 있음
- Manifest Active: 오류가 active이고 최종 상태에 의미 있는 흔적이 있음
- Latent Active: 오류가 active이지만 최종 실패에 관찰 가능한 흔적은 없음
최종 attribution 후보는 Costly Resolution과 Manifest Active처럼 terminal relevance가 있는 instance로 좁힌다. 이 필터링이 핵심이다. 장기 agent는 자주 틀리고 자주 고친다. 모든 local error를 같은 무게로 보면, debugging output은 “그럴듯한 에러 목록”일 뿐 실질적인 repair signal이 되지 않는다.
벤치마크: TrajErrBench
논문은 TrajErrBench라는 벤치마크도 만든다. 구성은 다음과 같다.
- 총 486개 manually annotated failed trajectories
- 400개는 τ²-Bench 기반 tool-use 및 user-interaction scenario
- 86개는 SWE-Bench Pro 기반 long-horizon coding trajectory
- SWE-Bench Pro 쪽 평균 길이는 약 119.7 step
Annotation은 세 명의 annotator가 수행하고, 적어도 두 명이 동의한 label을 ground truth로 쓴다. 논문에 따르면 critical-error step label의 Fleiss' kappa는 τ²-Bench에서 0.91, SWE-Bench Pro에서 0.67이다. 코딩 trajectory 쪽이 더 길고 복잡해서 agreement가 낮아지는 건 자연스럽다.
흥미로운 통계도 있다. TrajErrBench의 critical error는 꼭 초반에만 나오지 않는다. Agent가 먼저 정보를 수집하고, 중후반에 결정적인 판단을 내리는 구조가 많기 때문이다. 특히 SWE-Bench Pro에서는 task conflict가 73.4%로 높고, reasoning phase가 57.1%로 주요 실패 phase로 보고된다. 코딩 agent 실패가 단순히 “tool을 잘못 호출했다”보다 “축적한 repo context를 잘못 해석했다”에 가깝다는 신호로 볼 수 있다.
결과: 정확도는 낮지만 방향은 좋다
전체 결과에서 TRAJDEBUG는 평균 critical-step accuracy 34.11%를 기록한다. 논문 기준으로 같은 backbone direct prompting의 25.69%보다 8.42 point 높다. 숫자만 보면 낮아 보이지만, 이 task는 실패 trajectory만 보고 exact critical step을 맞히는 설정이다. 오히려 이 낮은 절대값이 현실적이다.
긴 trajectory에서 차이가 더 중요하다. 논문은 trajectory length가 길어질수록 대부분의 baseline 정확도가 크게 떨어진다고 보고한다. TRAJDEBUG도 영향을 받지만, 가장 긴 bucket에서 20% 이상을 유지했고 best baseline은 약 14% 수준까지 내려갔다고 설명한다.
Ablation도 설득력이 있다.
- Multi-granularity compression을 hard truncation으로 바꾸면 평균이 38.58에서 17.56으로 크게 하락한다.
- Evidence-grounded trigger를 제거하면 평균이 33.59로 내려간다.
- Error state classification을 제거하면 평균이 31.27로 내려간다.
즉 성능의 큰 축은 “긴 context를 어떻게 보존하며 줄이느냐”이고, 그 다음이 trigger와 state filtering이다. 내 해석은 이렇다. Agent trace debugging에서 가장 중요한 primitive는 fancy judge prompt가 아니라 압축 가능한 trace representation이다.
실패 진단을 agent 개선 신호로 쓰기
논문은 TRAJDEBUG의 output을 agent 개선 feedback으로 쓰는 실험도 한다. 실패한 trajectory를 진단해 system prompt에 targeted guidance로 넣고 같은 task를 다시 실행하는 per-trajectory repair 설정에서, 평균 success rate가 78.07에서 88.87로 올라간다고 보고한다. 별도 per-instance oracle 없이 일부 historical failure에서 만든 memory를 held-out task에 전달하는 설정에서도 평균 5.70 point 개선을 보였다고 한다.
여기서 과하게 해석하면 안 된다. 이건 “TRAJDEBUG를 붙이면 production agent가 자동으로 좋아진다”는 뜻이 아니다. 실험 설정, actor model, benchmark domain, feedback injection 방식에 의존한다. 다만 중요한 힌트는 있다. 실패 trace를 그냥 로그로 쌓아두는 것보다, critical error와 terminal footprint 중심으로 구조화하면 reusable failure memory가 될 가능성이 있다.
실무 agent runtime에 적용한다면
내가 이 논문을 agent 운영에 가져온다면 다음 네 가지를 먼저 만들 것 같다.
- Trace schema: 각 step에 instruction, action, observation, state diff, verification result를 구조화해서 저장한다.
- Evidence pointer: 모든 diagnosis는 원문 step id와 인용 가능한 snippet을 가져야 한다.
- Error lifecycle field: detected, resolved, costly, active, terminal footprint 같은 상태를 별도 필드로 둔다.
- Regression memory: critical error를 “다음 run에서 피해야 할 invariant”로 변환해 test/eval에 넣는다.
코딩 agent라면 특히 다음 invariant가 필요하다.
task constraint
-> referenced files / forbidden files
-> observed tool output
-> planned edit
-> actual patch
-> test result
-> unresolved violation이 정도가 있어야 “왜 이 PR이 실패했는가”를 다음 run의 guidance로 바꿀 수 있다. 단순히 “테스트를 더 돌려라”, “주의 깊게 읽어라” 같은 reflection은 대부분 쓸모가 없다. 좋은 failure memory는 구체적인 violated reference와 재발 방지 조건을 가져야 한다.
한계와 주의할 점
첫째, 정확도는 아직 낮다. 평균 34.11%는 baseline보다 낫지만, critical production decision을 자동화하기에는 부족하다. 이건 agent debugging이 쉬워졌다는 신호가 아니라, 기존 방식이 더 취약하다는 신호에 가깝다.
둘째, LLM 기반 detector 자체가 비용을 만든다. Multi-granularity view 생성, trigger detection, attribution을 매 실패마다 돌리면 운영비가 생긴다. 실무에서는 모든 run에 붙이기보다 실패한 run, 고비용 run, release-blocking eval run에 우선 적용하는 게 낫다.
셋째, 논문은 code와 data를 공개할 예정이라고 적고 있지만, 초안 작성 시점에는 실제 repo 공개 상태까지 검증하지 않았다. 따라서 재현성은 공개 이후 확인해야 한다.
넷째, terminal footprint 판단은 domain-specific하다. 고객지원에서는 잘못된 주문 제출이 irreversible footprint일 수 있고, 코딩에서는 금지 파일 수정이나 test contract 위반이 footprint가 된다. 범용 classifier 하나로 끝날 문제가 아니다.
내 결론
TRAJDEBUG의 메시지는 꽤 실용적이다. Long-horizon agent를 운영하려면 “성공률”만 볼 게 아니라 실패 trace에서 최초의 치명적 오류를 찾는 능력을 갖춰야 한다. 그래야 eval failure가 다음 harness patch, memory update, tool policy 수정으로 이어진다.
이 논문을 한 문장으로 줄이면 이렇다.
Agent observability는 trace를 많이 저장하는 일이 아니라, 어떤 오류가 복구됐고 어떤 오류가 최종 실패로 살아남았는지 추적하는 일이다.
나는 이 관점이 맞다고 본다. 앞으로 agent runtime의 차별점은 모델 wrapper가 아니라 trace lifecycle, evidence citation, failure memory, regression replay 같은 “망했을 때 배우는 구조”에서 갈릴 가능성이 크다.