검증 함수를 에이전트 루프에 통합해 작업 완료 여부를 자동으로 판정하고, 테스트 결과를 피드백해 확률적 편차와 환각을 줄이면서 워크플로의 병목을 완화하는 방법을 설명한다.
수동으로 출력물을 복사해 붙이거나 계속 프롬프트를 던지는 대신, 검증 함수를 도구처럼 사용해 코딩 에이전트와 데이터 처리 에이전트를 자동으로 조종할 수 있다. 이렇게 하면 에이전트 기반 프로그래밍에서 흔한 작업을 병렬화하고, 에이전트형 코딩 워크플로의 병목을 줄일 수 있다(참고: https://en.wikipedia.org/wiki/Amdahl%27s_law).
업계에서 합의된 에이전트 루프는 대략 다음과 같다.
msg = []
while True:
msg.append(input())
while True:
output, tool_calls = prompt_llm(msg)
msg.append(output)
print("Agent: ", output)
if tool_calls:
msg.extend([
handle_tool_call(tc)
for tc in tool_calls
])
이 전제대로 동작하는 에이전트는 다음과 같은 지루한 사이클에 당신을 가둔다:
https://www.psychologytoday.com/us/blog/inside-the-box/201401/creativity-lesson-betty-crocker 같은 이유로 이 워크플로가 생산적으로 느껴질 수도 있지만, 테스트 출력을 창에서 에이전트로 수없이 복붙해야 하는 과정이 병목으로 느껴지기 시작할 것이다. 이를 자동화하려면, 에이전트가 스스로 테스트를 실행해 그 결과를 자신의 컨텍스트 윈도우로 되먹임하게 하라. 이렇게 자동화하면 백그라운드에서 돌아가도록 맡겨 주의를 덜 빼앗기면서, 코드가 안정된 상태에 도달할 것이라는 확신을 가질 수 있다.
실패하는 내 테스트를 고치고, pytest를 실행해 수정이 맞는지 검증해줘
프롬프트로 에이전트를 조종하는 방식은 이 제어 흐름을 구현하는 데 그럭저럭 괜찮다. 하지만 제어 흐름을 토큰 생성에 넘기기 때문에, 본질적으로 확률적이 되고 그에 따른 여러 재미있는 결과를 감수해야 한다. 대개는, 특히 값싼 일회성 작업에서는 괜찮다.
검증을 에이전트 루프 안으로 직접 도입하면, 목표를 달성할 때까지 루프를 끝내지 않도록 검증 컨텍스트가 에이전트로 되먹임된다.
msg = []
while True:
msg.append(input())
while True:
output, tool_calls = prompt_llm(msg)
msg.append(output)
print("Agent: ", output)
if tool_calls:
msg.extend([
handle_tool_call(tc)
for tc in tool_calls
])
+ complete, output = check_completed()
+ msg.append(output)
+ if complete:
+ break
에이전트가 작업 완료를 제출할 준비가 되면, check_completed() 함수가 검증 명령(npm run test 같은)이나 작업 완료를 판정할 임의의 검증기를 실행한다. 작업이 미완료라면, 검증 출력이 메시지 히스토리에 들어가 자동 피드백 루프를 만든다.

이 접근법은 에이전트에 환경 상태에 대한 근거 있는, 통제된 접근을 제공한다. 에이전트는 환경을 관찰하는 도구를 가질 수 있지만, 프롬프트 기반 조종은 믿을 만하지 않다. 에이전트는 게을러지거나, 혼란스러워하거나, 성급히 성공을 선언하기 쉽다.
환경 상태 검증을 제어 흐름에 직접 박아 넣으면 다음 중 하나가 될 때까지 에이전트가 계속 시도하게 된다:
중요하게도, check_completed()는 에이전트가 해냈다고 생각하는 것과는 별개로, 에이전트가 환경에 가한 행동의 실제 결과 상태를 검증한다.
https://github.com/r33drichards/mini-agent-action 는 https://github.com/SWE-agent/mini-SWE-agent 를 응용해 이 제어 흐름을 구현한다. pip로 설치하고, 작업 완료까지 루프 도는 bash 도구를 가진 에이전트를 이렇게 실행할 수 있다:
pip install mini-agent-action
mini-agent-action --exec "python test.py" \
--task "fix this test, you can see it fail with python test.py. you will be validated against that cmd" \
--debug
이런 종류의 에이전트는 PR 브랜치를 지키게 해두면 매우 유용하다. 깨진 테스트가 있는 커밋을 푸시했을 때, 굳이 개입하지 않고 작업을 전환해 두고 이 에이전트가 테스트 실패의 해결책을 찾아오도록 기다릴 수 있다. Mini SWE Agent는 출력에 이런 수준의 제어가 없음에도 SWE-bench에서 70% 점수를 주장한다. 에이전트가 작업을 완전히 올바르게 끝내지 못하더라도, 최종 구현에서 일부 출력을 가져다 쓸 만큼 충분히 근접한 경우가 자주 있다. 에이전트는 기능 브랜치에 풀 리퀘스트를 만들기 때문에, 결과에 만족하면 그냥 머지하고, 마음에 들지 않으면 PR을 닫으면 된다.
이 같은 시스템은 사람이 에이전트에게 반응적으로 프롬프트를 던지게 하는 대신, 에이전트가 선제적으로 코드를 고치게 하면서도 최종 결과에 대한 인간의 소유권을 유지하게 해준다.
흔한 시나리오를 생각해 보자. 특정 스키마를 만족해야 하는 JSON 데이터를 받았다. 직접 변환 로직을 작성할 수도 있지만, 이 방식은 스케일에서 실패한다. 새로운 JSON 구조가 들어올 때마다 맞춤 변환 코드를 써야 하며, 다양한 입력을 처리할 때 이는 지속 불가능한 작업량이 된다.
에이전트는 런타임에 유효한 변환 코드를 생성함으로써 이를 해결한다. 변환된 출력이 대상 스키마와 일치하는지 확인하는 검증 함수를 에이전트 루프에 추가하라. 검증이 실패하면, 에이전트는 디버그 정보를 가지고 다시 실행되어 유효한 출력을 낼 때까지 반복한다.
이 접근에는 한계도 있다. 에이전트가 최소한의 빈 JSON 문서를 내보내는 식으로 검증을 통과시키는 경우가 있다. 수용 가능한 결과를 얻기까지 여러 번 실행해야 할 수도 있다. 그럼에도, 들어오는 스키마마다 맞춤 변환을 쓰는 것보다는 훨씬 적은 노력이 든다.
에이전트의 제어 흐름에 자동 검증을 통합하면 수동 개입을 제거하고 자율 시스템을 만들 수 있다.