OpenAI Agents SDK হলো agent বানানোর জন্য OpenAI-র library। এখানে একটা Agent-এ instructions আর tool দেওয়া থাকে, আর সেটা চালায় একটা Runner। SDK model-এর সাথে কথা বলে OpenAI API দিয়ে, তাই https://tokens.bd/v1 ঠিকানায় সে Tokens-এও পৌঁছাতে পারে। শুধু দুটো default পথে বাধা হয়, দুটোই সহজে ঠিক করা যায়। এক, আলাদা করে না বললে SDK Responses API ডাকে। দুই, model ID-তে slash থাকলে সে সেটাকে provider/model ধরে নেয়। Tokens-এর প্রতিটা model ID-তেই slash আছে, তাই এই পেজে দুটো জিনিসই কীভাবে সাজাতে হয় দেখানো হয়েছে।
Documentation-এর সাথে মিলিয়ে দেখা
এই গাইড OpenAI Agents SDK-র documentation থেকে নেওয়া। October 2026-এ মিলিয়ে দেখা হয়েছে Python package openai-agents 0.23.1 (প্রকাশ 2 October 2026) আর TypeScript package @openai/agents 0.20.0-এর সাথে। code-টা documentation আর SDK-র নিজের উদাহরণের সাথে মিলিয়ে দেখা হয়েছে, Tokens-এর বিরুদ্ধে শুরু থেকে শেষ পর্যন্ত চালিয়ে দেখা হয়নি। SDK দ্রুত বদলায়। তাই আপনার version-এর সাথে কিছু না মিললে official docs দেখে নিন।
যা যা লাগবে#
- API keys থেকে নেওয়া একটা Tokens key, যেটা
TOKENS_API_KEYনামে export করা। - /models থেকে একটা model ID, যেমন
deepseek/deepseek-v4.1-flash। Agent tool ডাকে, তাই এমন model নিন যেটা tool calling সাপোর্ট করে (Choosing a model)। - Python package-এর জন্য Python 3.10 বা তার পরের version। TypeScript package-এ নিজের client দিলে
openaipackage-এর version 7.2 বা তার পরের হতে হবে।
export TOKENS_API_KEY="tok_live_your_key"কেন default বদলাতে হয়#
| SDK-র default | Tokens-এ কী হয় | সমাধান |
|---|---|---|
| Responses API ব্যবহার করে | Tokens /v1/responses পাস করে দেয়, কিন্তু সেটা চলে শুধু তখনই যখন model-এর পেছনের provider নিজে এটা সাপোর্ট করে (Responses)। Chat Completions সব model-এ চলে। | OpenAIChatCompletionsModel নিন, অথবা set_default_openai_api("chat_completions") দিন। |
prefix/name-কে provider prefix ধরে নেয় | SDK-র documentation বলছে, অচেনা prefix হলে UserError ওঠে, আর openai/... হলে slash-এর পরের অংশটুকু রেখে বাকিটা ছেঁটে দেওয়া হয়। deepseek/deepseek-v4.1-flash-এর মতো Tokens ID এই নিয়মে আটকে যায়। | model object দিন, custom ModelProvider ব্যবহার করুন, অথবা prefix mode বদলে দিন। |
| Trace OpenAI-তে upload করে | Trace চলে OpenAI-র server-এ, আর তার জন্য OpenAI key লাগে। Tokens key দিলে upload-এ 401 হয়, যা আপনার log-এ দেখা যাবে। | Tracing বন্ধ করুন। |
SDK-র documentation এগুলো রেখেছে "non-OpenAI models" অংশে। যে provider-এ Responses নেই, সেখানে সে Chat Completions ব্যবহার করতে বলে। আর স্পষ্ট বলে, অচেনা prefix pass-through হয় না, UserError ওঠে।
Python: Chat Completions model object ব্যবহার করুন#
শুরুতে এই setup-টাই নিন। Tokens-এর দিকে তাক করা একটা AsyncOpenAI client বানাতে হবে, সেটাকে OpenAIChatCompletionsModel-এ মুড়ে agent-এর হাতে দিতে হবে। Agent model-এর নাম (string) না পেয়ে একটা model object পায়, তাই SDK model ID parse করে না। ফলে slash নিয়ে কোনো সমস্যাই হয় না।
pip install --upgrade openai-agentsimport asyncio
import os
from openai import AsyncOpenAI
from agents import Agent, OpenAIChatCompletionsModel, Runner, set_tracing_disabled
set_tracing_disabled(True) # traces would go to OpenAI; see the Tracing section
client = AsyncOpenAI(
base_url="https://tokens.bd/v1",
api_key=os.environ["TOKENS_API_KEY"],
)
agent = Agent(
name="Reviewer",
instructions="You are a concise senior engineer. Answer in at most three sentences.",
model=OpenAIChatCompletionsModel(model="deepseek/deepseek-v4.1-flash", openai_client=client),
)
async def main() -> None:
result = await Runner.run(agent, "When should I use a dataclass instead of a dict?")
print(result.final_output)
asyncio.run(main())base_url-এর শেষে /v1 রাখুন। model string-টা Tokens-এ যেমন লেখা তেমনই যায়, তাই সেটা /models-এর কোনো ID-র সাথে বা GET https://tokens.bd/v1/models-এর সাথে হুবহু মিলতে হবে।
Python: এক জায়গা থেকে সব agent-এর model ঠিক করুন#
অনেক agent থাকলে RunConfig-এর ভেতর দিয়ে একটা custom ModelProvider দিন। তাহলে পুরো run-এ একই model setup খাটে, আর Agent object-এ সাধারণ model নামই রাখা যায়। এটা SDK-র নিজের custom_example_provider.py উদাহরণ মেনে লেখা।
import asyncio
import os
from openai import AsyncOpenAI
from agents import (
Agent,
Model,
ModelProvider,
OpenAIChatCompletionsModel,
RunConfig,
Runner,
set_tracing_disabled,
)
set_tracing_disabled(True)
client = AsyncOpenAI(
base_url="https://tokens.bd/v1",
api_key=os.environ["TOKENS_API_KEY"],
)
class TokensModelProvider(ModelProvider):
def get_model(self, model_name: str | None) -> Model:
# The name arrives untouched, slash included.
return OpenAIChatCompletionsModel(
model=model_name or "deepseek/deepseek-v4.1-flash",
openai_client=client,
)
agent = Agent(
name="Assistant",
instructions="You are a helpful assistant.",
model="deepseek/deepseek-v4.1-flash",
)
async def main() -> None:
result = await Runner.run(
agent,
"Name two uses for asyncio.Semaphore.",
run_config=RunConfig(model_provider=TokensModelProvider()),
)
print(result.final_output)
asyncio.run(main())RunConfig শুধু ওই একটা Runner.run call-এর জন্য খাটে। এটা ছাড়া run করলে request চলে OpenAI-র নিজের endpoint-এ, আর OPENAI_API_KEY যা সেট করা আছে সেটাই ব্যবহার হয়।
বিকল্প: global client#
SDK-তে একটা global default-ও আছে। সব agent-ই Tokens ব্যবহার করবে, এমন হলে এটাই সবচেয়ে ছোট setup:
import os
from openai import AsyncOpenAI
from agents import set_default_openai_api, set_default_openai_client, set_tracing_disabled
set_default_openai_client(
AsyncOpenAI(base_url="https://tokens.bd/v1", api_key=os.environ["TOKENS_API_KEY"]),
use_for_tracing=False,
)
set_default_openai_api("chat_completions")
set_tracing_disabled(True)এই setup-এও model="deepseek/deepseek-v4.1-flash"-এর মতো সাধারণ string চলে যায় SDK-র default MultiProvider-এর ভেতর দিয়ে, আর সে প্রথম slash-এ ভেঙে ফেলে। Slash-এর আগের অংশটা SDK-র চেনা কোনো provider নয়, তাই default আচরণ হলো UserError: Unknown prefix ছোঁড়া। আর prefix যদি openai হয়, SDK কোনো শব্দ না করে শুধু slash-এর পরের অংশটা পাঠায়। Global setup-এর সাথে model string ব্যবহার করতে চাইলে provider নিজে বানান আর তাকে বলে দিন পুরো ID রেখে দিতে:
import os
from agents import MultiProvider, RunConfig
provider = MultiProvider(
openai_base_url="https://tokens.bd/v1",
openai_api_key=os.environ["TOKENS_API_KEY"],
openai_use_responses=False, # Chat Completions
openai_prefix_mode="model_id", # keep a leading "openai/" as part of the id
unknown_prefix_mode="model_id", # keep any other "provider/" as part of the id
)
run_config = RunConfig(model_provider=provider)openai_prefix_mode আর unknown_prefix_mode SDK-তে আছে openrouter/openai/gpt-4.1-mini-র মতো namespace-ওয়ালা ID কোনো OpenAI-compatible backend-এ পাঠানোর জন্য। তবে model object বা ওপরের ModelProvider-এর মতো সহজ পথে এই প্রশ্নটাই ওঠে না, তাই ওগুলোকেই বেছে নিন।
Note
use_for_tracing=False দিলে SDK এই client-এর key (মানে আপনার Tokens key) দিয়ে OpenAI-তে trace upload করা বন্ধ করে। এর default True। এই argument-টার কথা আছে SDK-র source docstring-এ, তার guide পেজগুলোতে নেই। তাই যে version install করছেন তার সাথে মিলিয়ে নিন।
Tracing: বন্ধ করে দিন#
SDK default-ভাবে trace OpenAI-র server-এ upload করে। OpenAI platform key না থাকলে agent ঠিকমতো চললেও log-এ 401 error আসতে থাকে। Documentation-এ tracing বন্ধ করার তিনটে উপায় আছে:
| কতটুকু জায়গা জুড়ে | কীভাবে |
|---|---|
| পুরো process | set_tracing_disabled(True), অথবা environment variable OPENAI_AGENTS_DISABLE_TRACING=1 |
| একটা run | RunConfig(tracing_disabled=True) |
Tracing চালু রেখে শুধু upload-এর জন্য আলাদা একটা OpenAI key দিতে চাইলে set_tracing_export_api_key(...) আছে। সেই key আনতে হবে platform.openai.com থেকে। ওটা আপনার Tokens key নয়, আর তখন আপনার prompt trace data হয়ে OpenAI-তে চলে যাবে। Prompt গোপন হলে tracing বন্ধই রাখুন।
Tool#
Agent-কে দিন type hint আর docstring-ওয়ালা Python function। এগুলো থেকেই SDK tool-এর schema বানিয়ে নেয়।
import asyncio
import os
from openai import AsyncOpenAI
from agents import (
Agent,
OpenAIChatCompletionsModel,
Runner,
function_tool,
set_tracing_disabled,
)
set_tracing_disabled(True)
client = AsyncOpenAI(
base_url="https://tokens.bd/v1",
api_key=os.environ["TOKENS_API_KEY"],
)
@function_tool
def get_weather(city: str) -> str:
"""Current weather for a city.
Args:
city: The city to look up.
"""
return f"{city}: light rain, 29C" # replace with a real lookup
agent = Agent(
name="Weather helper",
instructions="Use the tool when the user asks about the weather.",
model=OpenAIChatCompletionsModel(model="deepseek/deepseek-v4.1-flash", openai_client=client),
tools=[get_weather],
)
async def main() -> None:
result = await Runner.run(agent, "Do I need an umbrella in Dhaka?")
print(result.final_output)
asyncio.run(main())প্রকাশিত package-এ decorator-টার নাম function_tool। SDK-র নতুন documentation একই decorator import করে from agents.decorators import tool দিয়ে, যেটা ওর alias। যে version মিলিয়ে দেখা হয়েছে তাতে দুটোই চলে।
প্রতিটা tool call মানে Tokens-এ আরেকটা request। তাই কয়েক রাউন্ড tool চললে কয়েকটা request খরচ হয়, আর সেগুলো আপনার rate limits-এর হিসাবে পড়ে। Tool calling-এর জন্য এমন model লাগে যেটা তা সাপোর্ট করে (Tool calling)।
SDK-র documentation-এ কিছু tool আছে যেগুলো শুধু Responses API-তে চলে (যেমন ToolSearchTool), আর বলা আছে Chat Completions backend সেগুলো ফিরিয়ে দেয়। Web search বা file search-এর মতো hosted tool চলে OpenAI-র নিজের দিকে, তাই Tokens দিয়ে সেগুলো পাওয়া যায় না।
Output stream করুন#
Runner.run_streamed এমন একটা result দেয় যার ওপর loop চালিয়ে event পাওয়া যায়। SDK-র documentation-এ দেওয়া text streaming-এর loop এটাই:
import asyncio
import os
from openai import AsyncOpenAI
from openai.types.responses import ResponseTextDeltaEvent
from agents import Agent, OpenAIChatCompletionsModel, Runner, set_tracing_disabled
set_tracing_disabled(True)
client = AsyncOpenAI(
base_url="https://tokens.bd/v1",
api_key=os.environ["TOKENS_API_KEY"],
)
agent = Agent(
name="Writer",
instructions="You write short, plain answers.",
model=OpenAIChatCompletionsModel(model="deepseek/deepseek-v4.1-flash", openai_client=client),
)
async def main() -> None:
result = Runner.run_streamed(agent, input="Write a haiku about merge conflicts.")
async for event in result.stream_events():
if event.type == "raw_response_event" and isinstance(event.data, ResponseTextDeltaEvent):
print(event.data.delta, end="", flush=True)
print()
asyncio.run(main())Stream শেষ না হওয়া পর্যন্ত পড়তে থাকুন। Iterator শেষ না হলে run-ও শেষ হয় না। SDK-র streaming পেজে এই loop দেখানো হয়েছে default setup-এর জন্য। OpenAIChatCompletionsModel-এ একই রকম চলবে কিনা সেটা সেখানে বলা নেই, তাই আপনার model দিয়ে একবার test করে নিন। আরও দেখুন Streaming।
Tokens-এর stream-এ token-এর হিসাব আসে শুধু তখনই, যখন request-এ সেটা চাওয়া হয়। Chat Completions-এ এর জন্য SDK-তে ModelSettings(include_usage=True) field আছে (documentation অনুযায়ী field-টা শুধু Chat Completions-এ পাওয়া যায়)। agents থেকে ModelSettings import করুন আর দিন এভাবে: Agent(..., model_settings=ModelSettings(include_usage=True))।
কোনো provider streaming-এর সময় ভাঙা tool-call-এর টুকরো পাঠালে SDK-র একটা option আছে, MultiProvider-এ openai_buffer_streamed_tool_calls=True, যেটা সেগুলো জমিয়ে রাখে।
TypeScript#
TypeScript package-এর নাম @openai/agents। এর peer dependency হিসেবে zod 4 লাগে, আর নিজের client দিলে openai package-ও (version 7.2 বা তার পরের)।
npm install @openai/agents zod openaiimport OpenAI from "openai";
import {
Agent,
OpenAIChatCompletionsModel,
run,
setTracingDisabled,
tool,
} from "@openai/agents";
import { z } from "zod";
setTracingDisabled(true);
const client = new OpenAI({
apiKey: process.env.TOKENS_API_KEY,
baseURL: "https://tokens.bd/v1",
});
const getWeather = tool({
name: "get_weather",
description: "Current weather for a city",
parameters: z.object({ city: z.string() }),
async execute({ city }) {
return `${city}: light rain, 29C`; // replace with a real lookup
},
});
const agent = new Agent({
name: "Weather helper",
instructions: "Use the tool when the user asks about the weather.",
model: new OpenAIChatCompletionsModel(client, "deepseek/deepseek-v4.1-flash"),
tools: [getWeather],
});
const result = await run(agent, "Do I need an umbrella in Dhaka?");
console.log(result.finalOutput);OpenAIChatCompletionsModel-এর একটা instance দিলে ওই agent Chat Completions-এই থাকে, আর model ID parse হয় না। SDK-র নিজের উদাহরণে আরও দুটো পথ আছে: setOpenAIAPI("chat_completions")-এর সাথে setDefaultOpenAIClient(client) দিয়ে global পথ, আর OpenAIProvider({ openAIClient: client }) দিয়ে new Runner({ modelProvider }) পথ। এই পথগুলো slash-ওয়ালা model নাম কীভাবে সামলায়, TypeScript documentation-এ তা বলা নেই। তাই ওপরের model object-টাই ব্যবহার করুন।
Node-এ text stream করতে:
const stream = await run(agent, "Write a haiku about merge conflicts.", { stream: true });
stream.toTextStream({ compatibleWithNodeStreams: true }).pipe(process.stdout);
await stream.completed;Tracing বন্ধ করা যায় ওপরের মতো setTracingDisabled(true) দিয়ে, অথবা OPENAI_AGENTS_DISABLE_TRACING=1 দিয়ে। এই code চালান server-এ বা CLI-তে, browser bundle-এ নয়। Tokens CORS header পাঠায় না, আর যে-ই dev tools খুলবে সে-ই আপনার key দেখে ফেলবে।
ঠিকমতো চলছে কিনা দেখুন#
python agent.py চালান। Terminal-এ ছোট একটা উত্তর ছাপা হলে বুঝবেন key, base URL আর model ID ঠিক আছে। এরপর Dashboard-এ Usage analytics খুলে request-টা খুঁজুন। Call ফেল করলে আগে cURL দিয়ে endpoint test করুন। সেখানে 200 আসছে অথচ agent-এ ফেল করছে, তাহলে সমস্যা SDK setup-এ, key-তে নয়।
Model বাছাই#
Agent ঘুরতে থাকে: tool ডাকে, result পড়ে, আবার ডাকে। তাই model-কে tool call ভালো সামলাতে হবে আর লম্বা context ধরে রাখতে হবে। কিছু model সাধারণ chat-এ ঠিক উত্তর দেয়, কিন্তু tool-এ ফেল করে। কোন model agent-এর কাজে মানায়, তা Choosing a model-এ আছে, আর /models-এ প্রতিটা model-এর পেজে দেখা যায় তার context window কত আর tool সাপোর্ট করে কিনা। প্রতিটা উত্তরের দৈর্ঘ্যে সীমা দিতে চাইলে ModelSettings-এর মধ্য দিয়ে max_tokens সেট করুন। কয়েক রাউন্ড tool চললে অনেক token যেতে পারে, তাই agent-কে যে key দেবেন তাতে spend cap বসিয়ে দিন (API keys)।
সীমাবদ্ধতা আর যা চলে না#
- শুধু Responses-এ চলে এমন feature। Hosted tool (web search, file search, code interpreter),
previous_response_idআর Responses-only বাকি field Chat Completions পথে পাওয়া যায় না। Strict validation চালু না করলে SDK ওই field-গুলো চুপচাপ বাদ দিয়ে দেয় (OpenAIProvider-এstrict_feature_validation=True,MultiProvider-এopenai_strict_feature_validation=True)। - Structured output। SDK
json_schemaresponse format পাঠায়। Tokens ID-র পেছনের model সেটা সাপোর্ট না করলে upstream request ফিরিয়ে দেয়400(invalid_request) দিয়ে। Structured output সাপোর্ট করে এমন model নিন (Structured output)। - Audio আর Realtime। Audio output চাইলে Chat Completions adapter
AgentsException("Audio is not currently supported")ছোঁড়ে। Realtime আর voice agent-এর জন্য OpenAI-র নিজের endpoint লাগে, সেগুলো Tokens দিয়ে চলে না। - Tracing। Trace যায় OpenAI-তে, Tokens-এ নয়, আর Tokens key দিয়ে সেগুলো upload করা যায় না।
finish_reason="length"-এ খালি উত্তর। Model যদি কিছু output না দিয়েই length limit-এ থেমে যায়, adapterModelBehaviorErrorছোঁড়ে। এটা token বা reasoning budget-এর সমস্যা।max_tokensবাড়ান, নয়তো এমন model নিন যার লুকানো reasoning কম।
সমস্যা হলে#
UserError: Unknown prefix: <first part of your model id>। Model-টা agent-কে string হিসেবে দেওয়া হয়েছে, আর SDK-র default provider slash-এর আগের অংশটাকে provider prefix ধরে নিয়েছে। OpenAIChatCompletionsModel object দিন, ওপরের ModelProvider ব্যবহার করুন, নয়তো MultiProvider-এ unknown_prefix_mode="model_id" দিন।
404 model_not_found। হয় ID-তে বানান ভুল, নয়তো SDK শুরুর openai/ কেটে দিয়েছে। Tokens usage log-এর ID-র সাথে আপনি যেটা পাঠাতে চেয়েছিলেন সেটা মিলিয়ে দেখুন, আর GET https://tokens.bd/v1/models-এর সাথেও যাচাই করুন।
/v1/responses থেকে 404 বা 400। SDK এখনও Responses API-তেই আছে। OpenAIChatCompletionsModel ব্যবহার করুন, অথবা set_default_openai_api("chat_completions") দিন।
api.openai.com থেকে 401 error, বা log-এ "incorrect API key", অথচ agent উত্তর দিচ্ছে। এগুলো trace upload-এর error। Tracing বন্ধ করুন।
Tokens থেকে 401 invalid_api_key। TOKENS_API_KEY-এর key ভুল, নয়তো revoke করা। /dashboard/keys-এ গিয়ে নতুন একটা বানান।
402 insufficient_credits, 403 model_not_allowed_on_key, 429 window_exhausted। এগুলো অ্যাকাউন্টের সীমার ব্যাপার, SDK-র সমস্যা নয়। দেখুন Errors আর Troubleshooting। Agent একসাথে অনেক request ছুড়লে 429 concurrency_limit লাগতে পারে। তখন parallelism কমান (Rate limits)।
Error আসে SDK exception হয়ে। SDK OpenAI client-কে মুড়ে রাখে, তাই Tokens-এর error আসে openai exception হিসেবে। e.code আর e.response.headers.get("x-tokens-request-id") পড়ুন, আর support-এর সাথে যোগাযোগের সময় request id-টা দিয়ে দিন।