Свое первое знакомство с JSON Crew Project (на Ubuntu 24.04 LTS Server + LLM ollama) я начал с дефолтного создания, как crewai create crew

mkdir ~/project

cd ~/project

crewai create crew ai

По содержимому AGENTS.md предполагается два способоа создания проекта: JSON & Classic

Но судя по содержимому файла AGENTS.md существует еще классическое создание проекта, где мастер самостоятельно формирует структуру файлов. Хочу попробовать, может это для меня будет проще. Хотя проще оно станет после того, как набьешь руку в настройке инструмента, а то сейчас я даже и не знаю, как подступиться к своим задумкам.

Шаг №1: Устанавливаю в систему Python3:

ekzorchik@srv-s2404a:~$ sudo apt install -y software-properties-common

ekzorchik@srv-s2404a:~$ sudo add-apt-repository ppa:deadsnakes/ppa

ekzorchik@srv-s2404a:~$ sudo apt install -y python3.13 python3.13-venv python3.13-dev

ekzorchik@srv-s2404a:~$ python3.13 --version

Python 3.13.15

На заметку: я не буду устанавливать crew через утилиту uv, а сделаю это в каталоге проекта через pip

Шаг №2: Создаю каталог под проект:

На заметку: Проект — это получение информации о времени работы текущей Linux-системы.

ekzorchik@srv-s2404a:~$ mkdir project

ekzorchik@srv-s2404a:~$ python3.13 -m venv ~/project/

ekzorchik@srv-s2404a:~$ cd project/

ekzorchik@srv-s2404a:~/project$ source bin/activate

(project) ekzorchik@srv-s2404a:~/project$

(project) ekzorchik@srv-s2404a:~/project$ python -V

Python 3.13.15

(project) ekzorchik@srv-s2404a:~/project$ python -m ensurepip --upgrade

Looking in links: /tmp/tmpstov2f3u

Requirement already satisfied: pip in ./lib/python3.13/site-packages (26.2.1)

(project) ekzorchik@srv-s2404a:~/project$

(project) ekzorchik@srv-s2404a:~/project$ python -m pip install --upgrade pip

Requirement already satisfied: pip in ./lib/python3.13/site-packages (26.2.1)

(project) ekzorchik@srv-s2404a:~/project$

(project) ekzorchik@srv-s2404a:~/project$ python -m pip install crewai

Шаг №3: Отобразить список установленных библиотек в виртуальном окружении:

(project) ekzorchik@srv-s2404a:~/project$ pip list

Шаг №4: Сохранить список всех установленных библиотек в requirements.txt

(crewai) ekzorchik@srv-s2404a:~/project$ python -m pip freeze > requiremenets.txt

Шаг №5: Где находится установленный crewai:

(project) ekzorchik@srv-s2404a:~/project$ whereis crewai

crewai: /home/ekzorchik/project/bin/crewai

(project) ekzorchik@srv-s2404a:~/project$ crewai --version

crewai, version 1.15.22

(project) ekzorchik@srv-s2404a:~/project$

Шаг №6: Базовое использование строится на строке:

crewai [COMMAND] [OPTIONS] [ARGUMENTS]

Шаг №7: Cоздаем классический шаблон:

(project) ekzorchik@srv-s2404a:~/project$ crewai create crew my --classic

Creating folder my... (команда сделала за тебя первоначальную структуру проекта.)

Select a provider to set up:

1. openai

2. anthropic

3. gemini

4. nvidia_nim

5. groq

6. huggingface

7. ollama

8. watson

9. bedrock

10. azure

11. cerebras

12. sambanova

13. other

q. Quit

Enter the number of your choice or 'q' to quit: 7

Select a model to use for Ollama:

1. ollama/llama3.1

q. Quit

Enter the number of your choice or 'q' to quit: 1

API keys and model saved to .env file

Selected model: ollama/llama3.1

- Created my/.gitignore

- Created my/pyproject.toml

- Created my/README.md

- Created my/knowledge/user_preference.txt

- Created my/src/my/__init__.py

- Created my/src/my/main.py

- Created my/src/my/crew.py

- Created my/src/my/tools/custom_tool.py

- Created my/src/my/tools/__init__.py

- Created my/src/my/config/agents.yaml

- Created my/src/my/config/tasks.yaml

hint: Using 'master' as the name for the initial branch. This default branch name

hint: is subject to change. To configure the initial branch name to use in all

hint: of your new repositories, which will suppress this warning, call:

hint:

hint:   git config --global init.defaultBranch <name>

hint:

hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and

hint: 'development'. The just-created branch can be renamed via this command:

hint:

hint:   git branch -m <name>

Initialized empty Git repository in /home/ekzorchik/project/my/.git/

Crew my created successfully!

(project) ekzorchik@srv-s2404a:~/project$

Т.е. внутри каталога project создается еще один каталог окружения проекта.

Шаг №8: С учетом действий выше сейчас у меня каркас:

Каркас проекта через Classic

src/my/crew.py — центральное место (Agent -> Task -> Crew)

src/my/main.py — точка запуска — он создалась мастером и в моем редактировании не нуждается.

Initialized empty Git repository in /home/ekzorchik/project/my/.git/ — создан Git-репозитарий

(project) ekzorchik@srv-s2404a:~/project$ cd my

Шаг №9: Обозначаю переменные окружения проекта:

(project) ekzorchik@srv-s2404a:~/project/my$ nano .env

MODEL=ollama/llama3.1:8b

API_BASE=http://localhost:11434

OPENAI_API_KEY=none

CREWAI_TRACING_ENABLED=false

Шаг №10: Небольшое пояснение себе по файлам:

(project) ekzorchik@srv-s2404a:~/project/my$ tree

.

├── AGENTS.md

├── CLAUDE.md

├── GEMINI.md

├── knowledge

│   └── user_preference.txt

├── pyproject.toml

├── README.md

├── src

│   └── my

│       ├── config

│       │   ├── agents.yaml

│       │   └── tasks.yaml

│       ├── crew.py

│       ├── __init__.py

│       ├── main.py

│       └── tools

│           ├── custom_tool.py

│           └── __init__.py

└── tests

7 directories, 13 files

(project) ekzorchik@srv-s2404a:~/project/my$

  • src/my/config/agents.yaml — здесь описываем агента
  • src/my/config/tasks.yaml  — здесь описываем задачу
  • src/tools/check_uptime.py — сюда создаем tools
  • src/crew.py — здесь подключаем tool к Agent

Шаг №11: Создаем инструмент (находиться будет в каталоге tools) взаимодействия crew с выполняемой задачей:

(project) ekzorchik@srv-s2404a:~/project/my$ nano src/my/tools/check_uptime.py

from crewai.tools import BaseTool

import subprocess

class CheckUptimeTool(BaseTool):

    name: str = "check_uptime"

    description: str = (

        "Информация о том как долго система работает"

    )

    def _run(self) -> str:

        result = subprocess.run(

            ["uptime", "-p"],

            capture_output=True,

            text=True,

            check=True,

        )

        return result.stdout.strip()

Шаг №12: Подключаем в crew.py агент:

(project) ekzorchik@srv-s2404a:~/project/my$ nano src/my/crew.py

from crewai import Agent, Crew, Process, Task

from crewai.project import CrewBase, agent, crew, task

from my.tools.check_uptime import CheckUptimeTool

@CrewBase

class My():

    """My crew"""

    agents: list[Agent]

    tasks: list[Task]

    @agent

    def check_uptime(self) -> Agent:

        return Agent(

            config=self.agents_config['check_uptime'],

            tools=[CheckUptimeTool()],

            verbose=True

        )

    @task

    def check_uptime_task(self) -> Task:

        return Task(

            config=self.tasks_config['check_uptime_task'],

        )

    @crew

    def crew(self) -> Crew:

        """Creates the My crew"""

        return Crew(

            agents=self.agents,

            tasks=self.tasks,

            process=Process.sequential,

            verbose=True,

        )

Шаг №13: Привожу для себя содержимое main.py — я его не редактировал — это мастер сам его создал:

(project) ekzorchik@srv-s2404a:~/project/my$ cat src/my/main.py

#!/usr/bin/env python

import sys

import warnings

from datetime import datetime

from my.crew import My

warnings.filterwarnings("ignore", category=SyntaxWarning, module="pysbd")

def run():

    """

    Run the crew.

    """

    inputs = {

        'topic': 'AI LLMs',

        'current_year': str(datetime.now().year)

    }

    try:

        My().crew().kickoff(inputs=inputs)

    except Exception as e:

        raise Exception(f"An error occurred while running the crew: {e}")

def train():

    """

    Train the crew for a given number of iterations.

    """

    inputs = {

        "topic": "AI LLMs",

        'current_year': str(datetime.now().year)

    }

    try:

        My().crew().train(n_iterations=int(sys.argv[1]), filename=sys.argv[2], inputs=inputs)

    except Exception as e:

        raise Exception(f"An error occurred while training the crew: {e}")

def replay():

    """

    Replay the crew execution from a specific task.

    """

    try:

        My().crew().replay(task_id=sys.argv[1])

    except Exception as e:

        raise Exception(f"An error occurred while replaying the crew: {e}")

def test():

    """

    Test the crew execution and returns the results.

    """

    inputs = {

        "topic": "AI LLMs",

        "current_year": str(datetime.now().year)

    }

    try:

        My().crew().test(n_iterations=int(sys.argv[1]), eval_llm=sys.argv[2], inputs=inputs)

    except Exception as e:

        raise Exception(f"An error occurred while testing the crew: {e}")

def run_with_trigger():

    """

    Run the crew with trigger payload.

    """

    import json

    if len(sys.argv) < 2:

        raise Exception("No trigger payload provided. Please provide JSON payload as argument.")

    try:

        trigger_payload = json.loads(sys.argv[1])

    except json.JSONDecodeError:

        raise Exception("Invalid JSON payload provided as argument")

    inputs = {

        "crewai_trigger_payload": trigger_payload,

        "topic": "",

        "current_year": ""

    }

    try:

        result = My().crew().kickoff(inputs=inputs)

        return result

    except Exception as e:

        raise Exception(f"An error occurred while running the crew with trigger: {e}")

(project) ekzorchik@srv-s2404a:~/project/my$

Шаг №14: Изменяем содержимое agents.yaml (убираем двух демонстративных агентов researcher и reporting_analyst и оставляем одного агента check_uptime, которому в crew.py мы уже подключили CheckUptimeTool()):

(project) ekzorchik@srv-s2404a:~/project/my$ nano src/my/config/agents.yaml

check_uptime:

  role: >

    Linux System Administrator

  goal: >

    Получить время работы текущей Linux-системы

  backstory: >

    Ты системный администратор Linux.

    Для получения времени работы системы используй инструмент check_uptime.

    Не придумывай значение uptime, а используй результат инструмента.

Шаг №15: Изменяем tasks.yaml под единственный инструмент tool:

(project) ekzorchik@srv-s2404a:~/project/my$ nano src/my/config/tasks.yaml

check_uptime_task:

  description: >

    Получи время работы текущей Linux-системы,

    используя инструмент check_uptime.

    Не придумывай результат, используй значение,

    которое вернул инструмент.

  expected_output: >

    Точное значение uptime, возвращённое инструментом check_uptime.

  agent: check_uptime

Здесь важно соответствие имен:

•   check_uptime_task → совпадает с self.tasks_config[‘check_uptime_task’] в crew.py

•   agent: check_uptime → совпадает с агентом check_uptime в agents.yaml

•   check_uptime → имя инструмента, который подключается через CheckUptimeTool() в crew.py

Шаг №16: Запускаем проект:

(project) ekzorchik@srv-s2404a:~/project/my$ crewai run

Результат запуска проекта часть 1

Результат запуска проекта часть 2

Отработало. Да это было не легко, и я до сих пор не понимаю пошаговость.

(project) ekzorchik@srv-s2404a:~/project/my$ deactivate

ekzorchik@srv-s2404a:~/project/my$ cd ~

ekzorchik@srv-s2404a:~$

Шаг №17: Обратил внимание что я же создал виртуальное окружение под Python3.13, а в выводе выше после запуска зацепил взглядом, то используется CPython 3.12.3

То есть происходит примерно так:

~/project/

└── bin/                 ← твоё активное venv, Python 3.13

└── crewai

 

~/project/my/

└── .venv/               ← CrewAI создал отдельное окружение

└── Python 3.12.3

(project) ekzorchik@srv-s2404a:~/project/my$ cat .venv/bin/p

pdf2txt.py       pybase64         pygmentize       pymupdf          pyproject-build  python3          pytube

pdfplumber       pydoc.bat        pyjson5          pypdfium2        python           python3.12

(project) ekzorchik@srv-s2404a:~/project/my$ .venv/bin/python3 --version

Python 3.12.3

(project) ekzorchik@srv-s2404a:~/project/my$

У меня сейчас две разные среды:

~/project/
└── bin/python        → Python 3.13

~/project/my1/
└── .venv/python      → Python 3.12.3

И crewai run выбирает ".venv" проекта.

Шаг №18: С учетом проанализированного, предполагаю, что лучше не заставлять crewai автоматически менять архитектуру, лучше создать проект и явно создать uv, какую среду использовать (чтобы из нее бралась используемая версия Python3.13), вот только переменные окружения ".env" нужно располагать в каталоге указанной в UV_PROJECT_ENVIRONMENT это стоит не забыть:

ekzorchik@srv-s2404a:~$ export UV_PROJECT_ENVIRONMENT="$HOME/project"

ekzorchik@srv-s2404a:~$ source ~/.bashrc

ekzorchik@srv-s2404a:~$ mkdir ~/project

ekzorchik@srv-s2404a:~$ python3.13 -m venv ~/project/

ekzorchik@srv-s2404a:~$ cd project/

ekzorchik@srv-s2404a:~/project$ nano .env

MODEL=ollama/llama3.1:8b

API_BASE=http://localhost:11434

OPENAI_API_KEY=none

CREWAI_TRACING_ENABLED=false

ekzorchik@srv-s2404a:~/project$ source bin/activate

(project) ekzorchik@srv-s2404a:~/project$ python -m ensurepip --upgrade

(project) ekzorchik@srv-s2404a:~/project$ python -m pip install --upgrade pip

(project) ekzorchik@srv-s2404a:~/project$ python -m pip install crewai

(project) ekzorchik@srv-s2404a:~/project$ crewai create crew my --classic

Creating folder my...

Select a provider to set up:

1. openai

2. anthropic

3. gemini

4. nvidia_nim

5. groq

6. huggingface

7. ollama

8. watson

9. bedrock

10. azure

11. cerebras

12. sambanova

13. other

q. Quit

Enter the number of your choice or 'q' to quit: 7

Select a model to use for Ollama:

1. ollama/llama3.1

2. ollama/mixtral

q. Quit

Enter the number of your choice or 'q' to quit: 1

API keys and model saved to .env file

Selected model: ollama/llama3.1

- Created my/.gitignore

- Created my/pyproject.toml

- Created my/README.md

- Created my/knowledge/user_preference.txt

- Created my/src/my/__init__.py

- Created my/src/my/main.py

- Created my/src/my/crew.py

- Created my/src/my/tools/custom_tool.py

- Created my/src/my/tools/__init__.py

- Created my/src/my/config/agents.yaml

- Created my/src/my/config/tasks.yaml

hint: Using 'master' as the name for the initial branch. This default branch name

hint: is subject to change. To configure the initial branch name to use in all

hint: of your new repositories, which will suppress this warning, call:

hint:

hint:   git config --global init.defaultBranch <name>

hint:

hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and

hint: 'development'. The just-created branch can be renamed via this command:

hint:

hint:   git branch -m <name>

Initialized empty Git repository in /home/ekzorchik/project/my/.git/

Crew my created successfully!

(project) ekzorchik@srv-s2404a:~/project$

(project) ekzorchik@srv-s2404a:~/project$ cd my

(project) ekzorchik@srv-s2404a:~/project/my$ python --version

Python 3.13.15

(project) ekzorchik@srv-s2404a:~/project/my$

Вот что я хотел, чтобы все было стандартизировано

ну а дальше берем наполнение из выше представленных шагов.

Короче я пока не знаю, что лучше делать самим или использовать мастер. Ладно продолжаю свое изучение crewai.

На этом пока все, с уважением автор блога ekzorchik.