콘텐츠로 이동

LLM 연결 (LLMs)

CrewAI에서 에이전트의 '두뇌'를 담당하는 게 바로 LLM이에요. CrewAI는 여러 LLM 제공사를 네이티브 SDK로 연결해서, 프로젝트 성격에 맞는 모델을 골라 쓸 수 있게 해 줘요.

개념: LLM이 뭐예요?

LLM은 대량의 텍스트 데이터로 학습된 AI 시스템이에요. CrewAI 에이전트가 문맥을 이해하고, 결정을 내리고, 사람처럼 자연스러운 응답을 생성하는 데 이게 핵심이 돼요. 쉽게 말하면, 에이전트가 '생각'하는 부분을 LLM이 맡는다고 보면 돼요.

모델을 고를 때는 크게 두 가지를 신경 써요.

컨텍스트 윈도우(Context Window) — LLM이 한 번에 처리할 수 있는 텍스트의 양이에요. 윈도우가 크면(예: 128K 토큰) 더 많은 문맥을 넣을 수 있지만, 비싸고 느려질 수 있어요.

온도(Temperature) — 일부 모델이 지원하는 샘플링 조절 값이에요. 값이 낮으면 결과가 더 집중적이고, 높으면 변동성이 커져요. 다만 최근 나온 추론(reasoning) 계열 모델 중에는 이 파라미터를 무시하거나, 더 이상 쓰지 않거나, 아예 거부하는 경우도 있어요. 쓰기 전에 선택한 모델의 문서를 꼭 확인해 주세요.

모델 설정하는 곳

CrewAI 코드에서 모델을 지정하는 자리는 세 군데예요. 어떤 자리를 선택해도, 그 다음엔 해당 제공사의 설정(예: API 키)을 채워줘야 해요.

1. 환경 변수 (Environment Variables)

제일 간단한 시작 방법이에요. .env 파일이나 앱 코드에서 바로 모델을 환경 변수로 넣는 방식이에요. crewai create로 프로젝트를 만들었다면 이미 설정돼 있을 거예요.

MODEL=provider/model-id  # 예: openai/gpt-5.6-terra

# 여기 API 키도 함께 설정해 주세요. 아래 'Provider' 섹션을 참고하세요.

실무 포인트: API 키는 절대 버전 관리(version control)에 커밋하지 마세요. 반드시 .env 파일이나 시스템의 시크릿 관리 기능을 쓰는 게 원칙이에요.

2. YAML 설정

에이전트 설정을 YAML 파일로 정의하는 방법이에요. 버전 관리와 팀 단위 협업에 특히 좋아요.

researcher:
    role: Research Specialist
    goal: Conduct comprehensive research and analysis
    backstory: A dedicated research professional with years of experience
    verbose: true
    llm: provider/model-id  # 예: anthropic/claude-sonnet-4-6
    # (자세한 건 아래 provider 설정 예시를 참고하세요)

YAML 방식의 장점은 이래요:

  • 에이전트 설정을 버전 관리할 수 있고
  • 모델을 쉽게 바꿔 끼울 수 있으며
  • 설정 파일을 팀원끼리 공유할 수 있고
  • 모델 선택 이유를 문서로 남길 수 있어요

3. 코드에서 직접 설정

최대한 유연하게 할 땐 Python 코드에서 바로 LLM을 설정해요.

from crewai import LLM

# 기본 설정
llm = LLM(model="provider/model-id")  # 예: gemini/gemini-3.6-flash

# 세부 파라미터를 넣은 고급 설정
llm = LLM(
    model="provider/model-id",
    timeout=120,          # 응답 대기 최대 시간
    max_tokens=4000,      # 응답 길이 제한
    response_format={"type": "json"},  # 구조화된 출력을 위한 설정
)

temperature, top_p 같은 샘플링 조절 값이나, 패널티 파라미터, 토큰 제한 이름, 추론 제어 같은 건 모델마다 달라요. 선택한 제공사와 모델이 지원할 때만 추가하는 게 좋아요. 아래 provider 예시와 해당 모델 문서를 참고하세요.

제공사가 둘로 나뉜다는 점

CrewAI는 OpenAI, Anthropic, Google(제미나이 API), Azure, AWS Bedrock, Snowflake Cortex까지는 네이티브 SDK로 연결돼요. 이 경우 제공사 전용 extra만 설치하면 돼요(예: uv add "crewai[openai]").

그 외 모든 제공사는 LiteLLM을 통해서 동작해요. 그런 제공사를 쓸 계획이라면 프로젝트에 의존성을 추가해야 해요.

uv add 'crewai[litellm]'

실무 포인트: 모델은 자주 추가되고 사라져요. 문서에 나온 모델 ID는 작성 시점 기준이라, 배포 전에 반드시 제공사 모델 카탈로그에서 ID와 수명 주기(lifecycle)를 확인하는 습관이 필요해요. 계정·리전·클라우드 플랫폼에 따라 다를 수도 있어요.

주요 제공사 설정 예시 (일부)

OpenAI — OpenAI Python SDK로 네이티브 통합돼요.

from crewai import LLM

llm = LLM(
    model="openai/gpt-5.6-terra",
    api_key="your-api-key",        # 또는 OPENAI_API_KEY 환경 변수
    reasoning_effort="medium",
    max_completion_tokens=4000
)

Anthropic (Claude) — Anthropic Python SDK로 네이티브 통합돼요. max_tokens은 필수 파라미터예요.

from crewai import LLM

llm = LLM(
    model="anthropic/claude-sonnet-4-6",
    api_key="your-api-key",   # 또는 ANTHROPIC_API_KEY
    max_tokens=4096           # Anthropic에서는 필수
)

Anthropic은 stop 대신 stop_sequences를 쓰고, 시스템 메시지를 대화와 분리해서 처리해요. 첫 메시지는 항상 사용자 메시지여야 하고, 메시지는 사용자-어시스턴트가 번갈아 와야 해요 (이건 자동으로 처리돼요).

Google (Gemini API) — Google Gen AI Python SDK로 네이티브 통합돼요.

from crewai import LLM

llm = LLM(
    model="gemini/gemini-3.6-flash",
    api_key="your-api-key",  # 또는 GOOGLE_API_KEY/GEMINI_API_KEY
    max_output_tokens=8192,
    stop_sequences=["END", "STOP"],
    stream=True,
    safety_settings={
        "HARM_CATEGORY_HARASSMENT": "BLOCK_NONE",
        "HARM_CATEGORY_HATE_SPEECH": "BLOCK_NONE"
    }
)

구조화된 출력 (Structured Outputs) — Pydantic 모델을 response_format으로 넘기면, LLM 출력을 자동으로 파싱·검증해 구조화된 Python 객체로 만들어 줘요. 수동 후처리가 줄어드는 게 큰 장점이에요.

from crewai import LLM
from pydantic import BaseModel

class Dog(BaseModel):
    name: str
    age: int
    breed: str

llm = LLM(model="openai/gpt-5.6-terra", response_format=Dog)

response = llm.call(
    "Analyze the following messages and return the name, age, and breed. "
    "Meet Kona! She is 3 years old and is a black german shepherd."
)
print(response)

# 출력:
# Dog(name='Kona', age=3, breed='black german shepherd')

실무 포인트: 구조화된 출력은 제공사와 모델에 따라 지원 여부가 달라요. 프로덕션에서 의존하기 전에 꼭 선택한 모델로 테스트해 보세요.

실무 관점: 스트리밍, 비동기, 컨텍스트 최적화

스트리밍 (Streaming)stream=True를 켜면 응답이 생성되는대로 조각(chunk) 단위로 전달돼요. 사용자 입장에서 더 반응성이 좋아져요. 각 조각마다 LLMStreamChunkEvent 이벤트가 발생하고, 리스너에서 이를 받아 처리할 수 있어요. 이벤트에는 에이전트·태스크 정보가 포함돼서, 특정 에이전트가 어떤 LLM 호출을 하는지 추적하고 감사(audit)하는 데 특히 유용해요.

from crewai import LLM

llm = LLM(
    model="openai/gpt-5.6-terra",
    stream=True  # 스트리밍 활성화
)

비동기 호출 (Async LLM Calls)acall 메서드를 쓰면 여러 LLM 요청을 블로킹 없이 동시에 실행할 수 있어요. 고처리량 애플리케이션이나 병렬 에이전트 작업에 적합해요.

import asyncio
from crewai import LLM

async def main():
    llm = LLM(model="openai/gpt-4o")
    # 단일 비동기 호출
    response = await llm.acall("What is the capital of France?")
    print(response)

asyncio.run(main())

acall은 동기 call이 지원하는 파라미터(messages, tools, callbacks 등)를 모두 그대로 지원해요.

컨텍스트 관리와 성능 최적화 — CrewAI는 토큰 카운팅·추적, 필요 시 요약, 큰 컨텍스트의 태스크 분할을 자동으로 처리해요. 작업 규모에 맞는 컨텍스트 윈도우 모델을 고르는 게 토큰 비용 최적화의 기본이에요.

  • 작은 작업(최대 4K 토큰): 표준 모델
  • 중간 작업(4K~32K): 향상된 모델
  • 큰 작업(32K 초과): 대형 컨텍스트 모델

드롭 파라미터 (drop_params) — CrewAI는 내부적으로 제공사 네이티브 SDK를 쓰기 때문에, 불필요한 추가 파라미터를 내려보낼 수 있어요. 예를 들어 stop 파라미터를 보내지 않으려면 이렇게 빼면 돼요.

from crewai import LLM
import os

os.environ["OPENAI_API_KEY"] = "<api-key>"

o3_llm = LLM(
    model="o3",
    drop_params=True,
    additional_drop_params=["stop"]
)

인터셉터 (Transport Interceptors) — OpenAI와 Anthropic 제공사에서 전송 계층에 훅을 걸어 요청/응답 주기를 가로챌 수 있어요. 메시지 변환·필터링, API 상호작용 디버깅에 유용해요. 단, 두 메서드 모두 받은 객체(또는 같은 타입의 객체)를 반환해야 하고, 받은 객체를 수정하면 예상치 못한 동작이나 크래시가 날 수 있어요.

자주 겪는 문제와 해결책

  1. 인증 문제 — 대부분 API 키 형식과 환경 변수 이름을 확인하면 해결돼요. (OpenAI는 OPENAI_API_KEY=sk-..., Anthropic은 ANTHROPIC_API_KEY=sk-ant-...)
  2. 모델 이름 — 모델 이름에는 반드시 제공사 접두사(prefix)를 붙여야 해요. gpt-4가 아니라 openai/gpt-4처럼요.
  3. 컨텍스트 길이 — 대규모 작업은 더 큰 컨텍스트 모델을 쓰는 게 좋아요. 예를 들어 openai/gpt-4o는 128K 토큰을 지원해요.

더 알아보기

원문: CrewAI 공식 문서 — LLMs