공유 메모리와 블랙보드 패턴(Shared Memory and Blackboard Patterns)

2026년의 멀티 에이전트 시스템에는 두 가지 접근이 공존합니다. 하나는 메시지 풀(message pool) 입니다. AutoGen GroupChat이나 MetaGPT처럼 모든 에이전트(agent)가 다른 모든 에이전트의 메시지를 봅니다. 다른 하나는 구독 기반 블랙보드(blackboard with subscription) 입니다. Context-Aware MCP나 Matrix framework처럼 에이전트가 관련 이벤트(event)를 구독합니다. 두 구조 모두 멀티 에이전트 시스템에서 상태(state)를 가진 유일한 부분이며, 그래서 흥미로운 버그가 살아 있는 곳이기도 합니다. 가장 대표적인 실패 모드는 메모리 오염(memory poisoning) 입니다. 한 에이전트가 환각(hallucination)으로 만들어낸 "사실"을 다른 에이전트들이 검증된 정보처럼 받아들이고, 즉시 충돌(crash)하지 않기 때문에 디버깅하기 훨씬 어려운 방식으로 정확도가 서서히 무너집니다. 이 강의는 표준 라이브러리(stdlib)만으로 두 구조를 모두 만들고, 오염 공격(poisoning attack)을 주입한 뒤, 실제 운영 환경에서 작동하는 세 가지 완화책을 보여줍니다.

유형: Learn + Build 언어: Python (stdlib, threading) 선수 지식: Phase 16 · 04 (멀티 에이전트 기본 모델), Phase 16 · 09 (병렬 Swarm과 네트워크형 아키텍처) 예상 시간: 약 75분

문제

멀티 에이전트 시스템에는 에이전트들이 사실(facts)을 공유할 장소가 필요합니다. 가장 단순한 선택지는 "모든 것을 메시지로 넘기는 것"입니다. 하지만 이것은 불필요한 복사를 추가하면서 공유 상태(shared state)를 다시 만드는 것과 같습니다. 또 다른 선택지는 "모두에게 전역 로그(global log)를 주는 것"입니다. 그러나 전역 로그는 한없이 커지고 쉽게 오염됩니다. 세 번째 선택지는 "에이전트마다 별도의 뷰(view)를 사영(projection)해서 제공하는 것"입니다. 확장성은 좋지만 스키마(schema) 부담이 큽니다.

여러 에이전트 중 하나가 환각을 일으켜 그 환각을 공유 상태에 기록하면, 그 상태를 읽는 모든 하류(downstream) 에이전트는 환각을 사실로 받아들입니다. 사람이 알아차릴 때쯤이면 추론 사슬(reasoning chain)은 이미 다섯 단계 정도 깊어져 있고, 근본 원인(root cause)은 가장 처음 세 번째로 작성된 메시지일 수 있습니다. 멀티 에이전트의 정확도 저하를 디버깅하는 일은 단순한 충돌을 디버깅하는 것보다 훨씬 어렵습니다.

이것이 메모리 오염입니다. MAST 분류 체계(MAST taxonomy; Cemri et al., arXiv:2503.13657)에서 두 번째로 많이 문서화된 실패 군(failure family)이며, 구조적인 문제입니다. 출처 정보(provenance)와 쓰기 불가능한 검증자(unwritable verifier)가 없는 공유 메모리 설계는 언젠가 반드시 이 문제를 드러냅니다.

사전 테스트

2문제 · 이 강의를 시작하기 전에 얼마나 알고 있는지 확인해보세요

1.멀티 에이전트 시스템에서 공유 상태(shared state)의 두 가지 주요 토폴로지는 무엇인가요?

2.멀티 에이전트 시스템에서 '메모리 오염(memory poisoning)'이란 무엇인가요?

0/2 답변 완료

개념

두 가지 주요 토폴로지(topology)

전체 메시지 풀(Full message pool). 모든 에이전트가 모든 메시지를 읽습니다. AutoGen GroupChat과 MetaGPT가 이 방식을 사용합니다. 단순하고 투명하며 검사하기(inspectable) 쉽지만, 에이전트가 약 10개를 넘어가면 각 에이전트의 컨텍스트(context)가 다른 에이전트들의 작업으로 가득 차기 때문에 잘 확장되지 않습니다.

agent-A ──write──▶ ┌────────────────┐ ◀──read── agent-D
                   │ message pool   │
agent-B ──write──▶ │                │ ◀──read── agent-E
                   │ (global log)   │
agent-C ──write──▶ └────────────────┘ ◀──read── agent-F

구독 기반 블랙보드(Blackboard with subscription). 에이전트가 관심 있는 토픽(topic)을 선언하면, 기반 구조(substrate)가 관련 메시지만 전달합니다. CA-MCP(arXiv:2601.11595)와 Matrix 탈중앙화 프레임워크(decentralized framework; arXiv:2511.21686)가 이 방식을 사용합니다. 더 큰 규모로 확장되지만, 구독이 의미를 가지려면 사전 스키마 설계가 필요합니다.

                   ┌─ topic: prices ──┐
agent-A ──pub────▶ │                  │ ──▶ agent-D (subscribed)
                   ├─ topic: orders ──┤
agent-B ──pub────▶ │                  │ ──▶ agent-E (subscribed)
                   ├─ topic: alerts ──┤
agent-C ──pub────▶ │                  │ ──▶ agent-F (subscribed)
                   └──────────────────┘

각 방식이 유리한 경우

  • 전체 풀(Full pool) 은 에이전트 수가 적고(10개 미만), 에이전트들이 서로 이질적이며, 대화(conversation)가 짧은 시야(short-horizon)일 때 좋습니다. 모두가 모든 것을 보기 때문에 누가 무엇을 말했는지 추적하기 쉽습니다.
  • 블랙보드(Blackboard) 는 에이전트 수가 많고, 역할(role)은 비슷하지만 인스턴스(instance)는 많은 스웜(swarm) 구조이며, 대화가 오래 지속(long-running)되는 상황에서 좋습니다. 라우팅(routing)이 토큰 비용(token cost)과 컨텍스트 오염(context pollution)을 줄여 줍니다.

운영 시스템은 둘을 섞어 쓰는 경우가 많습니다. 상단에는 작은 전체 풀(계획 계층, planning layer)을, 그 아래에는 블랙보드(작업 계층, worker layer)를 두는 식입니다.

메모리 오염, 한 시나리오로 보기

세 에이전트가 연구 작업(research task)을 수행한다고 가정해 봅시다. 에이전트 A는 검색 에이전트(retrieval agent), 에이전트 B는 요약 에이전트(summarizer), 에이전트 C는 분석 에이전트(analyst)입니다.

  1. A가 페이지를 가져와 공유 상태에 메시지를 씁니다. "The study reports a 42% accuracy improvement."
  2. 실제 페이지에는 "4.2% improvement"라고 적혀 있었습니다. A가 소수점(decimal)을 환각으로 만들어 냈습니다.
  3. B가 공유 상태를 읽고 씁니다. "Large 42% accuracy gain reported (source: A)."
  4. C가 공유 상태를 읽고 씁니다. "Recommend adoption — 42% lift is transformative."
  5. 최종 보고서는 실제로 존재하지 않았던 42% 수치를 인용합니다.

어떤 에이전트도 충돌하지 않았습니다. 어떤 테스트도 실패하지 않았습니다. 시스템은 표면적으로는 "동작"했습니다. 환각은 공유 상태를 통해 한 에이전트의 컨텍스트에서 모든 하류 에이전트의 추론으로 옮겨 갔습니다.

왜 이것이 구조적인 문제인가

공유 상태가 없다면 에이전트 A의 환각은 A의 컨텍스트 안에만 머무릅니다. 하류 에이전트는 다시 가져오거나(fetch) 다시 유도(re-derive)하면서 오류를 잡아낼 수도 있습니다. 그러나 단순한(naive) 공유 상태에서는 A의 컨텍스트가 곧 모두의 컨텍스트가 되고, 환각은 사실처럼 세탁(launder)됩니다.

문제는 공유 상태 자체가 아닙니다. 문제는 출처 정보(provenance)가 없고 독립적인 검증자(verifier)도 없는 공유 상태 입니다. 세 가지 완화책이 이 문제를 다룹니다.

  1. 모든 쓰기에 출처 정보를 붙입니다. 공유 상태의 모든 항목(entry)에 누가 썼는지, 언제 썼는지, 어떤 프롬프트(prompt) 아래에서 썼는지, 그리고 해당된다면 어떤 출처(source)를 인용했는지를 기록합니다. 하류 에이전트는 출처 정보에 맞추어 회의적인 태도로 읽습니다.
  2. 쓰기에 버전(version)을 부여하고 추가 전용(append-only) 으로 다룹니다. 정정(correction)은 기존 항목을 그 자리에서 덮어쓰는(in-place update) 것이 아니라, 이전 항목을 대체(supersede)하는 새 항목으로 추가합니다. 감사 기록(audit trail)이 보존됩니다.
  3. 공유 상태에 쓸 수 없는 에이전트를 최소 한 명 둡니다. 읽기 전용(read-only) 검증자 에이전트는 항목을 표본 추출(sample)하고 출처를 다시 가져와 불일치(inconsistency)를 표시(flag)합니다. 검증자는 풀(pool)에 쓸 수 없기 때문에, 풀에 의해 오염될 수도 없습니다.

블랙보드의 전례(Hayes-Roth, 1985)

블랙보드 패턴은 LLM 에이전트보다 40년 앞서 등장했습니다. Hayes-Roth(1985, "A Blackboard Architecture for Control")는 전역 블랙보드를 관찰하고, 부분 해법(partial solutions)을 기여하며, 다른 출처를 촉발(trigger)하는 전문가 지식 출처(specialist Knowledge Sources)들을 설명했습니다. 2026년의 블랙보드(CA-MCP, Matrix)는 같은 패턴입니다. 다만 지식 출처(Knowledge Source)가 LLM 에이전트이고, 부분 해법이 JSON 덩어리(blob)일 뿐입니다. 오래된 문헌에는 쓰기 경합(write contention), 기회주의적 제어(opportunistic control), 일관성(consistency)에 대한 해결책이 이미 문서화되어 있고, 현대 시스템은 이를 다시 발견하고 있습니다.

사영(Projection)과 전체 뷰

순수한 블랙보드는 모든 구독자(subscriber)에게 동일한 사영(토픽 단위, topic-scoped)을 줍니다. 더 공격적인 설계는 에이전트별 사영(per-agent projection) 입니다. 각 에이전트가 자기 역할에 맞춘 뷰를 받습니다. LangGraph의 상태 리듀서(state reducer)가 2026년 기준 정석(canonical) 구현입니다. 리듀서 함수(reducer function)는 전역 상태(global state)를 역할별 슬라이스(role-specific slice)로 접어 넣습니다.

에이전트별 사영은 더 큰 규모로 확장되지만 스키마가 필요합니다. 스키마가 없으면 모든 에이전트 프롬프트 안에서 임시 사영(ad-hoc projection)을 매번 다시 만들게 됩니다.

쓰기 경합(Write-contention) 패턴

여러 에이전트가 동시에 쓰는 것은 LLM 문제이기 전에 동시성(concurrency) 문제입니다. 세 가지 패턴이 작동합니다.

  • 순차 쓰기자(Sequential writer; single producer). 모든 쓰기가 하나의 코디네이터 에이전트(coordinator agent)를 거쳐 직렬화됩니다. 단순하지만 병목(bottleneck)이 됩니다.
  • 버전 관리를 동반한 낙관적 동시성(Optimistic concurrency with versioning). 각 항목에 버전이 있고, 쓰기자는 버전 불일치(version mismatch) 시 실패한 뒤 재시도(retry)합니다. 데이터베이스에서 오래 쓰인 고전적 기법입니다.
  • 토픽 분할(Topic partitioning). 서로 다른 에이전트가 서로 다른 토픽을 소유합니다. 토픽 간 경합(cross-topic contention)이 없습니다. 대신 분할 경계(partition boundary)를 사람이 설계해야 합니다.

대부분의 2026년 프레임워크는 순차 쓰기자를 기본으로 둡니다. LLM 호출(call)이 충분히 느려서 경합이 드물게 발생하고, 병목이 크게 문제 되지 않기 때문입니다.

쓰기 불가능한 검증자(unwritable verifier)

가장 핵심적인 완화책은 읽기 전용 검증자입니다. 구현 규칙은 다음과 같습니다.

  • 검증자는 팀과 상태를 공유합니다. 즉, 블랙보드나 풀을 읽습니다.
  • 검증자는 공유 상태에 대한 쓰기 핸들(write handle)이 없습니다. 별도의 검증 채널(verification channel)에만 쓸 수 있습니다.
  • 검증자는 쓰기에 인용된 출처를 독립적으로 다시 가져오고, 불일치가 있을 때 표시합니다.
  • 검증자의 출력(output)은 사람이나 별도의 결정 에이전트(decision agent)로 전달되며, 풀로 다시 들어가지 않습니다.

이 분리(separation)가 없으면 검증자의 출력 역시 풀의 새 항목이 됩니다. 그러면 오염된 풀이 검증자를 오염시키고, 검증자가 다시 자기 자신의 검증 결과를 오염시키게 됩니다.

직접 만들기

code/main.py는 표준 라이브러리 Python만으로 두 토폴로지, 장난감 수준의 오염 공격(toy poisoning attack), 그리고 세 가지 완화책을 구현합니다.

  • MessagePool — 스레드 안전한(thread-safe) 추가 전용 로그이며, 전체 읽기(read-out)를 제공합니다.
  • Blackboard — 토픽 키 기반(topic-keyed) 발행/구독(pub/sub) 구조이며, 에이전트별 구독을 가집니다.
  • ProvenanceEntry — 모든 쓰기에 (writer, timestamp, prompt_hash, source_uri) 를 기록합니다.
  • PoisoningScenario — 에이전트 A가 소수점을 환각으로 만들어내는 세 에이전트 연구 작업을 실행하고 최종 보고서(final report)를 출력합니다.
  • Verifier — 출처를 다시 가져와 불일치를 표시하는 읽기 전용 에이전트입니다. 검증자가 있는 동일한 시나리오를 실행합니다.

실행 방법은 다음과 같습니다.

python3 code/main.py

예상 출력:

  • 실행 1 (검증자 없음): 환각으로 만들어진 42%가 최종 보고서까지 전파됩니다.
  • 실행 2 (검증자 포함): 검증자가 불일치를 표시하고, 풀에 "flagged" 표시가 붙으며, 최종 보고서에는 정정(retraction)이 포함됩니다.

사용해보기

outputs/skill-memory-auditor.md 는 멀티 에이전트 시스템의 공유 메모리 설계를 출처 정보, 버전 관리, 검증자 분리(verifier separation) 관점에서 감사(audit)하는 스킬(skill)입니다. 새로운 멀티 에이전트 아키텍처(architecture)를 운영에 올리기 전에 실행하세요.

배포 전 확인

공유 메모리 설계에서는 다음을 확인합니다.

  • 모든 쓰기에 출처 정보를 기록합니다. (writer, timestamp, prompt_hash, tool_calls_cited, source_uri).
  • 로그를 추가 전용으로 만듭니다. 정정은 대체된(superseded) 항목을 참조하는 새 항목입니다.
  • 독립적인 출처 접근을 가진 읽기 전용 검증자 에이전트를 최소 하나 배포합니다.
  • 검증자 출력은 공유 풀이 아니라 별도 채널로 전달합니다.
  • 대체(supersession) 쓰기의 비율을 로그에 남깁니다. 이 비율이 올라가는 것은 환각 패턴의 조기 증거(early evidence)일 수 있습니다.

연습문제

  1. (쉬움) code/main.py를 실행합니다. 실행 1에서는 환각이 전파되고, 실행 2에서는 검증자가 이를 잡아내는지 확인합니다.
  2. (중간) 두 번째 환각을 추가합니다. 에이전트 B가 데이터셋 크기(dataset size)를 지어내게 합니다. 검증자는 어느 한쪽에 맞추어 손으로 조율(hand-tuned)되지 않더라도 둘 다 잡아내야 합니다.
  3. (중간) 전체 풀을 토픽 분할(prices, summaries, analyses)이 있는 블랙보드로 바꿉니다. 토픽 분할이 어떤 오염 시나리오를 더 어렵게 만들고, 어떤 경우에는 도움이 되지 않는지 분석합니다.
  4. (어려움) Hayes-Roth(1985, "A Blackboard Architecture for Control")를 읽습니다. 이 강의에서 다루지 않았지만 2026년 시스템이 이득을 볼 수 있는 제어 패턴(control pattern) 두 가지를 찾아내세요.
  5. (어려움) CA-MCP(arXiv:2601.11595)를 읽습니다. CA-MCP의 공유 컨텍스트 저장소(Shared Context Store)를 code/main.pyMessagePool 또는 Blackboard 클래스 중 하나에 매핑(mapping)합니다. CA-MCP는 그 위에 어떤 원시 요소(primitive)들을 추가합니까?

핵심 용어

용어흔한 설명실제 의미
메시지 풀(Message pool)"공유 채팅 기록"모든 에이전트가 읽는 추가 전용 로그다. 투명성은 높지만 확장성이 낮다.
블랙보드(Blackboard)"공유 작업 공간"토픽 키 기반 발행/구독 구조다. 에이전트는 관련 토픽을 구독한다. 더 큰 규모로 확장된다.
출처 정보(Provenance)"누가 무엇을 썼는가"각 쓰기에 붙는 메타데이터(metadata)다. 작성자(writer), 시각(timestamp), 프롬프트, 출처를 포함한다.
메모리 오염(Memory poisoning)"환각이 퍼지는 것"한 에이전트의 오류가 공유 상태로 들어가 하류 에이전트가 이를 사실로 채택하는 현상이다.
추가 전용(Append-only)"그 자리 갱신 없음"정정은 이전 항목을 대체하는 새 항목이다. 감사 기록을 보존한다.
쓰기 불가능한 검증자(Unwritable verifier)"독립 감사자"출처를 다시 가져와 불일치를 표시하는 읽기 전용 에이전트다.
사영(Projection)"범위가 한정된 뷰"전역 상태에서 계산되는 에이전트별 뷰다. LangGraph의 리듀서가 정석 사례다.
지식 출처(Knowledge Source)"전문가 에이전트"Hayes-Roth가 1985년에 블랙보드 참여자를 부른 용어다.

더 읽을거리

실습 코드

이 강의의 실습 코드 1개

main
Code

산출물

이 강의에서 생성된 프롬프트, 스킬, 코드 산출물 1개

memory-auditor

Audit a multi-agent system's shared-memory design for provenance, versioning, verifier separation, and projection schema. Flag memory-poisoning exposure before production.

Skill

확인 문제

3문제 · 모두 맞추면 완료 표시가 가능합니다

1.공유 메모리를 감사(audit)하는 검증자(verifier) 에이전트가 공유 풀에 쓸 수 없어야 하는 이유는 무엇인가요?

2.강의에서 메모리 오염 방지를 위해 권장하는 세 가지 완화책은 무엇인가요?

3.전체 메시지 풀 대신 토픽 분할(topic-partitioned) 블랙보드를 선택해야 하는 경우는 언제인가요?

0/3 답변 완료

추가 문제 풀기

AI가 강의 내용을 바탕으로 새로운 문제를 생성합니다