Why Python?
Estimated time: about 12 min.
The problem this module solves
Open a job posting for "AI agents", a recent book on the subject, or a popular tutorial: the code is very often in Python. For a .NET developer, the implicit message is clear — AI happens elsewhere, and you'll have to change language, tooling, and ecosystem to be part of it.
This module examines that reflex before writing a single line of code. Not to say that Python is a bad choice, but to tell apart two jobs that get lumped together under the same word, "AI" — and to show that the one that consists of building an agent is a job you already do.
Two jobs behind the word "AI"
Training a model is the work of research and data science teams: preparing massive datasets, computing on GPUs, tuning billions of parameters. That's where Python became the standard, with libraries such as NumPy and PyTorch and Jupyter notebooks. On that ground, Python is the sensible choice.
Building an agent is something else. The model already exists, hosted by a provider or on a machine you control. You don't modify it: you call it. The work consists of:
- sending an HTTP request containing the conversation and the list of available tools;
- reading a JSON response;
- deciding what to do with that response: display some text, or run a tool;
- sending the result back to the model, and starting over until you get a final answer;
- handling everything that can go wrong along the way.
HTTP requests, JSON deserialization, calls into business code, error handling: that's the daily routine of a .NET application developer. None of these steps depends on a scientific computing library.
What an exchange with an LLM actually looks like
Here, in a simplified, provider-independent form, is what an agent sends to the model:
{
"messages": [
{ "role": "user", "content": "Where is my order 4512?" }
],
"tools": [
{
"name": "getOrder",
"description": "Retrieves the status of an order from its number",
"parameters": { "orderId": "integer" }
}
]
}
And what the model may answer:
{
"type": "tool_call",
"name": "getOrder",
"arguments": { "orderId": 4512 }
}
The model has no access to your order database: it asks for the tool to be called. It's your program that runs getOrder 4512, adds the result to the conversation, and sends everything back to the model; the model then writes its final answer to the customer.
Remember this split, it structures the entire course:
| Step | Who does it? |
|---|---|
| Deciding that a tool is needed, choosing its arguments | the model |
| Running the tool | your code |
| Sending the result back to the model | your code |
| Writing the final answer from that result | the model |
| Deciding when to stop, and what to do if something goes wrong | your code |
All the "intelligence" sits behind the API. Everything else — the request, execution, response cycle — is ordinary application code.
The hidden cost of switching to Python
For a .NET team, adopting Python for this orchestration work isn't free:
- a second environment to master (Python versions, virtual environments, package manager);
- a second build, test, and deployment pipeline to maintain;
- a bridge to build to the existing business code, which stays in .NET;
- a skill to hire for or train, for a gain that doesn't address the heart of the problem.
And the tooling you need exists on the .NET side. In this course, you'll use three building blocks, all available on NuGet: Microsoft's Microsoft.Extensions.AI abstraction, designed so that your code doesn't depend on any particular model provider; the OllamaSharp library, which plugs it into a local model; and the official C# SDK for the MCP protocol, which you'll use in module 9.
And why F# rather than C#?
This whole course could be written in C#. But three properties of F# fit an agent's work particularly well:
- Lightweight scripts. An
.fsxfile run withdotnet fsiloads a NuGet package in one line, with no project and noMain. It's the "I'll try an idea in ten lines" experience that made Python successful, without leaving .NET. - Types that describe the possible cases. On every turn, the model's response is either a final text, or one or more tool call requests, or something unusable. Discriminated unions express exactly this "either… or…", and the compiler flags the case you forgot to handle.
- Errors that are part of the type. An LLM can get things wrong: request a tool that doesn't exist, forget an argument, send truncated JSON.
OptionandResultturn these failures into values that the code must handle, rather than exceptions discovered in production.
To give you an idea of where this is going, here's the type you'll meet in module 7 — no need to understand it in detail right now:
type AgentStep =
| FinalAnswer of text: string
| CallTools of calls: (string * Result<ToolCall, ToolError>) list
| InvalidResponse of reason: string
Three cases, and the compiler will warn you about any function that forgets one.
What Python keeps
This course doesn't claim that F# replaces Python everywhere. If your work consists of training or fine-tuning a model, doing heavy exploratory data analysis, or reusing a research library published only in Python, stay with Python: that's its ground.
The question to ask yourself is simple: am I making the model, or am I using it? In the second case — that of most application projects that "add AI" — your .NET stack is already ready.
Exercise — classify the tasks
For each of the following tasks, decide whether it falls under training a model (where Python is relevant) or building an agent (where .NET is enough), and write down the deciding reason: are the model's weights modified, or is the model only consumed?
- Fine-tuning an open-source model on 200,000 historical support tickets.
- Connecting a hosted LLM to the existing order-tracking API.
- Exposing the product catalog to an AI assistant through an MCP server.
- Measuring the quality of an assistant's answers on a set of 50 reference questions.
- Comparing three neural network architectures on an image dataset.
Write down your five answers before reading on.
Answers
- Training — the model's weights are modified: Python tooling.
- Agent — the model is called; the rest is HTTP and existing business code.
- Agent — this is precisely the subject of module 9.
- Agent — this is the trick question: the word "quality" evokes data science, but the model isn't modified. Sending 50 requests and comparing the answers to expectations is an automated test like any other.
- Training — research on the models themselves.
If you got task 4 wrong, remember the criterion rather than the vocabulary: it's not the topic ("quality", "AI", "data") that decides, it's the question "do the weights change?".
The common thread of this course
Throughout the following modules, you'll build an e-commerce support assistant able to answer "where is my order?". It will call an LLM, decide when to look up the orders, cleanly handle the model's aberrant responses, add guardrails against failures, then expose its tool through MCP.
What you just did
You told training a model apart from building an agent, saw that an exchange with an LLM boils down to HTTP requests and JSON where the model asks and your code runs, and identified what makes F# a good fit for this work: lightweight scripts, types that enumerate the possible cases, and errors handled as values.
In the next module, you get hands-on: you install a local model with Ollama, then a few-line .fsx script sends your first question to that LLM, with no project, no Main — and no Python.
Check your understanding
A bank wants an assistant "personalized for each customer": for every conversation, its code reads the customer's profile (language, preferred tone, products held) from the existing database and inserts it into the message sent to a hosted model. What kind of work is this?
Of these four projects, which one genuinely justifies adopting Python tooling?
A travel assistant receives "Do I need an umbrella in Lyon tomorrow?". The model answers `{"type":"tool_call","name":"getForecast","arguments":{"city":"Lyon","day":"tomorrow"}}`. What happens next?
Want to hear about the next modules?
The Academy stays free and open-access, no sign-up required. If you'd just like to be notified by email when a new module ships, here you go — no obligation, unsubscribe anytime with one click.