# CrewAI

> Tokens-এ CrewAI-র agent আর crew চালান: custom base URL আর custom_openai-সহ LLM class, model ID কীভাবে লিখবেন, streaming, tool call, rate limit আর troubleshooting।

CrewAI একটা Python framework, যেখানে agent-রা একটা crew হয়ে একসাথে কাজ করে। প্রতিটা agent একটা `LLM` পায়, আর CrewAI সেই LLM-এর request যেকোনো OpenAI-compatible endpoint-এ পাঠাতে পারে। Tokens তেমনই একটা: CrewAI আপনার Tokens key দিয়ে OpenAI Chat Completions request পাঠায় `https://tokens.bd/v1`-এ।

যে জায়গাটায় সবাই আটকায় সেটা হলো model string। Tokens-এর model ID-র মধ্যে আগে থেকেই একটা slash থাকে (`provider/model`), আর CrewAI প্রথম slash-এর আগের অংশটাও পড়ে। কী লিখতে হবে তা পরের section-এ দেখানো হয়েছে।

:::note[কী কী যাচাই করা হয়েছে]
এই পেজ লেখা হয়েছে CrewAI-র LLMs documentation (docs.crewai.com, 2026 সালের অক্টোবরে দেখা) আর PyPI ও GitHub-এ থাকা `crewai` 1.15.27-এর source দেখে (release হয়েছে 9 অক্টোবর 2026-এ)। নিচের routing-এর নিয়মগুলো এসেছে ওই source-এর `llm.py` থেকে, কারণ documentation-এর পেজে সেগুলো লেখা নেই। Code-টা documentation আর source দেখে মেলানো হয়েছে, Tokens-এর বিরুদ্ধে শুরু থেকে শেষ পর্যন্ত চালিয়ে দেখা হয়নি।
:::

## যা যা লাগবে

- [API keys](/docs/api-keys) থেকে নেওয়া একটা Tokens key, `TOKENS_API_KEY` নামে export করা।
- [/models](/models) থেকে একটা model ID। আপনার agent tool ব্যবহার করলে এমন model নিন যা tool calling সাপোর্ট করে ([Choosing a model](/docs/choosing-a-model))।
- Python 3.10 থেকে 3.13 (CrewAI 1.15.27 লিখেছে `>=3.10,<3.14`)।

```bash
pip install crewai
export TOKENS_API_KEY="tok_live_your_key"
```

CrewAI-র docs `uv` দিয়ে install করতে বলে (command line tool-এর জন্য `uv tool install crewai`, project-এর ভেতরে `uv add crewai`)। সাধারণ script-এর জন্য `pip`-ও একইভাবে চলে। `crewai` আগে থেকেই `openai` package-এর ওপর নির্ভর করে, তাই এই setup-এ `litellm` extra লাগে না।

## LLM সাজান

```python title="llm.py"
import os
from crewai import LLM

llm = LLM(
    model="deepseek/deepseek-v4.1-flash",
    base_url="https://tokens.bd/v1",
    api_key=os.environ["TOKENS_API_KEY"],
    custom_openai=True,
    timeout=120,
    max_retries=2,
)
```

প্রতিটা অংশ কী করে:

| Setting                  | কেন                                                                                                                                                                                                                  |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `model`                  | Tokens-এর model ID, [/models](/models)-এ যেভাবে লেখা আছে ঠিক সেভাবে।                                                                                                                                                 |
| `base_url`               | `https://tokens.bd/v1`, `/v1`-সহ। CrewAI এটা OpenAI Python SDK-কে দিয়ে দেয়, আর SDK শেষে `/chat/completions` জুড়ে নেয়।                                                                                                  |
| `custom_openai=True`     | Model string দেখতে যেমনই হোক, এই LLM-এর জন্য CrewAI-কে তার নিজস্ব native OpenAI client ব্যবহার করতে বাধ্য করে। CrewAI-র নিজের gateway উদাহরণেও এটা আছে। এর সাথে custom endpoint-ও লাগে, তাই `base_url` দিতে ভুলে গেলে error আসে। |
| `timeout`, `max_retries` | Response-এর জন্য কত সেকেন্ড অপেক্ষা করবে আর কতবার retry করবে। CrewAI-র docs-এ দুটোই আছে। না দিলে OpenAI SDK-র default খাটে (10 মিনিট, 2 বার retry)।                                                                  |

### Model ID কীভাবে লিখবেন

`custom_openai=True` থাকলে Tokens-এর ID ঠিক catalog-এ যেমন আছে তেমনই লিখুন, আগে বাড়তি কোনো prefix ছাড়া। CrewAI শুরুর `openai/` থাকলে সেটা কেটে নেয়, বাকিটা না বদলে পাঠায়। তাই `deepseek/deepseek-v4.1-flash` Tokens-এ পৌঁছায় `deepseek/deepseek-v4.1-flash` হিসেবেই।

দুটো ক্ষেত্রে সাবধান থাকুন:

- **`custom_openai=True` বাদ দেবেন না।** এটা না থাকলে CrewAI প্রথম slash-এর আগের অংশটাকে provider-এর নাম ধরে। Tokens-এর কোনো ID এমন নামে শুরু হতে পারে যা CrewAI নিজের provider বলে চেনে (`deepseek/` তার একটা), আর তখন request Tokens-এ না গিয়ে সেই provider-এর client-এ চলে যায়। LiteLLM-এর ধরনে `model="openai/<tokens id>"` আর `base_url` দিলেও OpenAI client-এ পৌঁছানো যায়, কিন্তু `custom_openai=True` দিলে আন্দাজের কিছু থাকে না।
- **যে ID নিজেই `openai/` দিয়ে শুরু।** শুরুর `openai/` কেটে ফেলা হয়। Tokens-এর কোনো ID যদি নিজেই `openai/` দিয়ে শুরু হয়, তাহলে দুবার লিখুন: `model="openai/openai/<name>"`।

CrewAI-র LLMs পেজ বলে সবসময় provider prefix দিতে। Tokens-এর ID তো আগে থেকেই `provider/model`, তাই সেই নিয়ম মেটানো আছে। CrewAI-র নিজের custom-endpoint উদাহরণেও gateway-র ID এভাবেই দেওয়া হয়।

### বদলে environment variable ব্যবহার করুন

CrewAI `OPENAI_BASE_URL` আর `OPENAI_API_KEY`-ও পড়ে (এর docs-এ দুটোই আছে):

```bash
export OPENAI_BASE_URL="https://tokens.bd/v1"
export OPENAI_API_KEY="$TOKENS_API_KEY"
```

```python
from crewai import LLM

llm = LLM(model="deepseek/deepseek-v4.1-flash", custom_openai=True)
```

এই variable-গুলো পুরো shell জুড়ে খাটে। একই shell-এ OpenAI-ভিত্তিক অন্য যে tool-ই চলুক, তার traffic-ও Tokens-এ যাবে। `base_url` আর `api_key` code-এ দিলে বদলটা শুধু CrewAI-তেই সীমিত থাকে।

## ঠিকমতো চলছে কি না দেখুন

আগে agent ছাড়া শুধু LLM-টাকেই call করে দেখুন:

```python title="check.py"
from llm import llm

print(llm.call("Reply with the single word: ready"))
```

স্বাভাবিক একটা বাক্য ফেরত এলে বুঝবেন key, base URL আর model ID, তিনটেই ঠিক। Token খরচ না করে ID যাচাই করতে চাইলে catalog-টা list করুন:

```bash
curl -s https://tokens.bd/v1/models -H "Authorization: Bearer $TOKENS_API_KEY"
```

## ছোট্ট একটা crew

```python title="crew.py"
from crewai import Agent, Crew, Task
from llm import llm

reviewer = Agent(
    role="Python code reviewer",
    goal="Point out bugs and unclear names in short snippets",
    backstory="You review pull requests for a small team and keep feedback short.",
    llm=llm,
    max_iter=5,
)

task = Task(
    description="Review this function and list the problems:\n\ndef avg(xs): return sum(xs)/len(xs)",
    expected_output="A bullet list with at most three items.",
    agent=reviewer,
)

crew = Crew(agents=[reviewer], tasks=[task])
result = crew.kickoff()

print(result.raw)
print(crew.usage_metrics)
```

`result.raw` হলো চূড়ান্ত text। `crew.usage_metrics` ওই run-এর token count দেখায়। তবে Tokens-এ আপনার বিল কত হলো তা দেখবেন Dashboard-এর [usage পেজ](/docs/usage-and-alerts) থেকে, CrewAI-র সংখ্যা থেকে নয়।

`max_iter` ঠিক করে একটা agent উত্তর দেওয়ার আগে সর্বোচ্চ কয়টা reasoning ধাপ নিতে পারবে (CrewAI-র default 20)। প্রতিটা ধাপ মানে একটা request, আর Tokens সেটার বিল করে। তাই test করার সময় কম cap দিলে খরচও কম হয়।

## Response stream করুন

LLM-এ `stream=True` দিন:

```python
streaming_llm = LLM(
    model="deepseek/deepseek-v4.1-flash",
    base_url="https://tokens.bd/v1",
    api_key=os.environ["TOKENS_API_KEY"],
    custom_openai=True,
    stream=True,
)
```

CrewAI প্রতিটা chunk-এর জন্য একটা `LLMStreamChunkEvent` ছাড়ে। নিচের listener-টা CrewAI-র LLMs পেজের উদাহরণ:

```python
from crewai.events import BaseEventListener, LLMStreamChunkEvent

class MyCustomListener(BaseEventListener):
    def setup_listeners(self, crewai_event_bus):
        @crewai_event_bus.on(LLMStreamChunkEvent)
        def on_llm_stream_chunk(self, event: LLMStreamChunkEvent):
            print(f"Received chunk: {event.chunk}")

my_listener = MyCustomListener()
```

Crew চালানোর আগেই listener-টা বানিয়ে নিন। Streaming চালু থাকলে CrewAI Tokens-এর কাছে `stream_options.include_usage` চায়, তাই usage-এর সংখ্যাও আসে। Wire format-এর জন্য [Streaming](/docs/streaming) দেখুন।

## Tool call

`crewai.tools`-এর `@tool` আর `tools` argument দিয়ে agent-কে tool দিন:

```python
from crewai import Agent
from crewai.tools import tool
from llm import llm

@tool("Get weather")
def get_weather(city: str) -> str:
    """Current weather for a city. Use it when the user asks about the weather."""
    return f"{city}: light rain, 29C"

agent = Agent(
    role="Travel helper",
    goal="Answer weather questions for travellers",
    backstory="You know Bangladesh well.",
    llm=llm,
    tools=[get_weather],
)
```

Custom endpoint-এর জন্য function calling-এর আলাদা কোনো switch নেই। CrewAI-র source-এ OpenAI provider-এর `supports_function_calling()` সবসময় true ফেরত দেয়, শুধু o1-ধরনের model হলে দেয় না। তাই CrewAI tool পাঠায় OpenAI-র format-এ। Model সেগুলো ঠিকমতো ডাকবে কি না, সেটা নির্ভর করে model-এর ওপর: [/models](/models)-এ তার পেজ দেখুন আর পড়ুন [Tool calling](/docs/tool-calling)। কোনো model tool এড়িয়ে গেলে code বদলানোর আগে অন্য model চেষ্টা করুন।

## সীমা আর যা খেয়াল রাখবেন

- **প্রতি মিনিটের request।** একাধিক agent-এর crew অল্প সময়ে অনেক request ছুড়তে পারে। আপনার plan-এর সীমার নিচে থাকতে `Agent`-এ `max_rpm` দিন (CrewAI-র docs-এ এটাকে প্রতি মিনিটের request-এর cap বলা হয়েছে)। সীমা পেরোলে `429 rate_limited` আসে। দেখুন [Rate limits](/docs/rate-limits)।
- **Parallel task।** একসাথে চলা task-গুলো আপনার অ্যাকাউন্টের concurrent request-এর সীমার হিসাবে পড়ে আর `429 concurrency_limit` ফেরত আসতে পারে। Task-গুলো পরপর চালান, নয়তো parallelism কমান।
- **লম্বা generation।** Gateway একটা response-এর জন্য 600 সেকেন্ড পর্যন্ত অপেক্ষা করে। CrewAI-র `timeout` এর সমান বা কম রাখুন, আর খুব লম্বা output হলে `stream=True` দিন।
- **যা এখানে ধরা হয়নি।** CrewAI-র যে feature নিজে থেকে embeddings model ডাকে (memory, knowledge source), সেগুলো এই পেজে সাজানো হয়নি। Tokens embeddings চালায় ([Embeddings](/docs/embeddings)), কিন্তু ওই feature-গুলোকে একই endpoint-এ দেখিয়ে দেওয়ার কাজটা আপনাকেই করতে হবে।

## সমস্যা হলে

| লক্ষণ                                                                         | কারণ ও সমাধান                                                                                                                                                                           |
| ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ImportError: Unable to initialize LLM ... LiteLLM fallback package is not installed` | CrewAI তার OpenAI client বেছে নেয়নি, LiteLLM-এ fallback করেছে। `custom_openai=True` আর `base_url` দিন। `crewai[litellm]` install করলেও error থামে, কিন্তু তখন routing করে LiteLLM। |
| Error message-এ অন্য কোনো provider-এর API key-এর কথা                          | Model string CrewAI-র নিজের কোনো provider-এর সাথে মিলে গেছে। `custom_openai=True` দিন।                                                                                                   |
| `401 missing_api_key` বা `invalid_api_key`                                    | Key request-এ পৌঁছায়নি। `api_key=` সরাসরি দিন, আর crew যে process-এ চলছে সেখানে `TOKENS_API_KEY` set আছে কি না দেখুন। দেখুন [API keys](/docs/api-keys)।                               |
| `404 model_not_found`                                                         | ID ভুল, অথবা ID-র নিজের `openai/` অংশটা CrewAI কেটে দিয়েছে। [/models](/models) থেকে ID copy করুন; যে ID `openai/` দিয়ে শুরু, তাতে prefix-টা দুবার লিখুন।                              |
| `402 insufficient_credits`                                                    | Plan-এর credit আর Wallet মিলিয়েও request-এর খরচ কুলোচ্ছে না। [Billing](/dashboard/billing)-এ টাকা যোগ করুন। `max_iter` ধাপ পর্যন্ত চলা loop-এ credit দ্রুত শেষ হয়।                       |
| `429 rate_limited` বা `concurrency_limit`                                     | Request বেশি হয়ে গেছে। `max_rpm` দিন, task পরপর চালান, `Retry-After`-এ বলা সেকেন্ড অপেক্ষা করুন। `window_exhausted` মানে plan-এর একটা window শেষ, তাই reset না হওয়া পর্যন্ত retry করে লাভ নেই। |
| Timeout                                                                       | `LLM`-এ `timeout` বাড়ান, অথবা stream করুন। `504 upstream_timeout` আসে upstream থেকে, 600 সেকেন্ড পর। request ছোট করে দেখুন।                                                             |

সব code-এর তালিকা [Errors](/docs/errors) পেজে। [Support](/docs/support)-এর কাছে সাহায্য চাইলে `x-tokens-request-id` response header-টা সাথে দিন। এই পেজের উদাহরণগুলো response header দেখায় না, তাই ওটা পেতে call-টা একবার [cURL](/docs/curl) আর `-i` দিয়ে চালিয়ে নিন।

---
Page: https://tokens.bd/bn/docs/crewai
