18 KiB
Agent Pipeline 한계점 분석
결재 시스템 같은 대규모 크로스도메인 프로젝트에서 현재 파이프라인이 왜 제대로 동작할 수 없는가
1. 에이전트 컨텍스트 격리 문제
현상
executor.ts의 spawnAgent()는 매번 새로운 Cursor Agent CLI 프로세스를 생성한다. 각 에이전트는 systemPrompt + taskDescription + fileContext만 받고, 이전 대화/결정/아키텍처 논의는 전혀 알지 못한다.
// executor.ts:64-118
function spawnAgent(agentType, prompt, model, workspacePath, timeoutMs) {
const child = spawn(agentPath, ['--model', model, '--print', '--trust'], {
cwd: workspacePath,
stdio: ['pipe', 'pipe', 'pipe'],
});
child.stdin.write(prompt); // 이게 에이전트가 받는 전부
child.stdin.end();
}
문제 본질
- 에이전트는 "왜 이렇게 만들어야 하는지" 모른다. 단지 task description에 적힌 대로 만든다
- 결재 시스템의 설계 의도 (한국 기업 결재 문화, 자기결재/상신결재/합의결재/대결/후결)는 task description에 다 담을 수 없다
- PM과 사용자 사이에 오간 아키텍처 논의 (이벤트 훅 시스템, 제어관리 연동, 엔티티 조인으로 결재 상태 표시) 같은 결정 사항이 전달되지 않는다
결재 시스템에서의 구체적 영향
- "ApprovalRequestModal에 결재 유형 선택을 추가해라"라고 지시하면, 에이전트는 기존 모달 코드를 읽겠지만, 왜 그 UI가 그렇게 생겼는지, 다른 패널(TableListConfigPanel)의 Combobox 패턴을 왜 따라야 하는지 모른다
- 실제로 이 대화에서 Combobox UI가 4번 수정됐다. 매번 "다른 패널 참고해서 만들라"고 해도 패턴을 정확히 못 따라했다
2. 파일 컨텍스트 3000자 절삭
현상
// executor.ts:124-138
async function readFileContexts(files, workspacePath) {
for (const file of files) {
const content = await readFile(fullPath, 'utf-8');
contents.push(`--- ${file} ---\n${content.substring(0, 3000)}`); // 3000자 잘림
}
}
문제 본질
주요 파일들의 실제 크기:
approvalController.ts: ~800줄 (3000자로는 약 100줄, 12.5%만 보인다)improvedButtonActionExecutor.ts: ~1500줄ButtonConfigPanel.tsx: ~600줄ApprovalStepConfigPanel.tsx: ~300줄
에이전트가 수정해야 할 파일의 전체 구조를 이해할 수 없다. 앞부분만 보고 import 구문이나 초기 코드만 파악하고, 실제 수정 지점에 도달하지 못한다.
결재 시스템에서의 구체적 영향
approvalController.ts를 수정하려면 기존 함수 구조, DB 쿼리 패턴, 에러 처리 방식, 멀티테넌시 적용 패턴을 전부 알아야 한다. 3000자로는 불가능improvedButtonActionExecutor.ts의 제어관리 연동 패턴을 이해하려면 파일 전체를 봐야 한다- V2 컴포넌트 표준을 따르려면 기존 컴포넌트(
v2-table-list/등)의 전체 구조를 참고해야 한다
3. 에이전트 간 실시간 소통 부재
현상
병렬 실행 시 에이전트들은 서로의 작업 결과를 실시간으로 공유하지 못한다:
// executor.ts:442-454
if (state.config.parallel) {
const promises = readyTasks.map(async (task, index) => {
if (index > 0) await sleep(index * STAGGER_DELAY); // 500ms 딜레이뿐
return executeAndTrack(task);
});
await Promise.all(promises); // 완료까지 기다린 후 PM이 리뷰
}
PM 에이전트가 라운드 후에 리뷰하지만, 이것도 round-N.md의 텍스트 기반 리뷰일 뿐이다.
문제 본질
- DB 에이전트가 스키마를 변경하면, Backend 에이전트가 그 결과를 같은 라운드에서 즉시 반영할 수 없다
- Frontend 에이전트가 "이 API 응답 구조 좀 바꿔줘"라고 Backend에 요청할 수 없다
- 협업 모드(
CollabMessage)가 존재하지만, 이것도 라운드 단위의 비동기 메시지이지 실시간 대화가 아니다
결재 시스템에서의 구체적 영향
- DB가
approval_proxy_settings테이블을 만들고, Backend가 대결 API를 만들고, Frontend가 대결 설정 UI를 만드는 과정이 최소 3라운드가 필요하다 (각 의존성 해소를 위해) - 실제로는 Backend가 DB 스키마를 보고 쿼리를 짜는 과정에서 "이 컬럼 타입이 좀 다른 것 같은데"라는 이슈가 생기면, 즉시 수정 불가하고 다음 라운드로 넘어간다
- 라운드당 에이전트 호출 1~3분 + PM 리뷰 1~2분 = 라운드당 최소 3~5분. 8개 phase를 3라운드씩 = 최소 72~120분 (1~2시간)
4. 시스템 프롬프트의 한계 (프로젝트 특수 패턴 부재)
현상
prompts.ts의 시스템 프롬프트는 범용적이다:
// prompts.ts:75-118
export const BACKEND_PROMPT = `
# Role
You are a Backend specialist for ERP-node project.
Stack: Node.js + Express + TypeScript + PostgreSQL Raw Query.
// ... 멀티테넌시, 기본 코드 패턴만 포함
`;
프로젝트 특수 패턴 중 프롬프트에 없는 것들
| 필수 패턴 | 프롬프트 포함 여부 | 영향 |
|---|---|---|
V2 컴포넌트 레지스트리 (createComponentDefinition, AutoRegisteringComponentRenderer) |
프론트엔드 프롬프트에 기본 구조만 | 컴포넌트 등록 방식 오류 가능 |
| ConfigPanelBuilder / ConfigSection | 언급만 | 직접 JSX로 패널 만드는 실수 반복 |
| Combobox UI 패턴 (Popover + Command) | 없음 | 실제로 4번 재수정 필요했음 |
| 엔티티 조인 시스템 | 없음 | 결재 상태를 대상 테이블에 표시하는 핵심 기능 구현 불가 |
| 제어관리(Node Flow) 연동 | 없음 | 결재 후 자동 액션 트리거 구현 불가 |
| ButtonActionExecutor 패턴 | 없음 | 결재 버튼 액션 구현 시 기존 패턴 미준수 |
| apiClient 사용법 (frontend/lib/api/) | 간략한 언급 | fetch 직접 사용 가능성 |
| CustomEvent 기반 모달 오픈 | 없음 | approval-modal 열기 방식 이해 불가 |
| 화면 디자이너 컨텍스트 | 없음 | screenTableName 같은 설계 시 컨텍스트 활용 불가 |
결재 시스템에서의 구체적 영향
- 이벤트 훅 시스템을 만들려면 기존
NodeFlowExecutionService의 실행 패턴, 액션 타입 enum, 입력/출력 구조를 알아야 하는데, 프롬프트에 전혀 없다 - 엔티티 조인으로 결재 상태 표시하려면 기존 엔티티 조인 시스템이 어떻게 작동하는지(reverse lookup, join config) 알아야 하는데, 에이전트가 이 시스템 자체를 모른다
5. 단일 패스 실행 + 재시도의 비효율
현상
// executor.ts:240-288
async function executeTaskWithRetry(task, state) {
while (task.attempts < task.maxRetries) {
const result = await executeTaskOnce(task, state, retryContext);
task.attempts++;
if (result.success) break;
// 검증 실패 → retryContext에 에러 메시지만 전달
retryContext = failResult.retryContext || `이전 시도 실패: ${result.agentOutput.substring(0, 500)}`;
await sleep(2000);
}
}
문제 본질
- 재시도 시 에이전트가 받는 건 이전 에러 메시지 500자뿐이다
- "Combobox 패턴 대신 Select 박스를 썼다" 같은 UI/UX 품질 문제는 L1~L6 검증으로 잡을 수 없다 (빌드는 통과하니까)
- 사용자의 실시간 피드백("이거 다른 패널이랑 UI가 다른데?")을 반영할 수 없다
검증 피라미드(L1~L6)가 못 잡는 것들
| 검증 레벨 | 잡을 수 있는 것 | 못 잡는 것 |
|---|---|---|
| L1 (TS 빌드) | 타입 에러, import 오류 | 로직 오류, 패턴 미준수 |
| L2 (앱 빌드) | Next.js 빌드 에러 | 런타임 에러 |
| L3 (API 호출) | 엔드포인트 존재 여부, 기본 응답 | 복잡한 비즈니스 로직 (다단계 결재 플로우) |
| L4 (DB 검증) | 테이블 존재, 기본 CRUD | 결재 상태 전이 로직, 병렬 결재 집계 |
| L5 (브라우저 E2E) | 화면 렌더링, 기본 클릭 | 결재 모달 Combobox UX, 대결 설정 UI 일관성 |
| L6 (커스텀) | 명시적 조건 | 비명시적 품질 요구사항 |
결재 시스템에서의 구체적 영향
- "자기결재 시 즉시 approved로 처리"가 올바르게 동작하는지 L3/L4로 검증 가능하지만, "자기결재 선택 시 결재자 선택 UI가 숨겨지고 즉시 처리된다"는 UX는 L5 자연어로는 불충분
- "합의결재(병렬)에서 3명 중 2명 승인 + 1명 반려 시 전체 반려" 같은 엣지 케이스 비즈니스 로직은 자동 검증이 어렵다
- 결재 완료 후 이벤트 훅 → Node Flow 실행 → 이메일 발송 같은 체이닝된 비동기 로직은 E2E로 검증 불가
6. 태스크 분할의 구조적 한계
현상: 파이프라인이 잘 되는 경우
[DB 테이블 생성] → [Backend CRUD API] → [Frontend 화면] → [UI 개선]
각 태스크가 독립적이고, 새 파일을 만들고, 의존성이 단방향이다.
현상: 파이프라인이 안 되는 경우 (결재 시스템)
[DB 스키마 변경]
↓ ↘
[Controller 수정] [새 API 추가] ← 기존 코드 500줄 이해 필요
↓ ↓ ↑
[모달 수정] [새 화면] ← 기존 UI 패턴 준수 필요 + 엔티티 조인 시스템 이해
↓
[V2 컴포넌트 수정] ← 레지스트리 시스템 + ConfigPanelBuilder 패턴 이해
↓
[이벤트 훅 시스템] ← NodeFlowExecutionService 전체 이해 + 새 시스템 설계
↓
[엔티티 조인 등록] ← 기존 엔티티 조인 시스템 전체 이해
문제 본질
- 기존 파일 수정이 대부분이다. 새 파일 생성이 아니라 기존 코드에 기능을 끼워넣어야 한다
- 패턴 준수가 필수다. "돌아가기만 하면" 안 되고, 기존 시스템과 일관된 방식으로 구현해야 한다
- 설계 결정이 코드 작성보다 중요하다. "이벤트 훅을 어떻게 설계할까?"는 에이전트가 task description만 보고 결정할 수 없다
7. PM 에이전트의 역할 한계
현상
// pm-agent.ts:21-70
const PM_SYSTEM_PROMPT = `
# 판단 기준
- 빌드만 통과하면 "complete" 아니다 -- 기능이 실제로 동작해야 "complete"
- 같은 에러 2회 반복 -> instruction에 구체적 해결책 제시
- 같은 에러 3회 반복 -> "fail" 판정
`;
PM은 round-N.md(에이전트 응답 + git diff + 테스트 결과)와 progress.md만 보고 판단한다.
PM이 할 수 없는 것
| 역할 | PM 가능 여부 | 이유 |
|---|---|---|
| 빌드 실패 원인 파악 | 가능 | 에러 로그가 round-N.md에 있음 |
| 비즈니스 로직 검증 | 불가 | 실제 코드를 읽지 않고 git diff만 봄 |
| UI/UX 품질 판단 | 불가 | 스크린샷 없음, 렌더링 결과 못 봄 |
| 아키텍처 일관성 검증 | 불가 | 전체 시스템 구조를 모름 |
| 기존 패턴 준수 여부 | 불가 | 기존 코드를 참조하지 않음 |
| 사용자 의도 반영 여부 | 불가 | 사용자와 대화 맥락 없음 |
결재 시스템에서의 구체적 영향
- PM이 "Backend task 성공, Frontend task 실패"라고 판정할 수는 있지만, **"Backend가 만든 API 응답 구조가 Frontend가 기대하는 것과 다르다"**를 파악할 수 없다
- "이 모달의 Combobox가 다른 패널과 UI가 다르다"는 사용자만 판단 가능
- "이벤트 훅 시스템의 트리거 타이밍이 잘못됐다"는 전체 아키텍처를 이해해야 판단 가능
8. 안전성 리스크
역사적 사고
"과거 에이전트가 범위 밖 파일 50000줄 삭제하여 2800+ TS 에러 발생"
— user rules
결재 시스템의 리스크
수정 대상 파일이 시스템 핵심 파일들이다:
| 파일 | 리스크 |
|---|---|
improvedButtonActionExecutor.ts (~1500줄) |
모든 버튼 동작의 핵심. 잘못 건드리면 시스템 전체 버튼 동작 불능 |
approvalController.ts (~800줄) |
기존 결재 API 깨질 수 있음 |
ButtonConfigPanel.tsx (~600줄) |
화면 디자이너 설정 패널 전체에 영향 |
v2-approval-step/ (5개 파일) |
V2 컴포넌트 레지스트리 손상 가능 |
AppLayout.tsx |
전체 레이아웃 메뉴 깨질 수 있음 |
UserDropdown.tsx |
사용자 프로필 메뉴 깨질 수 있음 |
files 필드로 범위를 제한하더라도, 에이전트가 --trust 모드로 실행되기 때문에 실제로는 모든 파일에 접근 가능하다:
// executor.ts:78
const child = spawn(agentPath, ['--model', model, '--print', '--trust'], {
code-guard가 일부 보호하지만, 구조적 파괴(잘못된 import 삭제, 함수 시그니처 변경)는 코드 가드가 감지 불가하다.
9. 종합: 파이프라인이 적합한 경우 vs 부적합한 경우
적합한 경우 (현재 파이프라인)
| 특성 | 예시 |
|---|---|
| 새 파일 생성 위주 | 새 CRUD 화면 만들기 |
| 독립적 태스크 | 테이블 → API → 화면 순차 |
| 패턴이 단순/반복적 | 표준 CRUD, 표준 Form |
| 검증이 명확 | 빌드 + API 호출 + 브라우저 기본 확인 |
| 컨텍스트 최소 | 기존 시스템 이해 불필요 |
부적합한 경우 (결재 시스템)
| 특성 | 결재 시스템 해당 여부 |
|---|---|
| 기존 파일 대규모 수정 | 해당 (10+ 파일 수정) |
| 크로스도메인 의존성 | 해당 (DB ↔ BE ↔ FE ↔ 기존 시스템) |
| 복잡한 비즈니스 로직 | 해당 (5가지 결재 유형, 상태 전이, 이벤트 훅) |
| 기존 시스템 깊은 이해 필요 | 해당 (제어관리, 엔티티 조인, 컴포넌트 레지스트리) |
| UI/UX 일관성 필수 | 해당 (Combobox, 모달, 설정 패널 패턴 통일) |
| 설계 결정이 선행 필요 | 해당 (이벤트 훅 아키텍처, 결재 타입 상태 머신) |
| 사용자 피드백 반복 필요 | 해당 (실제로 4회 UI 수정 반복) |
10. 개선 방향 제안
현재 파이프라인을 결재 시스템 같은 대규모 프로젝트에서 사용하려면 다음이 필요하다:
10.1 컨텍스트 전달 강화
- 프로젝트 컨텍스트 파일:
.cursor/rules/수준의 프로젝트 규칙을 에이전트 프롬프트에 동적 주입 - 아키텍처 결정 기록: PM-사용자 간 논의된 설계 결정을 구조화된 형태로 에이전트에 전달
- 패턴 레퍼런스 파일: "이 파일을 참고해서 만들어라"를 task description이 아닌 시스템 차원에서 지원
10.2 파일 컨텍스트 확대
- 3000자 절삭 → 전체 파일 전달 또는 최소 10000자 이상
- 관련 파일 자동 탐지 (import 그래프 기반)
- 참고 파일(reference files)과 수정 파일(target files) 구분
10.3 에이전트 간 소통 채널
- 라운드 내에서도 에이전트 간 중간 결과 공유 가능
- "Backend가 API 스펙을 먼저 정의 → Frontend가 그 스펙 기반으로 구현" 같은 단계적 소통
- 질문-응답 프로토콜 (현재 CollabMessage가 있지만 실질적으로 사용 안 됨)
10.4 PM 에이전트 강화
- 코드 리뷰 기능: git diff만 보지 말고 실제 파일을 읽어서 패턴 준수 여부 확인
- 아키텍처 검증: 전체 시스템 구조와의 일관성 검증
- 사용자 피드백 루프: PM이 사용자에게 "이 부분 확인 필요합니다" 알림 가능
10.5 검증 시스템 확장
- 비즈니스 로직 검증: 상태 전이 테스트 (결재 플로우 시나리오 자동 실행)
- UI 일관성 검증: 스크린샷 비교, 컴포넌트 패턴 분석
- 통합 테스트: 단일 API 호출이 아닌 시나리오 기반 E2E
10.6 안전성 강화
--trust모드 대신 파일 범위 제한된 실행 모드- 라운드별 git diff 자동 리뷰 (의도치 않은 파일 변경 감지)
- 롤백 자동화 (검증 실패 시 자동
git checkout)
부록: 결재 시스템 파이프라인 실행 시 예상 시나리오
시도할 경우 예상되는 실패 패턴
Round 1: DB 마이그레이션 (task-1)
→ 성공 가능 (신규 파일 생성이므로)
Round 2: Backend Controller 수정 (task-2)
→ approvalController.ts 3000자만 보고 수정 시도
→ 기존 함수 구조 파악 실패
→ L1 빌드 에러 (import 누락, 타입 불일치)
→ 재시도 1: 에러 메시지 보고 고치지만, 기존 패턴과 다른 방식으로 구현
→ L3 API 테스트 통과 (기능은 동작)
→ 하지만 코드 품질/패턴 불일치 (PM이 감지 불가)
Round 3: Frontend 모달 수정 (task-4)
→ 기존 ApprovalRequestModal 3000자만 보고 수정
→ Combobox 패턴 대신 기본 Select 사용 (다른 패널 참고 불가)
→ L1 빌드 통과, L5 브라우저 테스트도 기본 동작 통과
→ 하지만 UI 일관성 미달 (사용자가 보면 즉시 지적)
Round 4-6: 이벤트 훅 시스템 (task-7)
→ NodeFlowExecutionService 전체 이해 필요한데 3000자만 봄
→ 기존 시스템과 연동 불가능한 독립적 구현 생산
→ PM이 "빌드 통과했으니 complete" 판정
→ 실제로는 기존 제어관리와 전혀 연결 안 됨
최종: 8/8 task "성공" 판정
→ 사용자가 확인: "이거 다 뜯어 고쳐야 하는데?"
→ 파이프라인 2시간 + 사용자 수동 수정 3시간 = 5시간 낭비
→ PM이 직접 했으면 2~3시간에 끝
작성일: 2026-03-03
대상: Agent Pipeline v3.0 (_local/agent-pipeline/)
맥락: 결재 시스템 v2 재설계 프로젝트 (docs/결재시스템_구현_현황.md)