절제 가능성 지식 그래프 — Who should undergo pancreatic resection?

누가 췌장 절제술의 대상인가

수술 전 병기 평가에서 절제 가능성 분류를 거쳐 치료 결정에 이르는 관계망이다. 노드를 클릭하면 연결된 이웃이 홉 거리별로 남고 나머지는 흐려진다.

노드를 끌어 옮기고, 빈 곳을 끌어 화면을 이동하며, 휠로 확대한다

노드를 클릭하면 정의와 연결 관계가 여기에 표시된다.

수술 전 평가 질환·병기 상태 절제 가능성 범주 치료 해부·병리 소견 절제 금기·불가 절제 적응
오케스트레이터-워커 패턴
Method Note · Multi-agent

오케스트레이터-워커 패턴의 실행 요건

한 세션이 과제를 하위 작업으로 분해하고 별도 세션에 배정한 뒤 결과를 취합하는 구성이다. 패턴의 원리는 실행 환경과 무관하나 구성 방법은 다르므로, 클로드 코드와 클로드 데스크탑을 각 절에서 병기한다. 생명의학 연구 작업을 예로 든다.

대상 · 다중 에이전트 실행이 처음인 연구자 환경 · Claude Code · Claude Desktop 기준 · 2026-08

01 패턴의 정의와 적용 조건

오케스트레이터-워커는 중앙의 한 세션이 과제를 하위 작업으로 분해하고, 각 하위 작업을 별도 세션에 배정한 다음, 반환된 결과를 하나로 취합하는 구성이다. Anthropic의 에이전트 설계 문서는 이를 중앙 모델이 작업을 동적으로 분해하고 워커 모델에 위임한 뒤 결과를 종합하는 방식으로 규정하고 있다.

단순 병렬 처리와 형태는 유사하나 결정적 차이가 하나 있으므로, 두 구성을 구분해서 선택해야 한다. 병렬 처리에서는 하위 작업이 사전에 정의되는 반면, 오케스트레이터-워커에서는 하위 작업의 수와 성격이 입력에 따라 실행 시점에 결정된다.

적용 조건

착수 시점에 하위 작업의 수와 성격을 예측할 수 없을 때 적용한다. 처리 대상이 몇 건인지, 각각에 어떤 처리가 필요한지가 입력을 확인해야 정해지는 경우가 여기에 해당한다. 대상 목록과 처리 방식이 미리 확정되어 있다면 병렬 처리로 충분하며, 오케스트레이터를 두면 비용만 증가한다.

적용하지 않아야 하는 경우도 명확하다. 작업 단계가 순차 의존 관계에 있어 앞 단계의 출력이 뒤 단계의 입력이 되는 구조라면 분해의 이득이 없으므로 단일 세션에서 처리한다. 작업량이 작을 때에도 마찬가지이며, 분해와 취합에 드는 비용이 실행 비용을 초과한다.

이 절의 내용은 실행 환경과 무관하게 성립한다. 환경에 따라 달라지는 것은 워커를 정의하고 배정하는 방법이므로, 다음 절에서 대조한다.

ORCHESTRATOR 분해와 배정 과제 정의서 작성 WORKER · 병렬 워커 01 work/01/ 에만 기록 워커 02 work/02/ 에만 기록 워커 03 work/03/ 에만 기록 SYNTHESIS 취합 출처 표시 유지
동일 세션이 분해와 취합을 모두 담당하므로, 두 지점이 같은 오류원을 공유한다

02 두 환경의 구성 차이

이 노트에서 코드는 터미널에서 실행되는 클로드 코드를, 데스크탑은 데스크탑 앱의 작업 세션을 가리킨다. 차이는 네 지점에 집중되어 있다.

항목클로드 코드클로드 데스크탑
워커 정의 정의 파일로 사전 등록한다. .claude/agents/*.md(프로젝트) 또는 ~/.claude/agents/*.md(사용자) 사전 등록 수단이 없으므로 배정 지시문에 역할을 직접 기술하거나, 역할 파일을 읽도록 지시한다
도구 제한 정의 파일의 tools 또는 disallowedTools로 워커별 도구를 한정한다 워커별 도구 한정 수단이 없으므로 쓰기 범위를 지시문으로만 제한한다
파일 위치 워커가 오케스트레이터와 동일한 파일시스템에서 실행되므로 경로 변환이 필요 없다 워커 실행 환경과 사용자 파일 위치가 분리되어 있으므로 경로 변환이 필요하다
쓰기 충돌 차단 정의 파일에 isolation: worktree를 지정하면 워커가 독립된 git worktree에서 실행된다 격리 수단이 없으므로 디렉토리 분할을 지시문으로 강제한다
모델 지정 정의 파일의 model로 워커마다 지정한다 워커별 지정 수단이 없다
권한 승인 설정 파일의 규칙이 워커의 동작에도 적용되며, 워커 자신의 권한 설정은 반영되지 않는다 사용자 승인이 오케스트레이터 세션에서 처리된다
상속되는 맥락 CLAUDE.md, MCP 서버 설정, 스킬, git 상태가 워커에 전달된다 세션에서 사용 가능한 도구와 스킬이 전달되나, 원격 도구는 워커가 먼저 확보해야 한다
중첩 깊이 최대 3단계까지 허용되며 환경변수로 조정한다 문서화된 값이 확인되지 않는다
차이를 한 문장으로

클로드 코드에서는 워커의 제약을 정의 파일로 강제하고, 데스크탑에서는 지시문으로 요청한다. 전자는 위반이 차단되는 반면 후자는 위반이 사후에 발견되므로, 데스크탑에서는 쓰기 범위 분할과 산출물 위치 지정을 지시문에서 더 명시적으로 기술해야 한다.

두 환경에서 동일한 것

다음 항목은 환경과 무관하게 성립하므로, 이 노트의 나머지 절 대부분이 양쪽에 그대로 적용된다.

  • 워커는 오케스트레이터의 대화 이력을 승계하지 않는다
  • 워커의 중간 작업 내역은 오케스트레이터에 전달되지 않고 최종 결과만 요약 형태로 반환된다
  • 워커는 오케스트레이터 세션에 종속되므로 세션이 종료되면 복구되지 않는다
  • 같은 세션 안에서는 종료된 워커를 이어서 호출하여 대화 맥락을 유지한다

두 번째 항목이 파일 기록을 필수로 만든다. 중간 산출물이 오케스트레이터에 도달하지 않으므로, 워커가 파일로 남기지 않은 내용은 취합 시점에 존재하지 않는 것과 같다.

03 구조적 전제 세 가지

이 구성은 다음 세 조건이 충족될 때에만 의도대로 작동하므로, 실행 전에 각각을 확인해야 한다.

컨텍스트 격리

워커 세션은 오케스트레이터 세션의 대화 이력을 승계하지 않는다. 배정 시점에 지시문으로 전달한 문장과 워커가 직접 읽은 파일만이 워커에 존재하는 정보이며, 오케스트레이터가 앞서 확인한 사실이라도 명시하지 않으면 전달되지 않는다.

이 격리는 결함이 아니라 이 구성을 쓰는 이유이다. 각 워커의 컨텍스트가 자기 작업 단위로만 채워지므로, 단일 세션에서 전체를 처리할 때보다 각 하위 작업에 배정되는 컨텍스트가 넓어진다. 다만 전달 누락이 곧 정보 부재로 이어지므로, 과제 정의서의 완결성이 결과 품질을 직접 좌우한다.

환경별 차이 · 상속되는 맥락

코드 대화 이력은 상속되지 않으나 CLAUDE.md와 MCP 서버 설정, 스킬, git 상태는 워커에 전달되므로, 프로젝트 규약을 CLAUDE.md에 두면 과제 정의서를 그만큼 줄이게 된다.

데스크탑 세션에서 사용 가능한 스킬은 전달되나, 사용자 파일에 접근하는 원격 도구는 워커가 작업 시작 전에 직접 확보해야 하므로 이 절차를 지시문 첫 항목에 둔다.

파일이 유일한 전달 매개

워커가 반환하는 서술 요약은 오케스트레이터의 컨텍스트에 남으나 세션이 종료되면 소실되며, 워커가 수행한 중간 작업은 애초에 반환되지 않는다. 결과를 보존하려면 워커가 파일로 기록해야 하고, 기록 위치는 배정 시점에 지정한다.

환경별 차이 · 경로

코드 워커가 오케스트레이터와 같은 작업 디렉토리에서 실행되므로 상대 경로를 그대로 쓴다. 다만 isolation: worktree를 지정한 경우에는 워커의 변경이 별도 worktree에 기록되므로, 산출물을 공용 디렉토리에 남기려면 그 점을 고려하여 경로를 지정한다.

데스크탑 워커의 실행 환경과 사용자 파일 위치가 분리되어 있으므로 같은 파일이 두 개의 경로로 지칭된다. 지시문에 두 경로를 모두 제시하고 변환 규칙을 명시해야 하며, 워커가 자신의 실행 환경에 파일을 기록하면 그 파일은 사용자에게 도달하지 않는다.

쓰기 범위 분할

워커가 병렬로 실행되므로 두 워커가 같은 파일에 기록하면 결과가 소실된다. 각 워커에 겹치지 않는 디렉토리를 배정하고, 배정 범위 밖은 읽기만 허용한다.

조사 영역의 중복은 이와 구분해야 한다. 두 워커가 같은 대상을 조사하도록 배정하는 것은 결함이 아니며, 두 관측이 어긋날 경우 그 불일치 자체가 확인 대상이 된다. 분리해야 하는 것은 파일 쓰기 범위이지 조사 범위가 아니다.

환경별 차이 · 분할을 강제하는 방법

코드 정의 파일의 tools에서 쓰기 도구를 제외하면 조사 전용 워커가 파일을 수정하는 경로 자체가 차단되고, isolation: worktree를 지정하면 편집 워커 사이의 충돌이 차단된다.

데스크탑 도구 수준의 제한 수단이 없으므로 분할이 지시문 준수에 의존한다. 배정 범위를 한 줄로 명시하고, 취합 시점에 각 워커의 산출물이 배정된 디렉토리에만 생성되었는지 확인한다.

04 실행 절차

절차 자체는 양쪽에서 동일하며, 5단계의 실행 방법만 달라진다.

단계수행 내용산출
1적용 여부를 판정한다. 하위 작업이 사전에 확정되면 병렬 처리로, 순차 의존이 강하면 단일 세션으로 전환한다판정 근거 1행
2작업 디렉토리를 확정하고 실행 단위 디렉토리를 생성한다<날짜>-<주제>/
3과제 정의서를 작성하고 사용자 승인을 받는다BRIEF.md
4작업을 분해하고 배정표를 작성하여 다시 승인을 받는다배정표
5워커를 전원 병렬로 실행하고 반환된 식별자를 기록한다work/NN/
6산출물을 취합하고 각 항목의 출처를 표시한다SUMMARY.md
7결과가 파일에 기록되었는지 확인하고 종료한다실행 기록 1행

승인 지점을 두 곳(3단계와 4단계)에 두는 이유는 되돌림 비용의 분포이다. 워커가 실행된 이후에 과제 정의나 배정을 수정하면 이미 소비한 실행 비용이 회수되지 않으므로, 실행 전에 확인 절차를 배치한다.

실행 단위 디렉토리 구조

디렉토리의 논리 구조는 두 환경에서 동일하다. 달라지는 것은 어디에 두는가워커에게 어떻게 지시하는가이다.

# 논리 구조 — 양쪽 공통
<프로젝트>/_runs/<YYYYMMDD>-<주제>/
    BRIEF.md          # 과제 정의서
    SUMMARY.md        # 취합 결과
    work/01-<작업명>/OUTPUT.md   # 워커 01 산출물
    work/02-<작업명>/OUTPUT.md
    work/03-<작업명>/OUTPUT.md
INDEX.md              # 실행 이력 누적

디렉토리를 대상 프로젝트 안에 두면 실행 기록이 분석 대상과 함께 보존되므로, 몇 개월 뒤에 결과의 근거를 다시 확인할 때 두 자료를 함께 열람하게 된다.

배치와 경로 표기

항목클로드 코드클로드 데스크탑
위치 오케스트레이터의 작업 디렉토리 안에 둔다. 별도 제약이 없다 연결된 폴더 안에 두어야 한다. 그 밖에 만든 파일은 사용자에게 도달하지 않는다
경로 표기 상대 경로를 그대로 쓴다
_runs/20260831-대조/work/01/
두 경로를 병기한다. 사용자 기준 절대 경로와 워커 실행 환경 기준 경로가 다르다
정의 파일 .claude/agents/에 별도로 둔다. 실행 단위 디렉토리와 분리된다 역할 파일을 쓰는 경우 연결된 폴더 안 임의 위치에 둔다
버전 관리 프로젝트가 저장소이면 _runs/의 추적 여부를 먼저 정한다. 워커에 전달되는 git 상태에 실행 기록이 포함된다 버전 관리와 무관하게 파일로만 남는다
재실행 시 정리 이전 실행 디렉토리를 삭제하거나 이동한다 워커의 파일 삭제가 기본적으로 허용되지 않으므로 날짜로 디렉토리를 분리하고 덮어쓰지 않는다
코드 · 격리 설정과 산출물 위치

코드 워커에 isolation: worktree를 지정하면 그 워커의 기록이 독립된 worktree에 남으므로 주 작업 트리의 _runs/에 나타나지 않는다. 취합 단계에서 산출물을 찾지 못하는 원인이 대개 이것이다.

조사 결과를 한곳에 모으는 작업에서는 격리를 지정하지 않는 편이 낫고, 편집 충돌 때문에 격리가 필요하다면 산출물을 어디에서 회수할지 배정 시점에 정해 둔다.

환경별 차이 · 2단계와 5단계

코드 2단계에서 정의 파일을 함께 준비한다. 정의 파일을 .claude/agents/에 두면 버전 관리 대상이 되므로 이후 실행에서 동일한 워커 구성이 재현된다. 5단계에서는 사전 등록한 워커를 이름으로 호출한다.

데스크탑 정의 파일 등록 단계가 없으므로 5단계에서 지시문에 역할 전체를 담는다. 역할 기술이 반복된다면 역할 정의를 별도 파일로 두고 워커가 읽도록 지시하는 방법으로 지시문 길이를 줄인다.

05 과제 정의서에 포함할 항목

워커가 대화 이력을 승계하지 않으므로, 정의서는 그 자체로 완결되어야 한다. 다음 다섯 항목을 포함한다.

항목기재 내용
목표무엇이 확인되면 과제가 종료되는지를 한 문단으로 기술한다
배경필요한 맥락을 기재하되 확인된 사실과 미확인 전제를 구분하여 적는다
제약수정을 금지하는 파일, 준수해야 하는 절차, 실행을 허용하지 않는 명령을 명시한다
완료 조건산출물이 갖추어야 할 형식과 내용을 항목별로 기재한다
배정표워커 번호, 작업 단위, 쓰기 범위를 표로 정리한다

배경을 두 갈래로 나누는 이유는 전제의 전파 때문이다. 정의서에 기재한 내용은 워커에게 검증된 사실로 수용되므로, 오케스트레이터가 확인하지 않은 추정을 사실과 섞어 적으면 모든 워커가 동일한 오류를 공유한 상태에서 작업을 시작하게 된다.

환경별 차이 · 정의서의 분량

코드 프로젝트 공통 규약(코딩 규칙, 디렉토리 구조, 금지 명령)은 CLAUDE.md가 워커에 전달하므로 정의서에서 생략한다. 정의서에는 이번 과제에만 해당하는 내용을 남긴다.

데스크탑 이에 해당하는 자동 전달 경로가 없으므로 공통 규약도 정의서에 포함하거나, 규약 파일을 지정하여 워커가 읽도록 지시한다.

배정 대조

정의서에 등장하는 모든 관심 항목을 나열하고 각각이 어느 워커에 배정되었는지 표로 대조한다. 배정되지 않은 항목은 범위 밖으로 명시하며, 명시하지 않고 누락하면 해당 항목이 처리되지 않았다는 사실 자체가 기록에 남지 않는다.

06 워커 정의와 배정 지시문

이 절이 두 환경에서 가장 크게 갈리는 부분이다. 전달해야 하는 정보는 같으나 전달 경로가 다르다.

클로드 코드 — 정의 파일과 호출

워커의 역할과 제약을 마크다운 파일로 등록하며, 프론트매터에 적용 조건을 기재한다. 프로젝트 스코프인 .claude/agents/가 사용자 스코프인 ~/.claude/agents/보다 우선한다.

# .claude/agents/extractor.md
---
name: extractor
description: 지정된 문서에서 정의된 항목만 추출하여 표로 기록한다
tools: Read, Grep, Glob, Write   # 허용 도구를 한정한다
model: sonnet
---

# 이하 본문에 역할 규약을 기술한다
- 배정된 작업 단위 하나만 수행한다
- 산출물은 지정된 디렉토리에만 기록한다
- 확인하지 못한 항목은 미확인으로 표시한다

도구 지정에는 두 방식이 있으므로 목적에 따라 선택한다. tools는 허용 목록을 지정하고 disallowedTools는 금지 목록을 지정하며, 두 필드를 함께 쓰면 금지 목록이 우선 적용된다. 조사 전용 워커에서 쓰기 도구를 제외하면 파일 수정 경로 자체가 차단되므로 지시문 준수에 의존하지 않게 된다.

편집 작업을 병렬로 배정할 경우에는 isolation: worktree를 지정하여 각 워커를 독립된 git worktree에서 실행한다. 변경이 없는 임시 worktree는 자동으로 정리된다.

클로드 데스크탑 — 지시문에 역할을 담는다

사전 등록 수단이 없으므로 다음 요소를 지시문에 순서대로 담으며, 순서를 유지하는 편이 누락을 줄인다.

[1] 역할과 식별자
[2] 실행 환경 준비 # 원격 파일 접근 도구를 먼저 확보하게 한다
[3] 작업 디렉토리 경로 # 사용자 기준 경로와 실행 환경 기준 경로를 모두 제시한다
    BRIEF.md 를 먼저 읽도록 지시한다
[4] 작업 단위 # 하나만 배정한다
[5] 쓰기 허용 범위 # work/NN/ 안으로 한정한다
[6] 참조할 절차나 방법론 <명칭 | 없음>
[7] 산출물 형식과 기록 위치
    실행 환경 내부에 기록하지 않도록 명시한다

항목 2와 7이 데스크탑에서 추가되는 부분이다. 원격 도구를 확보하지 않은 상태로 파일 접근을 시도하면 작업이 실패하고, 실행 환경 내부에 기록한 파일은 사용자에게 도달하지 않는다.

양쪽에 공통되는 원칙

작업 단위를 하나만 배정하는 것이 중요하다. 두 개 이상을 배정하면 워커가 둘 사이의 우선순위를 자체적으로 결정하며, 그 결정 근거는 산출물에 남지 않는다.

배정 시 확인할 사항

존재하지 않는 절차나 도구의 명칭을 지시문에 기재하면, 워커가 해당 항목의 확보에 실패한 상태로 작업을 계속 진행하는 경우가 발생한다. 명칭을 기재하기 전에 실행 환경에 실제로 존재하는지 확인하고, 배정할 항목이 없으면 없음이라고 명시한다.

권한 처리

코드 설정 파일의 권한 규칙이 워커의 동작에도 동일하게 적용되며, 워커 정의 파일에 기재한 권한 설정은 반영되지 않는다. 따라서 워커가 실행할 명령의 승인 범위는 오케스트레이터 세션 기준으로 정한다.

데스크탑 승인 요청이 오케스트레이터 세션에서 처리되므로, 승인 대기가 발생하면 해당 워커의 진행이 지연된다. 승인이 필요한 동작을 여러 워커에 분산 배정하면 대기가 누적되므로 한 워커로 모으는 편이 낫다.

07 취합 단계의 오류원

분해와 취합을 같은 세션이 담당하므로, 취합물은 워커 산출물과 달리 별도의 대조 절차를 거치지 않는다. 이 구조가 취합 단계를 이 구성의 최대 오류원으로 만들며, 이 점은 두 환경에서 동일하다.

실무적으로 다음 두 가지를 권장한다.

  • 취합표의 각 행에 출처를 표시한다. 어느 워커의 어느 절에서 옮겨 온 항목인지를 기재하면, 판정이 옮겨지는 과정에서 변형되었는지를 사후에 확인하게 된다.
  • 집계는 파일에서 기계적으로 수행한다. 항목 수를 서술 요약에서 읽어 옮기지 않고 파일을 직접 세면, 요약 과정에서 발생하는 누락이 차단된다.

워커의 서술 요약을 그대로 취합물에 옮기는 것도 오류원이다. 워커가 특정 작업을 수행하지 못하였다고 보고한 경우, 그 사유를 확인하지 않고 기록하면 미확인 진술이 확정된 사실로 전환된다. 파일 부재 진술은 목록 조회로, 시각 진술은 수정 시각 확인으로 각각 대조한다.

08 비용과 한계

항목내용
토큰 소비워커마다 과제 정의서와 참조 자료를 독립적으로 읽으므로 소비량이 워커 수에 비례하여 증가한다. 워커 수는 독립적으로 존재하는 작업 축의 수와 일치시키고, 그 이상으로 늘리지 않는다
세션 종속성워커는 오케스트레이터 세션에 종속되어 실행되므로 세션이 종료되면 복구되지 않는다. 종료 전에 결론이 파일에 기록되었는지 확인해야 한다
실행 시간병렬 실행이므로 가장 오래 걸리는 워커의 실행 시간이 곧 전체 소요 시간이 되며, 작업 단위 사이의 분량 편차가 크면 이득이 감소한다
재현성동일한 정의서로 재실행하여도 산출물이 동일하지 않다. 결론의 근거를 파일에 남겨야 사후 검토가 성립한다

워커 수를 정하는 기준을 다시 정리하면, 수를 먼저 정하고 역할을 배정하는 순서가 아니라 독립적인 작업 축을 먼저 식별하고 그 수만큼 워커를 배정하는 순서이다. 축이 명확한 셋이 축이 불분명한 다섯보다 취합하기 쉽다.

환경별 차이 · 비용 조절 수단

코드 정의 파일에서 워커마다 모델을 지정하고 최대 턴 수를 제한하므로, 단순 추출 작업에 경량 모델을 배정하여 비용을 낮추게 된다. 중첩 깊이는 최대 3단계까지 허용되며 환경변수로 조정한다.

데스크탑 워커별 모델 지정과 턴 수 제한 수단이 없으므로, 비용은 워커 수와 각 워커에 전달하는 자료의 분량으로만 조절한다.

09 생명의학 작업 적용 예

다음 세 사례는 하위 작업의 수가 입력을 확인해야 정해지는 경우이므로 이 구성에 해당하며, 두 환경에서 모두 성립한다.

다기관 데이터셋의 변수 정의 대조

기관별 코드북의 수와 각 코드북에서 확인해야 할 변수의 범위가 파일을 열어 봐야 정해진다. 기관 하나를 워커 하나에 배정하고, 각 워커가 자기 코드북에서 대상 변수의 정의와 단위, 결측 코드를 추출하여 기록한다. 취합 단계에서 정의가 상충하는 변수 목록을 작성하면, 통합 분석 전에 조정이 필요한 항목이 특정된다.

이 작업은 원본을 수정하지 않는 조사 작업이므로, 클로드 코드에서는 워커의 허용 도구에서 편집 도구를 제외하여 원본 훼손 경로를 차단하게 된다.

파이프라인 산출물과 방법 기재 내용의 대조

분석 스크립트가 실제로 수행하는 처리와 원고의 방법 절에 기재된 절차가 일치하는지를 확인하는 작업이다. 스크립트 측과 원고 측을 각각 별도 워커에 배정하고, 두 산출물을 취합하여 불일치 항목을 정리한다. 두 워커가 서로의 자료를 읽지 않은 상태에서 각각 추출하므로, 한쪽 서술이 다른 쪽 해석을 유도하는 상황이 발생하지 않는다.

이 배정이 유효한 이유

단일 세션에서 스크립트와 원고를 함께 읽으면 먼저 읽은 자료가 뒤에 읽는 자료의 해석 틀을 형성한다. 두 자료를 분리된 컨텍스트에서 각각 추출한 뒤 대조하면 이 영향이 차단되므로, 대조 작업에서는 분해 자체가 방법론적 이득을 낳는다.

문헌 집합의 항목별 추출

선별을 통과한 논문의 수가 검색 결과를 확인해야 정해지고, 논문마다 추출 가능한 항목의 범위가 다르다. 논문을 분량에 따라 묶어 워커에 배정하고, 각 워커가 정의서에 지정된 항목만 추출하여 동일한 표 형식으로 기록한다. 추출 항목과 표 형식을 정의서에서 고정하지 않으면 취합 단계에서 열 구성이 워커마다 달라지므로, 형식 지정이 특히 중요하다.

적용하지 않는 경우

단일 데이터셋에 대한 통계 분석은 전처리, 모델 적합, 진단, 보고가 순차 의존 관계에 있으므로 이 구성의 대상이 아니다. 반면 동일한 데이터에 서로 다른 모델링 전략을 적용하여 비교하는 작업은 전략마다 독립된 축이 성립하므로 대상이 된다.

10 점검 목록

점검 시점이 둘로 나뉘므로 항목도 나누어 배치한다. 앞의 항목들은 워커를 실행하기 전에 확인하며, 이 시점을 넘기면 되돌림 비용이 실행 비용만큼 발생한다. 뒤의 세 항목은 취합과 종료 시점에 확인한다.

워커를 실행하기 전 · 양쪽 공통

  • 하위 작업의 수가 입력에 따라 결정되는 과제인가
  • 작업 단계가 순차 의존 관계에 있지 않은가
  • 작업 디렉토리와 실행 단위 디렉토리를 생성하였는가
  • 과제 정의서의 배경에서 확인된 사실과 미확인 전제를 구분하였는가
  • 완료 조건을 산출물 형식 수준까지 기재하였는가
  • 배정 대조를 수행하고 미배정 항목을 범위 밖으로 명시하였는가
  • 워커별 쓰기 범위가 겹치지 않는가
  • 지시문에 기재한 절차와 도구가 실행 환경에 존재하는가

워커를 실행하기 전 · 코드

  • 워커 정의 파일의 스코프를 확인하였는가(프로젝트 스코프가 사용자 스코프보다 우선한다)
  • 조사 전용 워커의 허용 도구에서 편집 도구를 제외하였는가
  • 편집 작업을 병렬로 배정한 경우 격리 설정을 지정하였는가
  • 격리를 지정한 워커의 산출물을 어디에서 회수할지 정하였는가
  • 실행 단위 디렉토리를 저장소에서 추적할지 정하였는가
  • 워커가 실행할 명령이 오케스트레이터 세션의 권한 규칙으로 허용되는가

워커를 실행하기 전 · 데스크탑

  • 실행 단위 디렉토리를 연결된 폴더 안에 생성하였는가
  • 경로 변환 규칙을 지시문에 명시하였는가
  • 원격 파일 접근 도구를 먼저 확보하도록 지시문에 기재하였는가
  • 실행 환경 내부에 산출물을 기록하지 않도록 명시하였는가
  • 승인이 필요한 동작이 여러 워커에 분산되어 있지 않은가

취합과 종료 시점 · 양쪽 공통

  • 취합표의 각 행에 출처를 표시하였는가
  • 집계 수치를 서술 요약이 아니라 파일에서 직접 세었는가
  • 결론이 파일에 기록되었는가
정리

이 구성의 이득은 병렬 실행 속도가 아니라 컨텍스트 분리에서 발생한다. 각 하위 작업이 독립된 컨텍스트에서 처리되므로 상호 간섭이 차단되며, 대조 성격의 작업에서는 이 분리 자체가 방법론적 요건이 된다. 다만 분리된 결과를 하나로 되돌리는 취합 단계가 남으므로, 그 지점의 출처 표시와 기계적 집계가 결과의 신뢰도를 결정하게 되는 것이다.

참고 — 패턴의 정의와 병렬 처리와의 구분은 Anthropic, Building Effective Agents를 따랐다. 클로드 코드의 워커 정의 파일, 도구 제한, 격리, 권한 상속, 중첩 깊이는 Subagents, Tools reference, Worktrees, Permission modes 문서에서 확인하였다. 데스크탑 측 서술은 실제 실행에서 관측한 동작에 근거하며, 동시 실행 한도는 두 환경 모두 문서에서 확인되지 않았다.

\n\n \n\n\n여러 개가 도는 것과 팀이 도는 것 \n \n
Study Note · Claude Code · Agent Teams

여러 서브에이전트가 도는 것과
에이전트 팀이 도는 것은 다르다

멀티에이전트를 만들었다고 생각하는 상황 셋 가운데 둘은 팀이 아니다. 공식 문서가 정의하는 것이 무엇이고, 어떻게 만들며, 언제 그것이 나은지, 그리고 처음 구성할 때 무엇이 어긋나는지를 정리한다.

Domain · Claude Code Base · 공식 문서 v2.1.178+ · Anthropic Engineering · Cognition Date · 2026-08-30

01 무엇이 팀이 아닌가

멀티에이전트에 관심은 많은데 무엇을 가리키는 말인지가 사람마다 다르다. 실무에서 흔히 마주치는 세 가지 상황을 먼저 정리한다. 셋 다 "여러 개가 돌았다"는 점은 같지만, 공식 정의에 비추면 팀은 하나뿐이다.

상황 A — 여러 작업을 시켰더니 에이전트가 여러 개 떴다

가장 흔한 오해이다. 프롬프트 하나에 여러 일을 시키면 Claude가 스스로 작업을 나누어 여러 개를 띄운다. 화면 아래 에이전트 패널에 행이 여러 줄 뜨므로 팀이 생긴 것처럼 보인다. 그러나 이것은 subagent이다.

공식 문서가 이 혼동을 직접 언급한다. 서브에이전트는 팀원과 같은 패널에 표시되므로, 패널만 보고 팀이 만들어졌다고 확인할 수 없다. 팀이 필요하면 다시 요청하되 에이전트 팀임을 명시하라고 적혀 있다.

상황 B — 폴더를 셋 만들어 각각 작업하고 종합한다

데스크톱에서 폴더를 세 개 만들고 각각 작업한 뒤 결과를 모아 다시 작업하는 방식도 멀티에이전트로 불린다. 이 구성에서 조율하는 주체는 사람이다. 에이전트끼리는 서로의 존재를 모르고, 한쪽의 발견이 다른 쪽에 닿는 경로가 없으며, 종합은 매번 사람이 손으로 한다. 정체는 수동 파이프라인이다.

이 방식이 나쁘다는 뜻은 아니다. 오히려 의존이 적고 단계가 분명한 작업에서는 이쪽이 저렴하고 추적도 쉽다. 다만 이것을 멀티에이전트라 부르면 무엇을 자동화했고 무엇을 여전히 사람이 하고 있는지가 가려진다.

상황 C — 병렬로 돌면 멀티에이전트이다

병렬 실행은 서브에이전트도 한다. 병렬이냐 순차냐는 실행 방식이고, 팀이냐 아니냐는 소통 구조이다. 축이 다르므로 하나로 다른 하나를 판별할 수 없다.

가르는 기준 하나

팀원끼리 리드를 거치지 않고 직접 메시지를 주고받는가. 공유 작업 목록에서 스스로 작업을 집어가는가. 이 둘이 되면 팀이고, 안 되면 아니다. 나머지 차이는 전부 여기서 파생된다.

상황실제 정체판별법
A · 여러 개가 떴다서브에이전트 팀원 이름으로 서로에게 메시지를 보낼 수 있는지 확인한다. 패널 표시는 근거가 아니다
B · 폴더 셋수동 파이프라인 조율 주체가 사람이면 에이전트 시스템이 아니라 사람이 오케스트레이터인 워크플로이다
C · 병렬 실행판별 불가 병렬은 실행 방식이다. 소통 구조를 따로 확인해야 한다

02 공식 정의

공식 문서는 둘을 나란히 놓고 다섯 축으로 비교한다. 표를 먼저 보고, 구조 차이를 그림으로 확인한다.

서브에이전트에이전트 팀
컨텍스트 자체 창을 갖되 결과가 호출자에게 돌아간다 자체 창을 갖고 완전히 독립이다
소통 호출자에게 결과를 반환한다 팀원끼리 직접 메시지를 주고받는다
조율 메인 에이전트가 전부 관리한다 메시지로 자율 조율하고 공유 작업 목록을 함께 쓴다
적합 결과만 있으면 되는 집중된 과제 논의와 협업이 필요한 복잡한 작업
토큰 낮다 — 결과를 요약해 되돌린다 높다 — 팀원마다 독립 인스턴스이다
서브에이전트 구조와 에이전트 팀 구조의 비교 서브에이전트는 메인 에이전트가 배정하고 결과를 돌려받는 별 모양이며, 에이전트 팀은 팀원끼리 잇는 가로선과 공유 작업 목록이 추가된 형태이다. SUBAGENTS AGENT TEAM 메인 에이전트 agent A agent B agent C 배정하고 결과를 돌려받는다 에이전트 사이에는 선이 없다 team-lead @alpha @beta @gamma 서로 직접 닿는다 공유 작업 목록 · 직접 메시지
fig.1 — 위쪽 배정선은 양쪽이 같다. 다른 것은 아래쪽 가로선 하나이며,
그 선이 있으면 팀원이 리드를 거치지 않고 서로에게 닿는다.
버전 주의

v2.1.178부터 팀을 미리 만드는 절차가 사라졌다. TeamCreateTeamDelete 도구는 더 이상 존재하지 않고, Agent 도구의 team_name 입력은 받되 무시된다. 정리도 세션 종료 시 자동으로 이루어진다. 예전 자료를 따라 하다 막히는 지점이 대개 여기이다.

03 만드는 방법

1단계 — 플래그를 켠다

에이전트 팀은 실험 기능이며 기본값이 꺼짐이다. 변수가 없으면 세션 시작 시 팀이 구성되지 않고, 팀 디렉토리도 만들어지지 않으며, Claude가 팀원을 띄우거나 제안하지도 않는다.

// ~/.claude/settings.json
{
  "env": {
    "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
  }
}
켜 두면 생기는 일

플래그가 켜져 있는 동안에는 Claude가 스스로 이름을 붙인 서브에이전트가 팀원으로 뜬다. 요청하지 않은 위임에서도 팀이 만들어지고, 그만큼 토큰을 쓴다.

되돌리려면 값을 "0"으로 둔다. 세션을 새로 시작할 필요는 없다 — 설정 파일의 env 값은 저장 시 실행 중인 세션에 다시 적용되고, 서브에이전트를 띄울 때마다 변수를 다시 읽는다.

다만 사용자 settings.json"0"은 셸 export를 이긴다. 프로젝트 설정 · 로컬 설정 · --settings 페이로드 · 관리형 설정은 사용자 설정보다 뒤에 적용되므로 그쪽에서 "1"이면 그쪽이 이긴다.

2단계 — 대화형 세션이어야 한다

-p 헤드리스 모드와 Agent SDK 세션에서는 팀원이 생기지 않는다. 플래그가 켜져 있어도 이름 붙은 서브에이전트가 일반 서브에이전트로 실행된다. 자동화 스크립트 안에서 팀을 기대하면 안 된다.

3단계 — 자연어로 요청한다

별도 명령이 없다. 과제와 원하는 팀원을 말로 설명하면 Claude가 띄우고 조율한다. 공식 문서의 예시가 잘 작동하는 이유는 세 역할이 서로를 기다리지 않고 독립적으로 탐색할 수 있기 때문이다.

# 공식 문서 예시 — 세 역할이 독립적이다
코드베이스 전반의 TODO 주석을 추적하는 CLI 도구를 설계하고 있다.
팀원 셋을 띄워 서로 다른 각도에서 탐색하게 하라.
하나는 UX, 하나는 기술 아키텍처, 하나는 악마의 변호인.

인원과 모델을 직접 지정할 수도 있다. 모델은 다음 순서로 첫 번째로 해당하는 것이 적용된다.

  • CLAUDE_CODE_SUBAGENT_MODELinherit이 아닌 값이 설정되어 있을 때
  • 소집 프롬프트가 그 팀원에 대해 지정한 모델
  • 서브에이전트 정의의 modelin-process 팀원에 한한다
  • 리드의 현재 모델

teammateDefaultModel은 v2.1.234에서 제거되었다. 남아 있는 값은 무시된다.

4단계 — 정말 팀인지 확인한다

패널에 행이 뜨는 것만으로는 확인이 되지 않는다. 팀이 실제로 구성되면 패널이 이렇게 보인다.

Background
4 agents · 1 active shell

  Agents (3)
  Team: session-3b6f1708 (4)
❯ @team-lead
  @judge: idle
  @con: idle
  @pro: idle

  Shells (1)
  for i in $(seq 1 40); do echo "[$i/40]… (running)

↑/↓ to select · Enter to view · Esc to close

보라색으로 표시한 셋이 판별 근거이다.

표시무엇을 뜻하는가
Team: session-3b6f1708 (4) 팀 그룹 헤더가 붙는다. 이름이 공식 문서가 명시한 형식과 일치한다 — session- + 세션 ID 앞 여덟 자. 서브에이전트만 있으면 이 줄이 없고 Subagents (3)처럼 표시된다
@team-lead 리드가 행으로 나타나고 에이전트 타입이 team-lead이다. 팀 설정의 members 배열에서도 리드의 항목은 항상 이 타입을 갖는다
@judge · @con · @pro 이름에 @ 접두어가 붙는다. 이름으로 주소를 지정할 수 있다는 뜻이고, 여기서부터 팀원 간 직접 메시징이 가능하다
마지막 확인 — 실제로 주고받는가

표시만으로 부족하다면 한 번 시험한다. 팀원 둘에게 서로 반박하게 한 뒤 세 번째 팀원에게 판정을 맡긴다. 판정자가 앞선 둘이 주고받은 내용을 알고 있다면, 리드를 거치지 않은 경로가 실재한다는 뜻이다. 판정자는 그들에게 작업을 배정하지도 보고를 받지도 않았기 때문이다.

서브에이전트 구조에서는 원리적으로 불가능한 일이며, 이것이 팀을 쓰는 유일한 이유이다.

패널 조작

동작
↑ ↓팀원 선택
Enter선택한 팀원의 트랜스크립트를 열고 직접 메시지를 보낸다
x선택한 팀원을 중단한다
Ctrl+T작업 목록 토글
Esc선택 해제. 팀원을 보는 중이면 그 팀원의 턴을 중단한다

전원이 idle이 되면 30초 뒤 행이 숨겨지고 다음 턴에 다시 나타난다. 팀원은 그동안에도 실행 중이며 이름으로 주소를 지정할 수 있다. 넷 이상이 동시에 idle이면 넷째부터는 N idle agents 한 줄로 접힌다.

표시 모드

모드동작요건
in-process모든 팀원이 메인 터미널 안에서 돈다. 기본값없음
auto이미 tmux 안이거나 iTerm2 + it2이면 분할 화면, 아니면 in-process조건부
tmux분할 화면. tmux인지 iTerm2인지 자동 판별tmux 또는 iTerm2
iterm2iTerm2 네이티브 분할 화면 (v2.1.186+)it2 CLI

~/.claude/settings.jsonteammateMode로 바꾸거나 claude --teammate-mode auto로 세션 단위 지정한다. 분할 화면은 VS Code 통합 터미널 · Windows Terminal · Ghostty에서 지원되지 않는다.

모드가 정의 파일 적용 방식을 바꾼다

서브에이전트 정의를 팀원 역할로 재사용할 때, 표시 모드에 따라 본문이 덧붙느냐 대체하느냐가 갈린다.

  • 본문 — in-process는 기본 시스템 프롬프트에 덧붙이고, split-pane은 기본 프롬프트를 대체한다
  • tools — 정의의 목록으로 제한하되 in-process에는 SendMessage가 더해지고, Task 도구가 있는 세션이면 TaskCreate·TaskGet·TaskList·TaskUpdate도 더해진다
  • model — in-process만 사용한다. split-pane은 쓰지 않는다
  • skills어느 모드에서도 적용되지 않는다. 팀원은 프로젝트·사용자 설정에서 스킬을 로드한다
  • mcpServers — split-pane만 적용한다. in-process는 무시하고 프로젝트·사용자 설정을 따른다

저장 위치

팀 이름은 session- 뒤에 세션 ID 앞 여덟 자를 붙인 형태로 자동 생성된다.

대상경로수명
팀 설정~/.claude/teams/{team-name}/config.json 세션 종료 시 삭제
메일함~/.claude/teams/{team-name}/inboxes/{agent-name}.json 세션 종료 시 삭제
작업 목록~/.claude/tasks/{team-name}/ 남는다 · 업로드되지 않는다

팀 설정에는 세션 ID와 tmux 페인 ID 같은 런타임 상태가 들어 있다. 손으로 편집하거나 미리 작성하면 안 된다 — 다음 상태 갱신에서 덮어써진다. 프로젝트 쪽에 대응물은 없다. .claude/teams/teams.json을 만들어 두어도 설정으로 인식되지 않고 평범한 파일로 취급된다.

04 언제 팀이 나은가

공식 문서가 꼽는 강한 사례는 넷이다. 공통점은 팀원이 서로를 기다리지 않고 독립적으로 움직일 수 있다는 것이다.

사례팀이 값을 하는 이유
조사와 리뷰 여러 측면을 동시에 조사한 뒤 서로의 발견을 공유하고 반박한다
새 모듈 · 기능 각자 다른 조각을 소유하므로 서로를 밟지 않는다
경쟁 가설 디버깅 서로 다른 이론을 병렬로 검증하고 더 빨리 수렴한다
계층 교차 조율 프론트 · 백엔드 · 테스트를 각각 다른 팀원이 소유한다

경쟁 가설 — 팀이 아니면 안 되는 지점

단일 에이전트는 그럴듯한 설명 하나를 찾으면 탐색을 멈춘다. 순차 조사가 앵커링에 걸리기 때문이다. 공식 문서의 예시 프롬프트는 이 편향을 팀원을 명시적으로 적대적으로 만들어 깬다.

# 서로를 반증하게 하는 구조가 핵심이다
사용자가 한 메시지 뒤 앱이 종료된다고 보고한다.
팀원 5명을 띄워 서로 다른 가설을 조사하게 하라.
서로 대화하며 상대의 이론을 반증하도록 하고, 과학적 토론처럼 진행하라.
합의가 나오면 findings 문서를 갱신하라.

여러 조사자가 서로를 반증하려 들 때 살아남은 이론이 실제 원인일 가능성이 훨씬 높다. 이 구조는 서브에이전트로 만들 수 없다. 서로의 산출물을 읽고 반박하려면 리드를 거치지 않는 경로가 있어야 하기 때문이다.

쓰지 말아야 할 경우

  • 순차 과제 · 같은 파일 편집 · 의존이 많은 작업 — 단일 세션이나 서브에이전트가 더 낫다
  • 모든 에이전트가 같은 맥락을 공유해야 하는 작업
  • 진짜로 병렬화 가능한 부분이 적은 영역
  • 코딩 — 실시간으로 서로에게 조율하고 위임하는 일을 현재 LLM 에이전트가 잘하지 못한다

인원과 작업 크기

공식 권장은 3~5명으로 시작이다. 하드 리밋은 없지만 토큰이 인원수에 선형 비례하고, 조율 부담이 늘며, 어느 지점부터 수익이 체감한다. 집중된 3명이 흩어진 5명보다 낫다. 독립 작업이 15개라면 팀원 3명이 좋은 출발점이고, 팀원당 5~6개 작업이면 모두가 바쁘면서도 리드가 막힌 사람의 일을 재배정할 여지가 남는다.

작업 크기는 너무 작으면 조율 비용이 이득을 넘고, 너무 크면 점검 없이 오래 굴러 헛수고 위험이 커진다. 함수 하나 · 테스트 파일 하나 · 리뷰 하나처럼 분명한 산출물이 나오는 자족 단위가 적당하다.

비용

대상토큰 사용
일반 대화
단일 에이전트약 4×
멀티에이전트약 15×

출처 · Anthropic Engineering, How we built our multi-agent research system. 브라우징 과제에서 성능 분산의 95%를 세 요인이 설명하였고 토큰 사용량 하나가 80%를 차지하였다.

선행 판단

멀티에이전트는 과제 가치가 15배 비용을 정당화할 때만 성립한다. 순차냐 병렬이냐가 아니라 협상이 필요한가로 가른다. 결과만 필요하면 서브에이전트이고, 서로 반박해야 하면 팀이다.

캐시 비용 한 줄

in-process 팀원의 요청은 메인 대화의 캐시 TTL 구간 밖에 있어 기본 5분만 유지된다. 구독 플랜에서도 같다. 한 시간으로 늘리려면 subagentPromptCacheTtl1h로 둔다. 다만 API는 1시간 캐시 쓰기를 더 비싸게 청구한다.

05 아키텍처 다섯 패턴

실패를 모드로 분류할 수도 있고 구조로 분류할 수도 있다. 어떤 위상을 고르느냐에 따라 어떤 실패가 기본값으로 딸려오는지가 정해진다.

패턴동작구조적 약점비용
Generator
–Verifier
생성자가 산출하고 검증자가 기준으로 평가하여 반려하면 되돌린다 검증자 품질이 기준 정의에 전적으로 달린다. 좋은지 확인하라고만 지시받은 검증자는 결국 통과 도장을 찍는다 낮음~중간
Orchestrator
–Subagent
리드가 계획하고 경계가 정해진 하위 과제를 위임한 뒤 종합한다 오케스트레이터가 정보 병목이 된다. 한 하위 에이전트의 발견이 다른 쪽에 가려면 리드를 거치고 그 과정에서 세부가 소실된다 중간
Agent Teams 코디네이터가 지속형 워커를 띄우고 워커가 공유 큐에서 작업을 집어 자율 수행한다 엄격한 독립성이 전제이다. 중간 발견을 공유하기 어렵고, 작업 시간이 제각각이라 완료 감지가 복잡하며, 공유 자원 충돌에 세심한 분할이 필요하다 높음
Message Bus 중앙 라우터를 통해 이벤트 토픽을 발행·구독한다 라우팅 정확도가 결정적이며 잘못 분류된 이벤트는 조용히 실패한다 중간~높음
Shared State 중앙 조정자 없이 각자 영속 저장소를 읽고 쓴다 조율이 없으면 작업이 중복되거나 상반된 경로로 간다. 반응 루프가 생겨 서로에게 무한히 반응한다 높음
선택 지침

Orchestrator-Subagent에서 시작한다. 조율 부담이 가장 적으면서 가장 넓은 범위를 다룬다. 그다음은 실제로 관측된 마찰을 보고 올린다 — 하위 에이전트에게 지속적 맥락이 필요해지면 Agent Teams, 흐름이 이벤트 구동이면 Message Bus, 실시간 협업이 필요하면 Shared State.

반대 논거 — 애초에 만들지 말라

Cognition은 정반대 입장을 취한다. 여러 에이전트를 협업시키면 의사결정이 분산되고 맥락이 충분히 공유되지 않아 시스템이 취약해진다는 것이다. 이들이 드는 예는 명료하다. 한 하위 에이전트가 슈퍼마리오풍 배경을 만드는 동안 다른 하위 에이전트가 그 배경과 어울리지 않는 새를 만든다. 서로의 행동에 담긴 암묵적 설계 결정을 보지 못하였기 때문이며, 최종 에이전트는 이를 화해시키지 못한다.

2026년 현재의 수렴점

오케스트레이터 하나가 연속된 맥락을 소유하고, 수명이 짧은 읽기 전용 하위 에이전트를 띄워 압축된 요약을 돌려받는다. 병렬로 쓰기를 수행하는 무리는 맥락 파편화와 상반된 결정 때문에 여전히 취약하다.

논쟁의 결론은 "멀티에이전트가 맞다 또는 틀리다"가 아니라 하위 에이전트에게 쓰기 권한과 지속 맥락을 얼마나 줄 것인가로 이동하였다.

06 흔한 구성 오류

공식 문서의 문제 해결 절과 Anthropic의 프로덕션 교훈을 합쳐, 처음 팀을 구성할 때 실제로 부딪히는 순서대로 정리한다.

구성 단계

오류증상대응
팀이 아닌데
팀이라 믿는다
패널에 행이 여럿 뜨는 것만 보고 판단한다 리드의 타입이 team-lead인지, @이름 주소 지정이 되는지 확인한다. 아니면 에이전트 팀임을 명시해 다시 요청한다
세션 도중에
플래그를 켠다
팀원이 아니라 일반 서브에이전트로 뜬다 진짜 팀원이 필요하면 플래그를 "1"로 둔 채 세션을 새로 시작한다
헤드리스에서
팀을 기대한다
-p 모드·Agent SDK에서 팀원이 생기지 않는다 대화형 세션에서만 가능하다. 자동화 파이프라인은 서브에이전트로 설계한다
인원을
먼저 정한다
단순 질의에 팀원을 과하게 띄운다. 초기 Anthropic Research는 단순 질의에 하위 에이전트 50개를 띄우는 실패를 냈다 노력 배분 규칙을 프롬프트에 박는다 — 단순 질의 1명·도구 호출 3~10회, 비교 2~4명·10~15회, 복잡한 연구 10명 이상
소집 프롬프트가
얇다
팀원이 맥락 없이 시작해 엉뚱한 것을 판다 팀원은 CLAUDE.md·MCP·스킬은 로드하지만 리드의 대화 이력은 물려받지 않는다. 과제 세부를 소집 프롬프트에 직접 넣는다

실행 단계

오류증상대응
리드가
직접 구현한다
팀원을 기다리지 않고 리드가 작업을 시작한다. 팀이 한 명의 장황한 에이전트로 붕괴한다 공식 문서의 처방을 그대로 쓴다 — Wait for your teammates to complete their tasks before proceeding
같은 파일을
둘이 편집한다
덮어쓰기가 발생한다 팀원마다 다른 파일 집합을 소유하도록 작업을 나눈다
정보가
리드에서 막힌다
한 팀원의 발견이 다른 팀원에게 갈 때 리드를 거치며 세부가 소실된다 Orchestrator-Subagent 위상의 알려진 약점이다. 팀원 간 직접 메시징을 쓰거나 파일을 공유 매체로 둔다
작업 완료
표시가 누락된다
팀원이 완료 표시를 하지 않아 의존 작업이 막힌다 공식 문서가 인정한 제약이다. 실제 완료 여부를 확인하고 상태를 수동 갱신하거나 리드에게 재촉하게 한다
권한 요청이
리드에 몰린다
팀원 권한 프롬프트가 전부 리드 창에 뜬다 소집 전에 자주 쓰는 조작을 권한 설정에서 미리 승인해 둔다
조기 종료 팀원이 오류 뒤 복구하지 않고 멈춘다. 리드도 모든 작업이 끝나기 전에 끝났다고 판단한다 패널에서 팀원을 열어 출력을 확인하고 추가 지시를 주거나 대체 팀원을 띄운다. 리드에게는 계속하라고 말한다
방치 오래 두면 헛수고 위험이 커진다 진행을 점검하고 방향을 틀며 결과가 나오는 대로 종합한다
가장 비싼 오류

위 오류들은 실행 중에 알아차리고 고칠 수 있다. 그러나 하나는 이미 잃은 뒤에 안다 — /resume/rewind는 in-process 팀원을 복원하지 않는다. 팀을 띄우기 전에 결론이 어디에 남을지를 먼저 정해 두어야 한다.

07 시작 전 점검

아래를 모두 통과하지 못하면 서브에이전트나 단일 세션으로 끝내는 편이 낫다.

필요성

  • 결과만 필요한 것이 아니라 서로 반박·협상이 필요한 작업인가
  • 과제 가치가 15배 토큰 비용을 정당화하는가
  • 팀원이 서로를 기다리지 않고 독립적으로 움직일 수 있는가
  • 같은 파일을 여럿이 편집해야 하는 구조가 아닌가

구성

  • 인원을 독립적으로 존재하는 대안(또는 실패 축)의 수로 정했는가 — 3~5명에서 시작
  • 팀원당 작업 5~6개로 쪼갰는가
  • 소집 프롬프트에 목표 · 출력 형식 · 도구와 출처 안내 · 명확한 경계 넷을 넣었는가
  • 팀원마다 소유할 파일 집합을 나눴는가

환경

  • 플래그를 "1"로 둔 채 세션을 새로 시작했는가
  • 대화형 세션인가 (-p 헤드리스가 아닌가)
  • 자주 쓰는 조작의 권한을 미리 승인했는가
  • 결론을 남길 파일 경로를 정해 두었는가 — /resume으로 복구되지 않는다
한 줄 요약

팀을 만드는 법을 배우는 것보다 팀이 필요 없다는 것을 판정하는 법을 먼저 익히는 편이 이득이 크다. 공식 문서와 벤더 자료가 독립적으로 같은 말을 한다 — 하나로 시작하고 필요할 때만 늘려라.

08 출처

로컬 노트 · 20260830_RES_REF_멀티에이전트실패학습_02-아키텍처유형별

\n
\n\n
Claude Code 권한 모드 전환 — 요약
Claude Code · Permission Mode

세션을 끊지 않고 권한 모드를 바꾸는 방법

권한 모드는 Claude가 파일 편집이나 셸 명령 실행 전에 사용자에게 물어볼지를 결정한다. 세션을 종료하지 않고 실행 중에 바꿀 수 있다는 점이 실무에서 가장 유용하다.

Base · Claude Code CLI Docs · permission-modes Date · 2026-08-29

01 방법 1 — Shift+Tab 순환

세션 실행 중 언제든 Shift+Tab을 누르면 모드가 순환하며, 컨텍스트를 잃지 않으므로 탐색에서 편집으로 넘어가는 흐름을 그대로 이어갈 수 있다.

base cycle
default⏸ manual mode on
acceptEdits⏵⏵ accept edits on
plan⏸ plan mode on
auto⏵⏵ auto mode on
bypassPermissions는 활성화한 세션에서 plan과 auto 사이에 삽입된다

순환 순서는 default → acceptEdits → plan → auto → 다시 default이다. auto는 계정 요건을 충족한 세션에서 순환에 포함되고, Pro·Max·Team 플랜에서는 세션 자체가 auto로 시작하므로 첫 Shift+Tab이 곧바로 default로 이동한 뒤 그때부터 위 순서가 반복된다. bypassPermissions는 시작 시 활성화한 경우에만 planauto 사이에 삽입되며, dontAsk는 순환에 등장하지 않아 플래그로만 지정할 수 있다.

현재 모드는 상태 바에 표시되는데, 표기 자체가 성격을 구분한다. 는 실행 전에 멈춰 서는 모드이고 ⏵⏵는 묻지 않고 진행하는 모드이다.

02 방법 2 — 시작 시 플래그 지정

작업 성격이 미리 정해져 있다면 실행 시점에 지정하는 편이 확실하다. 같은 플래그가 비대화형 실행(-p)에도 적용된다.

claude                                # 기본 (Manual)
claude --permission-mode acceptEdits   # 파일 편집만 자동 승인
claude --permission-mode plan          # 읽기·탐색만
claude --permission-mode auto          # 분류기가 대신 검토

반복되는 패턴은 ~/.claude/settings.jsonpermissions.defaultMode로 고정한다. 다만 auto 값만은 프로젝트 설정 파일에서 적용되지 않으므로 사용자 설정에 두어야 한다.

03 모드별 자동 승인 범위

mode묻지 않고 실행되는 범위적합한 상황
default
(Manual)
읽기만민감한 작업, 낯선 코드
acceptEdits읽기, 작업 디렉터리 내 파일 편집, mkdir·mv·cp코드를 리뷰하며 반복 수정
plan읽기, 탐색용 명령수정 전 코드베이스 파악
auto대부분, 분류기 검사 수반장시간 작업
dontAsk사전 승인된 도구만CI·스크립트
bypassPermissions전부격리된 컨테이너·VM 한정
흔한 오해

acceptEdits는 전면 자동 승인이 아니다. 자동 승인은 작업 디렉터리 내부의 편집과 일부 파일시스템 명령에 한정되며, 그 밖의 셸 명령과 보호 경로(.git, .claude, 셸 설정 파일 등)에 대한 쓰기는 여전히 프롬프트가 표시된다.

04 운용 기준

권장 흐름
  • 낯선 코드베이스에 진입할 때는 --permission-mode plan으로 시작하여 구조를 먼저 파악한다
  • 계획이 확정되면 승인 항목에서 acceptEditsauto를 선택하여 편집으로 넘어간다
  • 리뷰가 필요해지면 Shift+Tab으로 default로 되돌려 개별 승인을 회복한다
  • 민감한 구간에서는 모드를 낮추는 대신 permissions.ask 규칙으로 해당 명령만 프롬프트를 강제한다

모드 선택이 결정하는 것은 결국 검토 비용을 언제 지불할 것인가이다. plan은 계획 단계에서 앞당겨 지불하고, acceptEditsgit diff 시점으로 미루며, auto는 그 비용의 상당 부분을 분류기에 위임한다. 작업의 되돌리기 난이도에 맞추어 이 지점을 조정하는 것이 권한 모드를 제대로 쓰는 방법이라는 것이다.

융합 전략과 모달리티 차원

Data flow · faithful redraw · Diagram Design

융합 전략과 모달리티 차원

네 전략은 동일한 파이프라인 위에서 차원 축소와 결합의 순서만 다르다. 막대 높이는 1 decade = 12px 규약으로 특징 차원 d 를 나타내고, 색은 모달리티를 구분하며, 보라색은 융합 연산 하나에만 쓰인다.

i초기 융합 · Early
초기 융합세 모달리티의 원 특징을 먼저 결합하고, 선택적 차원 축소를 거쳐 하나의 모델을 학습한다. 결합 벡터의 차원은 원 차원의 합이므로 고차원 모달리티가 대부분을 차지한다.임상d ≈ 10¹단백d ≈ 10³발현d ≈ 10⁴융합Σdₘ ≈ 10⁴축소 (선택)모델예측원 특징 상태에서 결합이 일어난다축소는 결합 이후에 한 번만 적용된다임상 지분 ≈ 0.02% · 고차원이 지배한다모든 특징이 동등하게 중요하다고 암묵적으로 가정하게 된다
ii초기-중간 융합 · Early-intermediate
초기-중간 융합모달리티마다 독립적으로 차원을 축소해 같은 크기의 표현으로 만든 뒤 결합한다. 축소가 결합보다 앞서므로 모달리티 지분이 균등해진다.임상d ≈ 10¹단백d ≈ 10³발현d ≈ 10⁴축소 110²축소 210²축소 310²융합Σkₘ ≈ 3·10²모델예측모달리티마다 독립적으로 축소한다축소가 결합보다 앞에 놓인다지분이 균등해지고 상호작용을 학습한다모달리티별 독립 축소로 저차원 모달리티의 신호가 보존된다
iii후기-중간 융합 · Late-intermediate
후기-중간 융합연관된 모달리티 부분집합에 차원 축소를 함께 적용해 단계적으로 결합한 뒤 나머지 모달리티와 이어 붙인다. 축소 단위에 도메인 지식을 반영할 수 있다.임상d ≈ 10¹단백d ≈ 10³발현d ≈ 10⁴축소 110²축소 2부분집합 공동10²융합Σk_g ≈ 2·10²모델예측연관된 모달리티를 먼저 묶어 축소한다축소 단위가 모달리티 부분집합이다융합 순서가 도메인 지식을 부호화한다생물학적으로 연관된 모달리티를 먼저 통합한 뒤 나머지를 결합한다
iv후기 융합 · Late
후기 융합모달리티마다 축소와 모델 학습을 독립적으로 수행하여 각각 하나의 위험 점수를 산출한 뒤 가중 결합한다. 최종 결합 단계의 입력 차원은 모달리티 개수와 같다.임상d ≈ 10¹단백d ≈ 10³발현d ≈ 10⁴축소 1모델 1d = 1축소 2모델 2d = 1축소 3모델 3d = 1예측 결합d = M예측모달리티마다 축소와 모델링을 독립 수행한다결합 대상이 특징이 아니라 예측값이다결합 입력 차원이 M 으로 고정된다모달리티별 전처리와 모델 계열을 자유롭게 선택할 수 있다
도식 범례막대 높이가 특징 차원의 상용로그에 비례한다는 규약과 모달리티·축소·융합·모델·출력 요소의 색과 형태 부호를 설명하는 범례.LEGEND임상 · 저차원 모달리티단백 · 중간 차원발현 · 고차원차원 축소 (선택 단계)융합 지점모델 · 예측 헤드막대 높이 = 12px × log₁₀(d) · d 는 해당 단계의 특징 차원이다
SKIN · encoded-editorial tokens  ·  TYPE · data flow  ·  DETAIL · faithful  ·  SOURCE · Nikolaou et al. npj Precis Oncol 9:128 (2025) Fig 1b
Unsloth Desktop / Mac Studio 64GB — Usable Memory Guide
UNSLOTH DESKTOP / 모델 선택 가이드
MAC STUDIO · 64GB 통합 메모리

Mac Studio 64GB를 위한
로컬 생성 모델

목적
Unsloth Desktop에서 실제로 운용하기 좋은 이미지·비디오 모델을 고른다.

원칙
64GB라는 총 메모리보다 Unsloth가 실제로 허용하는 usable memory를 먼저 확인한다.
01
선택 원칙

총 64GB보다
usable memory가 먼저다.

Mac Studio의 64GB는 CPU와 GPU가 함께 쓰는 통합 메모리다. 따라서 일반적인 CUDA 시스템처럼 GPU 메모리가 부족할 때 CPU RAM으로 offload해서 여유를 만드는 방식이 통하지 않는다. Unsloth Desktop은 macOS가 사용할 여유 공간을 별도로 남긴 뒤, 그 시점에 모델 로딩에 사용할 수 있는 usable memory를 계산한다.

현재 관찰된 사례
20GB free → 7GB usable

64GB 장비라도 다른 앱과 macOS가 메모리를 사용 중이면 실제 모델 로딩 허용량은 크게 줄어들 수 있다.

실전 판단 기준
weights < usable

모델 파라미터 수나 Mac의 총 메모리보다, 현재 usable memory와 실제 weight 크기의 관계가 더 중요하다.

핵심 수정: “Mac Studio 64GB이면 Q5/Q6부터 시작”이라는 단순한 기준은 안전하지 않다. 먼저 Unsloth가 표시하는 usable memory를 확인하고, 그 범위 안에 들어오는 더 작은 모델 또는 더 강한 양자화를 선택해야 한다.
02
이미지

Qwen은 목표 모델, 작은 quant가 출발점.

포스터, 인포그래픽형 구성, 복잡한 지시문, 이미지 안의 텍스트처럼 프롬프트 준수도가 중요한 작업에서는 Qwen-Image-2512-GGUF를 우선한다. 여러 구도와 아이디어를 빠르게 비교하는 단계에서는 Z-Image-Turbo-GGUF가 더 효율적이다.

모델
역할
양자화
용도
Z-Image-Turbo 4-bit
우선 테스트
4-bit
usable memory가 낮을 때 가장 먼저 시도할 이미지 모델
Qwen-Image-2512-GGUF
목표 모델
낮은 quant부터
메모리 여유가 확보됐을 때 최종 품질용으로 단계적으로 테스트
Z-Image-Turbo-GGUF
대안
작은 GGUF 우선
빠른 생성과 비교적 작은 메모리 요구를 노릴 때
FLUX.1-schnell-GGUF
조건부
weight 확인
실제 사례에서 약 18GB weights가 7GB usable memory 때문에 로딩 차단됨
탐색
Z-이미지-Turbo
최종
Qwen-이미지-2512
03
비디오

비디오도 작은 모델부터 실제 로딩을 확인.

LTX-2.3-GGUF는 기능적으로 매력적이지만, 64GB라는 이유만으로 주력 모델로 가정해서는 안 된다. 다른 대형 비디오 모델도 동일한 usable-memory 검사에서 로딩이 차단될 수 있다. 현재 메모리 여유가 작다면 Wan2.2-TI2V-5B-GGUF처럼 상대적으로 작은 계열을 먼저 확인하고, 이후 LTX-2.3 또는 MiniMax-H3로 확장하는 편이 현실적이다.

모델
역할
모드
용도
Wan2.2-TI2V-5B-GGUF
우선 테스트
작은 GGUF
대형 비디오 모델보다 먼저 로딩 가능성을 확인할 현실적인 출발점
LTX-2.3-GGUF
2단계
distilled 우선
충분한 usable memory가 확보됐을 때 초안→최종 워크플로에 사용
MiniMax-H3-GGUF
특수 목적
weight 확인
영상+오디오가 필요할 때. 로딩 전 usable memory와 실제 weight를 반드시 비교
Wan 2.2 T2V A14B (MoE)
후순위
대형
현재 usable memory가 작다면 우선순위를 낮추는 편이 안전
1단계 · 로딩 확인
Wan2.2 TI2V 5B
2단계 · 여유 확보 후
LTX-2.3
04
빠른 선택

모델보다 먼저 현재 usable memory를 본다.

Z-Image-Turbo 4-bit
이미지 / 시작
4-bit
usable memory가 낮을 때 첫 번째 후보
Qwen-Image-2512-GGUF
이미지 / 확장
낮은 quant부터
메모리 확보 후 품질 우선으로 전환
Wan2.2-TI2V-5B-GGUF
비디오 / 시작
작은 GGUF
대형 비디오 모델보다 먼저 실제 로딩 확인
LTX-2.3-GGUF
비디오 / 확장
distilled 우선
충분한 usable memory가 있을 때 주력으로 확장
운용 원칙: ① Activity Monitor에서 메모리 점유를 줄이고 ② Unsloth가 표시하는 usable memory를 확인한 뒤 ③ 그보다 작은 weight를 가진 모델/quant부터 로딩한다. 대형 모델은 “64GB 지원 여부”가 아니라 현재 usable memory에서 실제로 로드되는지를 기준으로 판단한다.
05
실제 오류 사례

64GB여도 로딩이 차단될 수 있다.

실제 Unsloth Desktop 메시지에서는 FLUX.1 weights가 약 18GB인데, 당시 시스템의 free memory는 약 20GB였고 OS용 여유 공간을 예약한 뒤 실제 usable memory는 약 7GB로 계산됐다. 이 경우 Unsloth는 OOM을 기다리지 않고 모델 로딩 자체를 중단한다.

왜 CPU offload가 해결책이 아닌가
Unified Memory

CPU와 GPU가 같은 메모리 풀을 공유하기 때문에 CPU로 옮겨도 총 사용량이 줄지 않는다.

강제 로딩 옵션
ALLOW_OVERSIZED_LOAD=1

안전 검사를 우회할 수 있지만 생성 중 swap 증가·급격한 속도 저하·프로세스 종료 위험이 있어 기본 해법으로 권장하지 않는다.

권장 순서: 다른 앱 종료 → Unsloth 재실행 → usable memory 확인 → 더 작은 quant 선택 → 낮은 해상도/프레임으로 테스트 → 필요 시 상위 모델로 확장.
06
참고 자료

공개 모델 페이지

Swiss Technical Editorial / Unsloth Desktop 기술 노트
2026-08-25 · usable-memory revision
cTfh와 소아 면역성 혈구감소증 — Haematologica 2026
Research Note · 소아 면역성 혈구감소증

소아 면역성 혈구감소증에서 circulating T follicular helper 세포 비율의 증가는 질환 아형 및 질병 활성도와 연관된다

Increased percentages of circulating T follicular helper cells associate with disease subtype and activity in pediatric immune cytopenias

소아 면역성 혈구감소증 환자 153명에서 CD4⁺ T follicular helper (cTfh) 세포 비율을 정량하여, 아형 감별과 질병 활성도 모니터링의 근거를 검증하고 아형별 면역 기전을 규명한 전향적 코호트 연구를 정리하였다.

Journal · Haematologica 2026;111(8):2684-2697 First author · Emily M. Harris Institution · Dana-Farber/Boston Children's · Harvard Medical School DOI · 10.3324/haematol.2025.287988

01 배제 진단이 남긴 미충족 수요

소아 면역성 혈구감소증은 저절로 관해되는 단일 계열 질환부터 다장기를 침범하는 치명적 면역이상까지 넓은 스펙트럼을 이루는데, 여기에는 면역혈소판감소증(ITP)과 온난항체 자가면역용혈빈혈(wAIHA), 면역호중구감소증, 그리고 두 계열 이상을 침범하는 Evans 증후군(ES)이 포함된다. 이 가운데 ES는 재발과 관해를 반복하는 만성 경과가 흔하고 소아 사망률이 7~35%로 보고되므로 조기에 식별할 임상적 필요가 크다.

그러나 ITP와 면역호중구감소증이 여전히 배제 진단에 머물러 있으므로, 두 계열 이상의 혈구감소를 보이는 환자가 실제로 ES인지 아니면 다른 원인의 혈구감소가 동반된 것인지 가릴 객관적 검사가 존재하지 않는다. 질병 활성도와 면역학적 동반이환, 치료 반응을 예측할 표지자 또한 확립되어 있지 않아 어떤 환자에게 유전자 검사와 혈액 외 자가면역 평가를 시행할 것인가라는 실무적 판단이 임상의의 재량에 맡겨져 있다.

why cTfh

Tfh 세포는 림프기관 배중심에서 B 세포를 활성화하여 항체 생산을 유도하는 CD4⁺ T 세포 아집단이며, 말초혈에서 이에 대응하는 cTfh 세포는 CD4⁺CXCR5⁺PD-1⁺ 표현형으로 배중심 Tfh 세포와 TCR 클론형 및 기능을 공유한다. 자가항체 생산을 촉진하므로 자가면역 기전의 중심에 놓이며, 무엇보다 이 측정은 대부분의 임상 검사실이 이미 보유한 장비로 낮은 시약 비용에 시행되는 기존 검사이므로 새로운 기술 개발 없이 곧바로 적용된다.

선행 연구에서 활동성 미치료 ES와 만성 ITP의 cTfh 확장이 보고된 바 있으나, 저자들은 cTfh 확장에 동반되는 임상 양상과 전사체 변화가 충분히 규명되지 않았다고 정리하였다. 이번 연구는 혈구감소 유무와 치료 상태를 제한하지 않고 등록하였으므로, 실제 진료에서 마주치는 환자군을 그대로 반영한 설계라는 것이다.

02 무엇을 어떻게 측정하였는가

Boston Children's Hospital의 단일기관 전향적 코호트 연구로서, 통상 진료 중 채취한 연구 검체를 이용하여 면역성 혈구감소증 환자 153명과 건강 대조군 78명을 분석하였다. 분석은 세 층위로 구성되며, 전체 환자를 대상으로 한 유세포분석과 28명의 CD4⁺ T 세포 단일세포 전사체, 그리고 혈장 사이토카인 23종 측정이 각각에 해당한다.

layer측정 대상규모핵심 정의
L1 · flowcTfh 백분율N=153 + 78CD4⁺ T 세포 중 CXCR5⁺PD-1⁺ 분획으로 정의하였다
L2 · scRNACD4⁺ T 전사체환자 28명 + 대조군라이브러리당 10,000세포로 시퀀싱하였고 PRJNA1233813에 공개하였다
L3 · plasma사이토카인 23종전체 코호트LEGENDplex 다중 비드 분석으로 측정하였다

코호트의 기저 불균형

세 아형의 기저 특성이 균질하지 않다는 점은 결과 해석의 전제로 먼저 짚어야 한다. ES는 연령 중앙값이 16.9세로 가장 높고 진단 후 경과가 1,420일로 나머지 두 군의 약 3.8배에 이르며 면역질환 동반율도 43%로 최고인 반면, wAIHA는 92%가 치료 중이어서 치료 효과와 질병 특성이 혼재되어 있다. 주요 항목을 다음 표에 정리하였다.

ITP (N=85)wAIHA (N=26)ES (N=42)Controls (N=78)
연령 중앙값, 세10.613.316.912.0
진단 후 경과일3743721,420
활동성 혈구감소53 (62%)8 (31%)24 (57%)
치료 중31 (36%)24 (92%)32 (76%)
면역질환 동반8 (9%)6 (23%)18 (43%)
혈액 외 자가면역7 (8%)8 (31%)12 (29%)
두 개의 절단값을 구분할 것

9.5%는 이번 연구의 ROC 분석에서 ES 감별을 위해 새로 도출한 값이며, 11.3%는 대조군 210명의 97.5 백분위수로 기존 문헌이 제시한 정상 참고치 상한이다. 종단 추적에서 cTfh가 정상화되었는지 판정할 때에도 11.3%를 기준으로 삼았으므로, 두 값은 서로 대체할 수 없는 별개의 기준이라는 것이다.

03 cTfh 게이팅 전략과 사용 마커

이번 연구에서 cTfh는 CD4⁺ T 세포 중 CXCR5와 PD-1을 함께 발현하는 분획의 백분율로 정의되었다. 분모가 전체 림프구나 전체 T 세포가 아니라 CD4⁺ T 세포라는 점은 9.5%나 11.3% 같은 절단값을 다른 검사실 자료와 비교할 때 반드시 확인해야 하는 전제이므로, 게이팅 순서를 먼저 정리한다.

림프구 FSC / SSC * 단일·생존 세포 singlet / viability * CD3⁺ * CD4⁺ denominator CXCR5⁺ CD185 PD-1⁺ CD279 · cTfh cTfh % = (CXCR5⁺PD-1⁺) / CD4⁺ × 100 동반 측정 Treg = CD4⁺ CD25^hi CD127^low · CLIA 승인 임상 검사 · 42명(ITP 15 · wAIHA 8 · ES 19)
FIG · 원문 본문이 기술한 정의(CD4⁺ 중 CXCR5⁺PD-1⁺)를 축으로 게이팅 순서를 재구성하였다. 보라색은 cTfh를 정의하는 두 마커를, 회색은 상류 게이트를 나타낸다. 별표(*)를 붙인 게이트는 본문에 기재되지 않은 통상적 절차이므로 원문의 실제 순서와 다를 수 있으며, 항체 클론과 형광색소를 포함한 전체 패널은 Online Supplementary Figure S1 및 Online Supplementary Methods에 수록되어 있다.

측정에 사용된 마커

원문 본문이 명시한 마커는 CD4·CXCR5·PD-1의 세 가지이며, Treg 측정에 쓰인 CD25·CD127이 별도로 기재되어 있다. 각 마커의 역할과 출처를 구분하여 다음 표에 정리하였다.

marker별칭역할출처
CD4백분율의 분모가 되는 CD4⁺ T 세포 집단을 규정한다본문 명시
CD3T 세포 계열을 선별하는 상류 게이트로서 통상 사용되나, 원문 본문에는 기재되어 있지 않다본문 미기재
CXCR5CD185여포 귀소 수용체로서 Tfh 계열의 정체성을 부여하며, 배중심 Tfh 세포와 공유되는 표지이다본문 명시
PD-1CD279활성화된 Tfh를 구분하는 표지로서, CXCR5와 조합되어야 cTfh가 정의된다본문 명시
CD25IL2RATreg 게이팅에서 고발현(hi) 분획을 선별한다동반 검사
CD127IL7RATreg 게이팅에서 저발현(low) 분획을 선별하여 활성화 T 세포와 구분한다동반 검사
마커 정의가 다르면 수치를 비교할 수 없다

저자들도 지적하듯 cTfh와 Treg를 정의하는 마커 조합이 연구마다 달라 문헌 간 직접 비교가 어렵다. 예를 들어 Kumar 등의 선행 연구는 CD4⁺CD127⁺CD25^low^CXCR5⁺ 세포를 유세포 분류한 뒤 표적 전사체를 분석하였으므로, PD-1을 필수 조건으로 두는 이번 연구의 정의와 같은 집단을 보고 있다고 단정할 수 없다. 따라서 9.5%라는 절단값을 다른 검사실에 옮겨 적용하려면 마커 조합과 분모 게이트가 동일한지부터 확인해야 한다는 것이다.

04 아형 감별과 9.5% 절단값

cTfh 중앙값은 ES에서 13.05%로 ITP 4.82%와 wAIHA 6.11%, 대조군 5.16%를 모두 크게 상회하였다. ES는 ITP(P<0.0001)와 wAIHA(P=0.0007), 대조군(P<0.0001) 전부에 대해 유의한 차이를 보인 반면, ITP와 wAIHA는 서로 간에도 대조군에 대해서도 차이가 관찰되지 않았다. 아형별 중앙값을 다음 그림에 정리하였다.

0 5 10 15 cTfh (% of CD4⁺) 4.82 6.11 13.05 5.16 ROC cutoff 9.5% ITP wAIHA ES Controls N=85 N=26 N=42 N=78
FIG · 아형별 cTfh 중앙값을 원문 Figure 2A에서 재구성하였다. 보라색은 관심 질환인 ES를, 회색은 비교군을 나타내며, 점선은 ROC에서 도출한 감별 절단값 9.5%이다.

ROC 분석에서 cTfh 9.5% 초과는 ES를 ITP 또는 wAIHA로부터 감별하는 데 민감도 76%, 특이도 86%를 나타내었다(AUC 0.8171, P<0.0001). 다만 양성예측도가 0.68에 그치는 반면 음성예측도는 0.91에 이르므로, 이 검사는 ES를 확진하는 도구라기보다 낮은 값으로 ES를 배제하는 데 강점을 지닌 검사로 이해하여야 한다.

sensitivity
76 %
cutoff cTfh > 9.5%
specificity
86 %
AUC 0.8171
PPV
0.68
95% CI 0.54–0.80
NPV
0.91
95% CI 0.84–0.95
가장 중요한 관찰

ITP와 wAIHA는 활동성 혈구감소가 동반되든 그렇지 않든 대조군과 차이가 없었던 반면, ES는 활동성 여부를 불문하고 대조군보다 높았다. 즉 cTfh 상승은 혈구감소라는 현상 자체가 아니라 ES라는 질환의 속성을 반영하며, 그러므로 아형 감별에 활용된다는 것이다.

05 활성도·치료·종단 추적

진단 표지자와 모니터링 지표는 요구 조건이 다르며, 후자는 시간에 따른 상태 변화를 따라가야 한다. ES 환자를 활성도와 치료 상태로 세분하였을 때 cTfh가 가장 높은 군은 활동성이면서 치료를 받지 않는 환자였고, 혈구 수치가 정상이면서 치료도 받지 않는 ES 환자만이 대조군과 동등한 수준을 회복하였다.

종단 측정이 가능하였던 51명에서는 이러한 관계가 개체 내 변화로도 확인되었다. 호전 중인 ES 환자 대부분은 cTfh가 정상화된 반면, 지속적으로 활동성인 ES 환자 대부분은 11.3%를 상회한 상태로 유지되었으며, ITP 88.5%(N=23)와 wAIHA 87.5%(N=7)는 추적 기간 내내 11.3% 미만을 유지하였다.

원문 내부 수치 불일치

종단 코호트의 구성이 본문과 그림 범례에서 어긋난다. 본문은 51명을 ITP 27명, wAIHA 6명, ES 18명으로 기술하였으나 Figure 2E 범례는 ITP 26명, wAIHA 8명, ES 18명으로 적어 합계가 52명이 된다. 본문에 제시된 88.5%(N=23)와 87.5%(N=7)는 각각 26명과 8명을 분모로 두어야 성립하므로, 백분율은 그림 범례 쪽 숫자와 부합한다. 결론에는 영향을 주지 않으나 인용 시에는 이 불일치를 함께 밝히는 편이 안전하다.

만성화 지표가 아니다

질병 이환 기간과 cTfh 백분율 사이에는 세 아형 모두에서 유의한 상관이 관찰되지 않았다. 오래 이환되었기 때문에 cTfh가 높은 것이 아니라 현재의 면역 활성 상태를 반영하므로, 시점별 모니터링 지표로서의 성격이 뒷받침된다는 것이다.

06 아형을 구분하는 인터페론 신호

단일세포 전사체 분석에서 가장 중요한 발견은 cTfh 백분율이 정상인 환자에게도 유전자 발현 수준의 이상이 남아 있다는 사실이다. wAIHA 환자는 세포 수로는 대조군과 구분되지 않았음에도 활성도와 무관하게 제1형 인터페론 서명이 뚜렷하게 항진되어 있었으며, 이는 백분율 측정만으로는 검출되지 않는 면역 이상이 존재함을 의미한다. 군별 전사체 특징을 다음 표에 정리하였다.

환자군cTfh 전사체 특징주 경로
활동성 ES · 미치료IFN-α/β(OASL, IFITM3)와 IFN-γ(IFNG, CXCR3, IL21) 신호가 동시에 항진되었고 TCR·PI3K/AKT·세포자멸사 경로가 증가한 반면 IL7R 신호는 감소하였다IFN-γ
활동성 ES · 치료 중IFN-γ와 Th1, T세포 활성화 신호가 감소하였고 Tfh 분화를 억제하는 VDR/RXR 축이 상향 조절되었다치료 효과
비활동성 ES · 치료 중T세포 소진을 매개하는 PD-1 경로와 세포자멸사 신호가 함께 상향 조절되었다치료 효과
비활동성 ES · 미치료T세포 발달·기능 관련 경로 중 유의하게 농축된 것이 없어 대조군과 동등하였다정상화
wAIHA · 치료 중활성도와 무관하게 IFN-α/β가 항진되었고, 활동성군에서는 IFN-γ와 IL-8도 증가하였다IFN-α/β
활동성 ITP · 미치료Notch1STAT3, CD28 공자극, IL-3, TGF-β가 감소하여 염증 신호의 부재가 확인되었다신호 없음

IFN-α/β 및 IFN-γ 경로 유전자를 대상으로 한 비계층적 군집분석에서는 활동성 미치료 ES와 활동성 wAIHA 치료군이 가장 강한 IFN 서명을 공유하며 함께 묶인 반면, ITP는 대조군과 가장 가깝게 군집되었다. 두 질환이 항진되는 경로를 달리한다는 점도 확인되었으며, 활동성 미치료 ES에서는 IFN-γ 표적 유전자가, 활동성 wAIHA에서는 IFIT1·MX1·OAS1/2/3·ISG15/18 등 IFN-α/β 표적 유전자가 각각 최고 발현을 나타내었다.

혈장 케모카인이 뒷받침하는 두 경로

사이토카인 23종 가운데 유의한 상승이 확인된 것은 두 가지이다. IFN-γ가 유도하는 CXCL9는 ES(P=0.0008)와 wAIHA(P=0.0357)에서 대조군보다 높았고 cTfh 백분율과 약하지만 유의한 상관을 보였다(r=0.3267, P=0.0003). 반면 IFN-α 표적인 CCL2는 wAIHA에서만 상승하였으나(P=0.0170) cTfh와는 상관되지 않았다(r=−0.0963, P=0.3431).

해석

CXCL9는 cTfh와 상관되고 CCL2는 그렇지 않다는 대비로부터, cTfh 확장이 제1형이 아니라 제2형 IFN 신호와 연결된다는 추론이 성립한다. 저자들은 두 케모카인을 각 경로의 저비용 지표로 제시하면서 제1형과 제2형 IFN 경로를 각각 wAIHA와 ES의 치료 표적 후보로 지목하였는데, JAK 억제제를 통한 차단 가능성은 wAIHA에 한정하여 언급하였다는 점도 함께 읽어야 하는 것이다.

07 한계와 임상 적용의 경계

가장 본질적인 한계는 표본 채취 시점에 있다. 연구 설계상 검체가 진단 시점에 수집되지 않았으므로, 단일 계열 혈구감소증 환자에서 cTfh 상승이 향후 ES 발생이나 혈액 외 자가면역 발현을 예측하는지는 이 자료로 답할 수 없다. 예측 표지자로서의 가치를 주장하려면 진단 시점 채혈을 전제로 한 전향적 검증 연구가 선행되어야 한다.

  • 종단 검체 수가 제한적이어서 개별 약제가 시간에 따른 cTfh 변화에 미치는 영향은 평가되지 못하였다.
  • 단일기관 연구이며 ES가 희귀질환이므로 절단값의 재현성은 다기관 코호트에서 확인되어야 한다.
  • ES군의 높은 연령과 긴 이환 기간, wAIHA군의 높은 치료율이 교란 요인으로 남는다. 다만 이는 저자들이 한계로 명시한 항목이 아니라 Table 1의 기저 특성에서 도출한 해석이다.
  • cTfh 확장이 질병 활성도에 기여하는 기전과, 자가반응성 T·B 세포가 인식하는 항원결정기는 규명되지 않았다.
  • cTfh와 Treg의 표지자 정의 및 대상 연령이 연구마다 달라 기존 문헌과의 직접 비교가 제한된다.
그래서 언제 측정하는가

cTfh 상승은 ES 진단뿐 아니라 선천면역이상과 혈액 외 자가면역의 동반과도 연관되었으나, 양성예측도가 0.68에 그치므로 단일 양성 결과만으로 ES를 확진하기에는 부족하다. 따라서 cTfh는 확진 검사가 아니라 추가 평가가 필요한 환자를 지목하고 치료 반응을 추적하는 분류·모니터링 도구로 규정되며, 원인이 불분명한 다혈구감소 환자에서 ES 가능성을 판단할 때와 어떤 환자에게 유전자 검사 및 다학제 자가면역 평가를 확대할지 결정할 때가 이 검사의 적응증이라는 것이다.

한 줄 요약

새로운 검사를 개발한 연구가 아니라 이미 임상 검사실에 존재하던 저비용 검사의 활용 맥락을 진단과 모니터링, 선별의 세 가지로 확장한 연구이며, 여기에 아형별로 구분되는 제1형·제2형 인터페론 신호라는 기전적 설명이 더해졌으므로 기존 진단 수단의 공백을 실용적으로 보완하려는 시도로 평가된다.

핵심 지표임상 용도
cTfh 게이팅 정의CD4⁺ CXCR5⁺ PD-1⁺분모를 CD4⁺ T 세포로 두고 백분율을 산출한다
cTfh > 9.5%Sn 76% / Sp 86% / NPV 0.91ES를 감별하거나 배제하는 데 사용한다
cTfh > 11.3%정상 참고치 상한질병 활성도의 정상화 여부를 시점별로 추적한다
혈장 CXCL9 / CCL2cTfh와의 상관 r=0.3267 / r=−0.0963각각 IFN-γ와 IFN-α/β 경로의 활성을 가리키는 지표이며, 진단 성능이 검증된 값은 아니다

Harris EM, Bourdine A, Magin L, et al. Increased percentages of circulating T follicular helper cells associate with disease subtype and activity in pediatric immune cytopenias. Haematologica 2026;111(8):2684-2697. doi:10.3324/haematol.2025.287988

t-SNE — 거리를 버리고 확률을 남기는 임베딩 · 개정 노트
Learning Note · Dimensionality Reduction

t-SNE는 거리를 버리고 확률만 남긴다

고차원 데이터를 평면에 옮기는 과정에서 t-SNE가 실제로 최소화하는 대상은 좌표 오차가 아니라 두 이웃 분포 사이의 쿨백-라이블러 발산이다. 2023년에 작성한 개론을 다시 쓰면서 목적함수와 최적화 절차를 복원하고, 해석해도 되는 것과 해석하면 안 되는 것을 구분하였다.

Domain · Manifold Learning / Visualization Base · van der Maaten & Hinton, JMLR 2008 Revision · v2 · 2026-08-18 Previous · medtalk.tistory.com

01 개정의 범위

이전 글은 t-SNE의 절차를 순서대로 나열하였으나 알고리즘이 무엇을 최소화하는지 끝까지 밝히지 않았다. 확률 변환과 t-분포 도입까지 서술하고도 목적함수인 쿨백-라이블러 발산(Kullback–Leibler divergence)과 그 기울기가 빠져 있었으므로, 군집이 갈라지는 이유를 설명할 근거가 사실상 없었다. 이번 개정은 그 공백을 메우고, 그동안 바뀐 구현 기본값과 후속 연구의 권고를 반영한다.

정정 항목을 먼저 정리한다. 아래 표의 좌측은 이전 글의 서술이며, 우측은 이 노트에서 대체한 내용이다.

이전 서술정정
목적함수를 명시하지 않았다KL 발산 최소화로 정의하고 기울기를 인력과 척력으로 분해하였다§06
조건부 확률에서 곧바로 저차원 배치로 넘어갔다대칭화 단계를 복원하였다. 이상점 처리에 필요한 과정이다§03
계산 복잡도를 O(n²)으로 단정하였다Barnes-Hut 근사에서 O(n log n)이며, 보간 기반 구현은 사실상 선형에 근접한다§09
perplexity를 표본 수의 1~3%로 권고하였다근거가 빈약한 기준이므로 삭제하고, 복수 값 비교를 절차로 제시하였다§04
n_iter와 무작위 초기화를 전제한 코드를 실었다인자명이 max_iter로 바뀌었고 기본 초기화는 PCA로 변경되었다§10
군집 간 거리만 해석 대상에서 제외하였다군집의 크기와 밀도, 빈 공간의 폭까지 해석 대상에서 제외된다§08
key insight

t-SNE는 좌표를 옮기는 알고리즘이 아니라 확률분포를 맞추는 알고리즘이다. 고차원의 이웃 분포 $P$와 저차원의 이웃 분포 $Q$를 정의한 다음, 두 분포의 차이를 기울기 하강으로 줄여 나가는 구조이므로, 결과 그림에서 읽어야 할 것도 좌표가 아니라 이웃 관계이다.

02 거리가 무너지는 지점

차원이 커지면 임의의 두 점 사이 거리는 서로 비슷한 값으로 수렴한다. 각 차원이 독립적으로 분포할 경우 거리의 기댓값은 $\sqrt{D}$에 비례하여 커지는 반면 분산은 그만큼 커지지 않으므로, 최근접 이웃까지의 거리와 최원점까지의 거리 비율이 1에 접근한다. 이 현상을 거리 집중(distance concentration)이라 하며, 다음 극한으로 요약된다.

$$\lim_{D\to\infty}\ \frac{d_{\max}(x)-d_{\min}(x)}{d_{\min}(x)}\ \longrightarrow\ 0$$

절대 거리의 정보량이 이렇게 줄어들면 임계값으로 이웃을 자르는 방식은 성립하지 않는다. 그러나 순위와 상대적 근접도는 끝까지 남으므로, 남은 정보만으로 배치를 결정하도록 문제를 다시 세우는 편이 합리적이다. t-SNE가 거리를 확률로 바꾸는 이유가 여기에 있으며, 확률로 바꾸는 순간 각 점마다 스케일을 따로 정하는 길이 열리게 되는 것이다.

03 거리를 확률로 바꾸는 절차

조건부 유사도

기준점 $x_i$가 이웃 $x_j$를 선택할 조건부 확률을 가우시안 커널로 정의한다. 분자는 두 점의 제곱 거리를 폭 $\sigma_i$로 나눈 값이며, 분모는 기준점을 제외한 모든 점에 대한 합이므로 행마다 합이 1이 된다.

$$p_{j\mid i}=\frac{\exp\!\left(-\lVert x_i-x_j\rVert^{2}/2\sigma_i^{2}\right)}{\sum_{k\neq i}\exp\!\left(-\lVert x_i-x_k\rVert^{2}/2\sigma_i^{2}\right)},\qquad p_{i\mid i}=0$$

여기에서 이전 글이 다룬 질문을 다시 짚어 둔다. 가우시안 분포를 쓰려면 평균이 필요하지 않으냐는 물음이었는데, 각 분포의 중심은 기준점 $x_i$ 자신이므로 전역 평균을 구할 일은 없으며 결정해야 할 값은 폭 $\sigma_i$ 하나뿐이다. 점마다 별도의 $\sigma_i$를 두는 설계 덕분에 밀집한 영역에서는 좁은 커널이, 성긴 영역에서는 넓은 커널이 적용되어 밀도 차이가 자동으로 보정된다.

대칭화 — 이전 글이 건너뛴 단계

조건부 확률 $p_{j\mid i}$는 대칭이 아니다. 이상점(outlier)은 어느 점에게도 가까운 이웃으로 선택되지 않으므로 해당 열의 확률이 모두 0에 가까워지고, 그 결과 기울기에 거의 기여하지 못하여 저차원에서 위치가 결정되지 않는다. 두 방향의 조건부 확률을 평균하여 결합확률로 바꾸면 이 문제가 해소된다.

$$p_{ij}=\frac{p_{j\mid i}+p_{i\mid j}}{2n},\qquad \sum_{i

이 정의에 따르면 모든 점 $i$에 대해 $\sum_j p_{ij}>\frac{1}{2n}$이 보장되므로, 이상점도 최소한의 인력을 받아 배치에 참여한다. 대칭화는 계산 편의를 위한 손질이 아니라 기울기가 모든 점에 도달하도록 만드는 필수 단계이다.

표기 정리

P는 고차원 이웃 분포로서 학습 중 고정되는 반면, Q는 저차원 이웃 분포로서 매 반복마다 갱신되며, n은 표본 수를 가리킨다. 두 분포 모두 전체 합이 1인 결합분포로 정규화된다.

04 perplexity와 σ의 이진 탐색

$\sigma_i$를 직접 지정하지 않고 perplexity라는 하나의 값으로 간접 지정한다. perplexity는 분포의 섀넌 엔트로피를 지수화한 값이며, 확률이 $k$개 점에 균등하게 퍼져 있으면 정확히 $k$가 되므로 유효 이웃 수로 읽힌다.

$$\mathrm{Perp}(P_i)=2^{H(P_i)},\qquad H(P_i)=-\sum_{j}p_{j\mid i}\log_2 p_{j\mid i}$$

$\sigma_i$가 커지면 엔트로피가 단조 증가하므로, 목표 perplexity를 만족하는 $\sigma_i$는 이진 탐색으로 점마다 따로 구해진다. 아래 위젯에서 목표값을 옮기면 커널 폭과 확률 배분이 어떻게 달라지는지 확인된다.

widget 01 · perplexity → σσ = —
좌측은 기준점과 이웃의 배치이며 점선 원은 반지름 $\sigma_i$를 나타낸다. 우측 막대는 거리순으로 정렬한 $p_{j\mid i}$이다. perplexity를 낮추면 확률이 최근접 몇 점에 쏠리고, 높이면 먼 이웃까지 분산되는 양상이 관찰된다.
이전 글에서 삭제한 권고

표본 수의 1~3%를 perplexity로 쓰라는 기준은 근거가 빈약하므로 삭제하였다. 실무에서는 5에서 50 사이의 몇 값으로 각각 실행하여 구조가 유지되는지 확인하는 절차가 표준이며, 수만 개 이상의 대규모 자료에서는 표본 수에 비례하여 키우거나 서로 다른 perplexity를 합성하는 방식이 제안되었다.

05 저차원 커널과 밀집 문제

저차원 배치의 유사도는 자유도 1의 스튜던트 t-분포, 즉 코시 커널로 정의한다. 고차원과 달리 폭 모수를 두지 않으므로 형태가 하나로 고정되며, 계산도 지수함수보다 저렴하다.

$$q_{ij}=\frac{\left(1+\lVert y_i-y_j\rVert^{2}\right)^{-1}}{\sum_{k\neq l}\left(1+\lVert y_k-y_l\rVert^{2}\right)^{-1}}$$

커널을 바꾼 이유는 밀집 문제(crowding problem)에 있다. $D$차원 공간에서 반지름 $r$ 안에 들어가는 부피는 $r^{D}$로 늘어나는 반면 평면에서는 $r^{2}$로만 늘어나므로, 고차원에서 중간 거리에 놓여 있던 다수의 이웃을 평면에 그대로 옮기면 자리가 부족하여 중심으로 몰린다. 꼬리가 두꺼운 커널을 쓰면 같은 확률을 훨씬 먼 거리에 배정하므로 중간 거리 이웃이 밀려날 공간이 생기고, 그 결과 군집 사이의 빈 공간이 확보된다.

widget 02 · gaussian vs student-t거리비 —
같은 유사도 값을 두 커널이 각각 어느 거리에 배정하는지 비교한다. 유사도가 낮아질수록 t-분포가 배정하는 거리가 급격히 멀어지며, 이 차이가 저차원에서 군집을 벌려 놓는 힘으로 작용한다.

06 목적함수와 인력·척력

무엇을 최소화하는가

두 분포를 맞추는 손실은 KL 발산으로 정의된다. 이전 글에서 누락되었던 부분이며, t-SNE의 성질 대부분이 이 한 줄에서 유도된다.

$$C=\mathrm{KL}(P\parallel Q)=\sum_{i}\sum_{j\neq i}p_{ij}\log\frac{p_{ij}}{q_{ij}}$$

KL 발산은 대칭이 아니므로 두 종류의 오류에 서로 다른 벌점이 부과된다. 고차원에서 가까웠던 쌍($p_{ij}$가 큼)을 저차원에서 멀리 두면($q_{ij}$가 작음) 손실이 크게 증가하는 반면, 원래 멀었던 쌍을 가깝게 두는 오류는 상대적으로 적은 벌점만 받는다. 지역 구조는 강하게 보존되고 전역 구조는 희생되는 t-SNE의 성향이 손실함수의 비대칭성에서 직접 나온다는 것이다.

기울기의 두 항

기울기는 닫힌 형태로 정리되며, 부호에 따라 인력과 척력으로 분해된다. $Z=\sum_{k\neq l}(1+\lVert y_k-y_l\rVert^{2})^{-1}$로 두면 다음과 같다.

$$\frac{\partial C}{\partial y_i}=4\sum_{j\neq i}\underbrace{p_{ij}q_{ij}Z\,(y_i-y_j)}_{\text{인력}}\;-\;4\sum_{j\neq i}\underbrace{q_{ij}^{2}Z\,(y_i-y_j)}_{\text{척력}}$$

인력 항은 고차원에서 가까웠던 쌍만 끌어당기므로 계산량이 이웃 수에 비례하는 반면, 척력 항은 모든 쌍에 작용하므로 전체 계산의 병목이 된다. Barnes-Hut 근사와 보간 기반 구현이 모두 척력 항을 겨냥한다는 사실도 이 분해에서 설명된다.

초기화와 과장 단계

손실이 볼록하지 않으므로 초기값과 학습 일정이 결과를 좌우한다. 초기 250회 반복 동안 $P$에 12를 곱하는 조기 과장(early exaggeration)을 적용하면 인력이 일시적으로 강해져 군집이 먼저 뭉치고, 과장을 해제한 뒤 척력이 군집을 분리한다. 초기화를 PCA 결과로 두면 무작위 초기화보다 전역 배치가 안정되므로 최근 구현은 이를 기본값으로 삼는다.

07 실시간 실행

아래 위젯은 10차원 모의 자료에 대해 정확해 방식의 t-SNE를 브라우저에서 직접 최적화한다. 조기 과장 구간에서 군집이 먼저 응집하였다가 해제 시점에 서로 밀려나는 과정, perplexity를 지나치게 낮출 때 하나의 군집이 여러 조각으로 갈라지는 현상, 초기화와 시드를 바꿀 때 배치가 회전하거나 재배열되는 양상을 같은 화면에서 비교하기 위한 구성이다.

반복 1000회분의 궤적은 배경에서 1초 남짓 만에 모두 계산되며 재생은 이와 분리되어 진행되므로, 대기 없이 임의 지점을 조회한다. 초반 170회처럼 배치가 거의 변하지 않는 구간은 5배로 빠르게 넘어가고 과장이 해제되는 250회 전후는 0.6배로 느려지도록 완급을 자동 배분하였으며, 이 동작은 자동 완급 항목을 해제하면 균일 속도로 전환된다.

widget 03 · live t-SNEiter 0 · KL —
10차원에서 생성한 240개 표본을 평면으로 옮긴다. 점 색은 생성 시점의 군집 표지이며 알고리즘에는 입력되지 않는다. 하단 곡선은 반복에 따른 KL 손실이고 보라색 구간은 조기 과장이 걸린 250회까지이며, 세로선은 현재 위치를 가리킨다. 궤적 전체가 배경에서 미리 계산되므로 반복 슬라이더로 임의 지점을 즉시 조회한다.

세 자료를 차례로 실행하면 알고리즘의 한계가 드러난다. 균등한 세 군집은 어떤 설정에서도 분리되지만, 크기와 밀도가 다른 세 군집은 평면에서 비슷한 면적으로 그려지므로 원본의 밀도 차이가 사라진다. 연속 곡선 자료에서는 perplexity가 낮을수록 하나의 구조가 여러 덩어리로 끊어지며, 이 조각들은 자료에 존재하지 않는 군집이다.

08 해석 규칙

t-SNE 그림에서 신뢰할 수 있는 정보는 제한적이다. 아래 표는 판단 대상별로 신뢰 수준을 정리한 것이며, 근거는 모두 앞 절의 목적함수에서 나온다.

읽으려는 것신뢰근거
어떤 점들이 서로 이웃인가높음$p_{ij}$가 큰 쌍에 벌점이 집중되므로 지역 이웃 관계는 우선 보존된다
군집이 몇 개로 갈라지는가조건부perplexity가 지나치게 낮으면 연속 구조도 조각난다. 복수 값으로 재실행하여 확인해야 한다
군집의 크기와 밀도없음점마다 $\sigma_i$가 달라 밀도가 정규화되므로 성긴 군집도 조밀하게 그려진다
군집 사이의 거리낮음척력의 절대 크기는 정규화 상수에 좌우된다. PCA 초기화에서 다소 개선되나 정량 해석은 성립하지 않는다
축의 방향과 좌표값없음손실이 회전과 평행이동에 불변이므로 축 자체에 의미가 없다

따라서 보고용 그림에는 최소한 perplexity, 반복 횟수, 초기화 방식, 난수 시드를 함께 기재해야 한다. 같은 자료라도 설정이 다르면 다른 그림이 나오므로, 설정을 밝히지 않은 t-SNE 그림은 재현이 불가능한 그림이라는 것이다.

검증 절차

군집 구조를 주장하려면 t-SNE 외의 근거를 덧붙인다. 원본 공간에서 시행한 군집화 결과를 색으로 겹쳐 보거나, 이웃 보존율 같은 정량 지표를 계산하거나, perplexity와 시드를 바꾼 여러 실행에서 같은 분리가 재현되는지 확인하는 방법이 있다.

09 계보와 대안

t-SNE는 갑자기 등장한 기법이 아니라 선형 사영에서 이웃 그래프 임베딩으로 이어지는 계보의 한 지점에 있다. 아래 도식은 주요 분기와 연도를 정리한 것이며, 보라색은 t-SNE 계열, 청록색은 이웃 그래프 계열, 회색은 선형·고전 다양체 기법이다.

tech tree · dimensionality reduction1901 → 2022
PCA 1901 · 선형 사영 MDS 1952 · 거리 보존 Isomap · LLE 2000 · 다양체 가정 SNE 2002 · 확률 변환 t-SNE 2008 · t-커널 · KL Barnes-Hut 2014 · O(n log n) FIt-SNE 2019 · 보간 척력 UMAP 2018 · 교차엔트로피 PaCMAP 2021 · 쌍 표집 인력·척력 스펙트럼 2022 · 두 계열의 통합 해석
SNE에서 t-SNE로의 전환은 커널 교체와 대칭화였고, 이후 분기는 대부분 척력 계산의 가속에 집중되었다. 하단 점선 상자는 t-SNE와 UMAP의 차이를 인력과 척력의 상대 세기 차이로 설명한 후속 연구를 가리킨다.

UMAP과의 비교

실무에서 가장 자주 비교되는 대안은 UMAP이다. 두 기법의 차이는 흔히 알려진 것보다 작으며, 초기화 방식과 척력의 세기를 맞추면 결과가 상당히 수렴한다는 분석이 보고되었다.

항목t-SNEUMAP
목적함수KL 발산을 최소화한다이진 교차엔트로피를 최소화한다
척력 계산정규화 상수를 근사하여 전체 쌍을 처리한다음성 표집으로 일부 쌍만 처리한다
기본 초기화PCA로 초기화한다스펙트럴 임베딩으로 초기화한다
전역 구조초기화에 크게 의존한다비교적 안정되나 역시 초기화에 의존한다
속도보간 구현에서 대규모 자료를 처리한다일반적으로 더 빠르다

10 구현과 점검 목록

scikit-learn 1.5에서 n_itermax_iter로 바뀌었고 1.7에서 이전 이름이 제거되었으므로, 이전 글의 코드는 최신 버전에서 동작하지 않는다. 아래는 현재 기본값을 명시적으로 적어 둔 형태이다.

# scikit-learn 1.5 이상 · 기본값을 명시적으로 기재
from sklearn.manifold import TSNE
from sklearn.decomposition import PCA

X50 = PCA(n_components=50, random_state=42).fit_transform(X)   # 잡음·계산량 감소

tsne = TSNE(
    n_components=2,
    perplexity=30,              # 5~50 범위에서 복수 값 비교
    early_exaggeration=12.0,   # 초기 250회 인력 강화
    learning_rate='auto',      # 표본 수에 비례 · 하한 50
    max_iter=1000,             # n_iter는 1.7에서 제거되었다
    init='pca',                # 1.2부터 기본값
    method='barnes_hut',       # 척력 근사 · O(n log n)
    random_state=42,
)
emb = tsne.fit_transform(X50)

print('KL:', tsne.kl_divergence_)    실행 간 비교 지표로 기록한다

수만 개 이상의 표본에서는 openTSNE가 더 적합하다. 보간 기반 척력 계산과 과장 계수 조절, 신규 표본의 기존 임베딩 투영을 지원하므로, 단일세포 전사체처럼 표본 수가 큰 자료에서 표준으로 쓰인다.

작성 후 점검 목록

  • PCA로 50차원 안팎까지 줄인 뒤 t-SNE에 넣었는가
  • perplexity를 최소 세 값으로 실행하여 구조가 재현되는지 확인하였는가
  • 반복이 조기 종료되지 않고 손실이 안정될 때까지 진행되었는가
  • 그림 설명에 perplexity, 반복 횟수, 초기화, 시드를 기재하였는가
  • 군집 크기와 군집 간 거리를 본문에서 해석하지 않았는가
  • 군집 주장을 원본 공간의 근거로 뒷받침하였는가
closing

t-SNE의 결과는 자료 자체의 기록이 아니라 특정 손실함수가 도달한 하나의 해이므로, 무엇을 최소화하였는지 파악하고 나면 그림에서 읽어도 되는 항목과 읽으면 안 되는 항목이 구분된다. 이 구분이 성립할 때 비로소 시각화가 논증의 근거로 쓰이게 되는 것이다.

Brushing & Linking — 4가지 효과 인터랙티브 데모
Interactive Demo · NCCN_KG_Explorer 효과 코드 적용

네 조각을 하나씩 켜고 끄며 확인하기

NCCN_KG_Explorer에 실제 적용된 효과 코드(스타일·하이라이트·레이아웃)를 그대로 옮겼다. 좌측 항목을 클릭하면 우측 그래프가 반응하고, 네 개의 토글로 각 효과를 독립적으로 켜고 끌 수 있다. 특히 ③ State Transition을 끈 채 클릭하면 색이 "툭" 바뀌고, 켜면 180ms로 보간되는 차이를 직접 볼 수 있다.

4 Effects 각 효과를 켜고 끄며 차이를 관찰하세요
스위치로 켜둔 뒤 버튼을 누르면 배치가 바뀌며 트랜지션이 보입니다 · 끄고 누르면 순간이동
Panels · 클릭해 보세요
좌측 Panels 클릭 → 하이라이트 · 상단 카드의 로 배치 전환
라이브러리 로딩 중… (잠시 후 좌측 항목을 클릭하세요)

지금 무슨 일이 일어나는가

Focus + ContextON
addClass('dim' / 'hot') · opacity .13
관련 노드는 .hot(border 3.2), 나머지는 .dim(opacity .13)으로 흐림. 끄면 전부 같은 밝기 — 무엇이 선택됐는지 안 보인다.
Animated CameraON
cy.animate({fit:...}, 420ms)
강조 대상으로 화면이 420ms에 걸쳐 이동·확대. 끄면 cy.fit()으로 순간이동(점프)한다.
State TransitionON
transition-* · 180ms
색·테두리·투명도가 180ms에 걸쳐 보간. 끄면 색이 "툭" 즉시 바뀐다. 차이가 가장 잘 보이는 토글.
Layout TransitionON
layout {animate:true, 620ms}
버튼을 누를 때마다 배치가 바뀐다(Flow→Concentric→Circle→Grid). 켜면 노드가 새 위치로 날아가고, 끄면 순간이동한다. 배치가 크게 달라져 차이가 뚜렷하다.
추천 실험 1 (③): ③만 끄고 좌측 항목을 두어 개 클릭해 보세요. 하이라이트는 되지만 색이 툭툭 바뀝니다. 다시 켜면 같은 클릭이 부드러워집니다 — cy.animate()(②)는 그대로인데도요. "부드러운 강조의 비결은 transition-* 두 줄"이라는 말의 증거입니다.
추천 실험 2 (④): 버튼을 연달아 눌러 배치를 Flow→Concentric→Circle→Grid로 바꿔 보세요. 노드가 새 위치로 날아갑니다. ④를 끄고 누르면 순간이동합니다 — 배치가 크게 달라지는 이 순간이 ④가 가장 잘 보이는 지점입니다.
원본 NCCN_KG_Explorer.html — 네 효과 핵심 코드
효과원본 코드위치
Focus + Context .dim opacity .13 / .hot border 3.2
addClass('dim')removeClass('dim').addClass('hot')
369–371
435–436
Animated Camera cy.animate({fit:{eles:coll}, duration:420}) 438
State Transition transition-property + transition-duration:180ms
(노드·엣지 둘 다)
333
357
Layout Transition animate:true, animationDuration:420 402
404
Brushing & Linking · 4-Layer Interactive Demo Cytoscape.js 3.28 + dagre
스크립트를 제거·재배치해도 안전. var LIBS = [ "https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.28.1/cytoscape.min.js", "https://cdnjs.cloudflare.com/ajax/libs/dagre/0.8.5/dagre.min.js", "https://cdn.jsdelivr.net/npm/cytoscape-dagre@2.5.0/cytoscape-dagre.min.js" ]; function loadScript(src){ return new Promise(function(resolve, reject){ // 이미 로드돼 있으면 스킵 if (document.querySelector('script[src="'+src+'"]')) { resolve(); return; } var s = document.createElement('script'); s.src = src; s.async = false; // 순서 보장 s.onload = function(){ resolve(); }; s.onerror = function(){ reject(new Error('load fail: '+src)); }; document.head.appendChild(s); }); } function ready(fn){ if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', fn); } else { fn(); } } function start(){ // cytoscape가 이미 있으면 바로, 아니면 순차 로드 var chain = Promise.resolve(); LIBS.forEach(function(src){ chain = chain.then(function(){ return loadScript(src); }); }); chain.then(function(){ if (typeof cytoscape === 'undefined') { throw new Error('cytoscape 로드 실패'); } boot(); }).catch(function(err){ console.error(err); var el = document.getElementById('status'); if (el) el.textContent = '라이브러리 로드 실패 — 네트워크/차단 여부를 확인하세요. ('+err.message+')'; }); } ready(start); // ===== 위젯 본체 ===== function boot(){ // ---------- data: NCCN PEDALL 축약 — 원본 type/r 체계 사용 ---------- const NODES = [ {id:'RISK', label:'Risk\nStratification', type:'assessment'}, {id:'SR', label:'Standard risk', type:'clinical_state'}, {id:'HR', label:'High risk', type:'clinical_state'}, {id:'IND', label:'Induction\ntherapy', type:'intervention'}, {id:'RA', label:'Response\nAssessment', type:'assessment'}, {id:'MRDQ', label:'MRD?', type:'condition'}, {id:'MRDP', label:'MRD+', type:'clinical_state'}, {id:'MRDN', label:'MRD−', type:'clinical_state'}, {id:'BLINA', label:'blinatumomab', type:'intervention'}, {id:'P4', label:'PEDALL-4', type:'reference'}, {id:'MAINT', label:'Maintenance', type:'intervention'}, {id:'SURV', label:'Surveillance', type:'reference'} ]; // [source, target, relation, edgeLabel?] const EDGES = [ ['RISK','SR','yields'],['RISK','HR','yields'], ['SR','IND','leads_to'],['HR','IND','leads_to'], ['IND','RA','leads_to'], ['RA','MRDQ','requires_check'], ['MRDQ','MRDP','yields','MRD+'],['MRDQ','MRDN','yields','MRD−'], ['MRDP','P4','leads_to'], ['MRDN','BLINA','leads_to'],['BLINA','MAINT','leads_to'],['MAINT','SURV','leads_to'] ]; // ---------- register dagre ---------- let DAGRE_OK=false; try{ if(typeof cytoscapeDagre!=='undefined'){cytoscape.use(cytoscapeDagre);DAGRE_OK=true;} else if(typeof window.cytoscapeDagre!=='undefined'){cytoscape.use(window.cytoscapeDagre);DAGRE_OK=true;} } catch(e){ console.warn('dagre reg failed',e); } // ---------- effect state ---------- const FX = {1:true,2:true,3:true,4:true}; // ---------- build style — NCCN_KG_Explorer 원본 체계 그대로 ---------- // 핵심: transition-* 는 FX[3] ON일 때만 주입. .dim/.hot 값은 원본과 동일. function buildStyle(){ const nodeBase = { 'label':'data(label)','text-wrap':'wrap','text-valign':'center','text-halign':'center', 'font-family':'IBM Plex Sans','font-size':'11px','font-weight':500, 'shape':'round-rectangle','border-width':1.4, 'width':118,'height':50,'padding':'8px','text-max-width':'104px','color':'#1a1d2e' }; if(FX[3]){ // ③ State Transition — 원본과 동일한 선언 nodeBase['transition-property']='opacity, border-width, background-color'; nodeBase['transition-duration']='180ms'; } const edgeBase = { 'width':1.8,'curve-style':'bezier','target-arrow-shape':'triangle','arrow-scale':.85, 'line-color':'#b4b8c4','target-arrow-color':'#b4b8c4', 'source-endpoint':'outside-to-node','target-endpoint':'outside-to-node' }; if(FX[3]){ edgeBase['transition-property']='opacity, line-color, width'; edgeBase['transition-duration']='180ms'; } return [ { selector:'node', style:nodeBase }, // 원본의 type별 색 — clinical_state/assessment/condition/intervention { selector:'node[type="clinical_state"]', style:{'background-color':'#f2edff','border-color':'#6d3fe0','color':'#3c3489'}}, { selector:'node[type="assessment"]', style:{'background-color':'#e3f7f4','border-color':'#0a7d6c','color':'#085041'}}, { selector:'node[type="condition"]', style:{'background-color':'#fff0e8','border-color':'#c94a10','color':'#712b13','shape':'diamond','width':96,'height':96,'text-max-width':'54px','font-size':'10px'}}, { selector:'node[type="intervention"]', style:{'background-color':'#e8f0fd','border-color':'#1d5fd4','color':'#0c447c'}}, { selector:'node[type="reference"]', style:{'background-color':'#eef0f5','border-color':'#4a5163','color':'#4a5163','font-family':'IBM Plex Mono','font-weight':600,'font-size':'11px'}}, { selector:'edge', style:edgeBase }, { selector:'edge[label]', style:{ 'label':'data(label)','font-family':'IBM Plex Mono','font-size':'9px','color':'#5a6378', 'text-background-color':'#f7f8fb','text-background-opacity':1,'text-background-padding':'2px' }}, // 원본의 r별 엣지 색 — yields/leads_to/requires_check { selector:'edge[r="yields"]', style:{'line-color':'#0a7d6c','target-arrow-color':'#0a7d6c'}}, { selector:'edge[r="leads_to"]', style:{'line-color':'#1d5fd4','target-arrow-color':'#1d5fd4'}}, { selector:'edge[r="requires_check"]', style:{'line-color':'#c94a10','target-arrow-color':'#c94a10'}}, // 원본과 동일한 dim/hot 값 { selector:'.dim', style:{'opacity':.13}}, { selector:'.hot', style:{'border-width':3.2,'z-index':99}}, { selector:'edge.hot', style:{'width':3.4,'z-index':99,'opacity':1}}, { selector:'node:selected', style:{'border-width':3.2}} ]; } function layoutOpts(){ const base = DAGRE_OK ? { name:'dagre', rankDir:'LR', nodeSep:26, rankSep:96, edgeSep:16, padding:40, fit:true } : { name:'breadthfirst', directed:true, fit:true, padding:40 }; base.animate = FX[4]; // ④ Layout Transition base.animationDuration = 420; // 원본과 동일 return base; } // ---------- init cytoscape ---------- const cy = cytoscape({ container:document.getElementById('cy'), elements:[ ...NODES.map(n=>({data:{id:n.id,label:n.label,type:n.type}})), ...EDGES.map(([s,t,r,lab],i)=>({data:{ id:'e'+i, source:s, target:t, r:r, ...(lab?{label:lab}:{}) }})) ], style:buildStyle(), layout:layoutOpts(), minZoom:0.4, maxZoom:2.2 }); // ---------- core: highlight — NCCN_KG_Explorer 원본 패턴 ---------- function highlight(coll, labelText){ // ① Focus + Context (원본: 전체 dim → 대상만 hot) if(FX[1]){ cy.elements().addClass('dim'); coll.removeClass('dim').addClass('hot'); } else { cy.elements().removeClass('dim'); cy.elements().removeClass('hot'); coll.addClass('hot'); } // ② Animated Camera (원본: cy.animate fit / 끄면 cy.fit 점프) if(FX[2]){ cy.animate({fit:{eles:coll, padding:70}, duration:420, easing:'ease-in-out'}); } else { cy.fit(coll, 70); } setStatus(labelText, coll); } function clearHL(){ cy.elements().removeClass('dim hot'); } // ---------- status line ---------- function setStatus(txt, coll){ const glyph={1:'①',2:'②',3:'③',4:'④'}; const on = [1,2,3,4].filter(i=>FX[i]).map(i=>glyph[i]).join(''); const warn = (!FX[3]?' · ③꺼짐 → 색 즉시 변경':'') + (!FX[2]?' · ②꺼짐 → 카메라 점프':''); document.getElementById('status').innerHTML = `선택: ${txt} · 강조 노드 ${coll.nodes().length}개 · 활성 효과 ${on||'없음'}${warn}`; } // ---------- build left list ---------- const LIST = [ {id:'RISK', name:'Risk Stratification', sub:'assessment · 시작점'}, {id:'RA', name:'Response Assessment', sub:'assessment · 분기 전'}, {id:'MRDQ', name:'MRD? (분기점)', sub:'condition · diamond'}, {id:'MRDP', name:'MRD+', sub:'state · reverse 데모'}, {id:'BLINA',name:'blinatumomab', sub:'intervention · incomers'} ]; const listEl = document.getElementById('list'); LIST.forEach(item=>{ const b=document.createElement('button'); b.className='list-item'; b.dataset.id=item.id; b.innerHTML=`${item.name}
${item.sub}
`; b.onclick=()=>{ document.querySelectorAll('.list-item').forEach(x=>x.classList.remove('active')); b.classList.add('active'); const n=cy.getElementById(item.id); // MRD+는 reverse(들어오는 경로), 그 외는 forward(나가는 경로) const coll = (item.id==='MRDP'||item.id==='BLINA') ? n.union(n.incomers()).union(n.incomers().sources()) : n.union(n.outgoers()).union(n.outgoers().targets()); highlight(coll, item.name); }; listEl.appendChild(b); }); // 그래프 직접 클릭 cy.on('tap','node',ev=>{ const n=ev.target; document.querySelectorAll('.list-item').forEach(x=>x.classList.remove('active')); const coll=n.union(n.outgoers()).union(n.outgoers().targets()); highlight(coll, n.data('label').replace(/\n/g,' ')); }); cy.on('tap',ev=>{ if(ev.target===cy){ clearHL(); document.getElementById('status').textContent='해제됨.'; }}); // 초기화 완료 — 상태줄 갱신 (function(){ var s=document.getElementById('status'); if(s) s.textContent='준비됨 — 좌측에서 항목을 클릭하세요.'; })(); // ---------- toggles ---------- function rebuildStyle(){ cy.style(buildStyle()); } function syncBadge(el, on){ if(!el) return; el.textContent = on?'ON':'OFF'; el.style.color = on?'var(--green)':'var(--coral)'; el.style.background = on?'var(--green-bg)':'#fff'; el.style.borderColor = on?'var(--green-bd)':'var(--coral-bd)'; } [1,2,3,4].forEach(i=>{ document.getElementById('fx'+i).addEventListener('change',e=>{ FX[i]=e.target.checked; // 상단 가로 바: 배지 + 카드 전체 off 표시 syncBadge(document.getElementById('tag'+i), FX[i]); const card=document.getElementById('tc'+i); if(card) card.classList.toggle('off', !FX[i]); // 하단 설명 카드 배지 const ctag=document.getElementById('ctag'+i); if(ctag){ ctag.textContent=FX[i]?'ON':'OFF'; ctag.style.color=FX[i]?'var(--green)':'var(--coral)'; ctag.style.background=FX[i]?'var(--green-bg)':'var(--coral-bg)'; } if(i===3) rebuildStyle(); // ③은 스타일 재빌드 필요 }); }); // ---------- action buttons ---------- // ④ 효과를 크게 보이게 — 레이아웃을 순환 전환 (노드가 크게 재배치됨) const LAYOUT_MODES = [ { key:'dagre-LR', label:'Flow ▸ (dagre LR)', shortLabel:'Flow ▸' }, { key:'dagre-TB', label:'Flow ▾ (dagre TB)', shortLabel:'Flow ▾' }, { key:'concentric', label:'Concentric ◎', shortLabel:'Concentric ◎' }, { key:'circle', label:'Circle ○', shortLabel:'Circle ○' }, { key:'grid', label:'Grid ▦', shortLabel:'Grid ▦' } ]; let layoutIdx = 0; function currentLayout(){ const mode = LAYOUT_MODES[layoutIdx].key; let base; if(mode==='dagre-LR' && DAGRE_OK) base={name:'dagre',rankDir:'LR',nodeSep:26,rankSep:96,edgeSep:16}; else if(mode==='dagre-TB' && DAGRE_OK) base={name:'dagre',rankDir:'TB',nodeSep:30,rankSep:60,edgeSep:16}; else if(mode==='concentric') base={name:'concentric',minNodeSpacing:34,concentric:n=>n.degree(),levelWidth:()=>2}; else if(mode==='circle') base={name:'circle'}; else if(mode==='grid') base={name:'grid',rows:3}; else base={name:'breadthfirst',directed:true}; base.fit=true; base.padding=40; base.animate = FX[4]; // ④ Layout Transition base.animationDuration = 620; // 조금 더 길게 — 이동이 잘 보이도록 base.animationEasing = 'ease-in-out'; return base; } const relayoutBtn = document.getElementById('relayout'); relayoutBtn.onclick=(e)=>{ e.preventDefault(); // label 안의 버튼 → 체크박스 토글 방지 e.stopPropagation(); layoutIdx = (layoutIdx + 1) % LAYOUT_MODES.length; relayoutBtn.textContent = '↻ ' + LAYOUT_MODES[layoutIdx].shortLabel; clearHL(); document.querySelectorAll('.list-item').forEach(x=>x.classList.remove('active')); cy.layout(currentLayout()).run(); document.getElementById('status').innerHTML = `레이아웃 전환: ${LAYOUT_MODES[layoutIdx].label} · ` + `${FX[4]?'노드가 새 배치로 이동(애니메이션)':'④꺼짐 → 순간이동'}`; }; document.getElementById('reset').onclick=(e)=>{ e.preventDefault(); clearHL(); layoutIdx = 0; relayoutBtn.textContent = '↻ ' + LAYOUT_MODES[0].shortLabel; document.querySelectorAll('.list-item').forEach(x=>x.classList.remove('active')); cy.layout(currentLayout()).run(); document.getElementById('status').textContent='초기화됨.'; }; } // ===== end boot() ===== })();
레날리도마이드와 IDH2 클론성 조혈 — Blood 2026
Blood 2026 · 논문 리뷰

레날리도마이드 이후의 B-ALL은
IDH2 클론성 조혈에서 시작된다

지난 글에서 다룬 연구가 레날리도마이드와 TP53 변이 클론, 그리고 골수성 종양(t-MN)의 관계였다면, 이번 연구는 같은 약제가 림프계 백혈병에서도 동일한 방식으로 작용함을 확인하였다. 핵심은 IDH2 R140Q 돌연변이와 IKAROS 소실이다.

Journal · Blood 2026;148(7):856-866 Cohort · LenB-ALL n=57 Date · 2026-08-15

00 한눈에 보기

57
분석된 레날리도마이드 연관 B-ALL 환자, 현재까지 최대 규모이다
23%
IDH2 R140Q 돌연변이가 확인된 비율
0.07%
일반적인 B-ALL에서 같은 돌연변이가 관찰되는 비율
63%
클론성 조혈 연관 유전자 변이를 동반한 비율
핵심 한 줄

레날리도마이드는 IDH2 돌연변이 조혈모세포 클론에 선택적 이점을 부여하고, 동시에 IKAROS 단백을 분해하여 B세포를 미성숙 단계에서 멈추게 한다. 이 두 기전이 작용하여 새로운 아형의 B-ALL이 발생하는 것이다.

01 어떻게 백혈병이 되는가

연구팀이 제안한 경로는 네 단계로 정리할 수 있다. 마지막 단계가 중요한데 일단 백혈병이 확립되면 약을 중단해도 되돌아가지 않는다는 것이다.

STEP 01 · 약물 다발골수종 유지요법으로 레날리도마이드를 장기간 투여한다 (중앙값 2.8년) STEP 02 · 클론 선택 IDH2 돌연변이 조혈모세포 클론이 선택적으로 확장된다 STEP 03 · 성숙 정지 약물이 IKAROS를 분해 → B세포가 전구체 단계에서 멈추고 유전자 재조합 효소(RAG) 활성이 계속 켜져 있게 된다 STEP 04 · 자립 IKZF1 결손과 DNA 과메틸화가 추가로 쌓이면 약을 중단해도 백혈병은 진행한다
fig 1 · 저자들이 제안한 백혈병 발생 경로

02 왜 IDH2가 특별한가

IDH2 R140Q는 원래 급성 골수성 백혈병(AML)에서 흔히 관찰되는 돌연변이로 일반적인 B-ALL에서는 거의 볼 수 없으나, 레날리도마이드를 투여받은 환자들의 B-ALL에서는 4명 중 1명꼴로 검출되었다.

레날리도마이드 연관 B-ALL n = 57 23% 성인 원발성 B-ALL n = 360 1.1% 소아·청년 원발성 B-ALL n = 1,428 0.07%
fig 2 · IDH2 R140Q 돌연변이 빈도 비교 (P < .0001)

환자 57명은 서로 겹치지 않는 세 그룹으로 구분되는데, 각 그룹은 동반되는 IKZF1(IKAROS 유전자) 이상의 형태까지 차이가 있었다.

그룹비율IKZF1 이상의 형태
IDH2 R140Q13/57 · 23%유전자 일부 결손이며 대부분 소수 클론에만 존재하여, 이차적으로 획득된 변화로 판단된다
TP5317/57 · 30%7번 염색체 소실과 함께 유전자 전체가 결손되었다
기타 (KRAS/NRAS 등)13/57 · 23%일반적인 B-ALL과 유사한 양상을 보였다
덧붙임

IDH2 그룹은 기존에 정립된 22개 B-ALL 분자 아형 어디에도 분류되지 않았으며, 유전자 발현과 DNA 메틸화 양상에서 독립된 집단을 형성하였고, 오히려 IDH2 변이 AML·T-ALL과 더 유사하였다.

03 "백혈병 세포만의 문제가 아니다"

이 연구의 결정적 증거는 돌연변이가 발견된 위치인데, IDH2 변이는 백혈병 세포에서만 검출되지 않았다. 골수계·림프계 세포에서도 검출되었고, 백혈병이 관해된 뒤에도 남아 있었다.

ORIGIN IDH2 변이 조혈모세포 단구 IDH2mt 검출 적혈구 전구세포 IDH2mt 검출 골수계 전구세포 IDH2mt 검출 T세포 · NK세포 일부 환자에서 검출 성숙 B세포 10%에서 검출 백혈병 모세포 (B-ALL) 최종 결과물
fig 3 · IDH2 돌연변이가 검출된 세포 계열 (FACS 분획 및 단일세포 RNA-seq)

또한 미세잔존질환(MRD)이 음성으로 전환된 관해기에도 13명 중 4명에서 IDH2 변이가 낮은 농도로 계속 검출된 반면, IKZF1 결손은 관해기에 전혀 검출되지 않았다.

해석

IDH2 변이는 백혈병보다 먼저 존재하던 클론성 조혈이고, IKZF1 결손은 백혈병이 만들어지는 과정에서 나중에 추가된 사건으로 순서가 명확히 밝혀졌다.

04 지난 글과 이어 보면

2022년 Sperling 등의 연구와 이번 연구는 표적 세포 계열이 다를 뿐, 논리 구조가 같다. 레날리도마이드가 특정 돌연변이 클론에 선택적 이점을 준다는 논리이다.

Sperling 2022 (지난 글)Horns 2026 (이번 글)
발생 종양골수성 종양 t-MNB세포 급성림프모구백혈병 LenB-ALL
핵심 돌연변이TP53IDH2 R140Q
선택 기전CK1α 분해로 p53 의존적 세포사멸을 회피한다IKAROS 분해로 성숙이 정지되고 RAG 활성이 지속된다
기원전백혈병성 클론성 조혈전백혈병성 클론성 조혈 동일

05 임상적으로 무엇이 달라지나

  • 치료 표적이 생긴다. IDH2 변이 AML에는 이미 에나시데닙 같은 IDH2 억제제가 쓰이고 있는데, 과메틸화 표현형을 고려하면 탈메틸화제도 후보가 될 수 있다. 즉, 표준 B-ALL 요법 외의 선택지가 열리게 되는 것이다.
  • 검사 전략이 달라진다. 골수종 병력이 있는 고령의 B-ALL 환자에서는 IDH2·TP53·DNMT3A 등 클론성 조혈 연관 유전자와 IKZF1 결손을 함께 확인해야 아형을 정확히 규명할 수 있다.
  • 선별검사 논의는 아직 열려 있다. IDH2 클론성 조혈 자체는 매우 드물고 통상적인 검사로는 검출되지 않는 낮은 농도로 존재할 수 있어, 유지요법 전 고감도 선별검사가 유용한지는 전향적 연구가 필요하다. 지난 글의 TP53에서 제기된 질문과 동일한 지점이다.
읽을 때 주의할 점
  • 후향적 다기관 연구이며 치료력 자료의 완결성이 균일하지 않다.
  • ALL 진단 이전 시점의 검체가 확보되지 않아, 변이 클론이 약물 투여 전부터 존재하였는지는 직접 증명하지 못하였다.
  • 멜팔란 등 선행 항암치료의 기여를 분리하지 못하였고, IKAROS 단백 수준을 확인한 단백체 데이터도 없다.
  • IDH2 그룹의 환자 수가 13명으로 적어 일부 분석의 검정력이 제한적이다.
결론

레날리도마이드 유지요법의 생존 이득은 분명하므로, 결론은 투약을 회피하자는 것이 아니라 고위험 환자를 사전에 식별하고 이차 백혈병이 발생하였을 때 아형에 맞춘 치료를 준비하자는 것이다.

참고문헌
Horns JM, Beder T, Künstner A, et al. IDH2 clonal hematopoiesis and IKAROS loss cooperate in a B-ALL subtype after lenalidomide therapy for multiple myeloma. Blood 2026;148(7):856-866.
doi:10.1182/blood.2025031047 · 대표소속: University Medical Center Schleswig-Holstein, Campus Kiel, Germany

관련 글 · 레날리도마이드, TP53 돌연변이 양성 골수성 종양 발생 위험 증가 — Blood 2022

+ Recent posts