How AI Coding Tools Actually Work — A Developer’s Honest Take

I’ll be straight with you — when I first started using GitHub Copilot, I was a little suspicious of it. It felt too good. You start typing a function name and it just… finishes it. Correctly. Sometimes it writes twenty lines I would have written myself, almost word for word.

And then other times it confidently generates something that looks right, compiles fine, and silently does the wrong thing. I’ve shipped one of those. It wasn’t fun to debug.

So I started paying more attention to when it helps and when it doesn’t — and that pushed me to actually understand what’s going on under the hood. Not at the research-paper level, but enough to use these tools without being caught off guard by them.

This is what I wish someone had explained to me before I started relying on them.

What these tools actually are

AI coding tools like GitHub Copilot, ChatGPT, and Cursor are built on large language models — LLMs. The core idea behind an LLM is that it’s been trained on enormous amounts of text: documentation, Stack Overflow answers, GitHub repositories, tutorials, and more. Through that training, it learns statistical patterns — which tokens (words, characters, code symbols) tend to follow which other tokens.

That’s worth sitting with for a second. The model isn’t reasoning through your problem the way you are. It’s predicting what code is likely to come next based on everything it’s seen before. When it works, it’s because your problem looks like patterns it’s seen a thousand times. When it fails, it’s usually because your context is specific enough that those patterns don’t apply.

This is why Copilot is excellent at writing a useState hook or a forEach loop but sometimes bizarre when you ask it about a niche Magento 2 configuration or a custom internal API it’s never seen.

Why the suggestions feel so accurate

The reason completions feel eerily correct is that most code follows predictable conventions. If you name a function getUserById, there are only so many reasonable ways to implement it. The model has seen hundreds of variations of that function across GitHub. It’s not being clever — it’s pattern-matching against a huge training set.

Where this works really well: boilerplate, standard library usage, common patterns, familiar algorithms, converting between formats, writing tests for straightforward logic. Basically, anything that a junior developer could write correctly given enough Stack Overflow time.

Where it starts to struggle: anything involving your specific business logic, your internal APIs, nuanced error handling requirements, anything that requires understanding state across multiple files, or anything where the “right” answer depends on context the model doesn’t have.

Context is everything — and it’s limited

One thing that trips people up: LLMs have a context window. That’s the amount of text they can “see” at once when generating a response. For Copilot working inside your editor, the context is typically the current file and maybe a few related files, not your entire codebase.

This is why Copilot can write a perfect helper function in isolation but suggest something completely off when that function needs to interact with three other services it can’t see. It’s working with partial information and filling in the rest with assumptions based on training data.

When I started treating Copilot as a tool that can only see what’s directly in front of it — rather than a tool that understands my whole project — my expectations got a lot more realistic. And I stopped being surprised when it made assumptions I hadn’t asked it to make.

The hallucination problem is real

If you’ve used ChatGPT for coding help, you’ve probably run into this: it generates code that references a method or package that doesn’t exist. It’s completely confident about it. The error only shows up when you actually run the thing.

This happens because the model is optimising for plausible-sounding output, not for verifiable correctness. It doesn’t have access to your runtime. It can’t check whether a method actually exists in the version of the library you’re using. It’s extrapolating from patterns — and sometimes those extrapolations are wrong.

The fix is boring but important: always verify. If a model tells you to use a specific API method, check the documentation. If it writes a function that handles a critical path — user authentication, payment processing, data validation — review it like you’d review any external code. Because that’s essentially what it is.

What actually makes these tools worth using

Despite all of that, I use AI coding tools every day. Here’s where they genuinely earn their keep for me:

Speeding up the stuff I know how to do but don’t want to type. Writing SQL queries for straightforward CRUD operations, generating TypeORM entity boilerplate, setting up a basic Express route — Copilot handles these faster than I do and I trust the output because I know exactly what correct looks like.

First drafts of things I’ll rewrite. When I’m starting a new utility function or a component I haven’t built before, having a suggestion to react to is faster than staring at a blank file. Even if I rewrite 80% of it, that starting point saves time.

Explaining unfamiliar code. Pasting a confusing function into ChatGPT and asking “what does this do and why” is genuinely useful when you’re working in a codebase you didn’t write.

Writing tests. This one surprised me. AI tools are pretty good at generating unit tests for isolated functions because the pattern is consistent: arrange, act, assert. It’s not glamorous work, but it’s work I’d otherwise put off.

A note on prompt quality

The output quality of any AI coding tool scales directly with how well you describe what you want. Vague input gets vague output.

“Write a function to handle errors” gets you something generic. “Write a TypeScript function that catches fetch errors, logs them with the request URL and status code, and returns a typed error object with message and statusCode fields” gets you something you can actually use.

This is why I think of using these tools as a skill in itself. The developers I’ve seen get the most out of Copilot and ChatGPT aren’t the ones who treat it like magic — they’re the ones who’ve learned to give it precise, specific context about what they actually need.

Where I think this is going

Tools like Cursor and the latest Claude integrations are starting to work with broader project context — multiple files, terminal output, error messages. That addresses some of the limitations I mentioned above. The context window problem is getting better.

But the fundamental nature of these tools isn’t going to change: they’re pattern-matchers trained on existing code. They’re going to keep being excellent at things that look like things they’ve seen, and they’re going to keep struggling with genuinely novel problems.

Which means the most valuable skill isn’t learning to use AI tools — it’s developing the judgment to know when to trust them and when to verify.

That’s not a knock on the tools. It’s just an honest read of what they are.

If you’ve had a moment where Copilot saved you twenty minutes or confidently sent you down the wrong path for an hour — I’d genuinely like to hear which happens more often for you. Drop it in the comments.