01
계획은 있는데 실행과 이어져 있지 않았다
에이전트 작업에는 처음부터 두 가지 기록이 있었습니다. 하나는 모델이 세운 계획이고, 다른 하나는 실제로 무엇을 했는지 남는 실행 로그입니다. 문제는 둘이 서로를 가리키지 않는다는 점이었습니다. 계획의 두 번째 단계가 도구를 몇 번 썼는지, 계획과 실행이 얼마나 어긋났는지 물어볼 방법이 없었습니다.
로드맵은 다음 단계로 Execution Graph를 지목합니다. 노드마다 의존성과 필요 권한, 비용 상한, 재시도 정책, 완료 조건을 직접 갖는 DAG입니다. 그런데 그런 노드를 설계하려면 먼저 노드에 무엇을 붙여야 하는지 알아야 하고, 그건 실측 없이는 알 수 없습니다. 그래서 그래프를 짓기 전에 붙일 자리부터 만들기로 했습니다.
02
먼저 턴이 무엇을 하려 했는지부터 남겼다
1.21.0에서 각 턴이 어떤 도구를 호출하려 했는지를 스텝에 영속화했습니다. 같은 릴리스에서 일시적인 LLM 오류에 대한 지수 백오프 재시도와, 승인 요청이 반복해서 무응답일 때 승인 필요 도구를 걷어내는 강등도 각각 스텝으로 남기게 했습니다.
의도는 단순합니다. 재시도와 강등이 실제로 얼마나 자주 발동하는지를 로그를 뒤지지 않고 데이터베이스에서 바로 세려는 것입니다. 나중에 노드별 재시도 정책을 정할 때 근거가 될 숫자를 미리 쌓아 두는 셈입니다.
03
모르면 비워 둔다
1.22.0에서 마이그레이션 088이 실행 스텝 테이블에 계획 단계 인덱스를 nullable 컬럼으로 추가했습니다. 스텝을 기록하는 시점에 진행 중인 계획 단계의 인덱스를 결정적으로 찍습니다. 여기에 모델의 판단은 한 번도 개입하지 않습니다.
가장 중요한 선택은 무엇을 하지 않을지였습니다. 진행 중인 단계가 없으면 첫 미완료 단계로 때려 맞히는 대신 그냥 비워 둡니다. 이 컬럼의 목적이 계획과 실행이 얼마나 맞는지를 재는 것인데, 모르는 값을 지어내면 계측 자체가 무의미해지기 때문입니다.
- 귀속 대상: 어시스턴트 응답과 계획 스텝, 도구 결과, 재시도
- 의도적으로 비우는 대상: 마무리 턴, 승인 강등, 사용자 개입, 코드 diff처럼 특정 단계에 속한다고 말하기 어려운 관리 이벤트
- 기존 행에는 영향이 없고, 같은 마이그레이션을 여러 번 돌려도 결과가 같습니다
04
첫 실측은 45%였고, 원인은 코드가 아니었다
쌓인 데이터를 후향으로 재 보니 엄격한 기준에서 귀속 커버리지는 45% 언저리였습니다. 절반이 조금 안 되는 스텝만 어느 단계에서 나왔는지 말할 수 있다는 뜻입니다.
원인을 갈라 보니 코드 쪽 문제가 아니었습니다. 40%는 모델이 계획을 갱신하면서 진행 중 표시를 아예 남기지 않은 경우였습니다. 명시적으로 그렇게 하라고 지시해도 두 번째 단계에서 표시가 빠지는 것을 라이브에서 재현했습니다.
여기서 갈림길이 하나 생깁니다. 프롬프트로 마킹을 더 강하게 유도할 것인가, 코드로 보정할 것인가. 프롬프트를 건드리면 다른 동작까지 흔들릴 수 있어, 그 판단은 전향 데이터가 쌓인 뒤로 미뤘습니다.
덤으로 얻은 것도 있습니다. 노드 하나가 도구를 몇 번 부르는지 분포가 나왔는데, 중앙값이 4회이고 최대는 26회였습니다. 나중에 노드별 비용 상한을 정할 때 이 분포가 근거가 됩니다.
05
모델을 설득하는 대신 결정적으로 보정했다
증분 3은 프롬프트를 그대로 두고 코드에서 빈칸을 메웁니다. 계획을 만든 직후와 어떤 단계가 완료되거나 막힌 뒤에, 진행 중인 단계가 하나도 없으면 첫 번째 미착수 단계를 진행 중으로 올립니다. 선형 실행을 가정한 결정적 규칙이고 여기에도 모델 판단은 없습니다.
다만 모델이 말한 것은 존중합니다. 이미 진행 중인 단계가 있으면 아무것도 하지 않고, 모델이 명시적으로 미착수로 되돌린 단계는 다시 올리지 않습니다. 자동 보정은 환경변수로 끌 수 있고 기본은 켜져 있으며, 테스트 여섯 건이 이 규칙을 지킵니다.
06
화면에 나오지 않으면 검증되지 않는다
마지막으로 작업 상세 타임라인에 각 스텝이 어느 단계에 속하는지 뱃지로 표시했습니다. 백엔드는 손대지 않았습니다. 스텝 응답에 이미 컬럼이 들어 있었기 때문에 화면에서 읽기만 하면 됐고, 네 개 로케일에 키 하나를 추가했습니다.
계측을 화면에 올린 이유는 예쁘게 보이려는 것이 아니라, 눈으로 볼 수 있어야 틀린 것을 알아차리기 때문입니다. 실제로 그다음에 알아차린 것이 있습니다.
07
계측 자체에 사각이 있었다
같은 흐름에서 도구 결과가 얼마나 잘리는지를 재는 계측을 넣었습니다. 고치기 전에 먼저 재자는 원칙이었습니다. 그런데 채팅에서 PDF 작업으로 자동 위임되는 경로를 브라우저로 점검하다가, 샌드박스 작업에서는 이 계측이 한 건도 기록하지 않는다는 사실이 드러났습니다.
원인은 경로였습니다. 샌드박스 도구는 턴 실행기를 거치지 않고 별도의 실행 경로를 타는데, 계측을 그 도구들이 지나가지 않는 자리에 붙여 놓았던 것입니다. 실측에서는 도구 결과 스텝이 두 건 남았는데 기록 시도는 0건이었습니다.
1.22.1에서 결과가 실제로 잘리는 지점으로 계측을 옮기고, 거기 박혀 있던 매직넘버를 기존 환경변수로 일원화했습니다. 먼저 재고 나중에 고친다는 원칙은, 계측이 맞는 자리에 있을 때만 성립합니다.
08
다음
지금 있는 것은 스텝을 계획 노드에 귀속시키는 계측과, 진행 표시가 비었을 때의 결정적 보정, 그리고 그 결과를 보여 주는 화면입니다. 아직 없는 것은 노드가 자기 의존성과 필요 권한, 비용 상한, 재시도 정책, 완료 조건을 직접 갖는 영속 DAG입니다.
다음 판단의 근거는 숫자입니다. 자동 보정을 켠 뒤 45%가 전향 데이터에서 어디까지 올라가는지, 그리고 노드당 도구 호출 분포의 꼬리가 어디에서 끊기는지가 노드에 붙일 비용 상한과 완료 조건의 첫 후보가 됩니다.
근거 자료
OpenMake