에이전트는 무엇으로 실행되는가
AI Agent, Subagent, Harness, Loop, Goal, Planning과 Graph를 하나의 실행 구조 안에서 구분하고, 각 요소가 언제 필요한지 정리한다.
첫 글에서는 긴 작업을 수행하는 에이전트가 잃는 것이 과거의 정보만은 아닐 수 있다고 썼다. 더 치명적인 것은 “이 일이 끝나면 어디로 돌아가야 하는가”라는 복귀 위치와 아직 이행하지 않은 의무다. 그래서 Goal, Plan, CallFrame과 Event Log를 모델의 Context 밖에 두는 Runtime을 제안했다.
그런데 이 구조를 설명하려 하면 비슷해 보이는 용어가 한꺼번에 등장한다. AI Agent, Subagent, Harness, Loop, Goal, Planning, Graph가 각각 무엇이고 어디까지를 책임지는지 경계가 흐리다. Agent를 여러 개 띄우면 Graph가 되는지, Plan을 잘 쓰면 Harness가 필요 없는지, Loop를 고치면 장기 작업이 해결되는지도 분명하지 않다.
이 글에서는 이 용어를 기능 목록이 아니라 실행의 책임으로 구분한다. 먼저 하나의 최소 실행을 놓고, 실패를 해결하는 데 필요한 구조를 한 층씩 추가해 본다.
Agent는 모델이 아니라 실행 주체다
LLM API를 한 번 호출하는 것과 Agent를 실행하는 것은 다르다. 모델 호출은 입력을 받아 출력을 생성한다. Agent는 그 출력을 바탕으로 도구를 선택하고, 환경을 바꾸고, 결과를 관찰한 뒤 다음 행동을 결정한다.
관찰 → 판단 → 행동 → 결과 관찰
↑ │
└────────────────────┘
그래서 Agent는 모델 하나의 이름보다 다음 요소가 묶인 실행 주체에 가깝다.
- 현재 달성해야 할 Goal
- 모델에 제공할 Context
- 사용할 수 있는 Tool과 권한
- 행동 결과가 반영되는 Environment
- 다음 행동이나 종료를 결정하는 Loop
- 성공과 실패를 판정할 기준
같은 모델을 사용해도 Tool, 권한, 종료 조건이 다르면 다른 Agent처럼 동작한다. 반대로 모델을 교체해도 이 실행 계약을 유지하면 같은 역할을 이어받을 수 있다. Agent의 정체성을 모델의 Context에만 두지 말아야 하는 이유다.
Loop는 Agent의 한 걸음과 멈춤을 결정한다
가장 단순한 Agent Loop는 모델을 호출하고 Tool 결과를 다시 넣는 과정을 반복한다.
while not done:
context = compile(state)
action = model(context, tools)
result = execute(action)
state = reduce(state, action, result)
짧지만 각 줄에는 설계 결정이 들어 있다.
compile: 현재 상태 중 무엇을 모델에게 보여줄 것인가model: 어떤 출력 형식과 Tool을 허용할 것인가execute: 권한, 시간과 비용을 어디까지 허용할 것인가reduce: Tool 결과를 어떤 상태 변화로 인정할 것인가done: 누가 어떤 근거로 완료를 선언할 것인가
Loop Engineering은 Prompt 문장을 다듬는 일보다 이 전이 규칙을 설계하는
일에 가깝다. 같은 실패를 무한히 Retry하지 않는 규칙, 쓰기 전에 읽도록 하는
규칙, 변경 후 검증을 강제하는 규칙, 예산을 넘기면 yielded 상태로 멈추는
규칙이 여기에 들어간다.
Loop만으로도 짧은 작업은 처리할 수 있다. 그러나 현재 상태가 대화 안에만 있다면 Loop가 중단되거나 Context가 압축될 때 같은 위치에서 재개하기 어렵다. Loop는 다음 한 걸음을 관리하고, Runtime 상태는 여러 걸음 사이의 연속성을 관리한다.
Harness는 실행 가능한 범위를 만든다
Harness는 Agent를 둘러싼 실행 환경 전체다. 모델이 유능해도 Harness가 허술하면 잘못된 파일을 수정하고, 실패한 테스트를 놓치고, 완료되지 않은 일을 끝났다고 선언할 수 있다.
Harness에는 보통 다음 책임이 들어간다.
| 책임 | 예시 |
|---|---|
| Context 구성 | 저장소 지침, 관련 코드, 현재 Plan 선택 |
| Tool 계약 | 입력 Schema, timeout, 결과 크기 제한 |
| 권한 통제 | 읽기·쓰기 범위, network와 secret 접근 |
| 상태 보존 | Task 상태, Event Log, Checkpoint |
| 품질 판정 | 테스트, 타입 검사, 정적 분석, Reviewer |
| 관찰 가능성 | Trace, 비용, 지연, 실패 원인 |
| 복구 | Retry, rollback, resume, 사용자 요청 |
OpenAI의 Harness Engineering 사례에서는 거대한 지침 파일에 모든 지식을 넣기보다 짧은 안내 문서와 구조화된 저장소 문서를 연결하고, 코드와 문서의 규칙을 자동으로 검사하는 방향을 택했다. Harness Engineering 사례
핵심은 모델이 모든 규칙을 매번 기억하기를 기대하지 않는 것이다. 중요한 제약은 가능한 한 실행 환경이 검사한다. “테스트를 실행하라”는 문장만 주는 것보다 테스트 결과를 완료 조건에 연결하는 편이 강하다.
Goal은 방향이 아니라 완료 조건이다
“로그인 버그를 고친다”는 방향은 알려주지만 언제 멈춰도 되는지는 알려주지 않는다. 어떤 증상을 고쳐야 하는지, 기존 동작 중 무엇을 보존해야 하는지, 어떤 검증을 통과해야 하는지가 빠져 있다.
실행 가능한 Goal에는 적어도 네 가지가 필요하다.
Outcome
사용자가 만료된 세션으로 접근하면 로그인 화면으로 이동한다.
Constraints
정상 세션의 기존 redirect 동작은 바꾸지 않는다.
Non-goals
인증 방식과 세션 저장소는 교체하지 않는다.
Acceptance criteria
재현 테스트와 기존 인증 테스트가 모두 통과한다.
Goal은 Agent를 더 의욕적으로 만드는 Prompt가 아니다. 작업 범위를 잘라내고 완료를 판정하는 계약이다. 실행 중 Goal을 바꿔야 한다면 수정 전후를 revision으로 남겨야 한다. 그렇지 않으면 이전 Goal에서 만든 Plan과 새 완료 조건이 조용히 섞인다.
Planning은 불확실성을 실행 가능한 단위로 바꾼다
Goal이 “어디까지 가야 하는가”를 정한다면 Plan은 “어떤 순서로 불확실성을 줄일 것인가”를 정한다. 좋은 Plan은 미래의 모든 구현을 예언하지 않는다. 현재 알 수 있는 의존성, 검증 지점과 되돌릴 조건을 드러낸다.
1. 증상을 재현하고 실패 조건을 고정한다.
2. 인증 흐름과 세션 판정 지점을 추적한다.
3. 원인 가설을 가장 작은 테스트로 반증한다.
4. 영향 범위가 가장 작은 수정을 적용한다.
5. 재현 테스트와 회귀 테스트를 실행한다.
이 Plan이 유용한 이유는 단계 수가 많아서가 아니다. 조사 전에는 3단계의 구현을 확정하지 않았고, 수정 전에 실패를 재현하며, 마지막에 완료 기준과 연결했기 때문이다.
OpenAI의 ExecPlan도 과거 대화 없이 문서와 현재 작업 트리만으로 재개할 수 있는 자기 완결적 Plan을 강조한다. ExecPlan 안내
Plan에는 바뀌지 않아야 할 부분과 새 정보에 따라 바뀌어야 할 부분이 함께 있다. Goal, milestone, dependency와 acceptance criteria는 안정적으로 유지하고, 구현 후보와 예상 비용은 관찰 결과에 따라 갱신한다. Plan을 지키는 것보다 틀린 Plan을 근거와 함께 고치는 편이 중요하다.
Subagent는 병렬화보다 Context 경계다
Subagent를 추가하면 가장 먼저 병렬 실행을 떠올리기 쉽다. 그러나 더 근본적인 효과는 Context와 책임의 경계를 만드는 데 있다.
상위 Agent가 저장소 조사, 구현, 테스트 로그와 문서 작성을 모두 같은 Context에서 처리하면 각 작업의 세부 정보가 서로 밀어낸다. 조사 전용 Subagent에는 질문과 읽기 권한만 주고, 결과를 구조화해 돌려받을 수 있다.
Parent
objective: 인증 실패 원인을 좁힌다.
calls:
- Code explorer: 관련 실행 경로와 근거 위치 반환
- Test explorer: 기존 테스트와 누락된 경계 조건 반환
integrates:
두 결과를 비교해 수정할 Task를 만든다.
Subagent를 쓸 만한 조건은 다음과 같다.
- 독립적으로 정의할 수 있는 결과가 있다.
- 필요한 Context를 제한할 수 있다.
- 결과를 검증할 방법이 있다.
- 쓰기 범위나 파일 소유권의 충돌을 피할 수 있다.
- 위임 비용보다 Context 분리나 병렬화 이익이 크다.
반대로 같은 파일을 여러 Agent가 동시에 고치거나, 결과 계약 없이 “전체를 알아서 개선해 달라”고 위임하면 조정 비용만 늘어난다. Subagent 수는 지능의 배수가 아니다. 호출, 검증, 충돌 해결과 결과 통합이라는 비용도 함께 늘어난다.
Graph는 그림이 아니라 의존성과 상태다
Task가 하나뿐이면 Loop로 충분하다. Task가 여러 개이고 선후 관계, 분기, 병렬 실행과 재검증이 필요하면 Graph가 유용해진다.
재현 ─→ 원인 추적 ─→ 수정 ─→ 회귀 테스트
└────→ 문서 확인 ─────┘
Graph Engineering을 단순히 Agent를 여러 개 연결하는 일로 보면 핵심을 놓친다. Node와 Edge마다 실행 조건과 상태 전이가 있어야 한다.
- Node는 입력, 산출물, 소유자와 완료 조건을 가진다.
- Edge는 단순 순서뿐 아니라 dependency, call, handoff, retry, invalidation을 표현한다.
- Scheduler는 실행 가능한 Node 중 무엇을 먼저 고를지 결정한다.
- Runtime은 전이가 규칙에 맞는지 확인하고 Event로 기록한다.
모델이 Graph를 제안할 수는 있지만 실제 상태 전이는 Runtime이 커밋하는 편이
안전하다. 모델의 문장 하나로 completed가 되지 않고, 필요한 산출물과 검증이
있을 때만 다음 Node를 연다.
Graph가 항상 필요한 것은 아니다. 선형 작업을 Graph 플랫폼에 올리면 상태와 운영 비용만 증가한다. 다음 조건이 반복될 때 도입할 이유가 생긴다.
- 독립적으로 실행할 분기가 여러 개다.
- 결과를 합치는 Join이 필요하다.
- 일부 입력 변경이 특정 결과만 무효화해야 한다.
- 중단 후 정확한 Node에서 재개해야 한다.
- 실패 경로와 Retry를 감사할 필요가 있다.
각 개념은 서로를 대체하지 않는다
지금까지의 관계를 한 장으로 줄이면 다음과 같다.
Goal ── 완료 계약
│
Plan ── 불확실성을 줄일 실행 순서
│
Graph ─ Task의 의존성, 분기와 상태
│
Loop ── 현재 Node에서 다음 행동을 고르는 반복
│
Agent ─ 모델과 Tool로 행동하는 실행 주체
│
Harness ─ Context, 권한, 상태, 검증과 복구를 제공하는 환경
Subagent ─ Graph의 일부 Task를 별도 Context와 계약으로 수행하는 실행 주체
Goal을 잘 썼다고 Plan이 생기지 않고, Plan이 있다고 실행 상태가 보존되지 않는다. Subagent를 늘린다고 의존성이 관리되지 않으며, Graph를 그렸다고 완료 조건이 검증되지도 않는다. 각 요소는 서로 다른 실패를 막는다.
작은 구조부터 추가한다
처음부터 모든 층을 구현할 필요는 없다. 내가 적용한다면 실패의 크기에 따라 다음 순서로 추가한다.
- 한 번의 모델 호출로 충분한가 확인한다.
- Tool 결과를 보고 수정해야 하면 Loop를 둔다.
- 완료가 모호하면 Goal과 acceptance criteria를 외부화한다.
- 여러 단계가 필요하면 재시작 가능한 Plan을 만든다.
- 권한, 상태와 검증을 반복해서 다루면 Harness가 책임지게 한다.
- Context를 분리할 독립 작업이 생기면 Subagent에 계약으로 위임한다.
- 분기, dependency, Join과 invalidation이 반복되면 Graph로 승격한다.
이 순서의 목적은 용어를 모두 사용하는 데 있지 않다. 현재 실패를 막는 가장 작은 구조를 선택하는 데 있다.
다음 글에서는 실행 구조보다 더 어려운 질문으로 넘어간다. Agent가 코드를 읽고 과거 작업을 기억한다고 할 때, 그 안에서 무엇을 사실로 취급할 수 있는가. 소스 문자열, AST, Code Graph, 실행 결과와 Agent Memory는 서로 다른 종류의 근거다. 이들을 구분하지 않으면 잘 만든 Runtime도 오래된 기억을 정확하게 반복하는 시스템이 될 수 있다.