LLM WikiAccess-protected knowledge portal
← 스터디 홈
27편 · 약 14분

CrewAI 1.14: 에이전트 메모리·지식·흐름을 교체 가능한 컴포넌트로 분리한 방법

왜 이 릴리스를 봐야 하나

2026년 6월 11일 공개된 CrewAI 1.14.7은 단순한 기능 추가 릴리스가 아니다. 핵심은 메모리·지식·RAG·흐름(Flow) 인프라를 모두 교체 가능한 백엔드로 분리했다는 구조적 변화다.

이전까지 CrewAI는 메모리 저장소(ChromaDB/SQLite), 벡터 검색(내장 RAG), 흐름 런타임을 프레임워크 내부에 강하게 결합해 두었다. 그 결과 몇 가지 운영 문제가 반복됐다.

  • 동시에 여러 Crew를 실행하면 공유 ChromaDB에 쓰기 충돌이 생겼다.
  • 프로덕션에서 메모리 백엔드를 Postgres나 Redis로 바꾸려면 프레임워크 내부를 직접 건드려야 했다.
  • Flow 상태가 실행 전반에 걸쳐 무제한으로 커지다 OOM으로 이어지는 사고가 드물지 않았다.
  • flow.py 하나에 DSL·정의·런타임이 뒤섞여 있어, Flow를 테스트하거나 커스터마이즈하기 어려웠다.

1.14.7은 이 문제를 한꺼번에 건드렸다. 무엇을 바꿨는지보다, 왜 이 구조가 필요했는지를 먼저 보자.


변경 핵심 한눈에 보기

변화무엇이 바뀌었나운영자가 확인할 포인트
플러거블 백엔드memory, knowledge, rag, flow에 커스텀 구현 주입 가능기존 기본값(ChromaDB/SQLite) 그대로 동작, 교체 시 인터페이스 준수 여부 확인
잠금 백엔드 오버라이드기본 locking 구현을 교체 가능분산 환경에서 Redis 기반 분산 락으로 교체 가능
런타임 상태 run-scoped각 실행마다 상태를 격리공유 상태 오염 방지, 메모리 증가 한계 설정 가능
FlowDefinition 분리DSL → Definition → Runtime 3단 분리Flow 구조 변경 없이 실행 엔진만 교체 가능
Chat API대화형 흐름용 API 추가multi-turn 시나리오에서 Flow와 대화 상태를 분리해 관리
LLM 이벤트 표면화finish_reason, sampling params, response.id 노출비용 추적·재현·디버깅 시 모델 응답 세부 정보를 직접 접근

전체 아키텍처 변화

CrewAI 1.14 아키텍처: 교체 가능한 백엔드 레이어 Crew / Agent Layer Task 실행 · Agent 간 위임 · LLM 이벤트(finish_reason, sampling_params, response.id) Chat API → multi-turn 대화 흐름 진입점 Flow Layer Flow DSL FlowDefinition Runtime 상태 run-scoped: 각 실행마다 독립 복사 → 동시 실행 시 오염 없음 Memory · Knowledge · RAG Layer (플러거블) 단기 메모리 기본: LanceDB ← 커스텀 교체 가능 장기 메모리 기본: SQLite3 ← 커스텀 교체 가능 엔티티 메모리 기본: LanceDB RAG 기반 검색 지식 PDF·CSV· JSON·Excel 플러거블 백엔드 인터페이스 (1.14에서 공개) VectorDBMemoryProvider KnowledgeStorageProvider RAGSearchProvider FlowPersistenceBackend LockingBackend (분산 락) 커스텀 / 외부 백엔드 (교체 가능) Postgres pgvector Qdrant / Weaviate OpenSearch Redis 분산 락 S3/GCS FlowPersistence Mem0 장기/엔티티 메모리 단기/엔티티 메모리 지식·RAG 동시 실행 환경 Flow 중단·재개 외부 메모리 서비스
CrewAI 1.14 플러거블 백엔드 아키텍처

이 구조에서 핵심을 짚으면 하나다. Crew·Agent 코드는 그대로 두고, 아래 레이어(메모리·지식·흐름 저장소)를 조직의 기존 인프라로 연결할 수 있다.


메모리 시스템: 세 가지 역할과 기본 저장소

CrewAI 메모리는 역할별로 세 층으로 나뉜다.

단기 메모리 (Short-Term Memory)

현재 실행 세션 안에서 에이전트끼리 주고받은 맥락을 보관한다. 기본 저장소는 LanceDB(이전 버전은 ChromaDB였고, 동시 쓰기 충돌 문제 이후 전환됐다). 세션이 끝나면 사라진다.

from crewai import Crew, Process

crew = Crew(
    agents=[researcher, analyst],
    tasks=[research_task, analysis_task],
    process=Process.sequential,
    memory=True,          # 단기·장기·엔티티 메모리 모두 활성화
    verbose=True,
)

장기 메모리 (Long-Term Memory)

Task 결과를 세션을 넘어 영구 보관한다. 기본 저장소는 SQLite3. 에이전트는 과거 실행에서 배운 결과를 다음 실행에서 참조한다. crew.kickoff() 결과가 자동으로 기록된다.

운영 주의점: 기본 SQLite 파일 경로는 플랫폼별 앱 데이터 디렉터리에 생성된다. 컨테이너 환경이라면 재시작 시 초기화된다. 영구 보존이 필요하면 파일을 마운트하거나 외부 DB로 교체해야 한다.

엔티티 메모리 (Entity Memory)

사람·장소·개념 같은 엔티티를 RAG로 추적한다. "지난번 검색에서 나온 'AWS S3' 관련 내용"처럼, 현재 세션 안에서 반복 등장하는 엔티티 정보를 빠르게 불러온다. 기본 저장소는 LanceDB(벡터 인덱스).


플러거블 백엔드: 기본값을 바꾸는 방법

1.14에서 가장 중요한 변화는 인터페이스 공개다. 백엔드를 교체하는 방식은 Crew 생성 시 명시적으로 주입하는 것이다.

from crewai import Crew, Process
from crewai.memory import VectorDBMemoryProvider  # 예시 인터페이스

# Postgres pgvector를 단기 메모리로 사용하는 예시
class PgvectorProvider(VectorDBMemoryProvider):
    def store(self, text: str, metadata: dict) -> None:
        # pgvector INSERT
        ...

    def search(self, query: str, top_k: int = 5) -> list[dict]:
        # pgvector ANN 검색
        ...

crew = Crew(
    agents=[...],
    tasks=[...],
    memory=True,
    memory_config={
        "short_term": {"provider": PgvectorProvider()},
        "entity": {"provider": PgvectorProvider()},
    },
)

잠금 백엔드도 같은 방식으로 교체된다.

from crewai.locking import LockingBackend

class RedisLock(LockingBackend):
    def acquire(self, key: str, timeout: float) -> bool:
        ...
    def release(self, key: str) -> None:
        ...

crew = Crew(
    ...,
    locking_config={"backend": RedisLock(redis_client=redis_client)},
)

런타임 상태 격리: 동시 실행의 핵심 변화

1.14 이전 버전에서 동시에 여러 crew를 실행하면 전역 Flow 상태가 오염됐다. crew.kickoff() 두 개를 동시에 부르면 서로의 Task 결과가 뒤섞이는 버그가 보고됐었다.

1.14.7의 "Scope runtime state per run" 변경은 이 문제를 직접 건드렸다.

  • kickoff() 호출마다 상태 사전을 _copy_state()로 독립 복사한다.
  • 복사 불가능한 객체는 graceful fallback으로 처리해 실행이 멈추지 않는다.
  • 상태 크기가 무제한으로 커지는 것을 방지하기 위해 run 단위로 생명주기를 바인딩한다.
import asyncio
from crewai import Crew

crew = Crew(agents=[...], tasks=[...], memory=True)

# 동시에 두 실행을 시작해도 상태가 섞이지 않는다
results = await asyncio.gather(
    crew.kickoff_async(inputs={"topic": "AI"}),
    crew.kickoff_async(inputs={"topic": "DB"}),
)

Flow 아키텍처 분리: DSL → Definition → Runtime

flow.py가 단일 파일에서 세 모듈로 나뉘었다. 이 변화는 테스트 가능성과 커스터마이징 양쪽에 영향을 준다.

DSL 레이어: @start, @listen, @router 같은 데코레이터로 Flow를 선언한다. 1.14에서 트리거가 route-aware decorator로 바뀌어 조건 분기를 표현하기 더 쉬워졌다.

FlowDefinition 레이어: DSL 메타데이터를 읽어 노드 그래프를 구성한다. 이 레이어를 분리한 덕분에 Flow 정의 자체를 직렬화하거나 검사하는 도구를 따로 만들 수 있다.

Runtime 레이어: 실제로 노드를 실행하고 상태를 관리한다. 기본 런타임 외에 커스텀 런타임을 주입할 수 있고, FlowPersistenceBackend를 달아두면 Flow 중단·재개(pause/resume)가 가능해진다.


Chat API: 대화형 흐름의 진입점

1.14에서 추가된 Chat API는 multi-turn 대화를 Flow 안에서 구조적으로 다루기 위한 인터페이스다. 기존에는 대화 상태와 Flow 실행 상태를 별도로 관리해야 했다.

from crewai.flow.chat import ChatSession

session = ChatSession(crew=support_crew)

# turn 1
response1 = await session.send("MySQL 복제 지연이 발생하고 있습니다")

# turn 2: 이전 대화 맥락 유지
response2 = await session.send("binlog position이 어디쯤인지 확인하는 명령이 뭔가요?")

이 API는 conversational_definition을 분리한 리팩터링과 맞닿아 있다. 대화 맥락과 실행 상태를 섞지 않아, 긴 대화를 반복해도 Flow 상태 증가가 대화 이력과 따로 관리된다.


LLM 이벤트 표면화: finish_reason, sampling_params, response.id

이번 릴리스에서 조용하지만 운영 관점에서 중요한 변화 중 하나다.

LLM 호출 결과에서 finish_reason, sampling_params, response.id가 이벤트로 노출된다. 이 세 가지가 생기면 무엇을 할 수 있나.

  • finish_reason: stop인지 length인지 content_filter인지 알 수 있다. 출력이 잘린 이유를 분류할 수 있다.
  • sampling_params: 실제 요청에 사용된 temperature, max_tokens를 기록한다. 운영 중 파라미터 변화를 추적할 수 있다.
  • response.id: LLM 프로바이더의 응답 ID를 보관해 특정 응답을 재현하거나 청구 내역과 매칭할 수 있다.
# 이벤트 핸들러로 LLM 이벤트 수집
from crewai.events import LLMCallbackHandler

class CostTracker(LLMCallbackHandler):
    def on_llm_end(self, response):
        print(response.finish_reason)   # "stop" | "length" | ...
        print(response.id)              # 프로바이더 응답 ID
        print(response.usage)           # input_tokens, output_tokens

운영자가 바로 확인할 체크리스트

업그레이드 전

  • [ ] 현재 메모리 저장소가 ChromaDB라면 LanceDB로 전환됐는지 확인한다.
  • [ ] 기존 코드에서 flow.py 내부를 직접 참조하는 부분이 있으면 새 모듈 경로로 교체한다.
  • [ ] 동시 실행 환경에서 공유 ChromaDB를 쓰던 코드는 이제 run-scoped 격리가 자동 적용된다.

메모리 백엔드 선택 기준

시나리오권장 백엔드
단일 인스턴스, 간단한 프로토타입기본값 (LanceDB + SQLite)
컨테이너 환경, 상태 영구 보존 필요외부 DB (Postgres pgvector, Qdrant)
다중 인스턴스 동시 실행중앙화 벡터 DB + 분산 락 (Redis)
외부 메모리 서비스 통합Mem0 어댑터

프로덕션 배포 체크

  • [ ] 잠금 백엔드를 인메모리 기본값으로 두면 다중 프로세스 환경에서 race condition이 생긴다. Redis 기반 잠금으로 교체한다.
  • [ ] FlowPersistenceBackend 없이 long-running Flow를 운영하면 프로세스 재시작 시 상태를 잃는다.
  • [ ] LLM 이벤트 핸들러를 달아 finish_reason과 response.id를 기록하면 컨텍스트 오버플로우 탐지와 비용 분류가 가능해진다.
  • [ ] Chat API를 쓸 때 세션 유지 기간과 메모리 수명을 함께 설계한다. 세션이 길어지면 단기 메모리가 커진다.

이 릴리스를 한 문장으로

CrewAI 1.14는 에이전트 프레임워크를 애플리케이션 레이어로 가져오는 릴리스다. 메모리·지식·흐름 저장소를 인터페이스로 분리함으로써, 프레임워크를 바꾸지 않고 조직의 기존 데이터 인프라 위에 에이전트를 올릴 수 있게 됐다.

References

  • CrewAI Release 1.14.7 (GitHub, 2026-06-11): https://github.com/crewAIInc/crewAI/releases/tag/1.14.7
  • CrewAI Changelog: https://docs.crewai.com/en/changelog
  • CrewAI Memory Documentation: https://www.aidoczh.com/crewai/en/concepts/memory.html
  • CrewAI Memory in Production (ActiveWizards): https://activewizards.com/blog/crewai-memory-systems-in-production-persistence-retrieval-and-state-recovery/
  • How we built Cognitive Memory for Agentic Systems (CrewAI blog): https://blog.crewai.com/how-we-built-cognitive-memory-for-agentic-systems/
  • AI Agent Memory: LangGraph vs CrewAI vs AutoGen (DEV Community): https://dev.to/foxgem/ai-agent-memory-a-comparative-analysis-of-langgraph-crewai-and-autogen-31dp
  • CrewAI State Management (DeepWiki): https://deepwiki.com/crewAIInc/crewAI/3.3-state-management