cd /news/artificial-intelligence/from-software-engineer-to-ai-enginee… · home topics artificial-intelligence article
[ARTICLE · art-81009] src=dev.to ↗ pub= topic=artificial-intelligence verified=true sentiment=· neutral

From Software Engineer to AI Engineer - Part 1: A whole new world

A developer at a payments company introduces a series on AI engineering, building a real application called PayIQ—an assistant for merchants to perform payment operations. The series covers concepts like structured outputs, tool usage, agent loops, and evaluation, using Anthropic's models and LangChain libraries.

read10 min views1 publishedJul 30, 2026

You are a software engineer. Your craft honed through years of careful practice. Then suddenly, there are these chatbots and agents. Overnight, your colleagues got a new title on LinkedIn: "AI engineer". Some are already SENIOR AI engineers. You're curious about this new world, and might want to catch up and become part of it yourself.

If this is you, then join me on this tour through the concepts and patterns that make up the field of AI engineering. We will find that AI application development is mostly 'just' software engineering, applied to one genuinely strange new non-deterministic component: the LLM.

During the tour, we build a real application, end to end. Every article adds a new layer. We link the new patterns and words to existing software engineering concepts you already know.

Before take-off, I'd like to establish one vocabulary rule used throughout: "the model" means the LLM itself (large language model, like GPT or Claude), and what AI engineers build around it will be referred to as "the application", "the agent" or "the harness".

As I work at a payments company myself, I figured I'd stick to my domain. PayIQ, the application we build, is an assistant for merchants to perform payment operations: issue refunds, defend chargebacks, calculate processing fees. Give it a charge amount and a payment method, and it computes what a refund actually costs (spoiler: more than the refund amount). Ask it whether a chargeback is worth fighting, and it does the expected-value math using your knowledge base. Ask it something it can't responsibly answer, and it asks for what's missing. No guessing, no hallucinations.

By the end, PayIQ will have structured outputs that can be consumed by other systems, a tool belt of financial calculators, retrieval over a knowledge base, an agent loop with persistent memory, an orchestration graph with steps the model cannot skip, token streaming behind a FastAPI service, a regression eval suite, and layered injection defense. And don't worry if some of those words mean nothing to you. That's only a matter of time from here.

Each article is 10-15 minutes of reading and builds on the earlier ones deliberately (part 2's structured output is used in part 3's tool usage), so I suggest going through them sequentially. This first article lays the foundations and performs a simple interaction with the model.

A companion repository (https://github.com/BjornvdLaan/ai-engineering-articles-code-samples) contains all the code samples so that you can try it yourself as well. The examples use Anthropic's models. If you prefer a different provider (or locally hosted models) then I am sure your favorite chatbot can help adjust the configuration for you. No worries, LangChain's libraries are (mostly) model-agnostic.

Before getting into the code, let's build an accurate mental model of what models actually are. Not how neural networks or transformers work internally - we will leave that to smart scientists. What you as an aspiring AI engineer need is the operational mental model: what this thing consumes, what it costs, and what you can control. In its simplest form, a model is simply this interface:

f(list of input messages) -> output message

That's it. An important detail is that the input is a list of messages, not just the last prompt you gave. Each call to the model typically includes a system message ("application configuration"), the whole conversation so far ("the current state"), and the latest prompt. Given all these preceding messages, the model produces the next message in the conversation.

If you have used Codex, Claude Code or other "harnesses" then this might sound weird. You see it searching the internet, memorizing facts from previous sessions, keeping a todo list, reading documents you give it, writing and editing a codebase. All that magic is application logic built around the model by AI engineers, but all the model sees is just a list of input messages.

Messages are sent to a model as tokens, not characters or words. A component called a tokenizer first splits the text into tokens and assigns each a numeric token ID. Common words are often a single token, while uncommon words may be split into several. The model never sees the original text: it only processes these token IDs.

Besides serving as a unit of computation, tokens are also important because they are the unit of billing. You pay per input and output token. Treat tokens the way you treat compute-seconds in a cloud bill. An AI feature is the first kind of backend endpoint where the cost of a single request is large enough to care about. An agent that makes five model calls per user request costs real money at production traffic volumes. This is also a new security risk. Traditionally, a DDoS attack primarily consumed infrastructure resources (CPU, memory, bandwidth, and autoscaled instances). Now, every request may also consume billable tokens, adding a second, potentially much larger, cost component. The attack even has its own name: denial of wallet.

Each model has a maximum number of input tokens that it can process. This is called its context window, and can often hold hundreds of thousands of tokens. As discussed above, everything the model needs to answer a request must fit inside it: your system prompt, the conversation so far, retrieved documents, tool results, and any other context you provide. Think of it as the model's working memory. A larger context window lets you provide more information, but more context is not always better. As irrelevant information accumulates, the model has more distractions and important details become easier to miss. You will see this called context rot. More input tokens will also cost you more money! This is why "just paste everything in" doesn't scale: context engineering is about quality over quantity.

Now that we got some background info, it's time to see the model at work. This setup is needed once for all code samples throughout this series.

Prerequisites: Python 3.11+, an API key at your favorite provider, and not even five euros of credit for the whole series.

Create a new project directory (or clone the companion repo) and activate the Python virtual environment:

python3 -m venv .venv
source .venv/bin/activate

Create requirements.txt

:

langchain>=1.3,<2.0
langchain-core>=1.4,<2.0
langchain-text-splitters>=1.1,<2.0
langgraph>=1.2,<2.0
langgraph-swarm>=0.1
langchain-anthropic>=0.4
langchain-huggingface>=0.2
sentence-transformers>=3.0
langchain-mcp-adapters>=0.1
mcp>=1.9
fastapi>=0.115
uvicorn>=0.32
pydantic>=2.9
python-dotenv>=1.0

Most of these packages are for later parts (retrieval, MCP, the web layer), but installing them now means you never have to touch this file again.

Run pip install -r requirements.txt

, then create .env

in the project root. This is where you'll store the API key (and optionally other configuration):

ANTHROPIC_API_KEY=sk-ant-...

The API key for Anthropic is obtained from platform.claude.com.

Create 01_first_call.py

:

from dotenv import load_dotenv
from langchain.chat_models import init_chat_model

load_dotenv()

model = init_chat_model("anthropic:claude-sonnet-5")

response = model.invoke(
    "A customer is disputing a €480 online card payment, claiming they "
    "never made it. In two sentences, what are the two most important "
    "pieces of evidence I should gather before responding?"
)

print(response.content)
print("\n--- metadata ---")
print(response.usage_metadata)

Run it: python3 01_first_call.py

.

Two details to note in the code sample. First, init_chat_model

is LangChain's provider-agnostic constructor. The string "anthropic:claude-sonnet-5"

could also be "openai:gpt-5.5"

or "ollama:llama3.3"

with the rest of your application code staying the same. This is the same reason software engineers program against abstractions instead of concrete implementations: when you need to switch providers for cost, capability, or compliance reasons, you change configuration rather than redesign your system.

Second, look at usage_metadata

in the response. It shows input and output tokens for that call. These numbers determine the cost. Production AI systems monitor them the same way traditional applications monitor database queries, memory usage, and other resource consumption. You want a Grafana dashboard on these numbers.

Below is an example of what the output could be. We'll run it twice.

$ python3 01_first_call.py

The two most critical pieces of evidence are:

1. **Transaction authentication records** - Check whether the payment was verified through 3D Secure/Strong Customer Authentication (SCA), as successful two-factor authentication significantly shifts liability away from you and toward the cardholder or their bank.

2. **Delivery/fulfillment proof** - Gather evidence that the goods or services were delivered to the address or account linked to the cardholder, such as signed delivery confirmation, IP address logs, or account activity showing the customer used what was purchased.

--- metadata ---
{'input_tokens': 45, 'output_tokens': 119, 'total_tokens': 164, 'input_token_details': {'cache_read': 0, 'cache_creation': 0, 'ephemeral_5m_input_tokens': 0, 'ephemeral_1h_input_tokens': 0}}

$ python3 01_first_call.py

Pull the transaction's authentication data (AVS/CVV match results, and whether 3-D Secure/EMV 3DS was used with a successful cardholder authentication, e.g., SCA challenge completion) and the device/IP/geolocation and behavioral data captured at checkout (billing/shipping address match, device fingerprint, past purchase history from that account) to establish whether the legitimate cardholder likely completed the transaction. Also gather delivery confirmation or service usage records (proof of delivery, IP login after purchase, downloads, or usage logs tied to the account) to show the goods or services were actually received or accessed by the customer.

--- metadata ---
{'input_tokens': 57, 'output_tokens': 209, 'total_tokens': 266, 'input_token_details': {'cache_read': 0, 'cache_creation': 0, 'ephemeral_5m_input_tokens': 0, 'ephemeral_1h_input_tokens': 0}}

As you can see, running 01_first_call.py

a second time gives us a different answer. Ask it something it can't actually know, and it might invent an answer with total confidence. Both behaviors come from the same place: how the model produces text.

Models generate text one output token at a time. At each step, the model predicts a probability for every possible next token, samples one, appends it to the input, and repeats to get the next output token. Two consequences follow from that single mechanism, and both matter for everything we build after this.

The first is non-determinism. The model does not simply pick the most likely token every time. Rather, it samples from the distribution so the same input can produce a different output on the next call. How much freedom the sampling has, and whether you can influence it at all, differs per model. Some offer a temperature

setting. Working with this non-determinism is a key different with 'normal' software engineering.

The second is hallucination, the stories you've probably heard about models making things up. This traces back to how the model was built. Its designed to predict the next token, not to distinguish what is actually true. The model isn't retrieving facts; it's generating plausible text. If a question has a correct answer but the model lacks the necessary information, it may confidently produce a convincing but incorrect one. Model creators apply 'post-training' to teach the model to follow instructions, use specific formats, refuse some requests, and admit uncertainty more often. But it still does not give the model an internal fact checker.

Notice that these are two sides of the same coin: a model that samples plausible tokens rather than retrieving correct facts. The fix is usually not a better prompt. It is to build a system around the model that constrains its output and gives it the right information when correctness matters. That system is exactly what the rest of this series builds, and it's what AI engineers do.

Great job! You just took your first steps into AI engineering. We learned some theory and made our first model call. Obviously, this is not super useful yet. If your backend calls this model then you never know what kind of output to expect. The output message is unstructured and, therefore, cannot easily be parsed into an object like we do with JSON responses. The next article will do exactly that: making sure the model's output follows a structure that your code can count on.

── more in #artificial-intelligence 4 stories · sorted by recency
── more on @payiq 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/from-software-engine…] indexed:0 read:10min 2026-07-30 ·