🦙🧑‍🤝‍🧑Ollama와 CrewAI

Ollama는 로컬 환경에서 LLM을 실행하는 오픈소스 툴입니다. 지난 글에서 Docker로 Ollama와 Open-WebUI라는 툴을 실행해서 웹 브라우저로 로컬 LLM에게 질문을 해보는 튜토리얼을 진행한 적이 있었죠. (관련 블로그 글)

이번엔 Ollama와 CrewAI를 활용해서 로컬 LLM 기반으로 블로그 글을 작성해주는 시스템을 구축해보려합니다.

Ollama만으로도 충분히 블로그 글을 자동으로 작성할 수 있지 않냐고요? 물론 Ollama로 실행한 LLM에게 부탁해도 글을 써줍니다. 하지만 CrewAI라는 툴을 사용하면, 각자의 역할과 목표를 가지고 있는 여러 LLM 기반 작업자(에이전트)가 일련의 프로세스를 거쳐 더욱 체계적으로 글을 써줄 수 있거든요.

방금 이야기한 블로그 글 작성 시스템을 예로 들면서 알아보겠습니다. DevOps 관련 블로그 글을 쓸 때는 보통 아래와 같은 프로세스로 진행이 될 텐데요.

  1. 인터넷 자료 조사
  2. 조사한 내용을 토대로 글쓰기
  3. 작성한 글에 오탈자는 없는지 검수하기

이러한 각 과정을 수행하는 에이전트들을 둬서 서로 상호작용하며 작업을 수행하도록 시스템을 만드는 것이 CrewAI의 역할입니다.

게다가 CrewAI파이썬 기반으로 개발되었고 직관적인 명령어들을 사용하기 때문에, 쉽고 빠르게 여러 에이전트로 구성된(Multi-Agent) 작업 수행 시스템을 구축할 수 있다는 장점도 있습니다.

CrewAI에이전트는 역할, 목표, 배경으로 정의하는데요. 각 에이전트가 작업을 수행할 때 자신은 어떤 배경을 가지고 있고, 어떤 목표를 수행하는지 등을 미리 알려주는 거죠.

위의 블로그 글 작성 시스템으로 다시 돌아와서, 위에서 언급한 프로세스의 3가지 작업을 담당하는 CrewAI 에이전트들을 아래처럼 정의해보겠습니다.

  • 인터넷 자료 조사
    • 역할: Researcher
    • 목표: 최신 DevOps 관련 토픽 조사
    • 배경: IT 대기업에서 근무 중인 세계적인 Researcher
  • 글쓰기
    • 역할: Writer
    • 목표: DevOps 관련 블로그 글 작성
    • 배경: IT 관련 글 작성에 특화된 최고의 Technical Writer
  • 검수하기
    • 역할: Proofreader
    • 목표: 기술 블로그 글 검수
    • 배경: IT 분야에 특화된 유명 Proofreader

그리고 각 수행되어야 하는 작업도 아래와 같이 정의할 수 있습니다.

  • 최신 DevOps 관련 뉴스 조사
    • 담당 에이전트: Researcher
    • 출력물 설명: 약 3문단 분량의 최신 DevOps 관련 리포트
  • 조사 리포트를 기반으로 DevOps 관련 블로그 글 한 편 작성
    • 담당 에이전트: Writer
    • 출력물 설명: 약 4문단 분량의 Markdown 형식 DevOps 관련 블로그 글
  • 제공된 블로그 글을 보다 자연스럽게 검수
    • 담당 에이전트: Proofreader
    • 출력물 설명: 약 4문단 분량의 Markdown 형식 DevOps 관련 블로그 글

웹 접근 관련 유의사항 로컬 LLM을 사용하는 상황에서 웹 접근이 필요한 Researcher 같은 경우엔 Google search API 서비스 등을 별도로 이용해야 합니다.

그래서 이번 실습에선 카드 등록 없이 이메일 등록으로 최대 2,500회 Google Search 쿼리가 가능한 Serper 서비스를 이용했습니다.

🖥️Ollama와 CrewAI로 블로그 글 작성 시스템 구축하기

이제 로컬에서 직접 Ollama와 CrewAI를 실행해서 블로그 글 작성 시스템을 구축해보도록 하겠습니다. 각 툴은 Docker로 로컬에 배포합니다.

이번 실습에선 Ollama의 llama3(8b) 모델을 활용할 예정인데요. 그럴려면 먼저 Ollama를 이용해서 llama3 모델을 로컬에 가져와야겠죠.

Ollama의 모델이 저장될 공간인 Docker volume을 먼저 아래 명령어로 생성합니다.

docker volume create ollama-local

Docker volume을 생성했다면 이제 compose.yaml라는 이름의 Docker compose 파일을 생성하겠습니다. Docker compose는 여러 Docker 컨테이너의 배포 설정을 쉽게 관리하고 실행할 수 있도록 정의하는 파일인데요. 지금은 우선 Ollama에 대해서만 정의해보겠습니다.

compose.yaml
services:
  ollama:
    image: ollama/ollama:0.1.34
    container_name: ollama
    ports:
      - "11434:11434"
    volumes:
      - ollama-local:/root/.ollama #LLM이 저장될 Volume 지정
volumes:
  ollama-local:
    external: true

compose.yaml 작성이 끝나면 해당 파일이 있는 경로의 터미널에서 아래 명령어로 Docker compose를 실행하겠습니다. 지금은 Docker compose 파일에 정의되어 있는 Ollama만 실행되겠죠?

docker compose up -d

Ollama가 정상 실행되었다면 터미널에 아래처럼 표시가 될 겁니다.

이제 실행된 Ollama 컨테이너에 접속해서 우리가 사용할 llama3 LLM을 가져오겠습니다.

먼저 아래 터미널 명령어로 Ollama 컨테이너에 접속합니다.

docker exec -it ollama bash

접속한 터미널은 아래와 유사한 모습일 겁니다.

이 상태에서 아래 Ollama 명령어를 입력해서 공개된 원격 저장소에서 LLM을 가져옵니다.

ollama pull llama3:8b

위 명령어를 입력하면 아래처럼 LLM을 가져오는데요. 가져온 LLM은 처음에 생성했던 Docker volume ollama-local에 저장됩니다.

compose.yaml 파일에서 Ollama 컨테이너와 ollama-local volume 연동 설정을 넣어두었기 때문에, compose.yaml 파일로 실행하는 Ollama는 llama3:8b LLM을 계속 사용할 수 있게 됩니다.

Ollama로 LLM 설치는 완료되었으니, exit 명령어로 컨테이너에서 나옵니다.

이제 CrewAI를 Docker로 실행해볼 건데요. CrewAI는 파이썬 패키지이므로, 우리가 작성해야 할 파일은 아래와 같이 총 3가지입니다.

  • CrewAI를 Docker에서 실행하기 위한 Dockerfile(crewai.Dockerfile)
  • CrewAI 관련 설정과 정의 후 실행하는 Python 스크립트(main-crewai.py)
  • main-crewai.py 실행에 필요한 패키지를 정의한 requirements.txt
crewai.Dockerfile
FROM python:3.12.4
 
WORKDIR /app
COPY requirements.txt ./requirements.txt
RUN pip install -r requirements.txt
 
COPY main-crewai.py ./
 
CMD [ "python3", "-u", "main-crewai.py" ]
main-crewai.py
import os
from crewai import Agent, Task, Crew, Process
from crewai_tools import SerperDevTool
 
# 로컬에 실행 중인 ollama에서 원하는 LLM 가져옴. 예제에선 llama3 (파라미터 사이즈 8b) 사용
from langchain.llms import Ollama
ollama_model = Ollama(
    base_url='http://ollama:11434',
    model="llama3:8b")
 
os.environ["OTEL_SDK_DISABLED"] = "true"
 
# researcher Agent가 웹에 접근해서 최신 IT 정보를 찾을 수 있도록 server.dev API 서비스 이용
os.environ["SERPER_API_KEY"] = "{자신의 serper API key를 넣어주세요}"  # serper.dev API key
search_tool = SerperDevTool()
 
# crewai 패키지로 원하는 Agent의 역할(role)과 목표(goal) 설정
# 최신 DevOps 관련 토픽을 조사하는 Agent 정의
researcher = Agent(
    role='Researcher',
    goal='Discover a newest and attracting topic about DevOps',
    backstory="You're world class researcher working on a big IT company",
    verbose=True,
    allow_delegation=False,
    llm=ollama_model,
    tools=[search_tool]
)
 
# 블로그 글을 작성하는 Agent 정의
writer = Agent(
    role='Writer',
    goal='Create DevOps blog post',
    backstory="You're a best technical writer who is specialized on writing IT content",
    verbose=True,
    allow_delegation=False,
    llm=ollama_model
)
 
# 작성된 글을 검수하는 Agent 정의
proofreader = Agent(
    role='Proofreader',
    goal='Edit and proofread technical article',
    backstory="You're a famous proofreader who is specialized on IT domain",
    verbose=True,
    allow_delegation=False,
    llm=ollama_model
)
 
# 정의한 Agent들로 수행할 작업(Task) 정의
research_task = Task(
    description='Investigate the latest DevOps news',
    agent=researcher,
    expected_output = 'A comprehensive 3 paragraphs long report on the latest and famous DevOps.'
)
 
writing_task = Task(
    description='Write a blog post about DevOps with one topic provided from the researcher',
    agent=writer,
    expected_output='A 4 paragraph article about DevOps formatted as markdown.',    
)
 
proofreading_task = Task(
    description='Proofread the provided blog post to make more natural article',
    agent=proofreader,
    expected_output='A 4 paragraph article about DevOps formatted as markdown.',    
)
 
# 위 Agent와 Task, 작업 프로세스를 정의
crew = Crew(
  agents=[researcher, writer, proofreader],
  tasks=[research_task, writing_task, proofreading_task],
  llm=ollama_model,
  verbose=2, # crew 작업 중에 발생하는 로그의 자세한 정도를 설정 가능.
  process=Process.sequential # Task가 순차적으로 실행될 수 있도록 sequential로 정의.
)
 
# 정의한 crew 실행 및 작업 과정에서 발생하는 로그 출력
result = crew.kickoff()
print(result)
requirements.txt
crewai==0.32.0
crewai-tools==0.2.6
langchain==0.1.20

CrewAI 관련 파일 준비가 끝났다면, 아래 Docker 명령어로 CrewAI가 실행될 Docker 이미지를 생성합니다.

docker build -t my-crewai -f crewai.Dockerfile .

CrewAI Docker 이미지 빌드가 끝났다면, 위에서 정의했던 compose.yaml 파일을 아래와 같이 최신화합니다.

compose.yaml
services:
  ollama:
    image: ollama/ollama:0.1.34
    container_name: ollama
    ports:
      - "11434:11434"
    volumes:
      - ollama-local:/root/.ollama
  crewai:
    image: my-crewai
    container_name: crewai
    depends_on:
      - ollama
    extra_hosts:
      - "telemetry.crewai.com:127.0.0.1" # To avoid 'Connection to telemetry.crewai.com timed out' error when using local LLM
volumes:
  ollama-local:
    external: true

이제 터미널에서 아래 Docker compose 명령어를 입력하면, CrewAI의 각 에이전트가 작업을 수행하는 과정과 최종 결과물을 터미널에서 확인할 수 있습니다. (명령어 마지막에 docker compose down을 연결한 것은 CrewAI 작업이 모두 완료되면 OllamaCrewAI 컨테이너 모두 정상 종료시키기 위함입니다.)

docker compose up -d && docker compose logs crewai -f && docker compose down

🗂️CrewAI의 에이전트들의 작업 과정과 최종 생성 결과물

이렇게 실행한 CrewAI의 로그를 살펴보면, 각 에이전트가 일하는 과정을 로그로 확인할 수 있습니다.

또한 에이전트가 내놓은 최종 결과물도 확인할 수 있죠.

CrewAI의 Researcher 에이전트가 작성한 리포트를 토대로 Writer 에이전트가 블로그 글을 써주는 등, 각 에이전트가 미리 정의된 프로세스대로 상호작용하는 것을 보니 정말 흥미로웠는데요.😄

블로그 글 작성 외에도 CrewAI를 활용해서 어떤 작업 프로세스를 수행할 수 있을지 궁금해지네요.😊

References