1. CrewAI 기술이란?
왜 필요한가 — 기존 방식의 한계
2023~2024년 LLM 에이전트를 처음 만들 때 대부분의 팀은 "하나의 큰 에이전트 + 30개의 도구" 패턴으로 시작했습니다. 빠르게 동작은 했지만 운영을 시작하자마자 세 가지 벽에 부딪혔습니다.
첫째, 도구 선택 오류가 폭증합니다. 도구 30개의 설명을 한 번에 컨텍스트에 넣으면 LLM은 비슷한 도구들 사이에서 자주 잘못된 선택을 합니다. 둘째, 시스템 프롬프트가 비대해집니다. "검색 시에는 이렇게, 이메일 작성 시에는 저렇게, 코드 리뷰는 또 이렇게…" 모든 페르소나가 한 프롬프트에 섞이며 어느 한 영역의 품질이 떨어지기 시작합니다. 셋째, 책임 분리가 안 됩니다. 출력이 잘못 나왔을 때 어느 도구·어느 단계·어느 역할에서 망가졌는지 추적하기가 어렵습니다.
해법은 인간 조직의 협업 구조를 흉내내는 것입니다. 리서처·작가·편집자 세 사람이 협업하듯, 각각의 역할을 가진 작은 에이전트들에게 일을 나눠 주고, 그 사이에 매니저를 둘 수도 있습니다. CrewAI는 이 발상을 가장 단순한 데코레이터 한 줄과 YAML로 표현한 프레임워크입니다.
기술 정의
CrewAI는 다음 다섯 요소를 한 패키지로 묶은 오픈소스 멀티에이전트 오케스트레이션 프레임워크입니다(MIT 라이선스, Python 3.10+).
- Agent — role / goal / backstory를 가진 LLM 페르소나
- Task — description / expected_output / agent를 가진 일감 단위
- Crew — 에이전트와 태스크를 묶는 팀, Process를 지정
- Process — Sequential(순차) 또는 Hierarchical(매니저 LLM이 위임)
- Tools / Memory / Knowledge — 도구 호출, 단·장기 메모리, RAG용 지식 소스
LangChain·LangGraph가 "낮은 추상화로 무엇이든 만들 수 있게" 하는 프레임워크라면, CrewAI는 "협업이라는 메타포를 정면에 세워 빠르게 돌리게" 하는 프레임워크입니다.
2. CrewAI 기술 특징
| 특징 | 설명 |
| 역할 기반 페르소나 | role / goal / backstory 세 필드만으로 인간이 읽기 쉬운 에이전트를 정의. 시스템 프롬프트의 분할 통치를 강제합니다. |
| 두 가지 프로세스 | Sequential(태스크가 줄을 서서 다음 에이전트에게 전달)과 Hierarchical(Manager LLM이 일을 쪼개 위임) 중 1줄로 선택. |
| YAML 우선 구성 | agents.yaml / tasks.yaml로 페르소나·일감을 분리. 비개발자도 프롬프트를 수정할 수 있고 코드 리뷰가 쉬워집니다. |
| 도구 위임 | 에이전트가 다른 에이전트에게 자연어로 질문하거나 일을 넘기는 기능(allow_delegation=True). 인간 팀의 "이건 네가 더 잘 알 것 같아"를 흉내냅니다. |
| 다층 메모리 | Short-term(현재 실행), Long-term(SQLite 영속), Entity(개체 사실), Contextual(요약) 4계층을 자동 관리합니다. |
| 모델 비종속 | LiteLLM 위에서 동작 — OpenAI / Anthropic / Bedrock / Vertex / Groq / Ollama / vLLM 등 100여 개 모델을 문자열만 바꿔 사용. |
| 구조화 출력 | output_pydantic / output_json으로 Task 결과를 강제 검증. 다음 에이전트가 받는 입력의 일관성을 확보합니다. |
| CrewAI Flows | 2024 후반 도입된 이벤트 기반 워크플로우 — Crew는 협업, Flow는 결정론적 분기·루프·병렬을 담당하는 보완재입니다. |
| 관측성 통합 | AgentOps / Langfuse / OpenLIT / MLflow Tracing과 즉시 결합. 에이전트별 토큰·도구 호출 횟수를 추적합니다. |
3. CrewAI 기술 동작방식
구성 요소
- Agent — role / goal / backstory + LLM 모델 + tools 리스트 + max_iter / max_rpm 등 가드레일.
- Task — 자연어 설명, 예상 출력 형태, 담당 에이전트, 의존 태스크(context=[...]), 출력 파일 경로(선택).
- Crew — 에이전트·태스크·process·memory·knowledge_sources를 모은 실행 단위. crew.kickoff(inputs={...})로 실행됩니다.
- Process — Process.sequential(기본) 또는 Process.hierarchical(manager_llm 필요).
- Tool — @tool 데코레이터 또는 BaseTool 상속. 내장 도구 60+종(검색·파일·코드실행·RAG·MCP).
- Memory — Short / Long / Entity / Contextual 4종. 기본 SQLite, 임베딩은 OpenAI / Cohere / Ollama 중 선택.
- Knowledge Sources — PDF·CSV·웹·텍스트를 임베딩해 에이전트의 사전지식으로 주입.
데이터 흐름
- Crew.kickoff(inputs) 호출 시 inputs가 모든 태스크의 description / expected_output 자리에 변수 치환됩니다.
- Sequential: 태스크 1 → 결과가 태스크 2의 context로 자동 주입 → 태스크 3 …
- Hierarchical: 사용자는 매니저 LLM에게 목표만 던지고, 매니저가 어떤 에이전트에게 어떤 순서로 위임할지를 LLM 추론으로 결정합니다.
- 각 에이전트는 ReAct 루프로 도구 호출과 추론을 반복(max_iter까지).
- Memory가 켜져 있으면 매 턴 임베딩이 저장되고, 다음 태스크 실행 시 contextual memory가 자동 검색·주입됩니다.
- 최종 산출물은 CrewOutput 객체 — raw / pydantic / json + per-task 출력 + token_usage가 모두 들어 있습니다.
4. CrewAI 기술 구성 및 흐름도
단계별 구조도 — Sequential

단계별 구조도 — Hierarchical

실제 처리 흐름 — "신규 SaaS 시장조사 보고서" 시나리오
- 사용자: "한국 중소기업 회계 SaaS 시장 조사 — 2026년 진입 전략."
- Researcher 에이전트가 SerperDevTool로 시장 규모·경쟁사·가격대를 검색.
- Analyst 에이전트가 검색 결과를 받아 SWOT 표를 생성, 출력은 SwotMatrix Pydantic 모델로 강제.
- Writer 에이전트가 SWOT + 원본 리서치를 결합해 임원용 1페이지 요약을 작성.
- Editor 에이전트가 사실 확인이 필요한 항목을 발견하면 delegation으로 Researcher에게 재질문(자연어).
- 최종 마크다운이 output_file="report.md"로 저장. CrewOutput에는 토큰 사용량과 각 단계 산출물이 그대로 보존.
5. CrewAI 기술 설치 방법
Python 3.10 이상이 필요합니다. 의존성 충돌이 잦으므로 가상환경(uv 또는 venv) 사용을 권장합니다.
# 기본 설치
pip install crewai
# 내장 도구 묶음 함께 설치 (Serper, ScrapeWebsite, FileRead 등)
pip install "crewai[tools]"
# uv 사용 (권장)
uv add "crewai[tools]"
# 프로젝트 스캐폴딩 (권장 — agents.yaml / tasks.yaml 자동 생성)
crewai create crew my_research_crew
cd my_research_crew
# 실행
crewai run
# 환경 변수 (.env)
OPENAI_API_KEY=sk-...
SERPER_API_KEY=... # SerperDevTool 사용 시
ANTHROPIC_API_KEY=sk-ant-... # Claude 사용 시
주의 — 설치 트러블슈팅
- chromadb 빌드 실패: 메모리 기능이 chromadb를 끌어옵니다. 윈도우에서는 Microsoft C++ Build Tools가 없으면 빌드가 깨집니다. WSL2를 쓰거나 사전 빌드 휠을 설치하세요.
- litellm 버전 충돌: LangChain·LlamaIndex와 함께 쓸 때 자주 충돌합니다. uv pip compile로 락파일을 만들어 고정하세요.
- Python 3.13은 의존성(특히 onnxruntime)이 아직 미지원인 경우가 있어 3.11~3.12를 권장합니다.
- 크롬 헤드리스 도구(ScrapeWebsite, Selenium 계열)는 컨테이너에서 --no-sandbox 옵션이 필요합니다.
6. CrewAI 기술 사용 방법
최소 예제 — 2 에이전트 Sequential
from crewai import Agent, Task, Crew, Process
from crewai_tools import SerperDevTool
researcher = Agent(
role="시장 리서처",
goal="{topic}에 대한 최신 시장 동향을 사실 기반으로 정리한다",
backstory="너는 컨설팅 펌에서 15년 일한 시니어 리서처다. "
"주장은 항상 출처 URL과 함께 제시한다.",
tools=[SerperDevTool()],
llm="openai/gpt-4o-mini",
max_iter=8,
verbose=True,
)
writer = Agent(
role="테크 라이터",
goal="리서치 자료를 임원이 5분에 읽을 보고서로 정리한다",
backstory="너는 IT 미디어에서 8년간 일한 테크 라이터다. "
"두괄식, 한 문장 한 메시지를 지킨다.",
llm="openai/gpt-4o",
verbose=True,
)
t_research = Task(
description="{topic} 시장 규모, 주요 플레이어 5곳, "
"최근 12개월 동향을 한국어로 정리하라.",
expected_output="요점 10개 이내의 마크다운 노트, 각 항목에 출처 URL.",
agent=researcher,
)
t_write = Task(
description="아래 리서치 노트를 토대로 1페이지 임원 보고서를 작성하라.",
expected_output="제목 / 핵심 3줄 / 시장 / 경쟁 / 권고 5개 섹션의 마크다운.",
agent=writer,
context=[t_research], # 자동 주입
output_file="report.md",
)
crew = Crew(
agents=[researcher, writer],
tasks=[t_research, t_write],
process=Process.sequential,
memory=True,
verbose=True,
)
result = crew.kickoff(inputs={"topic": "한국 중소기업 회계 SaaS 2026"})
print(result.raw)
print(result.token_usage)
실전 예제 — 커스텀 도구 + 구조화 출력
from crewai.tools import tool
from pydantic import BaseModel
from typing import List
@tool("internal_kb_search")
def internal_kb_search(query: str, top_k: int = 5) -> str:
"""사내 지식베이스에서 query에 대한 top_k개 문서 요약을 반환한다."""
docs = kb_client.search(query, k=top_k) # 사내 검색 호출
return "\n\n".join(f"- {d.title}: {d.snippet}" for d in docs)
class Risk(BaseModel):
name: str
severity: str # "low" | "medium" | "high"
mitigation: str
class RiskReport(BaseModel):
risks: List[Risk]
summary: str
risk_task = Task(
description="제품 출시 리스크를 사내 KB와 외부 검색으로 식별하라.",
expected_output="구조화된 RiskReport JSON.",
agent=analyst,
tools=[internal_kb_search, SerperDevTool()],
output_pydantic=RiskReport, # ← 결과 강제 검증
)
계층형(Hierarchical) — 매니저 LLM
crew = Crew(
agents=[researcher, analyst, writer],
tasks=[overall_goal_task], # 큰 목표 1개만
process=Process.hierarchical,
manager_llm="openai/gpt-4o", # 위임 결정용 모델
memory=True,
max_rpm=30, # 분당 호출 상한 (rate limit)
)
YAML 구성 (권장 패턴)
# config/agents.yaml
researcher:
role: 시장 리서처
goal: "{topic} 시장의 최신 동향을 사실 기반으로 정리한다"
backstory: 컨설팅 펌 15년차 시니어 리서처
llm: openai/gpt-4o-mini
writer:
role: 테크 라이터
goal: 리서치를 임원용 1페이지 보고서로 다듬는다
backstory: IT 미디어 8년차
# config/tasks.yaml
research_task:
description: "{topic} 시장 규모와 주요 플레이어 5곳을 정리하라."
expected_output: 마크다운 노트
agent: researcher
write_task:
description: 리서치 노트를 1페이지 보고서로 다듬어라.
expected_output: 제목 / 핵심 3줄 / 5개 섹션
agent: writer
운영 시 고려사항
- 모델은 역할별로 분리하라. Researcher는 도구를 많이 쓰니 빠르고 저렴한 모델, Writer는 출력 품질이 중요하니 강한 모델 — 비용·품질을 동시에 잡습니다.
- max_iter / max_rpm은 반드시 설정. 미설정이면 무한 루프와 레이트 리밋 폭발의 직접 원인입니다.
- memory=True는 강력하지만 SQLite 위치를 컨테이너 밖 볼륨으로 빼두지 않으면 재배포마다 소실됩니다.
- 도구는 멱등(idempotent)으로. 에이전트가 같은 도구를 두 번 호출해도 부작용이 없어야 합니다(특히 메일 발송·DB INSERT).
- output_pydantic을 적극 사용해 다음 태스크의 입력 형식을 고정하세요. 자유 텍스트로 넘기면 후속 에이전트가 형식을 추측하다가 환각을 만듭니다.
- verbose=True는 개발에서만. 프로덕션에서는 AgentOps / Langfuse로 트레이스를 보내야 토큰·비용·실패 원인을 분석할 수 있습니다.
- 크리티컬한 호출은 Flow로 감싸기. Crew는 비결정적 협업, Flow는 결정론적 분기 — 결제·DB 변경처럼 정확한 순서가 필요한 단계는 Flow에 둡니다.
7. CrewAI 자주 쓰는 명령어 / API
| crewai create crew NAME | 권장 디렉터리·YAML 스캐폴딩 생성 |
| crewai run | 현재 프로젝트의 main.py를 실행 |
| crewai install | pyproject.toml 기반 의존성 설치 |
| crewai train -n N | N회 반복 실행하며 사람 피드백을 모아 프롬프트를 다듬기 |
| crewai test -n N --model M | 결정적 평가 — 같은 입력을 N번 돌려 산출물 일관성 측정 |
| crewai replay -t TASK_ID | 실패한 태스크 지점부터 재실행 (디버깅에 유용) |
| crewai reset-memories --all | SQLite 장기 메모리 / 임베딩 캐시 전체 초기화 |
| crewai flow create NAME | Flow(이벤트 기반 워크플로우) 스캐폴딩 |
| crew.kickoff(inputs=...) | 동기 실행 (CrewOutput 반환) |
| crew.kickoff_async(...) | 비동기 실행 (FastAPI / 워커용) |
| crew.kickoff_for_each(inputs=[...]) | 배치 실행 — 입력 리스트마다 동일 Crew 실행 |
| @tool("name") | 간단한 함수형 커스텀 도구 등록 |
| BaseTool 상속 | 스키마·캐시·에러 처리가 정교한 도구 작성 |
| output_pydantic=Model | Task 결과를 Pydantic 모델로 강제 검증 |
| allow_delegation=True | 에이전트가 동료 에이전트에게 위임·질문 허용 |
사례 — 배치 실행으로 100건 보고서 자동화
companies = [{"topic": f"{name} 2026 전망"} for name in target_list]
# 100건 동시 실행 (max_rpm으로 자동 throttle)
results = crew.kickoff_for_each(inputs=companies)
for inp, out in zip(companies, results):
save_to_db(inp["topic"], out.raw, out.token_usage)
8. CrewAI 활용방안
잘 어울리는 시나리오
- 역할이 자연스럽게 갈라지는 콘텐츠 워크플로우 — 리서치 → 작성 → 편집, 영업 메일 → 검토 → 개인화
- RAG 위에 얹은 보고서 자동화 — 사내 KB 검색 + 외부 검색 + 분석 + 작성을 분리
- 티켓 트리아지·근본 원인 분석 — Triager / Investigator / Recommender 3역
- QA / 평가(Judge) 파이프라인 — Generator + Critic + Refiner 패턴을 코드 100줄에 구현
- 비개발자가 프롬프트를 직접 손대야 하는 팀 — YAML 분리로 개발 / 도메인 협업 가능
대안 기술 비교
| LangGraph | 상태 그래프, 체크포인트, HITL이 강력 | 노드·엣지를 명시적으로 그려야 함, 진입장벽 | "역할 협업"이라는 메타포가 더 잘 맞을 때 — 보고서·콘텐츠·QA 파이프라인. |
| AutoGen 0.4+ | 액터 모델, 대화형 멀티에이전트, MS 백킹 | 메시지 스키마·런타임이 무겁고 학습곡선 가파름 | 짧은 시간에 데모를 만들거나, YAML로 페르소나를 비개발자에게 맡길 때. |
| PydanticAI | 단일 에이전트의 타입 안전·관측성 끝판왕 | 멀티에이전트 협업·매니저 위임은 직접 구현해야 | 3개 이상 역할이 협업하는 워크플로우면 CrewAI. 한 에이전트로 끝나면 PydanticAI. |
| OpenAI Agents SDK | OpenAI 모델 1차 지원, Handoff·Guardrails | 사실상 OpenAI 종속, 매니저·메모리 사상 좁음 | 다중 벤더 모델·온프레미스(Ollama) 폴백이 필요하면 CrewAI. |
| LangChain Agent | 통합 도구 수 최대 | 단일 에이전트 + 도구 패러다임에 멈춤 | "역할 분리"라는 추상화가 명시적으로 필요하면 CrewAI가 코드량을 절반으로 줄입니다. |
| Letta(MemGPT) | 장기기억 영속화, 컨텍스트 가상화 | 협업·역할 위임 기능이 약함 | 기억보다 협업이 중심이면 CrewAI. 두 가지를 결합해 쓰는 사례도 늘고 있습니다. |
언제 쓰면 안 되는가
- 결정론·원자성이 핵심인 트랜잭션 — 결제·송금·재고 차감처럼 정확한 순서가 강제돼야 한다면 Crew 대신 일반 코드 또는 CrewAI Flow.
- 실시간(≤ 500ms) 응답 — 멀티에이전트는 본질적으로 다중 LLM 호출이라 평균 5~30초가 듭니다. 챗봇 1차 응답에는 부적절합니다.
- 한 에이전트로 충분한 작업 — 분류·정보 추출·간단한 RAG는 PydanticAI 같은 단일 에이전트가 비용·디버깅 면에서 모두 우월.
- 20개 이상의 깊은 분기·루프 — 그래프가 복잡해지면 LangGraph 또는 자체 오케스트레이터가 더 명료합니다.
- 토큰 예산이 매우 빠듯한 환경 — 멀티에이전트는 같은 작업을 단일 에이전트로 하는 것보다 2~5배의 토큰을 씁니다.
현장 트러블슈팅 — 경험에서 나온 함정
① "토큰 비용이 갑자기 5배가 됐어요"
멀티에이전트는 한 에이전트 호출 = 여러 ReAct 턴 × 여러 에이전트입니다. 청구서가 폭발한 적이 한 번이라도 있다면 다음 4가지를 동시에 적용하세요. (1) 역할별로 모델 분리 — Researcher는 gpt-4o-mini, Writer만 gpt-4o. (2) max_iter=8~12로 ReAct 상한 설정. (3) 도구 결과가 길면 도구 안에서 요약·페이지네이션. (4) 메모리는 단계별로 끄고 켜기 — 모든 태스크에 memory=True를 켜면 contextual 검색이 매번 임베딩을 호출합니다.
② "에이전트가 같은 도구를 무한히 호출해요"
대부분 도구 출력이 너무 길거나, 출력이 LLM이 보기에 "성공인지 실패인지 애매한 형태"일 때 일어납니다. 도구는 항상 명시적인 성공/실패 신호를 텍스트에 포함시키세요(예: "OK: 5건 검색" 또는 "ERROR: timeout"). 그리고 반드시 max_iter와 max_rpm을 함께 박아 두세요. 디폴트로는 무한입니다.
③ "환각이 단계마다 부풀어오릅니다 (cascade hallucination)"
Sequential 모드에서는 한 에이전트의 환각이 다음 에이전트의 입력이 되면서 지수적으로 부풀어 오릅니다. 해법은 출력의 형태를 강제하는 것입니다. 모든 중간 태스크의 expected_output을 구체적으로 쓰고, 가능하면 output_pydantic을 적용해 다음 단계가 받는 입력의 스키마를 고정하세요. "출처 URL이 없는 사실은 적지 말 것" 같은 규칙은 backstory와 expected_output에 모두 명시해야 효과가 있습니다.
④ "분명히 도구가 있는데 에이전트가 안 써요"
LLM이 도구를 무시하는 가장 흔한 원인은 도구 docstring이 너무 짧거나 모호한 것입니다. 도구 설명에 (1) 무엇을 받고 (2) 무엇을 반환하며 (3) 언제 써야 하는지를 한 문장씩 적으세요. 그래도 안 쓰면 시스템 프롬프트(backstory)에 "답하기 전에 반드시 internal_kb_search를 1회 이상 호출한다"처럼 강제 절차를 명시하면 즉시 효과가 납니다.
⑤ "Hierarchical 모드에서 Manager가 같은 작업을 계속 위임해요"
Manager LLM은 작업 완료 조건이 모호하면 무한히 재위임합니다. 각 에이전트의 goal에 "완료의 정의(Definition of Done)"를 명시하세요. 예를 들어 "리서치 완료 = 출처 URL이 5개 이상이고 시장 규모 숫자가 1개 이상 포함"처럼. 또한 처음 도입할 때는 Sequential로 시작해 안정화한 뒤 Hierarchical로 전환하는 게 안전합니다. 아무 이유 없이 처음부터 Hierarchical을 쓰는 것은 권장하지 않습니다.
⑥ "프로덕션에서 갑자기 응답이 멈춥니다 (rate limit storm)"
Crew 1회 실행이 LLM 호출 30~80건이 되는 일은 흔합니다. kickoff_for_each로 100건을 동시에 돌리면 순식간에 RPM 한도를 친다는 뜻입니다. Crew 단위에 max_rpm을 박고, LiteLLM의 retry_strategy를 켜고, 가능하면 벤더 1차 + 폴백 1개로 구성하세요. 제 경험상 단일 벤더만 쓰는 운영은 일주일 안에 한 번은 사고가 납니다.
⑦ "메모리가 누적돼서 컨텍스트 한도를 초과합니다"
긴 대화·여러 차례 실행 후 context length exceeded가 뜨는 경우입니다. CrewAI는 contextual memory를 자동 검색·주입하는데, top_k가 크거나 entity memory가 누적되면 입력이 부풀어요. 정기적으로 crewai reset-memories --long로 정리하고, 운영에서는 메모리 임베딩 모델을 가벼운 것(예: text-embedding-3-small)으로 명시 지정하세요.
⑧ "delegation을 켰더니 매 턴 동료에게 사소한 걸 묻습니다"
allow_delegation=True는 강력하지만 남용되기 쉽습니다. 위임은 편집·검토 같은 마지막 단계 에이전트에만 켜고, 리서치·분석 단계 에이전트는 끄세요. 또 backstory에 "스스로 답할 수 있는 질문은 위임하지 않는다"는 규칙을 명시하면 위임 빈도가 절반 이하로 떨어집니다.
⑨ "프롬프트 인젝션으로 도구가 의도치 않게 호출됐어요"
사용자 입력이 backstory·system_prompt에 직접 들어가면 즉시 인젝션 표면이 됩니다. 사용자 입력은 항상 inputs 변수로 분리해 task description에만 주입하고, 파일 내용을 도구로 읽을 때는 결과를 [USER CONTENT] 같은 명시적 마커로 감싸 LLM이 "이건 명령이 아니라 데이터다"를 인식하게 만드세요. 결제·삭제 같은 위험 도구에는 휴먼 인 더 루프 확인 단계를 반드시 끼우세요(CrewAI Flow가 이 용도에 적합합니다).
⑩ "테스트가 너무 비결정적이라 CI에 못 넣겠어요"
Crew 통합 테스트는 본질적으로 비결정적입니다. 두 갈래로 푸세요. (a) 단위 — 도구 함수와 Pydantic 스키마는 LLM 없이 그냥 pytest로. (b) 통합 — 가짜 LLM 또는 녹화 / 재생(replay)으로. crewai test -n 5로 산출물의 품질 점수가 임계치를 넘는지를 합격 조건으로 두는 것도 좋습니다(완벽한 일치를 요구하면 영영 그린이 안 됩니다).
'AI(Artificial Intelligence)' 카테고리의 다른 글
| 양자머신러닝(QML)이란? 핵심 개념부터 하이브리드 아키텍처 구조 (0) | 2026.07.22 |
|---|---|
| Cline · VS Code 자율 코딩 에이전트 (1) | 2026.07.10 |
| StatefulSet 멀티노드 LLM 추론 한계 끝낸 K8s LeaderWorkerSet (1) | 2026.06.18 |
| AI Agent의 핵심 인프라, MCP(Model Context Protocol) (0) | 2026.06.10 |
| 다중 LLM 키·라우팅 지옥 끝낸 LiteLLM 2.x AI Gateway (0) | 2026.06.09 |