Multi-agent

다중 에이전트 라우팅

Status: active

여러 개의 격리된 에이전트를 실행합니다. 각 에이전트는 자체 워크스페이스, 상태 디렉터리(agentDir), 세션 기록을 가지며, 하나의 실행 중인 Gateway 안에서 여러 채널 계정(예: 두 개의 WhatsApp)을 함께 사용할 수 있습니다. 인바운드 메시지는 바인딩을 통해 올바른 에이전트로 라우팅됩니다.

여기서 에이전트는 워크스페이스 파일, 인증 프로필, 모델 레지스트리, 세션 저장소를 포함하는 전체 페르소나별 범위입니다. agentDir는 이 에이전트별 구성을 ~/.openclaw/agents/<agentId>/에 보관하는 온디스크 상태 디렉터리입니다. 바인딩은 채널 계정(예: Slack 워크스페이스 또는 WhatsApp 번호)을 이러한 에이전트 중 하나에 매핑합니다.

"하나의 에이전트"란 무엇인가요?

에이전트는 자체적으로 완전히 범위가 지정된 두뇌이며, 다음을 가집니다.

  • 워크스페이스(파일, AGENTS.md/SOUL.md/USER.md, 로컬 노트, 페르소나 규칙).
  • 인증 프로필, 모델 레지스트리, 에이전트별 구성을 위한 상태 디렉터리(agentDir).
  • ~/.openclaw/agents/<agentId>/sessions 아래의 세션 저장소(채팅 기록 + 라우팅 상태).

인증 프로필은 에이전트별입니다. 각 에이전트는 자체 위치에서 읽습니다.

text
~/.openclaw/agents/<agentId>/agent/auth-profiles.json

Skills는 각 에이전트 워크스페이스와 ~/.openclaw/skills 같은 공유 루트에서 로드된 다음, 구성된 경우 유효한 에이전트 Skills 허용 목록으로 필터링됩니다. 공유 기준에는 agents.defaults.skills를 사용하고, 에이전트별 대체에는 agents.list[].skills를 사용하세요. Skills: 에이전트별 vs 공유Skills: 에이전트 Skills 허용 목록을 참고하세요.

Gateway는 하나의 에이전트(기본값) 또는 여러 에이전트를 나란히 호스팅할 수 있습니다.

경로(빠른 맵)

  • 구성: ~/.openclaw/openclaw.json(또는 OPENCLAW_CONFIG_PATH)
  • 상태 디렉터리: ~/.openclaw(또는 OPENCLAW_STATE_DIR)
  • 워크스페이스: ~/.openclaw/workspace(또는 ~/.openclaw/workspace-<agentId>)
  • 에이전트 디렉터리: ~/.openclaw/agents/<agentId>/agent(또는 agents.list[].agentDir)
  • 세션: ~/.openclaw/agents/<agentId>/sessions

단일 에이전트 모드(기본값)

아무 작업도 하지 않으면 OpenClaw는 단일 에이전트를 실행합니다.

  • agentId의 기본값은 **main**입니다.
  • 세션은 agent:main:<mainKey>로 키가 지정됩니다.
  • 워크스페이스 기본값은 ~/.openclaw/workspace입니다(OPENCLAW_PROFILE이 설정된 경우 ~/.openclaw/workspace-<profile>).
  • 상태 기본값은 ~/.openclaw/agents/main/agent입니다.

에이전트 도우미

새로운 격리된 에이전트를 추가하려면 에이전트 마법사를 사용하세요.

bash
openclaw agents add work

그런 다음 인바운드 메시지를 라우팅하도록 bindings를 추가합니다(또는 마법사에 맡깁니다).

다음으로 확인하세요.

bash
openclaw agents list --bindings

빠른 시작

  • 각 에이전트 워크스페이스 만들기

    마법사를 사용하거나 워크스페이스를 수동으로 만듭니다.

    bash
    openclaw agents add codingopenclaw agents add social

    각 에이전트는 SOUL.md, AGENTS.md, 선택적 USER.md가 포함된 자체 워크스페이스와 전용 agentDir, 그리고 ~/.openclaw/agents/<agentId> 아래의 세션 저장소를 가집니다.

  • 채널 계정 만들기

    선호하는 채널에서 에이전트마다 하나의 계정을 만듭니다.

    • Discord: 에이전트마다 봇 하나를 만들고 Message Content Intent를 활성화한 뒤 각 토큰을 복사합니다.
    • Telegram: BotFather를 통해 에이전트마다 봇 하나를 만들고 각 토큰을 복사합니다.
    • WhatsApp: 계정마다 각 전화번호를 연결합니다.
    bash
    openclaw channels login --channel whatsapp --account work

    채널 가이드를 참고하세요. Discord, Telegram, WhatsApp.

  • 에이전트, 계정, 바인딩 추가하기

    agents.list 아래에 에이전트를 추가하고, channels.<channel>.accounts 아래에 채널 계정을 추가한 뒤, bindings로 연결합니다(아래 예시 참고).

  • 다시 시작하고 확인하기

    bash
    openclaw gateway restartopenclaw agents list --bindingsopenclaw channels status --probe
  • 여러 에이전트 = 여러 사람, 여러 성격

    여러 에이전트를 사용하면 각 agentId완전히 격리된 페르소나가 됩니다.

    • 서로 다른 전화번호/계정(채널별 accountId).
    • 서로 다른 성격(AGENTS.md, SOUL.md 같은 에이전트별 워크스페이스 파일).
    • 분리된 인증 + 세션(명시적으로 활성화하지 않는 한 교차 대화 없음).

    이를 통해 여러 사람이 하나의 Gateway 서버를 공유하면서도 각자의 AI "두뇌"와 데이터를 격리할 수 있습니다.

    에이전트 간 QMD 메모리 검색

    한 에이전트가 다른 에이전트의 QMD 세션 transcript를 검색해야 한다면 agents.list[].memorySearch.qmd.extraCollections 아래에 추가 컬렉션을 추가하세요. 모든 에이전트가 같은 공유 transcript 컬렉션을 상속해야 할 때만 agents.defaults.memorySearch.qmd.extraCollections를 사용하세요.

    json5
    {  agents: {    defaults: {      workspace: "~/workspaces/main",      memorySearch: {        qmd: {          extraCollections: [{ path: "~/agents/family/sessions", name: "family-sessions" }],        },      },    },    list: [      {        id: "main",        workspace: "~/workspaces/main",        memorySearch: {          qmd: {            extraCollections: [{ path: "notes" }], // resolves inside workspace -> collection named "notes-main"          },        },      },      { id: "family", workspace: "~/workspaces/family" },    ],  },  memory: {    backend: "qmd",    qmd: { includeDefaultMemory: false },  },}

    추가 컬렉션 경로는 에이전트 간에 공유될 수 있지만, 경로가 에이전트 워크스페이스 밖에 있으면 컬렉션 이름은 명시적으로 유지됩니다. 워크스페이스 안의 경로는 에이전트 범위로 유지되므로 각 에이전트가 자체 transcript 검색 세트를 유지합니다.

    하나의 WhatsApp 번호, 여러 사람(DM 분할)

    하나의 WhatsApp 계정을 유지하면서 서로 다른 WhatsApp DM을 서로 다른 에이전트로 라우팅할 수 있습니다. peer.kind: "direct"와 함께 발신자 E.164(예: +15551234567)로 매칭합니다. 답장은 여전히 같은 WhatsApp 번호에서 전송됩니다(에이전트별 발신자 ID 없음).

    예시:

    json5
    {  agents: {    list: [      { id: "alex", workspace: "~/.openclaw/workspace-alex" },      { id: "mia", workspace: "~/.openclaw/workspace-mia" },    ],  },  bindings: [    {      agentId: "alex",      match: { channel: "whatsapp", peer: { kind: "direct", id: "+15551230001" } },    },    {      agentId: "mia",      match: { channel: "whatsapp", peer: { kind: "direct", id: "+15551230002" } },    },  ],  channels: {    whatsapp: {      dmPolicy: "allowlist",      allowFrom: ["+15551230001", "+15551230002"],    },  },}

    참고:

    • DM 접근 제어는 에이전트별이 아니라 WhatsApp 계정별 전역(페어링/허용 목록)입니다.
    • 공유 그룹의 경우 그룹을 하나의 에이전트에 바인딩하거나 브로드캐스트 그룹을 사용하세요.

    라우팅 규칙(메시지가 에이전트를 선택하는 방식)

    바인딩은 결정적이며 가장 구체적인 항목이 우선합니다.

  • peer 매칭

    정확한 DM/그룹/채널 ID.

  • parentPeer 매칭

    스레드 상속.

  • guildId + roles

    Discord 역할 라우팅.

  • guildId

    Discord.

  • teamId

    Slack.

  • 채널에 대한 accountId 매칭

    계정별 폴백.

  • 채널 수준 매칭

    accountId: "*".

  • 기본 에이전트

    agents.list[].default로 폴백하고, 없으면 첫 번째 목록 항목으로 폴백합니다. 기본값: main.

  • 동률 처리와 AND 의미론
    • 같은 계층에서 여러 바인딩이 매칭되면 구성 순서상 첫 번째 항목이 우선합니다.
    • 바인딩이 여러 매칭 필드(예: peer + guildId)를 설정하면 지정된 모든 필드가 필요합니다(AND 의미론).
    계정 범위 세부 정보
    • accountId를 생략한 바인딩은 기본 계정에만 매칭됩니다. 모든 계정에 매칭되지 않습니다.
    • 모든 계정에 걸친 채널 전체 폴백에는 accountId: "*"를 사용하세요.
    • 하나의 계정을 매칭하려면 accountId: "<name>"을 사용하세요.
    • 나중에 같은 에이전트에 같은 바인딩을 명시적 계정 ID와 함께 추가하면, OpenClaw는 기존 채널 전용 바인딩을 중복하지 않고 계정 범위 바인딩으로 업그레이드합니다.

    여러 계정 / 전화번호

    여러 계정을 지원하는 채널(예: WhatsApp)은 각 로그인을 식별하기 위해 accountId를 사용합니다. 각 accountId를 다른 에이전트로 라우팅할 수 있으므로, 하나의 서버가 세션을 섞지 않고 여러 전화번호를 호스팅할 수 있습니다.

    accountId가 생략되었을 때 채널 전체 기본 계정을 원하면 channels.<channel>.defaultAccount를 설정하세요(선택 사항). 설정하지 않으면 OpenClaw는 default가 있으면 그것으로 폴백하고, 없으면 구성된 첫 번째 계정 ID(정렬 기준)로 폴백합니다.

    이 패턴을 지원하는 일반적인 채널은 다음과 같습니다.

    • whatsapp, telegram, discord, slack, signal, imessage
    • irc, line, googlechat, mattermost, matrix, nextcloud-talk
    • zalo, zalouser, nostr, feishu

    개념

    • agentId: 하나의 "두뇌"(워크스페이스, 에이전트별 인증, 에이전트별 세션 저장소).
    • accountId: 하나의 채널 계정 인스턴스(예: WhatsApp 계정 "personal""biz").
    • binding: (channel, accountId, peer) 및 선택적으로 길드/팀 ID를 기준으로 인바운드 메시지를 agentId로 라우팅합니다.
    • 직접 채팅은 agent:<agentId>:<mainKey>로 접힙니다(에이전트별 "main"; session.mainKey).

    플랫폼 예시

    에이전트별 Discord 봇

    각 Discord 봇 계정은 고유한 accountId에 매핑됩니다. 각 계정을 에이전트에 바인딩하고 봇별 허용 목록을 유지하세요.

    json5
    {  agents: {    list: [      { id: "main", workspace: "~/.openclaw/workspace-main" },      { id: "coding", workspace: "~/.openclaw/workspace-coding" },    ],  },  bindings: [    { agentId: "main", match: { channel: "discord", accountId: "default" } },    { agentId: "coding", match: { channel: "discord", accountId: "coding" } },  ],  channels: {    discord: {      groupPolicy: "allowlist",      accounts: {        default: {          token: "DISCORD_BOT_TOKEN_MAIN",          guilds: {            "123456789012345678": {              channels: {                "222222222222222222": { allow: true, requireMention: false },              },            },          },        },        coding: {          token: "DISCORD_BOT_TOKEN_CODING",          guilds: {            "123456789012345678": {              channels: {                "333333333333333333": { allow: true, requireMention: false },              },            },          },        },      },    },  },}
    • 각 bot을 guild에 초대하고 Message Content Intent를 활성화합니다.
    • 토큰은 channels.discord.accounts.<id>.token에 있습니다(기본 계정은 DISCORD_BOT_TOKEN을 사용할 수 있음).
    에이전트별 Telegram bot
    json5
    {  agents: {    list: [      { id: "main", workspace: "~/.openclaw/workspace-main" },      { id: "alerts", workspace: "~/.openclaw/workspace-alerts" },    ],  },  bindings: [    { agentId: "main", match: { channel: "telegram", accountId: "default" } },    { agentId: "alerts", match: { channel: "telegram", accountId: "alerts" } },  ],  channels: {    telegram: {      accounts: {        default: {          botToken: "123456:ABC...",          dmPolicy: "pairing",        },        alerts: {          botToken: "987654:XYZ...",          dmPolicy: "allowlist",          allowFrom: ["tg:123456789"],        },      },    },  },}
    • BotFather로 에이전트마다 하나의 bot을 만들고 각 토큰을 복사합니다.
    • 토큰은 channels.telegram.accounts.<id>.botToken에 있습니다(기본 계정은 TELEGRAM_BOT_TOKEN을 사용할 수 있음).
    • 같은 Telegram 그룹에 여러 bot이 있는 경우 각 bot을 초대하고 응답해야 하는 bot을 멘션합니다.
    • 각 그룹 bot에 대해 BotFather Privacy Mode를 비활성화한 다음, Telegram이 설정을 적용하도록 bot을 다시 추가합니다.
    • channels.telegram.groups로 그룹을 허용하거나, 신뢰할 수 있는 그룹 배포에만 groupPolicy: "open"을 사용합니다.
    • 발신자 사용자 ID는 groupAllowFrom에 넣습니다. 그룹 및 슈퍼그룹 ID는 groupAllowFrom이 아니라 channels.telegram.groups에 속합니다.
    • 각 bot이 자체 에이전트로 라우팅되도록 accountId로 바인딩합니다.
    에이전트별 WhatsApp 번호

    Gateway를 시작하기 전에 각 계정을 연결합니다.

    bash
    openclaw channels login --channel whatsapp --account personalopenclaw channels login --channel whatsapp --account biz

    ~/.openclaw/openclaw.json (JSON5):

    js
    {  agents: {    list: [      {        id: "home",        default: true,        name: "Home",        workspace: "~/.openclaw/workspace-home",        agentDir: "~/.openclaw/agents/home/agent",      },      {        id: "work",        name: "Work",        workspace: "~/.openclaw/workspace-work",        agentDir: "~/.openclaw/agents/work/agent",      },    ],  },   // Deterministic routing: first match wins (most-specific first).  bindings: [    { agentId: "home", match: { channel: "whatsapp", accountId: "personal" } },    { agentId: "work", match: { channel: "whatsapp", accountId: "biz" } },     // Optional per-peer override (example: send a specific group to work agent).    {      agentId: "work",      match: {        channel: "whatsapp",        accountId: "personal",        peer: { kind: "group", id: "1203630...@g.us" },      },    },  ],   // Off by default: agent-to-agent messaging must be explicitly enabled + allowlisted.  tools: {    agentToAgent: {      enabled: false,      allow: ["home", "work"],    },  },   channels: {    whatsapp: {      accounts: {        personal: {          // Optional override. Default: ~/.openclaw/credentials/whatsapp/personal          // authDir: "~/.openclaw/credentials/whatsapp/personal",        },        biz: {          // Optional override. Default: ~/.openclaw/credentials/whatsapp/biz          // authDir: "~/.openclaw/credentials/whatsapp/biz",        },      },    },  },}

    일반적인 패턴

    WhatsApp 일상 작업 + Telegram 심층 작업

    채널별로 분리합니다. WhatsApp은 빠른 일상용 에이전트로, Telegram은 Opus 에이전트로 라우팅합니다.

    json5
    {  agents: {    list: [      {        id: "chat",        name: "Everyday",        workspace: "~/.openclaw/workspace-chat",        model: "anthropic/claude-sonnet-4-6",      },      {        id: "opus",        name: "Deep Work",        workspace: "~/.openclaw/workspace-opus",        model: "anthropic/claude-opus-4-6",      },    ],  },  bindings: [    { agentId: "chat", match: { channel: "whatsapp", accountId: "*" } },    { agentId: "opus", match: { channel: "telegram", accountId: "*" } },  ],}

    참고:

    • 이 예제는 accountId: "*"를 사용하므로 나중에 계정을 추가해도 바인딩이 계속 작동합니다.
    • 나머지는 chat에 유지하면서 단일 DM/그룹만 Opus로 라우팅하려면 해당 피어에 대한 match.peer 바인딩을 추가합니다. 피어 매치는 항상 채널 전체 규칙보다 우선합니다.

    같은 채널에서 한 피어만 Opus로

    WhatsApp은 빠른 에이전트에 유지하되, DM 하나만 Opus로 라우팅합니다.

    json5
    {  agents: {    list: [      {        id: "chat",        name: "Everyday",        workspace: "~/.openclaw/workspace-chat",        model: "anthropic/claude-sonnet-4-6",      },      {        id: "opus",        name: "Deep Work",        workspace: "~/.openclaw/workspace-opus",        model: "anthropic/claude-opus-4-6",      },    ],  },  bindings: [    {      agentId: "opus",      match: { channel: "whatsapp", accountId: "*", peer: { kind: "direct", id: "+15551234567" } },    },    { agentId: "chat", match: { channel: "whatsapp", accountId: "*" } },  ],}

    피어 바인딩은 항상 우선하므로 채널 전체 규칙보다 위에 둡니다.

    WhatsApp 그룹에 바인딩된 가족 에이전트

    전용 가족 에이전트를 단일 WhatsApp 그룹에 바인딩하고, 멘션 게이팅과 더 엄격한 도구 정책을 적용합니다.

    json5
    {  agents: {    list: [      {        id: "family",        name: "Family",        workspace: "~/.openclaw/workspace-family",        identity: { name: "Family Bot" },        groupChat: {          mentionPatterns: ["@family", "@familybot", "@Family Bot"],        },        sandbox: {          mode: "all",          scope: "agent",        },        tools: {          allow: [            "exec",            "read",            "sessions_list",            "sessions_history",            "sessions_send",            "sessions_spawn",            "session_status",          ],          deny: ["write", "edit", "apply_patch", "browser", "canvas", "nodes", "cron"],        },      },    ],  },  bindings: [    {      agentId: "family",      match: {        channel: "whatsapp",        peer: { kind: "group", id: "120363999999999999@g.us" },      },    },  ],}

    참고:

    • 도구 허용/거부 목록은 도구이며 Skills가 아닙니다. Skill이 바이너리를 실행해야 한다면 exec가 허용되어 있고 해당 바이너리가 sandbox에 존재하는지 확인합니다.
    • 더 엄격한 게이팅을 위해 agents.list[].groupChat.mentionPatterns를 설정하고 채널에 대해 그룹 허용 목록을 계속 활성화해 둡니다.

    에이전트별 sandbox 및 도구 구성

    각 에이전트는 자체 sandbox와 도구 제한을 가질 수 있습니다.

    js
    {  agents: {    list: [      {        id: "personal",        workspace: "~/.openclaw/workspace-personal",        sandbox: {          mode: "off",  // No sandbox for personal agent        },        // No tool restrictions - all tools available      },      {        id: "family",        workspace: "~/.openclaw/workspace-family",        sandbox: {          mode: "all",     // Always sandboxed          scope: "agent",  // One container per agent          docker: {            // Optional one-time setup after container creation            setupCommand: "apt-get update && apt-get install -y git curl",          },        },        tools: {          allow: ["read"],                    // Only read tool          deny: ["exec", "write", "edit", "apply_patch"],    // Deny others        },      },    ],  },}

    장점:

    • 보안 격리: 신뢰할 수 없는 에이전트의 도구를 제한합니다.
    • 리소스 제어: 특정 에이전트는 sandbox에 두고 다른 에이전트는 호스트에 유지합니다.
    • 유연한 정책: 에이전트별로 다른 권한을 적용합니다.

    자세한 예제는 다중 에이전트 sandbox 및 도구를 참고하세요.

    관련 항목

    Was this useful?
    On this page

    On this page