당신이 몰랐던 에이전트: 원리, 아키텍처 및 엔지니어링 실무

@HiTw93
중국어3개월 전 · 2026년 3월 19일
1.7M
5.1K
1.2K
121
10.7K

TL;DR

이 기술 가이드는 AI 에이전트 아키텍처의 핵심 원리를 탐구하며, 안정적인 자율 시스템 구축을 위한 컨텍스트 엔지니어링, ACI 도구 설계 및 강력한 평가 프레임워크를 강조합니다.

0. TL;DR

"당신이 모르는 Claude Code: 아키텍처, 거버넌스, 엔지니어링 관행"을 작성한 후, Agent의 기본 레이어에 대한 이해가 충분히 깊지 않다는 것을 깨달았습니다. 팀이 Agent 기반 비즈니스 솔루션을 구축한 상당한 경험과 결합하여, 체계적인 검토의 필요성을 느꼈습니다. 그래서 자료, 오픈소스 구현, 그리고 제 코드를 살펴보며 이 글을 정리했습니다.

이 글은 엔지니어링 결과에 가장 큰 영향을 미치는 Agent 아키텍처 부분, 즉 제어 흐름, 컨텍스트 엔지니어링, 도구 설계, 메모리, 멀티 에이전트 구성, 평가, 추적, 보안에 초점을 맞춥니다. 마지막으로 OpenClaw 구현을 사용하여 이러한 설계 원칙을 하나로 묶어 설명합니다.

이를 정리하면서 몇 가지 결론이 초기 가정과 달랐습니다. 더 비싼 모델이 가져오는 개선 효과는 예상보다 작은 경우가 많았고, 대신 Harness와 검증 테스트의 품질이 성공률에 더 큰 영향을 미쳤습니다. Agent 동작을 디버깅할 때는 도구 정의를 먼저 확인하세요. 대부분의 도구 선택 오류는 부정확한 설명에서 비롯됩니다. 또한 평가 시스템 자체의 문제는 Agent 버그보다 발견하기 어려운 경우가 많습니다. Agent 코드를 계속 수정해도 성공하지 못한다면, 해답은 이러한 영역에 있을 수 있습니다.

1. Agent 루프의 기본 동작

Agent 루프의 핵심 구현 로직을 추상화하면 20줄 미만의 코드입니다:

typescript
1const messages: MessageParam[] = [{ role: "user", content: userInput }];
2
3while (true) {
4 const response = await client.messages.create({
5 model: "claude-opus-4-6",
6 max_tokens: 8096,
7 tools: toolDefinitions,
8 messages,
9 });
10
11 if (response.stop_reason === "tool_use") {
12 const toolResults = await Promise.all(
13 response.content
14 .filter((b) => b.type === "tool_use")
15 .map(async (b) => ({
16 type: "tool_result" as const,
17 tool_use_id: b.id,
18 content: await executeTool(b.name, b.input),
19 }))
20 );
21 messages.push({ role: "assistant", content: response.content });
22 messages.push({ role: "user", content: toolResults });
23 } else {
24 return response.content.find((b) => b.type === "text")?.text ?? "";
25 }
26}

해당 제어 흐름은 다음과 같습니다: 모델이 일반 텍스트를 반환할 때까지 지각(Perception) -> 결정(Decision) -> 행동(Action) -> 피드백(Feedback)의 연속적인 순환입니다:

Tw93 - inline image

많은 Agent 구현체와 공식 SDK를 살펴보면 구조는 비슷합니다. 루프 자체는 상당히 안정적입니다. 최소 구현에서 하위 에이전트 지원, 컨텍스트 압축, 스킬 로딩에 이르기까지 메인 루프는 거의 변경되지 않습니다. 새로운 기능은 일반적으로 루프 내부를 수정하기보다는 루프 외부에 계층화됩니다.

새로운 기능은 주로 세 가지 방식으로 통합됩니다: 도구 세트와 핸들러 확장, 시스템 프롬프트 구조 조정, 상태를 파일이나 데이터베이스로 외부화. 루프 본체는 거대한 상태 머신이 되어서는 안 됩니다. 모델은 추론을 처리하고, 외부 시스템은 상태와 경계를 처리합니다. 이 역할 분담이 확립되면 핵심 루프 로직은 자주 조정할 필요가 거의 없습니다.

워크플로우와 Agent의 차이점은 무엇인가요?

Anthropic은 직접적으로 구분합니다: 실행 경로가 코드에 미리 작성된 시스템은 워크플로우(Workflow)이고, LLM이 다음 단계를 동적으로 결정하는 시스템은 Agent입니다. 핵심 차이는 누가 제어권을 쥐고 있느냐입니다. 실제로 Agent라고 불리는 많은 제품은 워크플로우에 가깝지만, 어느 쪽이 본질적으로 우월하다고 할 수는 없습니다. 중요한 것은 작업에 맞는 올바른 솔루션을 찾는 것입니다.

Tw93 - inline image

하나의 다이어그램으로 보면 더 직관적입니다:

Tw93 - inline image

다섯 가지 일반적인 제어 패턴

대부분의 AI 시스템을 분해하면 이 다섯 가지 패턴의 조합입니다. 많은 시나리오에서 완전한 Agent 자율성은 필요하지 않으며, 이 패턴 중 몇 가지를 결합하는 것만으로 충분합니다. 핵심은 어떤 설계가 작업에 적합한지입니다.

  1. 프롬프트 체이닝(Prompt Chaining): 작업을 순차적 단계로 나누어 각 LLM 단계가 이전 출력을 처리합니다. 코드 체크포인트를 추가할 수 있습니다. 생성 후 번역, 개요 작성 후 본문 작성과 같은 선형 프로세스에 적합합니다.
  2. 라우팅(Routing): 입력을 분류하여 전문화된 프로세스로 전달합니다. 간단한 질문은 경량 모델로, 복잡한 질문은 강력한 모델로 보냅니다. 기술 지원과 결제 문의는 다른 로직을 따릅니다.
  3. 병렬화(Parallelization): 두 가지 변형이 있습니다: 섹셔닝(Sectioning, 작업을 독립적인 하위 작업으로 분할)과 보팅(Voting, 동일한 작업을 여러 번 실행하여 합의 도출). 고위험 결정이나 다각적 관점이 필요한 경우에 적합합니다.
  4. 오케스트레이터-워커(Orchestrator-Workers): 중앙 LLM이 작업을 동적으로 분해하여 워커 LLM에 위임한 후 결과를 종합합니다. 이는 nanobot의 spawn 도구와 learn-claude-code의 하위 에이전트 모드의 원형입니다.
  5. 평가자-최적화자(Evaluator-Optimizer): 생성기가 출력을 생성하고, 평가자가 기준이 충족될 때까지 루프에서 피드백을 제공합니다. 번역이나 창작 글쓰기처럼 코드로 품질 기준을 정확히 정의하기 어려운 작업에 적합합니다.
Tw93 - inline image

이러한 패턴은 제어 흐름을 구축하는 방법을 해결합니다. 이제 좀 더 엔지니어링 중심적인 질문을 살펴보겠습니다: 시스템이 왜 안정적으로 실행될까요?

2. Harness가 모델보다 더 중요한 이유

Harness는 Agent 주변에 구축된 테스트, 검증, 제약 인프라를 의미합니다. Harness는 최소한 네 가지 부분을 포함합니다: 승인 기준, 실행 경계, 피드백 신호, 폴백 방법.

모델도 중요하지만, 이러한 주변 엔지니어링 조건이 시스템의 안정적인 실행을 결정하는 경우가 많습니다. 이 판단은 코딩과 같이 검증 가능성이 높은 작업에서 가장 사실에 가깝지만, 공개 리서치나 다중 라운드 협상과 같은 검증이 약한 작업에서는 모델의 상한선이 여전히 더 중요합니다.

OpenAI의 Agent 우선 개발 방식

세 명의 엔지니어가 5개월 만에 거의 1,500개의 PR로 백만 줄의 코드를 작성했습니다. 이는 전통적인 개발 속도의 10배입니다. 이러한 속도는 단순히 모델 성능 때문이 아니라 올바른 엔지니어링 결정 덕분이었습니다:

  1. Agent가 볼 수 없는 콘텐츠는 존재하지 않습니다: 지식은 코드베이스 자체에 존재해야 합니다. 외부 문서는 실행 중인 Agent에게 보이지 않습니다. AGENTS.md는 약 100줄의 인덱스로 유지하고, 세부 사항은 필요 시 참조할 수 있도록 docs 디렉토리로 분할합니다.
  2. 문서화하지 말고 코드로 제약하세요: 문서의 규범은 쉽게 무시됩니다. Linter, 타입 시스템, CI 규칙에 인코딩된 제약은 실행 가능합니다. 아키텍처 계층화는 수동 검토가 아닌 커스텀 Linter에 의해 기계적으로 강제됩니다.
  3. 엔드 투 엔드 자율 작업 완료: 상태 확인 및 버그 재현부터 수정 구현 및 앱 검증 실행, PR 열기, 리뷰 처리, 병합까지 전체 체인에 사람의 개입이 필요 없습니다. Agent는 로그, 메트릭, 트레이스를 적극적으로 확인합니다.
  4. 병합 마찰 최소화: 간헐적인 테스트 실패는 진행을 차단하기보다 재시도로 처리합니다. 높은 처리량 환경에서는 수동 리뷰를 기다리는 비용이 작은 오류를 수정하는 비용보다 높은 경우가 많습니다. 코딩 규율이 사라진 것이 아니라 수동 검토에서 기계 실행 제약으로 이동한 것입니다.
Tw93 - inline image

앱은 Vector를 통해 로그, 메트릭, 트레이스를 Victoria 스토리지 계층으로 분산하며, 이는 LogQL, PromQL, TraceQL 인터페이스에 해당합니다. Codex는 이러한 인터페이스를 통해 쿼리, 상관 관계 분석, 추론을 수행합니다. 변경 후에는 앱을 재시작하고 워크로드를 재실행하여 결과를 Codex에 다시 피드백합니다. UI 여정(Journeys)도 입력값입니다. 이 관찰 가능성 스택은 작업별로 생성되고 완료 시 제거됩니다. Agent는 오류가 발생했다는 알림을 기다리지 않고 시스템 상태를 쿼리하여 수정 사항을 확인합니다.

Harness에 대한 핵심 결론은 무엇인가요?

Tw93 - inline image

다이어그램은 작업 명확성과 검증 자동화를 사용하여 작업을 네 가지 상태로 나눕니다. 오른쪽 위(명확한 목표, 자동화된 검증)는 Agent에게 이상적인 영역입니다. 왼쪽 위(명확한 작업이지만 수동 검토)는 사람의 검토 속도에 의해 제한됩니다. 오른쪽 아래(자동화된 피드백이지만 모호한 목표)는 잘못된 방향으로 효율적으로 움직이게 합니다. 왼쪽 아래(둘 다 부족)는 Agent를 무용지물로 만듭니다.

Harness의 역할은 작업을 오른쪽 위 영역으로 밀어 넣어 옳고 그름이 사람의 눈이 아닌 기계가 실행 가능한 기준으로 판단되도록 하는 것입니다.

3. 컨텍스트 엔지니어링이 안정성을 결정하는 이유

Transformer 어텐션의 복잡도는 O(n²)입니다. 컨텍스트가 길어질수록 핵심 신호가 노이즈에 묻히기 쉽습니다. 일반적인 실패 모드는 "컨텍스트 부패(Context Rot)"로, 관련 없는 콘텐츠가 컨텍스트를 지배하여 Agent의 결정 품질이 저하됩니다. 모델 능력 부족으로 보이는 많은 문제는 실제로는 컨텍스트 구성 불량 때문입니다.

컨텍스트를 계층화하는 이유는 무엇인가요?

문제는 일반적으로 창이 충분히 길지 않아서가 아니라 정보 밀도가 잘못되었기 때문입니다. 거의 사용되지 않는 항목을 매번 로드하거나 안정적인 규칙과 동적 상태를 혼합하면 모델이 유용한 것을 인식하기 어려워집니다.

Tw93 - inline image

해결책은 정보를 빈도와 안정성에 따라 계층화하는 것입니다:

  • 영구 계층(Permanent Layer): 정체성, 프로젝트 규칙, 절대 금지 사항. 모든 세션에서 유지되어야 하는 콘텐츠. 짧고, 명확하며, 실행 가능하게 유지하세요.
  • 온디맨드 로딩(On-Demand Loading): 스킬 및 도메인 지식. 설명자는 영구적으로 유지하지만, 전체 콘텐츠는 트리거될 때만 주입합니다.
  • 런타임 주입(Runtime Injection): 현재 시간, 채널 ID, 사용자 선호도와 같은 동적 정보. 필요에 따라 라운드별로 주입합니다.
  • 메모리 계층(Memory Layer): MEMORY.md에 기록된 세션 간 경험. 시스템 프롬프트에 직접 포함되지 않으며, 필요할 때만 읽습니다.
  • 시스템 계층(System Layer): 결정론적 로직을 위한 훅(Hooks) 또는 코드 규칙. 컨텍스트에서 완전히 제외됩니다.

결정론적 로직을 컨텍스트에 넣지 마세요. 훅, 코드 규칙, 도구 제약을 통해 표현할 수 있는 모든 것은 외부 시스템에서 처리해야 합니다.

세 가지 일반적인 압축 전략

  1. 슬라이딩 윈도우(Sliding Window): 오래된 메시지를 폐기합니다. 비용이 낮지만 초기 컨텍스트가 손실됩니다. 짧은 대화에 적합합니다.
  2. LLM 요약(LLM Summary): 모델이 요약을 생성합니다. 중간 비용이 들며 세부 사항은 손실되지만 결정은 유지됩니다. 긴 작업에 적합합니다.
  3. 도구 결과 교체(Tool Result Replacement): 원시 출력을 플레이스홀더로 대체합니다. 비용이 낮고 도구 사용이 많은 작업에 적합합니다.

슬라이딩 윈도우는 가장 쉽지만 초기 배경을 잃습니다. 고급 LLM 요약은 "분기 요약(branch summarization)"을 사용하여 아키텍처 결정, 미완료 작업, 주요 제약 조건을 명시적으로 보존합니다. 도구 교체에서 micro_compact는 매 라운드마다 이전 도구 출력을 교체하고, auto_compact는 컨텍스트가 임계값을 초과할 때 트리거됩니다.

중복 오버헤드 감소를 위한 프롬프트 캐싱

LLM 추론은 각 토큰에 대한 Key-Value 쌍을 계산합니다. 프리픽스가 이전 요청과 정확히 일치하면 캐시에서 읽습니다. 캐싱은 정확한 프리픽스 일치가 필요합니다. 캐시 친화적인 설계는 안정성에 중점을 둡니다: 시스템 프롬프트, 도구 정의, 긴 문서는 안정적이며 캐싱에 적합합니다. 동적 정보(시간, 입력, 도구 결과)는 끝에 배치해야 합니다.

이는 컨텍스트 계층화와 관련이 있습니다. 영구 계층이 안정적일수록 캐시 적중률이 높아지고 한계 비용이 낮아집니다. "짧고 안정적"인 것은 단지 토큰을 절약하기 위한 것이 아니라 캐시를 보호하기 위해서입니다. 지연된 스킬 로딩은 안정적인 프리픽스 뒤에 콘텐츠를 추가하여 도움이 됩니다. 직관에 반하는 점: 자주 변경되는 작은 시스템 프롬프트보다 안정적인 대형 시스템 프롬프트가 더 저렴할 수 있습니다. 후속 읽기에 대한 90% 할인이 초기 쓰기 비용을 능가하기 때문입니다.

왜 스킬을 온디맨드로 로드하나요?

스킬은 효과적인 패턴입니다: 시스템 프롬프트에는 인덱스만 유지하고, 필요할 때 전체 지식을 로드합니다.

typescript
1const systemPrompt = `
2사용 가능한 스킬:
3- deploy: 전체 프로덕션 배포 프로세스
4- code-review: 코드 리뷰 체크리스트
5- git-workflow: 브랜치 전략 및 PR 규범
6`;
7
8async function executeLoadSkill(name: string): Promise<string> {
9 return fs.readFile(`./skills/${name}.md`, "utf-8");
10}

스킬 설명은 토큰 부풀림을 피하기 위해 짧아야 하며 라우팅 조건 역할을 해야 합니다. 언제 사용해야 하는지, 언제 사용하지 말아야 하는지, 출력이 무엇인지 설명하세요. "사용 시기 / 사용하지 말아야 할 시기"를 부정적인 예시와 함께 사용하세요. 많은 라우팅 실패는 모델 능력이 아니라 불명확한 경계 때문입니다. 시스템 프롬프트는 규칙을 명확히 해야 합니다: 각 응답 전에 available_skills를 스캔하고, 일치하면 특정 SKILL.md를 로드하며, 한 번에 하나만 로드합니다.

Tw93 - inline image

데이터는 명확합니다: 부정적인 예시 없이 정확도는 73%에서 53%로 떨어집니다. 추가하면 85%로 올라가고 응답 시간이 18.1% 단축됩니다. 부정적인 예시가 핵심입니다.

스킬 설명자에는 두 가지 함정이 있습니다. 첫째, 단어 수: 모든 스킬에 대한 긴 설명이 누적됩니다. 둘째, 정밀도: "백엔드 도움"은 너무 모호합니다. 효과적인 설명자는 기능 소개가 아닌 라우팅 조건입니다. "나를 사용해야 할 때"가 "내가 할 수 있는 일"보다 더 중요합니다.

수량을 제어하세요: 영구 프롬프트에는 빈도가 높은 스킬만 유지하세요. 빈도가 낮은 스킬은 수동으로 도입하거나 문서로 유지할 수 있습니다. 일반적인 안티 패턴으로는 수백 줄의 매뉴얼을 스킬에 집어넣거나 하나의 스킬이 너무 많은 개별 작업(리뷰, 배포, 디버그)을 다루는 경우가 있습니다.

압축이 가장 쉽게 잃는 것은 무엇인가요?

가장 흔한 문제는 요약이 너무 길다는 것이 아니라 보존 우선순위가 잘못되었다는 것입니다. LLM은 다시 얻을 수 있을 것 같은 정보를 자주 삭제합니다. 도구 출력이 가장 먼저 사라지지만 관련 아키텍처 결정과 실패 경로도 함께 사라지는 경우가 많습니다. CLAUDE.md에 보존 우선순위를 명시적으로 정의하세요:

markdown
1### 압축 지침: 핵심 정보 유지 방법
2우선순위:
31. 아키텍처 결정 (요약하지 마세요)
42. 수정된 파일 및 주요 변경 사항
53. 검증 상태 (통과/실패)
64. 해결되지 않은 TODO 및 롤백 노트
75. 도구 출력 (삭제 가능, 통과/실패 결론만 유지)

또 다른 함정: 식별자를 변경하지 마세요. UUID, 해시, IP, 파일 이름은 정확히 보존해야 합니다. 커밋 해시의 한 글자 오류는 후속 도구 호출을 망가뜨립니다.

파일 시스템이 훌륭한 컨텍스트 인터페이스인 이유

Cursor는 이것을 "동적 컨텍스트 발견(Dynamic Context Discovery)"이라고 부릅니다: 기본적으로 적게 제공하고 필요할 때 읽습니다. 파일 시스템은 자연스러운 인터페이스입니다. 도구 호출은 종종 거대한 JSON을 반환합니다. 컨텍스트에 집어넣는 대신 파일에 쓰세요. Agent는 필요에 따라 grep이나 rg를 사용하여 읽을 수 있습니다. 이렇게 하면 컨텍스트가 깔끔하게 유지되고 개발자가 읽을 수 있습니다.

Cursor는 MCP 도구로 이를 검증했습니다: 도구 설명을 폴더에 동기화합니다. Agent는 기본적으로 도구 이름만 보고 필요에 따라 정의를 쿼리합니다. A/B 테스트에서 총 토큰 소비량이 46.9% 감소했습니다.

이것은 긴 작업 압축에도 효과적입니다. 기록을 폐기하는 대신 전체 채팅 로그를 파일에 저장하고 요약에서 경로를 참조하세요. Agent가 세부 사항이 필요하면 파일에서 검색할 수 있으므로 압축은 손실이 있지만 추적 가능한 작업이 됩니다.

4. 도구 설계가 Agent의 능력을 결정합니다

컨텍스트는 모델이 보는 것을 결정하고, 도구는 모델이 할 수 있는 것을 결정합니다. 양보다 질이 중요합니다. MCP 서버 5개만으로도 정의에 약 55,000 토큰이 소모될 수 있습니다. 이는 대화가 시작되기도 전에 200K 컨텍스트의 거의 30%를 차지합니다. 너무 많은 도구는 모델의 주의를 분산시킵니다.

대부분의 도구 문제는 도구가 너무 적어서가 아니라 잘못된 도구를 선택했거나, 설명을 이해할 수 없거나, 쓸모없는 데이터를 반환하기 때문입니다.

Tw93 - inline image

도구 설계의 진화

도구 설계는 세 단계를 거쳤습니다. 초기에는 기존 API를 단순히 도구로 래핑했습니다. 이후 선택 오류가 종종 엔지니어가 아닌 Agent를 위해 설계된 도구 때문이라는 것을 발견했습니다.

1세대: API 래핑: 각 엔드포인트가 하나의 도구입니다. 너무 세분화되어 있습니다. Agent는 하나의 목표를 위해 여러 도구를 조정해야 합니다.

2세대: ACI (Agent-Computer Interface): 도구는 저수준 API가 아닌 Agent의 목표에 해당합니다. create_fileset_permissions 대신 create_script(path, content, executable)을 제공합니다.

3세대: 고급 도구 사용: 발견 및 호출 최적화:

  • 도구 검색(Tool Search): 모든 정의를 한 번에 집어넣지 마세요. Agent는 search_tools를 통해 정의를 찾습니다. 컨텍스트 유지율이 95%에 도달합니다.
  • 프로그래매틱 도구 호출(Programmatic Tool Calling): 모델이 코드를 사용하여 여러 호출을 조정하도록 합니다. 중간 결과는 LLM 컨텍스트가 아닌 실행 환경에 유지됩니다. 토큰이 150,000에서 2,000으로 줄어들 수 있습니다.
  • 도구 사용 예시(Tool Use Examples): 각 도구에 1-5개의 실제 예시를 제공합니다. JSON Schema는 유형을 설명하지만 예시는 사용법을 보여줍니다. 정확도가 72%에서 90%로 상승할 수 있습니다.

ACI 도구 설계 원칙

도구 설계는 Agent에 직접적인 영향을 미칩니다. 단지 "호출할 수 있는가"가 아니라 "잘못 호출되었을 때 스스로 수정할 수 있는가"가 중요합니다.

잘못된 설계는 모호한 매개변수와 수정 불가능한 오류를 가지고 있습니다. 좋은 설계는 betaZodTool을 사용하여 정의와 구현을 바인딩하고, Zod를 사용한 형식 제약과 구조화된 오류 제안을 제공합니다:

typescript
1const updateTool = betaZodTool({
2 name: "update_yuque_post",
3 description: "Yuque 포스트 내용을 업데이트합니다. 새 포스트를 생성하지는 않습니다.",
4 inputSchema: z.object({
5 post_id: z.string().describe("Yuque 포스트 ID, '12345678'과 같은 숫자 문자열"),
6 title: z.string().optional().describe("포스트 제목, 변경되지 않았으면 생략"),
7 content_markdown: z.string().describe("Markdown 본문"),
8 }),
9 run: async (input) => {
10 const post = await getPost(input.post_id);
11 if (!post) throw new ToolError("포스트 ID가 존재하지 않습니다", {
12 error_code: "POST_NOT_FOUND",
13 suggestion: "유효한 post_id를 얻으려면 먼저 list_yuque_posts를 호출하세요",
14 });
15 return await updatePost(input.post_id, input.title, input.content_markdown);
16 },
17});
Tw93 - inline image

잘못된 설계는 무엇을 하는지만 말하고 언제 사용해야 하는지는 말하지 않습니다. 좋은 ACI 설계는 명확한 경계와 구조화된 오류를 가지고 있어 Agent가 올바르게 선택하고 실패를 빠르게 수정할 수 있도록 돕습니다. 도구를 먼저 디버깅하세요. 대부분의 오류는 모델 능력이 아닌 설명에 있습니다.

도구 메시지를 분리해야 하는 이유는 무엇인가요?

프레임워크는 내부 이벤트(압축, 알림)를 생성합니다. 이는 세션 기록에는 있어야 하지만 LLM으로 보내서는 안 됩니다. 토큰을 낭비하고 모델을 혼란스럽게 만들기 때문입니다. 해결책은 두 가지 메시지 유형입니다: 앱 계층용 AgentMessage(사용자 정의 필드 포함)와 LLM용 표준 Message(user, assistant, tool_result).

5. 메모리 시스템 설계

Agent는 본질적으로 시간적 연속성이 부족합니다. 세션이 끝나면 컨텍스트가 지워집니다. 세션 간 일관성을 달성하려면 메모리 계층을 부차적인 것이 아닌 인프라로 설계해야 합니다.

네 가지 유형의 메모리는 어디에 위치하나요?

해결하는 문제에 따라 분류됩니다:

  • 컨텍스트 윈도우 (작업 메모리): 현재 작업에 필요한 최소 정보. 토큰이 제한적이며 관리되어야 합니다.
  • 스킬 (절차적 메모리): 작업 수행 방법 (워크플로우, 규범). 필요 시 로드됩니다.
  • JSONL 세션 기록 (일화적 메모리): 발생한 일. 디스크에 유지되며 검색 가능합니다.
  • MEMORY.md (의미적 메모리): Agent가 기록한 안정적인 사실. 시스템 프롬프트에 주입됩니다.
Tw93 - inline image

MEMORY.md와 스킬이 협력하는 방법

핵심은 중요한 사실을 유지하면서 콘텐츠 양을 제어하는 것입니다.

ChatGPT의 4계층 메모리: 간단한 구조. 세션 메타데이터 (유지되지 않음), 사용자 메모리 (~33개 사실, 유지/주입됨), 대화 요약 (~15개 최근 요약, 유지됨), 현재 세션 (슬라이딩 윈도우).

OpenClaw 하이브리드 검색: 일일 로그 (memory/YYYY-MM-DD.md), 선별된 사실을 위한 MEMORY.md, 하이브리드 검색(70% 벡터 유사도 + 30% 키워드)을 사용하는 memory_search. 대부분의 Agent에게 구조화된 Markdown + 키워드 검색은 디버깅 가능성과 비용 측면에서 충분합니다.

메모리 통합 트리거 및 롤백

Tw93 - inline image

tokenUsage / maxTokens >= 0.5일 때 통합을 트리거합니다. 메시지를 요약하고, MEMORY.md에 추가하고, 인덱스를 업데이트합니다. 실패하면 원시 메시지를 아카이브에 씁니다. 프로세스는 되돌릴 수 있어야 합니다. 포인터를 이동하고 원시 데이터를 삭제하지 마세요.

6. Agent 자율성 점진적 증가

자율성에는 세 가지 인프라가 필요합니다: 세션 간 재개, 세션 내 진행 상황 제약, 느린 작업을 위한 백그라운드 I/O.

긴 작업을 세션 간에 계속하는 방법

긴 작업은 세션이 완료되기 전에 종료될 때 실패합니다. 안정적인 접근 방식은 초기화 Agent(Initializer Agent)코딩 Agent(Coding Agent) 를 사용하는 것입니다. 초기화 Agent는 한 번 실행되어 feature-list.json, init.sh, claude-progress.txt를 생성합니다. 그런 다음 코딩 Agent는 여러 세션에 걸쳐 실행되며, 이 파일들에서 재개하여 하나의 기능을 구현하고, 테스트를 실행하고, 진행 파일을 업데이트합니다. 이렇게 하면 작업이 외부 상태가 됩니다.

Tw93 - inline image

진행 상황을 컨텍스트가 아닌 파일에 유지하세요. 구조화를 위해 JSON을 사용하세요. feature-list.json의 모든 기능이 passes: true가 되어야만 작업이 완료됩니다.

작업 상태를 명시적으로 작성해야 하는 이유는 무엇인가요?

외부 앵커 없이 Agent는 표류하거나 조기에 완료합니다. 상태를 외부 제어 객체로 기록하세요:

json
1{
2 "tasks": [
3 {"id": "1", "desc": "설정 읽기", "status": "completed"},
4 {"id": "2", "desc": "스키마 수정", "status": "in_progress"}
5 ]
6}

제약 조건: 한 번에 하나의 in_progress만 허용됩니다. 각 단계 후에 상태를 업데이트하세요.

백그라운드 I/O 통합

느린 I/O(파일 작업, 네트워크)는 메인 루프를 차단해서는 안 됩니다. 느린 하위 프로세스를 백그라운드 스레드에 배치하고 다음 LLM 호출 전에 알림 큐를 통해 결과를 주입하세요. 이는 복잡한 비동기 런타임보다 유지 관리가 더 쉽습니다.

7. 멀티 에이전트 시스템 구성

멀티 에이전트 시스템을 엔지니어링하는 것은 격리와 협업에 관한 것입니다.

디렉터 모드(Director Mode): 동기식. 사람이 하나의 Agent와 긴밀하게 상호 작용합니다. 세션이 종료되면 컨텍스트가 손실됩니다.

코디네이터 모드(Coordinator Mode): 비동기 위임. 사람이 목표를 설정하고, Agent가 병렬로 작업하며, 사람이 출력을 검토합니다. 출력은 지속적인 아티팩트(PR, 브랜치)가 됩니다.

Tw93 - inline image

오케스트레이터는 병렬로 작업하는 하위 에이전트를 관리하며, JSONL 받은 편지함 프로토콜을 통해 통신하고 격리를 위해 Worktrees를 사용합니다.

Tw93 - inline image

하위 에이전트는 무엇에 적합한가요?

검색 및 시행착오는 메인 Agent의 컨텍스트를 오염시켜서는 안 됩니다. 메인 Agent는 결론만 필요합니다.

typescript
1const result = await runAgentLoop(task, { messages: [] });
2return summarize(result); // 메인 컨텍스트는 이 줄만 봅니다

협업을 프로토콜로 작성해야 하는 이유는 무엇인가요?

자연어 협업은 Agent가 약속을 잊어버리면서 실패합니다. 구조화된 프로토콜을 사용하세요:

typescript
1{ request_id, from_agent, to_agent, content, status: 'pending', timestamp }

충돌 복구를 위해 추가 전용 JSONL 받은 편지함을 사용하세요. 협업보다 격리가 먼저입니다.

Tw93 - inline image

멀티 에이전트 시스템에서 환각 증폭

오류는 Agent 간에 연쇄적으로 발생합니다. 교차 검증은 독립적인 Agent나 외부 피드백(테스트, 컴파일러)이 결론을 판단하도록 하여 이 연쇄를 끊습니다.

Tw93 - inline image

8. Agent 평가 방법

평가에는 테스트 케이스, 채점 기준, 자동화된 검증이 필요합니다.

Tw93 - inline image

전통적인 단일 턴 평가(프롬프트 -> 응답)로는 충분하지 않습니다. Agent 평가에는 도구와 환경이 필요합니다. 채점은 Agent가 말한 것뿐만 아니라 환경에서 발생한 일을 기반으로 합니다.

Tw93 - inline image

핵심 개념: 작업(Task) , 시도(Trial) , 채점자(Grader) . 트랜스크립트(Transcript) (실행 로그)와 결과(Outcome) (최종 상태). 둘 다 필요합니다. Agent가 "티켓이 예약되었습니다"라고 말할 수 있지만(트랜스크립트) 데이터베이스 레코드를 생성하지 못할 수 있습니다(결과).

평가 상태 및 지표

많은 팀이 여전히 수동 검토나 LLM 평가에 의존하고 있습니다. 일반적인 지표로는 Pass@k (이론적으로 가능한가?)와 Pass^k (프로덕션에서 안정적인가?)가 있습니다. 이 둘을 혼동하지 마세요.

Tw93 - inline image

세 가지 유형의 평가자

  1. 코드 평가자: 문자열 매칭, 유닛 테스트. 가장 높은 확실성.
  2. 모델 평가자: 기준에 기반한 LLM 평가. 의미론적 품질에 적합.
  3. 인간 평가자: 전문가 리뷰. 느리지만 기준선을 설정합니다.

처음부터 평가 시스템 구축하기

실제 실패 사례 20~50개로 시작하세요. 테스트가 서로 오염되지 않도록 환경 격리를 보장하세요. 긍정 사례와 부정 사례를 모두 포함하세요. 두 전문가가 특정 사례에 대해 의견이 다르다면, 기준이 아직 명확하지 않은 것입니다.

에이전트를 수정하기 전에 평가를 먼저 수정하세요

점수가 떨어지면 먼저 평가 시스템을 확인하세요. 환경 문제(메모리 제한, 평가자의 버그)는 모델 성능 저하처럼 보일 수 있습니다.

Tw93 - inline image

9. 실행 프로세스 추적

추적 없이는 실패를 재현할 수 없습니다. APM 지표(지연 시간, 오류율)만으로는 충분하지 않습니다. 추론 체인이 필요합니다.

추적에 무엇을 기록해야 할까?

전체 프롬프트, 다중 턴 메시지, 도구 호출/인수/반환값, 사고 체인, 최종 출력, 토큰 및 지연 시간.

2계층 관찰 가능성

  1. 수동 샘플링: 오류나 부정적 피드백에 대한 규칙 기반 샘플링으로 실패 패턴을 찾습니다.
  2. LLM 자동 평가: 수동 계층을 보정 기준으로 사용하여 추적을 전체적으로 커버합니다.
Tw93 - inline image

이벤트 스트림을 기반으로

tool_start, tool_end, turn_end에서 이벤트를 발생시킵니다. 다운스트림 시스템(로그, UI, 평가)은 코어 루프 코드를 변경하지 않고 이러한 이벤트를 소비합니다.

Tw93 - inline image

10. OpenClaw로 에이전트 구축하기

OpenClaw는 다섯 개의 분리된 계층을 사용합니다: 게이트웨이, 채널 어댑터, Pi 에이전트(코어 루프), 툴셋(ACI 설계), 컨텍스트/메모리.

Tw93 - inline image

메시지 버스 분리

메시지 버스는 채널과 에이전트를 분리합니다. 채널은 I/O만 처리하고, 에이전트는 처리만 담당합니다.

계층별 시스템 프롬프트

SOUL.md는 정체성과 완료 기준을 정의합니다. 프롬프트는 계층화됩니다: 런타임 정보 -> 정체성 -> 메모리 -> 스킬 -> 동적 주입.

Tw93 - inline image

보안 경계를 먼저 설정하세요

기능을 추가하기 전에 다음을 설정하세요: 사용자 허용 목록, 작업 공간 격리(경로 확인), 감사 로그.

프롬프트 인젝션 보호: 외부 콘텐츠를 신뢰할 수 없는 것으로 취급하세요. 소스-싱크 분리를 사용하세요. 에이전트에 필요하지 않은 도구를 제공하지 마세요. 민감한 작업에는 명시적인 인간 확인을 요구하세요.

공급자 폴백: 하나의 공급자(Anthropic -> OpenAI)가 실패하면 자동으로 전환합니다.

11. 일반적인 안티 패턴

  1. 시스템 프롬프트를 지식 베이스로 사용(너무 김).
  2. 도구 과잉(에이전트가 잘못된 도구를 선택함).
  3. 검증 루프 누락.
  4. 경계 없는 멀티 에이전트 시스템.
  5. 메모리 통합 부족(20턴 후 품질 저하).
  6. 평가 시스템 부재.
  7. 성급한 멀티 에이전트 복잡성.
  8. 기계적 제약 대신 기대치에 의존.

12. 결론

  1. 에이전트 코어는 안정적인 루프입니다. 새로운 기능은 외부화되어야 합니다.
  2. Harness는 모델보다 수렴에 더 큰 영향을 미칩니다.
  3. 컨텍스트 엔지니어링은 "컨텍스트 부패"를 방지합니다.
  4. ACI 도구 설계는 목표와 오류 수정에 중점을 둡니다.
  5. 메모리는 계층화됩니다(작업, 절차, 일화, 의미).
  6. 긴 작업은 외부화된 상태와 파일에 의존합니다.
  7. 멀티 에이전트 시스템에는 프로토콜과 격리가 필요합니다.
  8. 평가: Pass@k는 능력, Pass^k는 품질.
  9. 추적은 디버깅의 전제 조건입니다.
  10. 안정적인 에이전트는 분리 및 보안 경계와 같은 엔지니어링 세부 사항에 의존합니다.
Save to YouMind

Use YouMind to read viral articles deeply

Save the source, ask focused questions, summarize the argument, and turn a viral article into reusable notes in one AI workspace.

Explore YouMind

분석할 패턴 더 보기

최근 바이럴 아티클

더 많은 바이럴 아티클 보기