Skip to content

Chapter 2 · Environment Setup and First Crew ​

Chapter goals: Install CrewAI and configure model access, write a minimal sequential crew with two roles (researcher → writer), run it with kickoff(), and learn to read the execution log.

2.1 Installing CrewAI ​

CrewAI officially recommends managing environments with uv. First confirm Python version meets >=3.10 and ❤️.14:

bash
python3 --version        # Must be between 3.10 and 3.13

# Install uv (macOS / Linux)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install the crewai CLI (includes the framework itself)
uv tool install crewai

# Verify
crewai version

If you prefer the traditional approach, you can also install CrewAI directly into a project virtual environment with pip:

bash
python3 -m venv .venv && source .venv/bin/activate
pip install crewai

Version note

The official docs require underlying openai >= 1.13.3 (even if you're using a third-party compatible endpoint, CrewAI internally reuses the openai SDK's transport layer). If you hit dependency conflicts, upgrade pip first, then install.

2.2 Configuring Third-Party Model Credentials ​

Per course conventions, we use DeepSeek (any OpenAI-compatible service works the same way). Create a .env file in the project root:

bash
# .env — never commit real credentials to git
DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxx

Then read them in code via environment variables. Using python-dotenv to auto-load .env is the easiest approach:

python
# config.py — unified credential loading entry point
from dotenv import load_dotenv   # pip install python-dotenv
import os

load_dotenv()  # Reads .env from current directory and injects into environment

DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")
assert DEEPSEEK_API_KEY, "Please configure DEEPSEEK_API_KEY in .env first"

.env can also be loaded manually via export; the scaffold project in Chapter 17 auto-generates a .env template.

2.3 Verify Model Connectivity First ​

Before writing a crew, confirm the third-party endpoint actually works with 20 lines of code — ruling out key and network issues first makes debugging far more efficient than jumping straight into the framework:

python
# ping_llm.py — minimal connectivity test (no agent involved)
import os
from crewai import LLM

llm = LLM(
    model="openai/deepseek-chat",
    base_url="https://api.deepseek.com/v1",
    api_key=os.getenv("DEEPSEEK_API_KEY"),
)

print(llm.call("Introduce yourself in one sentence"))
# If it prints a response, all three — key, base_url, and model id — are correct

llm.call(prompt) is CrewAI's lowest-level LLM interface, bypassing the agent loop entirely for a direct conversation. It is also the standard approach for diagnosing model-layer issues.

2.4 First Two-Role Crew ​

Create my_first_crew.py: a "researcher" who summarizes key points, and a "writer" who expands those points into a short essay.

python
import os
from crewai import Agent, Task, Crew, Process, LLM

# 1) Third-party OpenAI-compatible model
deepseek = LLM(
    model="openai/deepseek-chat",
    base_url="https://api.deepseek.com/v1",
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    temperature=0.7,
)

# 2) Role 1: Researcher
researcher = Agent(
    role="Senior Industry Researcher",
    goal="Summarize 5 most valuable key points about the given topic",
    backstory="You have ten years of tech industry research experience, "
              "skilled at quickly grasping trend essences, "
              "and your output is always concise, structured, and free of fluff.",
    llm=deepseek,
    verbose=True,            # Prints execution trace — strongly recommended during learning
)

# 3) Role 2: Technical Writer
writer = Agent(
    role="Science Writer",
    goal="Rewrite the researcher's points into an accessible short essay",
    backstory="You are a well-known tech column author who excels at explaining "
              "complex concepts to零基础 readers.",
    llm=deepseek,
    verbose=True,
)

# 4) Task list: executed in definition order under sequential mode
research_task = Task(
    description="Research topic '{topic}' and summarize 5 key points.",
    expected_output="A numbered list of 5 key points, each no more than 30 characters.",
    agent=researcher,
)

write_task = Task(
    description="Based on the researcher's points, write a ~300-word introductory essay.",
    expected_output="A Markdown-formatted essay with a title and three subsections.",
    agent=writer,
)

# 5) Assemble and execute
crew = Crew(
    agents=[researcher, writer],
    tasks=[research_task, write_task],
    process=Process.sequential,   # Default value; written explicitly for clarity
    verbose=True,
)

result = crew.kickoff(inputs={"topic": "AI Agents"})
print("===== Final Result =====")
print(result.raw)

Run:

bash
export DEEPSEEK_API_KEY=sk-xxx
python my_first_crew.py

2.5 Understanding the kickoff Execution Process ​

With verbose=True enabled, the terminal prints sequentially:

  1. Task assignment: Working Agent: Senior Industry Researcher — which agent is currently executing;
  2. Raw output: the full LLM reply for that task;
  3. Task handoff: the first task's output is automatically injected into the second task's context;
  4. Token stats: after completion, token usage for this run is printed.

Key observations:

  • The {topic} placeholder was replaced by the value from inputs={"topic": ...} — this is CrewAI's template interpolation mechanism; both description and expected_output support it;
  • expected_output is not just decorative: it gets written into the prompt and directly affects output format and quality — write it carefully;
  • The last task's output becomes the entire Crew's output (result.raw).

Since definition and data are separated, the same crew can be reused with a different topic:

python
# One definition, multiple runs: only swap inputs
for topic in ["Large Model Inference Optimization", "Multi-Agent Collaboration"]:
    result = crew.kickoff(inputs={"topic": topic})
    print(f"[{topic}] -> {result.raw[:50]}...")

2.6 Common First-Run Error Troubleshooting ​

SymptomCauseFix
401 UnauthorizedAPI key not loaded or incorrectCheck that the env var name is DEEPSEEK_API_KEY
404 model not foundMissing /v1 in base_url or wrong model idDeepSeek endpoint must be https://api.deepseek.com/v1
Stuck with no outputVerbose not enabled, looks frozenAdd verbose=True to both Agent and Crew
Messy output formatexpected_output too vagueSpecify hard format requirements like "numbered list" or "Markdown"

2.7 Chapter Summary ​

  • Installation: official recommendation is uv tool install crewai, Python must be in the 3.10–3.13 range;
  • Third-party model integration: three件套 — model="openai/deepseek-chat" + base_url + api_key from environment variables;
  • Minimal crew five steps: define LLM → define Agents → define Tasks → assemble Crew → kickoff(inputs=...);
  • verbose=True is your eyes during learning; expected_output determines output quality; previous task output flows automatically into the next task.

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. In sequential flow, can the second Task see the first Task's output?

2. How does topic in inputs={"topic": "AI"} take effect?

3. When accessing OpenAI-compatible endpoints like DeepSeek, what should base_url be?

4. Regarding expected_output, which statement is correct?

🛠️ Hands-On Exercises ​

  1. Change this chapter's crew topic to something you're interested in, and change the writer's backstory to "rigorous academic editor" — compare the output style difference.
  2. Add a third role reviewer (proofreader) with a new review task: receive the article and produce a list of suggested revisions.
  3. Intentionally set DEEPSEEK_API_KEY to an empty value and run once; record the error message. Then intentionally omit /v1 from base_url and observe the behavior. Write both errors into your notes.

Your first Crew is running. Next, we deep dive into Agent role design methodology to make every角色 truly "stand out."