DeepSeek Vision and Grok Imagine models are now live on CometAPI →
guide/CometAPI 리서치

CometAPI를 사용하여 다중 모델 CrewAI 에이전트 생성하기:

CometAPI를 사용하여 단일 API 키와 기본 URL, 에이전트별 모델 할당, 제한된 폴백, 사용량 추적을 갖춘 CrewAI 멀티 에이전트 워크플로우를 구축하십시오.

CometAPI
AnnaAI 모델 및 API 리서치 팀
업데이트됨 Aug 25, 2026 21 분 읽기
CometAPI를 사용하여 다중 모델 CrewAI 에이전트 생성하기:
이 패턴 사용

첫 API 호출하기.

from openai import OpenAI

client = OpenAI(
    api_key="YOUR_COMETAPI_KEY",
    base_url="https://api.cometapi.com/v1",
)

response = client.chat.completions.create(
    model="gpt-5-mini",
    messages=[{"role": "user", "content": "Build this workflow."}],
)

print(response.choices[0].message.content)

CrewAI로 멀티 에이전트 시스템을 구축할 때, 서로 다른 에이전트가 서로 다른 모델을 사용할 수 있으면 훨씬 더 흥미로워집니다.

연구자는 빠르고 경제적인 모델이 유리할 수 있고, 분석가는 더 강한 추론 모델이 필요할 수 있으며, 작가는 고품질 장문 생성에 최적화된 모델이 필요할 수 있습니다. 전통적으로, 이러한 에이전트를 서로 다른 제공자에 연결하려면 별도의 API 자격 증명, 엔드포인트, SDK, 결제 시스템, 제공자별 설정을 관리해야 합니다.

더 깔끔한 아키텍처는 다음과 같습니다. 에이전트와 워크플로는 CrewAI가 관리하고, 모델 접근은 CometAPI가 관리합니다.

CometAPI는 OpenAI 호환 엔드포인트를 https://api.cometapi.com/v1 에 제공합니다. 따라서 애플리케이션은 여러 제공자의 모델로 가는 요청을 공통 API 인터페이스를 통해 라우팅할 수 있습니다. 현재 빠른 시작 문서에서는 OpenAI 표준 Python SDK를 API 키와 base URL만 바꿔서 사용하는 방법도 지원합니다.

이 튜토리얼에서는 다음과 같은 3-에이전트 CrewAI 워크플로를 구축합니다.

  • 연구: Gemini 3.7 Flash
  • 분석: Claude Opus 5
  • 최종 작성: GPT-5.6
  • 하나의 CometAPI API 키
  • 하나의 API base URL
  • 에이전트별 모델 설정
  • 일시적 실패에 대한 제한적 폴백
  • 프로덕션 복구를 위한 CrewAI 체크포인트
  • 토큰 및 실행 사용량 추적
  • 서버 측 모델 검증

핵심적인 아키텍처 경계는 간단합니다.

CrewAI는 에이전트 오케스트레이션을 담당합니다. CometAPI는 모델 접근을 담당합니다. 모델 ID가 라우팅을 정의합니다.


CrewAI 멀티에이전트 모델 라우팅이란?

CrewAI는 에이전트, 태스크, 크루 및 멀티에이전트 워크플로를 만드는 Python 프레임워크입니다. 각 에이전트는 자체 LLM 구성을 가질 수 있으며, Crew 는 이러한 에이전트가 태스크를 실행하고 컨텍스트를 교환하는 방식을 조정합니다.

CrewAI의 현재 LLM 구성은 OpenAI 호환 엔드포인트를 포함해 명시적 model, api_key, base_url 설정을 지원합니다.

이는 멀티 모델 아키텍처를 간단하게 만듭니다.

                         CometAPI                            │              https://api.cometapi.com/v1                            │        ┌───────────────────┼───────────────────┐        │                   │                   │   Researcher            Analyst             Writer        │                   │                   │ Gemini 3.7 Flash      Claude Opus 5         GPT-5.6

에이전트는 논리적으로 분리된 상태를 유지하지만, 모델 접근은 중앙집중화됩니다.

이는 모든 모델이 상호 교환 가능하다는 의미와는 다릅니다. OpenAI 호환 API는 공통 요청 인터페이스를 제공하지만, 동일한 컨텍스트 한도, 도구 지원, 추론 제어, 출력 동작, 지연 시간 또는 가격을 보장하지는 않습니다.

이 구분은 프로덕션 라우팅을 설계할 때 중요합니다.


왜 CrewAI와 CometAPI를 함께 사용할까요?

핵심 장점은 CrewAI가 갑자기 멀티 제공자 프레임워크가 되는 것이 아닙니다. CrewAI는 이미 여러 LLM 제공자를 지원합니다.

장점은 모델 접근을 하나의 API 레이어 뒤로 통합할 수 있다는 것입니다.

통합 API 레이어가 없다면, 3-에이전트 워크플로는 다음과 같을 수 있습니다.

AgentProviderCredentialIntegration
ResearcherGoogleGoogle API keyProvider-specific
AnalystAnthropicAnthropic API keyProvider-specific
WriterOpenAIOpenAI API keyProvider-specific

CometAPI를 사용하는 경우:

AgentModelCredentialEndpoint
ResearcherGemini 3.7 FlashCometAPI keyCometAPI
AnalystClaude Opus 5CometAPI keyCometAPI
WriterGPT-5.6CometAPI keyCometAPI

CometAPI의 현재 빠른 시작 문서는 OpenAI API base URL에 대한 대체로 사용할 수 있다고 설명하며, 동일한 서비스에서 여러 제공자의 모델을 나열합니다.

이를 통해 애플리케이션은 다음과 같은 유용한 분리를 얻습니다.

CrewAI

  • 에이전트 역할 정의
  • 태스크 정의
  • 컨텍스트 전달
  • 실행 제어
  • 에이전트 반복 관리
  • 크루 레벨 오케스트레이션 처리

CometAPI

  • 공통 모델 접근 레이어 제공
  • API 인증 중앙화
  • 모델 ID를 통한 모델 라우팅 제공
  • 하나의 API 엔드포인트 제공
  • 사용량 및 결제 가시성 중앙화

이 CrewAI 워크플로는 무엇을 만들까요?

예제는 세 개의 순차적 에이전트를 생성합니다.

CrewAI AgentPrimary ModelFallbackRole
Market Researchergemini-3.7-flashgpt-5.6사실 수집 및 리서치
Product Analystclaude-opus-5gpt-5.6증거 및 트레이드오프 종합
Technical Writergpt-5.6gemini-3.7-flash최종 의사결정 메모 작성

이는 벤치마크 순위가 아닌 예시 라우팅 정책입니다.

에이전트에 적합한 모델은 다음에 따라 달라집니다.

  • 태스크 복잡도
  • 필요한 컨텍스트 길이
  • 도구 사용
  • 구조화된 출력 요구
  • 지연 시간
  • 신뢰성
  • 토큰 비용
  • 출력 품질
  • 애플리케이션별 평가 결과

유용한 원칙은 다음과 같습니다.

에이전트가 수행하는 작업에 맞는 모델을 선택하세요. 제공자만으로 선택하지 마세요.


각 CrewAI 에이전트는 어떤 모델을 사용해야 할까요?

이 예제에서는 간단한 비용 대비 능력 전략을 따릅니다.

연구자: Gemini 3.7 Flash

리서치는 상대적으로 많은 정보를 처리하고 간결한 중간 결과를 생성하는 작업을 포함하는 경우가 많습니다.

따라서 빠른 모델은 대량 리서치 태스크에 유용할 수 있습니다.

"researcher": "gemini-3.7-flash"

분석가: Claude Opus 5

분석가는 범위는 더 좁지만 추론 집약적인 역할을 합니다. 리서치 출력을 받아 이를 권고안으로 전환합니다.

"analyst": "claude-opus-5"

작성자: GPT-5.6

최종 에이전트는 리서치와 분석을 개발자 대상의 의사결정 메모로 변환합니다.

"writer": "gpt-5.6"

중요한 점은 정확히 이 세 가지 할당이 아닙니다. 애플리케이션은 라우팅 정책을 고정하기 전에 대표 태스크에 대해 후보 모델을 평가해야 합니다.


시작 전에 무엇이 필요할까요?

필요한 것:

  • Python 3.10+
  • CrewAI
  • OpenAI Python SDK 호환성
  • python-dotenv
  • CometAPI API 키
  • 사용할 모델 ID

CometAPI의 현재 Python 통합은 OpenAI 호환 API를 지원하며, 공식 CometAPI Python 패키지는 COMETAPI_KEYCOMETAPI_BASE_URL 을 환경 변수 기반 설정 옵션으로 문서화하고 있습니다.

표준 엔드포인트:

https://api.cometapi.com/v1

배포 전에 선택한 모델 ID가 현재 사용 가능하며, CrewAI 워크로드에서 요구하는 엔드포인트와 파라미터를 지원하는지 확인하세요. 모델 카탈로그와 가격은 변경될 수 있습니다.


CrewAI와 의존성은 어떻게 설치하나요?

새 Python 환경을 만듭니다:

python -m venv .venv

활성화:

source .venv/bin/activate

Windows:

.venv\Scripts\Activate.ps1

그 다음 의존성 설치:

pip install "crewai[openai]" openai python-dotenv

아래 폴백 구현이 OpenAI SDK 예외 클래스를 직접 임포트하므로 openai 를 명시적으로 사용하는 것이 의도적입니다.

프로덕션에서는 테스트한 버전을 고정하고, 최신 부동 버전에 무기한 의존하지 마세요.

예를 들어:

crewai==YOUR_TESTED_VERSIONopenai==YOUR_TESTED_VERSIONpython-dotenv==YOUR_TESTED_VERSION

CrewAI의 LLM 레이어는 활발히 발전 중이므로, 정확한 생성자와 제공자 구성은 애플리케이션에서 사용하는 CrewAI 버전에 맞춰 확인해야 합니다. 현재 CrewAI 문서는 사용자 정의 base_url 과 API 키로 LLM 을 구성하는 방법을 지원합니다.


CometAPI API 키는 어떻게 구성하나요?

.env 파일을 만듭니다:

COMETAPI_KEY=your_cometapi_keyCOMETAPI_BASE_URL=https://api.cometapi.com/v1

Python에서 값을 로드합니다:

import osfrom dotenv import load_dotenvload_dotenv()COMETAPI_KEY = os.environ["COMETAPI_KEY"]COMETAPI_BASE_URL = os.getenv(    "COMETAPI_BASE_URL",    "https://api.cometapi.com/v1",)

.env 를 Git에 커밋하지 마세요.

.gitignore 에 추가:

.env.venv/__pycache__/

API 키는 서버 측 자격 증명으로 유지되어야 합니다. CometAPI의 현재 빠른 시작 가이드도 키를 소스 코드 대신 환경 변수에 저장할 것을 권장합니다.


CrewAI를 CometAPI에 어떻게 연결하나요?

CrewAI의 LLM 객체는 모델 이름, API 키, 사용자 정의 base URL을 받을 수 있습니다.

헬퍼를 만듭니다:

from crewai import LLMdef cometapi_llm(model_id: str) -> LLM:    return LLM(        model=model_id,        base_url=COMETAPI_BASE_URL,        api_key=COMETAPI_KEY,        timeout=60.0,        max_retries=0,    )

이는 동일한 구성을 모든 에이전트에 개별적으로 삽입하는 것보다 바람직합니다.

이제 각 에이전트는 모델 ID만 필요합니다:

research_llm = cometapi_llm("gemini-3.7-flash")analysis_llm = cometapi_llm("claude-opus-5")writing_llm = cometapi_llm("gpt-5.6")

max_retries=0 을 설정하나요?

폴백 제어 때문입니다.

하위 LLM 클라이언트가 자동으로 재시도하고 애플리케이션도 폴백을 구현하면, 하나의 실패가 폴백 로직이 실행되기 전에 여러 개의 숨겨진 요청으로 바뀔 수 있습니다.

명시적 라우팅을 다루는 튜토리얼에서는 애플리케이션이 언제 재시도하거나 모델을 전환할지 결정하도록 하는 것이 더 깔끔합니다.


모델 라우팅 정책은 어떻게 정의하나요?

프롬프트 바깥에서 라우팅을 유지하세요:

PRIMARY_MODELS = {    "researcher": "gemini-3.7-flash",    "analyst": "claude-opus-5",    "writer": "gpt-5.6",}FALLBACK_MODELS = {    "researcher": "gpt-5.6",    "analyst": "gpt-5.6",    "writer": "gemini-3.7-flash",}

이로써 명확한 구성 경계가 생깁니다.

이후 동일한 매핑을 다음으로 옮길 수 있습니다:

  • 환경 구성
  • YAML
  • JSON
  • 데이터베이스
  • 기능 플래그
  • 내부 모델 라우팅 서비스

에이전트 프롬프트를 다시 작성하지 않고도 가능합니다.


세 개의 CrewAI 에이전트를 어떻게 구축하나요?

에이전트별로 하나의 LLM 객체를 생성합니다.

from crewai import Agentdef build_agents(model_map: dict[str, str]):    researcher = Agent(        role="Market Researcher",        goal="Collect the facts needed to answer the topic",        backstory=(            "You create concise, source-aware research briefs "            "and clearly separate facts from assumptions."        ),        llm=cometapi_llm(model_map["researcher"]),        max_iter=3,        allow_delegation=False,    )    analyst = Agent(        role="Product Analyst",        goal="Turn research into a defensible recommendation",        backstory=(            "You identify evidence, assumptions, risks, "            "and trade-offs before making recommendations."        ),        llm=cometapi_llm(model_map["analyst"]),        max_iter=3,        allow_delegation=False,    )    writer = Agent(        role="Technical Writer",        goal="Produce a concise technical decision memo",        backstory=(            "You write clear technical explanations "            "without unnecessary marketing language."        ),        llm=cometapi_llm(model_map["writer"]),        max_iter=3,        allow_delegation=False,    )    return researcher, analyst, writer

모델 할당은 이제 에이전트의 역할 정의와 완전히 독립적입니다.

이것이 모델 라우팅을 실용적으로 만듭니다.


에이전트를 순차 태스크로 어떻게 연결하나요?

세 가지 태스크를 생성합니다:

from crewai import Taskdef build_tasks(researcher, analyst, writer):    research_task = Task(        description=(            "Research this topic: {topic}. "            "Return the key facts, uncertainties, "            "and relevant sources that the analyst should consider."        ),        expected_output=(            "A compact research brief containing facts, "            "uncertainties, and source references."        ),        agent=researcher,    )    analysis_task = Task(        description=(            "Using the research brief, analyze {topic}. "            "Identify the strongest conclusion and explain "            "the major trade-offs."        ),        expected_output=(            "A decision outline with evidence, "            "assumptions, risks, and trade-offs."        ),        agent=analyst,        context=[research_task],    )    writing_task = Task(        description=(            "Write a concise technical decision memo about {topic}. "            "State the recommendation early and preserve "            "important caveats."        ),        expected_output="A polished technical decision memo in Markdown.",        agent=writer,        context=[research_task, analysis_task],    )    return research_task, analysis_task, writing_task

의존성 체인은 다음과 같습니다:

Topic  ↓Research  ↓Analysis  ↓Final memo

분석가는 리서치 태스크의 출력을 받고, 작성자는 리서치와 분석 컨텍스트를 둘 다 받습니다.


크루는 어떻게 빌드하나요?

에이전트와 태스크를 결합합니다:

from crewai import Crew, Processdef build_crew(model_map: dict[str, str]) -> Crew:    researcher, analyst, writer = build_agents(model_map)    research_task, analysis_task, writing_task = build_tasks(        researcher,        analyst,        writer,    )    return Crew(        agents=[researcher, analyst, writer],        tasks=[            research_task,            analysis_task,            writing_task,        ],        process=Process.sequential,        verbose=True,    )

이제 모델 라우팅은 전적으로 구성 기반입니다.

다음을 변경해도:

"researcher": "gemini-3.7-flash"

리서치 프롬프트나 태스크 정의를 변경할 필요가 없습니다.


CrewAI 모델 폴백은 어떻게 동작해야 하나요?

프로덕션 지향 구현에서는 더 많은 주의가 필요합니다.

흔한 실수:

Any error   ↓Switch model

이는 지나치게 공격적입니다.

예를 들어, 다음 오류는 일반적으로 모델 폴백을 트리거해서는 안 됩니다:

400 Bad Request401 Unauthorized403 Forbidden404 Not Found422 Validation Error

모델을 전환해도 잘못된 API 키나 잘못된 요청은 고쳐지지 않습니다.

폴백은 다음과 같은 일시적 실패에 더 적합합니다:

408 Request Timeout429 Rate Limit500 Internal Server Error502 Bad Gateway503 Service Unavailable504 Gateway TimeoutConnection errorTimeout

따라서 폴백 정책은 다음과 같아야 합니다.

제한적이며 일시적인 실패에만 재시도하거나 모델을 전환하고, 폴백 모델이 동일한 요청 계약을 지원할 때만 그렇게 하세요.


재시도 가능한 오류는 어떻게 감지하나요?

OpenAI SDK의 에러 클래스를 사용할 수 있습니다:

from collections.abc import Iteratorfrom openai import (    APIConnectionError,    APIStatusError,    APITimeoutError,)def exception_chain(error: BaseException) -> Iterator[BaseException]:    current: BaseException | None = error    seen: set[int] = set()    while current is not None and id(current) not in seen:        seen.add(id(current))        yield current        current = (            current.__cause__            or current.__context__        )def should_fallback(error: BaseException) -> bool:    for current in exception_chain(error):        if isinstance(            current,            (APIConnectionError, APITimeoutError),        ):            return True        if isinstance(current, APIStatusError):            return (                current.status_code in {408, 429}                or current.status_code >= 500            )    return False

이는 의도적으로 408과 429를 제외한 400대 구성 오류를 제외합니다.


전체 크루를 재시도해야 하나요, 아니면 실패한 에이전트만 재시도해야 하나요?

두 가지 폴백 전략이 있습니다.

크루 레벨 폴백

가장 단순한 구현:

Start crew   ↓failure   ↓change routing   ↓run crew again

이해하기는 쉽지만, 완료된 태스크를 반복할 수 있습니다.

예를 들어:

Research → completedAnalysis → completedWriter → failed

전체 kickoff() 재시도는 다음을 실행할 수 있습니다:

Research → againAnalysis → againWriter → fallback

이것은 다음을 증가시킵니다:

  • 토큰 사용량
  • 지연 시간
  • API 비용
  • 부작용 발생 가능성

태스크 레벨 복구

프로덕션 워크플로는 완료된 작업을 체크포인트에 저장해야 합니다:

Research   ↓checkpoint   ↓Analysis   ↓checkpoint   ↓Writer fails   ↓retry writer with fallback

CrewAI는 현재 태스크 완료 후 실행 상태를 저장하고 실패 후 실행을 재개할 수 있는 체크포인트를 제공합니다. 문서화된 체크포인트 동작은 완료된 태스크를 건너뛰고 저장된 상태에서 하류 작업을 계속하도록 합니다.

이는 비용이 크거나 부작용이 있는 워크플로에 더 적합한 아키텍처입니다.


CrewAI 체크포인트는 어떻게 추가하나요?

프로덕션 워크플로에서는 크루에 체크포인트를 활성화하세요:

crew = Crew(    agents=[researcher, analyst, writer],    tasks=[        research_task,        analysis_task,        writing_task,    ],    process=Process.sequential,    checkpoint=True,    verbose=True,)

CrewAI의 체크포인트 시스템은 태스크 완료 후 실행 상태를 유지하고 체크포인트에서 크루를 복원할 수 있습니다.

예를 들어, 복원된 실행은 다음을 사용할 수 있습니다:

from crewai import CheckpointConfigresult = crew.kickoff(    from_checkpoint=CheckpointConfig(        restore_from="./.checkpoints/checkpoint.json",    ))

정확한 체크포인트 구성은 프로젝트에서 사용하는 CrewAI 버전에 맞추세요.

중요한 아키텍처 포인트:

먼저 체크포인트, 그 다음 폴백.

이로써 일시적 모델 실패가 이미 완료된 고비용 작업을 다시 실행하도록 강제하는 것을 방지합니다.


간단한 제한적 폴백은 어떻게 구현하나요?

튜토리얼에서는 간단한 크루 레벨 폴백을 시연할 수 있습니다.

def run_with_fallback(topic: str):    routes = [        PRIMARY_MODELS,        {            **PRIMARY_MODELS,            "writer": FALLBACK_MODELS["writer"],        },        {            **PRIMARY_MODELS,            "analyst": FALLBACK_MODELS["analyst"],            "writer": FALLBACK_MODELS["writer"],        },    ]    last_error = None    for attempt, model_map in enumerate(routes, start=1):        try:            crew = build_crew(model_map)            result = crew.kickoff(                inputs={"topic": topic}            )            return result, model_map        except Exception as error:            last_error = error            if not should_fallback(error):                raise            if attempt == len(routes):                raise            print(                f"Transient failure on attempt {attempt}. "                f"Trying bounded fallback route.",                flush=True,            )    raise RuntimeError(        "Crew execution failed after all fallback routes."    ) from last_error

중요한 구분을 주의하세요:

실패한 에이전트가 식별되었다고 주장하지 않습니다.

이는 제한적인 크루 레벨 폴백 전략입니다.

작고 상태가 없는 워크플로에서는 허용 가능할 수 있습니다. 리서치, 도구 또는 부작용이 비싼 프로덕션 워크플로에서는 체크포인트 기반 복구를 사용하세요.


CrewAI 토큰 사용량은 어떻게 추적하나요?

사용량 추적은 라우팅 레이어의 일부여야 하며, 사후 고려 사항이 되어서는 안 됩니다.

실행 끝에서 CrewAI 결과를 확인하세요:

result, selected_models = run_with_fallback(topic)print("Selected models:")print(selected_models)print("Final result:")print(result.raw)print("Usage:")print(result.token_usage)

사용 가능한 정확한 사용량 필드는 CrewAI 버전과 실행 경로에 따라 달라질 수 있으므로, 배포 버전에서 반환된 결과 객체를 진실의 근원으로 취급하세요.

프로덕션 사용량 기록에는 이상적으로 다음이 포함되어야 합니다:

job_idagentmodelinput_tokensoutput_tokenstotal_tokenslatency_msfallback_usedfallback_reasonstatuscreated_at

이를 통해 다음과 같은 질문에 답할 수 있습니다:

어떤 에이전트가 예산을 가장 많이 소비하나요?

분석가는 얼마나 자주 폴백하나요?

어떤 모델이 지연 시간이 가장 높은가요?

각 워크플로의 비용은 얼마인가요?


에이전트 수준에서 비용은 어떻게 제어하나요?

멀티 모델 라우팅은 실제 워크로드 차이를 반영할 때 가장 유용합니다.

예를 들어:

Researcher→ high volume→ lower-cost modelAnalyst→ low volume→ stronger reasoning modelWriter→ medium volume→ general-purpose production model

에이전트 구성으로 비용을 제한할 수도 있습니다.

예를 들어:

max_iter=3

은 에이전트의 반복 루프를 제한합니다. 이는 정확히 세 번의 API 호출이나 세 개의 토큰 예산으로 오해되어서는 안 됩니다.

추가 제어에는 다음이 포함됩니다:

  • 태스크 컨텍스트 제한
  • 중간 출력 요약
  • 반복 가능한 리서치 캐싱
  • 최대 입력 크기 제한
  • 지원되는 경우 최대 출력 토큰 제한
  • 도구 호출 제한
  • 사용자별 예산 설정
  • 워크플로별 예산 설정
  • 폴백 빈도 추적

배포 전에 모델은 어떻게 검증하나요?

모델 ID를 영구적으로 하드코딩하지 마세요.

모델은 다음과 같을 수 있습니다:

  • 사용 불가
  • 이름 변경
  • 사용 중단
  • 제한
  • 능력 변경
  • 가격 변경
  • 애플리케이션에서 사용하는 파라미터와 호환되지 않음

CometAPI는 프로그래밍 방식으로 쿼리할 수 있는 모델 카탈로그 엔드포인트를 제공하며, 퍼블릭 모델 디렉토리는 사람이 모델을 탐색하는 데 사용할 수 있습니다.

배포 전 검사는 다음과 같을 수 있습니다:

curl -s \  https://api.cometapi.com/api/models \  -H "Authorization: Bearer $COMETAPI_KEY"

그런 다음 구성된 모델 ID가 배포 전에 존재하는지 검증하세요.

예를 들어, CI 프로세스에서 다음을 검증할 수 있습니다:

gemini-3.7-flash → availableclaude-opus-5    → availablegpt-5.6          → available

가용성 확인을 애플리케이션 테스트의 대체물로 삼지 마세요. 모델이 카탈로그에 존재한다는 사실이, CrewAI 에이전트가 사용하는 모든 파라미터, 도구, 출력 형식을 지원한다는 의미는 아닙니다.


전체 CrewAI 예제는 어떻게 생겼나요?

다음은 통합 구현입니다:

import jsonimport osimport sysfrom collections.abc import Iteratorfrom dotenv import load_dotenvfrom openai import (    APIConnectionError,    APIStatusError,    APITimeoutError,)from crewai import Agent, Crew, LLM, Process, Taskload_dotenv()COMETAPI_KEY = os.environ["COMETAPI_KEY"]COMETAPI_BASE_URL = os.getenv(    "COMETAPI_BASE_URL",    "https://api.cometapi.com/v1",)PRIMARY_MODELS = {    "researcher": "gemini-3.7-flash",    "analyst": "claude-opus-5",    "writer": "gpt-5.6",}FALLBACK_MODELS = {    "researcher": "gpt-5.6",    "analyst": "gpt-5.6",    "writer": "gemini-3.7-flash",}def cometapi_llm(model_id: str) -> LLM:    return LLM(        model=model_id,        base_url=COMETAPI_BASE_URL,        api_key=COMETAPI_KEY,        timeout=60.0,        max_retries=0,    )def build_crew(model_map: dict[str, str]) -> Crew:    researcher = Agent(        role="Market Researcher",        goal="Collect the facts needed to answer the topic",        backstory=(            "You create concise, source-aware research briefs "            "and distinguish facts from assumptions."        ),        llm=cometapi_llm(model_map["researcher"]),        max_iter=3,        allow_delegation=False,    )    analyst = Agent(        role="Product Analyst",        goal="Turn research into a defensible recommendation",        backstory=(            "You evaluate evidence, assumptions, risks, "            "and trade-offs."        ),        llm=cometapi_llm(model_map["analyst"]),        max_iter=3,        allow_delegation=False,    )    writer = Agent(        role="Technical Writer",        goal="Produce a concise technical decision memo",        backstory=(            "You write clear technical explanations "            "without unnecessary hype."        ),        llm=cometapi_llm(model_map["writer"]),        max_iter=3,        allow_delegation=False,    )    research_task = Task(        description=(            "Research this topic: {topic}. "            "Return the key facts, uncertainties, "            "and relevant sources."        ),        expected_output=(            "A concise research brief with facts "            "and open questions."        ),        agent=researcher,    )    analysis_task = Task(        description=(            "Using the research brief, analyze {topic}. "            "Identify the strongest conclusion and "            "explain the major trade-offs."        ),        expected_output=(            "A decision outline with evidence, "            "assumptions, risks, and trade-offs."        ),        agent=analyst,        context=[research_task],    )    writing_task = Task(        description=(            "Write a concise technical decision memo "            "about {topic}. State the recommendation early "            "and preserve important caveats."        ),        expected_output=(            "A polished technical decision memo in Markdown."        ),        agent=writer,        context=[            research_task,            analysis_task,        ],    )    return Crew(        agents=[            researcher,            analyst,            writer,        ],        tasks=[            research_task,            analysis_task,            writing_task,        ],        process=Process.sequential,        verbose=True,    )def exception_chain(    error: BaseException,) -> Iterator[BaseException]:    current = error    seen: set[int] = set()    while current is not None and id(current) not in seen:        seen.add(id(current))        yield current        current = (            current.__cause__            or current.__context__        )def should_fallback(error: BaseException) -> bool:    for current in exception_chain(error):        if isinstance(            current,            (                APIConnectionError,                APITimeoutError,            ),        ):            return True        if isinstance(current, APIStatusError):            return (                current.status_code in {408, 429}                or current.status_code >= 500            )    return Falsedef run_with_fallback(topic: str):    routes = [        PRIMARY_MODELS,        {            **PRIMARY_MODELS,            "writer": FALLBACK_MODELS["writer"],        },        {            **PRIMARY_MODELS,            "analyst": FALLBACK_MODELS["analyst"],            "writer": FALLBACK_MODELS["writer"],        },    ]    last_error = None    for attempt, model_map in enumerate(        routes,        start=1,    ):        try:            crew = build_crew(model_map)            result = crew.kickoff(                inputs={                    "topic": topic,                }            )            return result, model_map        except Exception as error:            last_error = error            if not should_fallback(error):                raise            if attempt == len(routes):                raise            print(                f"Transient failure on attempt "                f"{attempt}; trying fallback.",                file=sys.stderr,            )    raise RuntimeError(        "No model route completed the crew."    ) from last_errordef main():    topic = (        sys.argv[1]        if len(sys.argv) > 1        else (            "Should a small SaaS add "            "AI-generated meeting summaries?"        )    )    result, selected_models = (        run_with_fallback(topic)    )    output = {        "selected_models": selected_models,        "raw": result.raw,        "tasks_output": [            task.raw            for task in result.tasks_output        ],        "token_usage": str(            result.token_usage        ),    }    print(        json.dumps(            output,            indent=2,            default=str,        )    )if __name__ == "__main__":    main()

원본 버전 대비 중요한 개선점은, 이제 코드가 예외가 정확히 실패한 에이전트를 식별한다고 잘못 암시하지 않는다는 것입니다.

이는 명시적으로 제한된 크루 레벨 폴백 구현입니다.

프로덕션에서는 동일한 라우팅 정책을 CrewAI 체크포인트와 결합하세요.


CrewAI 워크플로는 어떻게 실행하나요?

파일로 저장:

crewai_multi_model.py

그 다음 실행:

python crewai_multi_model.py \  "Should a small SaaS add AI-generated meeting summaries?"

성공적인 응답은 다음과 유사한 정보를 포함합니다:

{  "selected_models": {    "researcher": "gemini-3.7-flash",    "analyst": "claude-opus-5",    "writer": "gpt-5.6"  },  "raw": "<final decision memo>",  "tasks_output": [    "<research output>",    "<analysis output>",    "<writing output>"  ],  "token_usage": "<usage information>"}

정확한 응답과 사용량 값은 입력, 모델 동작, CrewAI 버전 및 실행 경로에 따라 달라집니다.

재시도 가능한 오류로 폴백 경로가 활성화되면, selected_models 객체는 해당 크루 실행에 사용된 경로를 보여줍니다.


프로덕션 모델 라우팅은 어떻게 설계해야 하나요?

프로덕션 라우팅 정책은 모델 품질 이상을 고려해야 합니다.

유용한 의사결정 함수:

Model Score =Quality+ Reliability+ Context Fit+ Tool Compatibility- Cost- Latency

여러 레벨에서 구현할 수 있습니다.

비용 기반 라우팅

Simple task → economical modelComplex task → premium model

지연 시간 기반 라우팅

Interactive request → fast modelBackground workflow → higher-quality model

신뢰성 기반 라우팅

Primary model     ↓transient failure     ↓fallback model

태스크 기반 라우팅

Research → Model AAnalysis → Model BWriting → Model CCode → Model D

마지막 방식은 각 에이전트에 고유한 역할을 부여하는 CrewAI에 특히 자연스럽습니다.


폴백을 어떻게 안전하게 만드나요?

견고한 폴백 시스템은 네 가지 규칙을 강제해야 합니다.

인증 오류에 대해 폴백하지 마세요

API 키가 잘못된 경우:

401

모델을 바꿔도 문제가 해결되지 않습니다.

잘못된 요청에 대해 폴백하지 마세요

요청이 잘못된 경우:

400422

모델을 바꾸는 대신 요청을 바로잡으세요.

무기한 폴백하지 마세요

하드 제한을 설정하세요:

MAX_FALLBACK_ATTEMPTS = 2

제한 없는 폴백 시스템은 비용이 많이 드는 재시도 루프가 될 수 있습니다.

폴백 모델은 요청 호환성을 갖추세요

폴백 모델은 에이전트가 요구하는 기능을 지원해야 합니다.

예를 들어, 기본 에이전트가 특정 도구나 구조화된 출력 동작을 요구하는 경우, 폴백도 동일한 계약을 지원해야 합니다.

OpenAI 호환이라는 것이 기능 호환을 의미하는 것은 아닙니다.


CrewAI + CometAPI에서 가장 흔한 오류는 무엇인가요?

SymptomLikely CauseFix
401 Unauthorized잘못되었거나 없는 API 키COMETAPI_KEY 확인; 폴백하지 않음
400 Bad Request잘못된 요청 파라미터요청 수정
404 Model Not Found오래된 모델 ID최신 모델 카탈로그 확인
408 Timeout일시적 요청 타임아웃제한적 정책 내에서 재시도
429 Rate Limited과도한 요청백오프 후 재시도
500–504서버/게이트웨이 일시적 실패제한적 폴백 사용
에이전트가 반복 재시도숨겨진 SDK 재시도max_retries 제어
완료된 태스크가 다시 실행됨전체 크루 재시도체크포인트 기반 복구 사용
모델 간 동작 차이모델 역량 차이각 모델 독립적으로 테스트
예상치 못한 CrewAI 생성자 오류버전 불일치CrewAI 버전 고정 및 검증

CrewAI 오류와 모델 오류를 어떻게 구분하나요?

디버깅 시 이 구분은 중요합니다.

구성 오류

Missing API keyInvalid model IDInvalid base URLUnsupported parameter

이들은 빠르게 실패해야 합니다.

제공자/API 오류

401403404429500503

상태에 따라 다른 처리가 필요합니다.

애플리케이션 오류

Agent output invalidTool returned malformed dataTask context missingSide effect failed

이들은 모델 변경으로 반드시 해결되지는 않습니다.

성숙한 에이전트 시스템은 다음을 분리하여 처리해야 합니다:

configuration      ↓API transport      ↓model execution      ↓agent logic      ↓tool execution      ↓application side effects

이는 다음과 같은 일반적 처리보다 훨씬 안전합니다:

except Exception:    use_fallback()

외부 부작용은 어떻게 보호하나요?

에이전트가 텍스트 생성 이상의 작업을 수행할 때 폴백은 훨씬 더 복잡해집니다.

예를 들어, 다음과 같은 에이전트를 상상해 보세요:

  1. 데이터베이스 레코드 생성
  2. 이메일 발송
  3. 외부 API 호출
  4. CRM 업데이트

외부 작업이 성공한 후 모델이 타임아웃되면, 전체 크루를 다시 실행하면 작업이 중복될 수 있습니다.

다음을 사용하세요:

  • idempotency 키
  • 태스크 체크포인트
  • 트랜잭션 경계
  • 실행 ID
  • 내구성 있는 태스크 상태
  • 명시적 부작용 확인

예를 들어:

job_id = crew_run_123task_id = writer_456

이러한 식별자를 외부 작업과 함께 저장하여 재시도 시 작업이 이미 수행되었는지 판단할 수 있도록 하세요.


멀티 모델 CrewAI 워크플로는 어떻게 모니터링하나요?

최소한 다음을 로그하세요:

workflow_idagentmodeltaskstart_timeend_timelatencystatusfallback_usedfallback_reasoninput_tokensoutput_tokenstotal_tokens

로그하지 마세요:

API keysprivate credentialsfull sensitive promptsprivate user dataunredacted model output

모델별로 모니터링:

신뢰성

success ratetimeout rate5xx ratefallback rate

성능

p50 latencyp95 latencyp99 latency

비용

input tokensoutput tokenscost per taskcost per completed workflow

품질

task success ratehuman evaluationstructured-output validitytool-call success

이를 통해 모델 라우팅은 하드코딩된 선호에서 관측 가능한 엔지니어링 시스템으로 전환됩니다.


직접 제공자 API와 CometAPI 중 무엇을 선택해야 하나요?

선택은 아키텍처에 따라 달라집니다.

ArchitectureCredentialsModel SwitchingProvider IntegrationCentralized Routing
Direct provider APIsMultipleCustomHighNo
Single providerOneLimitedLowLimited
CrewAI + CometAPIOne CometAPI credentialModel-ID basedLowerYes

애플리케이션이 하나의 제공자와 그 네이티브 기능만 필요하다면, 직접 통합도 충분히 합리적입니다.

CrewAI 애플리케이션이 여러 제공자의 모델을 필요로 하고 하나의 접근 레이어를 원한다면, CometAPI가 더 매력적입니다.

중요한 점은 CometAPI가 CrewAI를 대체하지 않는다는 것입니다.

대신:

CrewAIAgent orchestration       ↓CometAPIModel access       ↓Multiple models

각 레이어는 서로 다른 책임을 가집니다.


이 아키텍처는 어떻게 확장되나요?

라우팅 정책을 에이전트 정의에서 분리하면, 모델을 추가하더라도 애플리케이션 전체를 재구축할 필요가 없습니다.

예를 들어:

PRIMARY_MODELS = {    "researcher": "gemini-3.7-flash",    "analyst": "claude-opus-5",    "writer": "gpt-5.6",    "coder": "YOUR_CODE_MODEL",}

같은 아키텍처로 다음을 지원할 수 있습니다:

Research agentAnalysis agentCoding agentReview agentWriting agentFact-checking agent

각 에이전트는 동일한 CometAPI 접근 레이어를 공유하면서 서로 다른 모델을 가질 수 있습니다.

다음 단계는 라우팅을 동적으로 만드는 것입니다.

다음 대신:

"analyst": "claude-opus-5"

다음을 사용할 수 있습니다:

select_model(    task="analysis",    budget=budget,    latency_target=latency_target,)

라우팅 시스템은 애플리케이션 요구 사항에 따라 승인된 모델 중에서 선택할 수 있습니다.


CrewAI + CometAPI에 대한 최적의 프로덕션 아키텍처는 무엇인가요?

작은 워크플로:

User Input   ↓CrewAI   ↓CometAPI   ↓Models

프로덕션:

                     ┌───────────────┐                     │ Model Catalog │                     └───────┬───────┘                             │                             ▼User → CrewAI → Routing Policy → CometAPI           │          │             │           │          │             ├── Gemini           │          │             ├── Claude           │          │             └── GPT           │          │           │          ▼           │     Cost / Quality /           │     Latency / Policy           │           ▼      Checkpoints           │           ▼      Usage Tracking

핵심 프로덕션 구성 요소:

  1. 모델 허용 목록
  2. 에이전트별 라우팅
  3. 제한적 재시도
  4. 태스크 체크포인트
  5. 사용량 추적
  6. 비용 제어
  7. 모델 호환성 테스트
  8. 가시성(Observability)
  9. 멱등(idempotent) 부작용

이는 단순히 crew.kickoff()try/except 로 감싸는 것보다 훨씬 견고합니다.


하나의 CometAPI 키, 서로 다른 모델, 더 명확한 에이전트 역할

CrewAI와 CometAPI를 함께 생각하는 가장 유용한 방법은 두 개의 보완적인 레이어로 보는 것입니다.

CrewAI는 에이전트가 무엇을 하는지 정의합니다.

CometAPI는 에이전트가 모델에 어떻게 접근하는지 정의합니다.

이 분리는 대량 리서치 에이전트에는 빠른 모델을, 분석 에이전트에는 더 강한 추론 모델을, 최종 작성에는 범용 모델을 할당하면서도 워크플로 내부에서 제공자별 통합을 유지하지 않아도 되게 합니다.

가장 단순한 구현은 하나의 CometAPI 키와 하나의 OpenAI 호환 base URL을 사용합니다:

https://api.cometapi.com/v1

프로덕션에서는 아키텍처를 한 단계 더 나아가세요: 모델 라우팅을 구성에 유지하고, 배포 전에 모델 가용성을 검증하며, 일시적 실패에만 제한적 폴백을 사용하고, 완료된 태스크를 체크포인트하며, 모든 실행에 대해 모델 및 사용량 메타데이터를 기록하세요.

이는 CrewAI를 하나의 LLM에만 연결하는 것보다 훨씬 더 내구성 있는 패턴을 제공합니다.

CrewAI는 에이전트를 오케스트레이션합니다. CometAPI는 모델 접근을 중앙화합니다. 모델 ID가 라우팅을 제어합니다. 체크포인트는 완료된 작업을 보호합니다. 사용량 추적은 비용을 통제합니다.


자주 묻는 질문

CrewAI는 동일한 크루에서 여러 AI 모델을 사용할 수 있나요?

네. 각 CrewAI 에이전트에 다른 LLM 구성을 할당하면 됩니다. 각 구성은 동일한 CometAPI API 키와 base URL을 사용하면서 자체 모델을 지정할 수 있습니다.

CrewAI는 OpenAI 호환 API에 연결할 수 있나요?

네. CrewAI의 LLM 구성은 OpenAI 호환 엔드포인트를 위한 사용자 정의 base_url 과 API 키를 지원합니다.

CometAPI를 사용할 때 base URL은 다음과 같습니다:

https://api.cometapi.com/v1

GPT, Claude, Gemini에 각각 별도의 API 키가 필요하나요?

이러한 모델을 CometAPI를 통해 접근할 때, 애플리케이션은 에이전트별로 제공자 자격 증명을 구현하는 대신 CometAPI 자격 증명과 엔드포인트를 사용할 수 있습니다.

하나의 API 키가 모델의 역량이 동일하다는 의미인가요?

아니요. API 인터페이스는 통합될 수 있지만, 모델의 역량은 여전히 다릅니다. 컨텍스트 윈도우, 도구 지원, 파라미터, 출력 동작, 지연 시간, 가격은 모델마다 다를 수 있습니다.

한 모델이 실패하면 CrewAI 워크플로 전체를 재시도해야 하나요?

상태가 단순한 워크플로에만 해당합니다. 전체 크루 재시도는 완료된 태스크를 반복하고 비용을 증가시킬 수 있습니다. 프로덕션 워크플로에서는 완료된 태스크를 체크포인트하고, 가능한 경우 실패한 부분부터 재개하세요.

CrewAI의 현재 체크포인트 기능은 실행 상태를 보존하고 실패 후 재개하기 위해 설계되었습니다.

모든 CrewAI 예외가 모델 폴백을 트리거해야 하나요?

아니요. 인증, 잘못된 요청, 잘못된 모델 ID, 지원되지 않는 파라미터는 일반적으로 구성 변경이 필요하며, 다른 모델로는 해결되지 않습니다.

폴백은 타임아웃, 레이트 리밋, 일시적 5xx 응답과 같은 제한적 일시적 실패에 사용하는 것이 더 좋습니다.

각 CrewAI 에이전트의 비용은 어떻게 추적하나요?

각 태스크에 대해 에이전트 이름, 모델 ID, 토큰 사용량, 지연 시간, 실행 상태, 폴백 정보를 기록하세요. 이 데이터를 사용해 에이전트별 및 워크플로별 비용을 계산하세요.

에이전트에 할당된 모델을 동적으로 변경할 수 있나요?

네. 모델 ID를 에이전트 정의에 직접 넣지 말고 라우팅 구성에 보관하세요. 애플리케이션은 비용, 지연 시간, 태스크 유형, 가용성에 따라 모델을 선택할 수 있습니다.

CometAPI는 CrewAI의 대체재인가요?

아니요. 서로 다른 레이어에서 동작합니다. CrewAI는 에이전트와 태스크를 오케스트레이션하고, CometAPI는 통합된 모델 접근 레이어를 제공합니다.

현재 CometAPI 모델은 어디에서 찾을 수 있나요?

사람이 모델을 탐색하기 위한 CometAPI 모델 디렉토리 와 프로그래밍 방식 검증을 위한 모델 API를 사용하세요. CometAPI의 현재 빠른 시작 페이지는 텍스트, 이미지, 비디오, 오디오 카테고리에서 500개 이상의 모델을 나열합니다.


출처

학습 계속하기

이 글을 다음 결정과 연결하세요.

모든 주제 보기
게시일 Aug 25, 2026
최종 업데이트 Aug 25, 2026
0 회 조회
명확성, 출처 표기 및 최신 API 용어에 대해 검토되었습니다.

AI 개발 비용을 20% 절감할 준비가 되셨나요?

몇 분 안에 무료로 시작하세요. 무료 체험 크레딧 제공. 신용카드 불필요.

더 보기