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-এ দেখানো হয়েছে।
কী কী যাচাই করা হয়েছে
এই পেজ লেখা হয়েছে 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 থেকে নেওয়া একটা Tokens key,
TOKENS_API_KEYনামে export করা। - /models থেকে একটা model ID। আপনার agent tool ব্যবহার করলে এমন model নিন যা tool calling সাপোর্ট করে (Choosing a model)।
- Python 3.10 থেকে 3.13 (CrewAI 1.15.27 লিখেছে
>=3.10,<3.14)।
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 সাজান#
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-এ যেভাবে লেখা আছে ঠিক সেভাবে। |
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-এ দুটোই আছে):
export OPENAI_BASE_URL="https://tokens.bd/v1"
export OPENAI_API_KEY="$TOKENS_API_KEY"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 করে দেখুন:
from llm import llm
print(llm.call("Reply with the single word: ready"))স্বাভাবিক একটা বাক্য ফেরত এলে বুঝবেন key, base URL আর model ID, তিনটেই ঠিক। Token খরচ না করে ID যাচাই করতে চাইলে catalog-টা list করুন:
curl -s https://tokens.bd/v1/models -H "Authorization: Bearer $TOKENS_API_KEY"ছোট্ট একটা crew#
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 পেজ থেকে, CrewAI-র সংখ্যা থেকে নয়।
max_iter ঠিক করে একটা agent উত্তর দেওয়ার আগে সর্বোচ্চ কয়টা reasoning ধাপ নিতে পারবে (CrewAI-র default 20)। প্রতিটা ধাপ মানে একটা request, আর Tokens সেটার বিল করে। তাই test করার সময় কম cap দিলে খরচও কম হয়।
Response stream করুন#
LLM-এ stream=True দিন:
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 পেজের উদাহরণ:
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 দেখুন।
Tool call#
crewai.tools-এর @tool আর tools argument দিয়ে agent-কে tool দিন:
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-এ তার পেজ দেখুন আর পড়ুন Tool calling। কোনো model tool এড়িয়ে গেলে code বদলানোর আগে অন্য model চেষ্টা করুন।
সীমা আর যা খেয়াল রাখবেন#
- প্রতি মিনিটের request। একাধিক agent-এর crew অল্প সময়ে অনেক request ছুড়তে পারে। আপনার plan-এর সীমার নিচে থাকতে
Agent-এmax_rpmদিন (CrewAI-র docs-এ এটাকে প্রতি মিনিটের request-এর cap বলা হয়েছে)। সীমা পেরোলে429 rate_limitedআসে। দেখুন 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), কিন্তু ওই 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। |
404 model_not_found | ID ভুল, অথবা ID-র নিজের openai/ অংশটা CrewAI কেটে দিয়েছে। /models থেকে ID copy করুন; যে ID openai/ দিয়ে শুরু, তাতে prefix-টা দুবার লিখুন। |
402 insufficient_credits | Plan-এর credit আর Wallet মিলিয়েও request-এর খরচ কুলোচ্ছে না। 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 পেজে। Support-এর কাছে সাহায্য চাইলে x-tokens-request-id response header-টা সাথে দিন। এই পেজের উদাহরণগুলো response header দেখায় না, তাই ওটা পেতে call-টা একবার cURL আর -i দিয়ে চালিয়ে নিন।