
Ask in a Python-heavy forum which language to learn for building AI agents, and the answer is Python, without hesitation. Ask the same question where JavaScript developers hang out, and TypeScript comes back just as fast. Both sides have real projects to point to, and both are right in a way that makes the actual answer more useful than picking a side.
You don't need a special “AI language” to build an agent. Python and TypeScript both work well, and the right choice usually comes down to where the agent needs to run and what surrounds it, not which one is “better for AI.” Beyond the language, what actually matters is an SDK to talk to the model, somewhere to store and search knowledge once you need retrieval, and a way to see what the agent's tools are doing in production. Frameworks like LangChain or LlamaIndex are optional scaffolding on top of that, not a requirement.
The Language Question: Python or TypeScript
An agent loop — read the message, ask the model, run a tool, feed the result back — is ordinary application code. It doesn't need a training loop, doesn't touch a GPU, doesn't require anything Python has that TypeScript lacks or the other way round. What tips the decision is context, not the language itself.
Python is the default if you're already doing anything data-heavy around the agent: processing embeddings by hand, building a dataset, running things in a notebook, or working alongside libraries that only exist in Python's ecosystem. It's also usually the first language any new model feature ships examples in.
TypeScript (or plain JavaScript) is the pragmatic pick when the agent has to live inside something you're already building in Node — a Next.js API route, a Discord bot, a browser extension, a backend that's already TypeScript end to end. Bridging two runtimes just to add an agent to an existing Node app is extra operational weight for no real benefit.
Go and Rust show up too, mostly for the pieces around the agent rather than the loop itself — a high-throughput orchestration service, or a tool executor where every millisecond matters. Neither is a beginner's first choice for this.

The One Non-Negotiable: The SDK
Every agent needs exactly one required piece of tooling: an SDK that can call the model and hand back structured tool-call requests. Anthropic ships an official client for both ecosystems — @anthropic-ai/sdk for TypeScript, anthropic for Python — and every example throughout this series has used the TypeScript one. Nothing else on this list is required. A working agent is a language plus this one library plus the loop you write yourself.
Orchestration Frameworks: Useful, Just Not on Day One
LangChain, LlamaIndex, CrewAI, the Vercel AI SDK — these exist to save you from re-writing the same loop, memory handling, and retry logic on every project, and for a team shipping several agents they earn their place. The cost is an abstraction layer between you and what's actually happening in each request.
Building the raw loop first, the way every post in this series has, means that once you do reach for a framework, you can tell exactly what it's doing for you and what it's hiding. Reaching for one before that point usually means debugging the framework's behavior instead of the agent's.
The Rest of the Toolbox
flowchart TD
L[Pick a language: Python or TypeScript] --> S[Add the official SDK for that language]
S --> O[Optional orchestration framework on top]
S --> V[A place to store and search knowledge]
S --> G[Logging for every tool call]
O --> D[Deploy as a server or a script]
V --> D
G --> DFlow summary: Everything starts with a language and its official SDK. An orchestration framework is optional on top of that, while a knowledge store and per-call logging sit alongside it, and all three eventually need somewhere to actually run.
A handful of supporting pieces round out a real setup:
- A knowledge store, once retrieval matters — anything from an array with a similarity function for learning the mechanism, up to a proper vector database for production, as covered in the RAG post.
- Secrets management — the API key lives in an environment variable or your host's secret manager, never committed to the repository.
- A way to test without spending real API calls — every code example across this series so far has been verified by swapping the real client for a small scripted fake that returns fixed responses, which is exactly how you'd unit test an agent's logic without hitting the network on every run.
- Logging — a record of which tool was called, with what arguments, and what came back, for every step. Without it, a wrong answer in production is a guess instead of a lookup.
- A deployment target — a long-running server if the agent needs to hold state between requests, or a serverless function if each call is independent and short.
Two Languages, One Loop
The clearest way to compare Python and TypeScript for this is to write the exact same minimal agent in both and put them side by side. Both need only ANTHROPIC_API_KEY set to run.
TypeScript — install with npm install @anthropic-ai/sdk, save as agent/minimal-agent.ts, run with npx tsx agent/minimal-agent.ts:
// agent/minimal-agent.ts
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic();
const times: Record<string, string> = { Dhaka: '11:45 PM', London: '6:45 PM' };
const tools: Anthropic.Tool[] = [
{
name: 'get_time_in_city',
description: 'Get the current local time in a named city.',
input_schema: {
type: 'object',
properties: { city: { type: 'string' } },
required: ['city'],
},
},
];
function execute(name: string, input: { city: string }): unknown {
if (name === 'get_time_in_city') return { time: times[input.city] ?? 'unknown city' };
return { error: 'unknown tool' };
}
async function runAgent(question: string): Promise<string> {
const messages: Anthropic.MessageParam[] = [{ role: 'user', content: question }];
for (let step = 0; step < 4; step++) {
const response = await client.messages.create({
model: 'claude-sonnet-5',
max_tokens: 300,
tools,
messages,
});
messages.push({ role: 'assistant', content: response.content });
if (response.stop_reason !== 'tool_use') {
const block = response.content.find((b): b is Anthropic.TextBlock => b.type === 'text');
return block?.text ?? '';
}
const results: Anthropic.ToolResultBlockParam[] = [];
for (const block of response.content) {
if (block.type === 'tool_use') {
results.push({
type: 'tool_result',
tool_use_id: block.id,
content: JSON.stringify(execute(block.name, block.input as { city: string })),
});
}
}
messages.push({ role: 'user', content: results });
}
return 'Stopped: step limit reached';
}
runAgent('What time is it in Dhaka?').then(console.log);
Python — install with pip install anthropic, save as agent/minimal_agent.py, run with python agent/minimal_agent.py:
# agent/minimal_agent.py
from anthropic import Anthropic
client = Anthropic()
times = {"Dhaka": "11:45 PM", "London": "6:45 PM"}
tools = [
{
"name": "get_time_in_city",
"description": "Get the current local time in a named city.",
"input_schema": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
}
]
def execute(name, tool_input):
if name == "get_time_in_city":
return {"time": times.get(tool_input["city"], "unknown city")}
return {"error": "unknown tool"}
def run_agent(question):
messages = [{"role": "user", "content": question}]
for _ in range(4):
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=300,
tools=tools,
messages=messages,
)
messages.append({"role": "assistant", "content": response.content})
if response.stop_reason != "tool_use":
for block in response.content:
if block.type == "text":
return block.text
return ""
results = []
for block in response.content:
if block.type == "tool_use":
results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": str(execute(block.name, block.input)),
})
messages.append({"role": "user", "content": results})
return "Stopped: step limit reached"
print(run_agent("What time is it in Dhaka?"))
Line for line, they do the same four things: define one tool, execute it locally, loop until the model stops asking for tools, and return the text. Nothing about the agent's behavior changes between them.

What Actually Differs Between Them
Porting this exact loop from TypeScript to Python for this post, the difference that stood out wasn't syntax — it was how each language handles not knowing a block's exact type yet. In the TypeScript version, response.content.find((b): b is Anthropic.TextBlock => b.type === 'text') is a type predicate: once that line passes, the compiler knows block has a .text property, and autocomplete works before the code ever runs. In the Python version, block.text on a text block just works too, but nothing checks it ahead of time — if I called .text on a block that turned out to be a tool-use block, I'd only find out by running it and hitting an AttributeError. Neither is wrong. TypeScript catches that class of mistake before you run anything; Python catches it the moment you do.
Common Mistakes When Choosing Tools
- Picking a language based on “what's best for AI” instead of what the agent needs to run inside. The agent loop doesn't care. Your deployment target and existing codebase do.
- Reaching for a framework before writing the raw loop once. You lose the ability to tell what the framework is actually doing versus what it's hiding from you.
- Skipping logging until something breaks in production. By then you're reconstructing what happened from memory instead of reading it back.
- Treating the vector database as day-one infrastructure. Most agents don't need one until retrieval is actually part of the plan — an array works fine until it doesn't.
What's Next
The language and the SDK get an agent running locally. Making it follow a multi-step plan reliably, instead of reacting one tool call at a time, is worth its own post.
Frequently Asked Questions
Should I just pick whichever language I already know?
In almost every case, yes. The agent loop is regular application code, not machine learning code, so your existing language is usually the right start. Switch only for a specific reason — an existing Python data pipeline the agent needs to sit next to, or a requirement that it live inside a Node web app.
Do I need LangChain or a similar framework to get started?
No, and it often helps to wait. Build the raw loop with the official SDK first, the way every example in this series has, so you understand exactly what a framework would be doing for you before you add one.
Is Python actually better for AI agents than TypeScript?
Not for the agent loop itself — they're close to equivalent, as the side-by-side example shows. Python pulls ahead when data tooling matters: embeddings math, datasets, notebooks. TypeScript pulls ahead when the agent has to live directly inside a web app or an existing Node service.
Need a High-Performance Web App or Custom AI Solution?
I help founders, businesses, and engineering teams build lightning-fast web applications, resilient backend architectures, and intelligent AI workflows. Have an idea in mind? Let’s bring it to life.
Found this article helpful?
Give some claps to support more in-depth engineering logs!
Zahid Hasan Tonmoy
Author & Developer
MERN Full Stack Developer & AI Agent Developer based in Dhaka, Bangladesh. Writing about web development, React, PostgreSQL and my learning journey.