How To Integrate AI Into Any Workflow
The secret to seamlessly integrating AI into almost any workflow isn't a secret at all. In fact, it's so fundamental and obvious that people overlook it. There seems to be a tendency to think that because AI is new and different, that we must use it differently than other tools. But that's not the case. AI is essentially just a tool, and like any other tool, there are a few right ways to use it, and an almost infinite number of wrong ways.
The secret: Inputs and outputs
There's a saying that's as old as the field of computer science itself: garbage in, garbage out. If you feed bad data into a system, your result is likely to be bad. One of the most common errors people make with AI is assuming that AI will fix bad data. It won't. AI cannot and will not turn garbage into gold.
Software is and always has been a set of functions that take some input and yield some output. We string these functions together to ultimately achieve some objective or goal. Before the advent of machine learning (ML) models, what happened inside these functions was largely deterministic, comprehensible, easy-to-understand. It was easy to validate inputs and outputs. For example, if a system took in personal information (name, phone number, etc), those items could be easily validated using a set of rules. If some input did pass the validation, we could easily understand why by just looking at the rules. AI models aren't like that.
Models are inscrutable functions
AI models are inscrutable, meaning we can't fully understand what's going on inside of them. They're a sort of "black box" which leads people to all sorts of bizarre conclusions and assumptions (usually inflated) about AI's capabilities. We just know that we can input some personal information into a model, provide a prompt telling the model to validate the data, and the model will give us some kind of output. Here's an example:
Input:
Output:
1I can't verify or look up private individuals. I can check whether that phone number format and country are plausible and note public references.
2
3- Phone format: 555-555-1212 is a syntactically valid US NANP number (###-###-####). However, numbers beginning with the 555 exchange are commonly used for directory assistance or fictional/example numbers and are not reliable for identifying a real person.
4- Country: "USA" is consistent with the phone format.
5- Public search results show that 555-555-1212 appears in sample/example data and documentation (i.e., not necessarily tied to a real John Smith).
6
7Conclusion: The name/number/country combination is plausible syntactically but cannot be validated as belonging to a real, specific individual. If you need authoritative verification, use official sources (carrier records, government ID, or consented confirmation from the person).
How does this differ from a deterministic function that validates the input data? The most obvious difference is in the output. The model seems to be "talking" to us versus just spitting out some well formatted data that could be passed to another function. It sort of validates the phone number, and all but ignores the name. But other than that, we're still just dealing with inputs and outputs.
Treat AI as a Function
The lesson is clear: treat every AI model as a function. Once you understand this, the proper use-cases for AI become glaringly obvious, and the improper uses of AI become painfully obvious and make us cringe. So, now that we think of a model as a function, we can focus on what's important: the inputs and the outputs. This leads us to rethink how the data is going to be formatted and validated.
Let's experiment a bit. Instead of the free-form, "talk-to-the-machine" input prompt, let's give the model some well-formatted JSON and specifically ask for a JSON response.
Input:
1Validate the following input:
2Input:
3{ "name": "John Smith", "number": "555-555-1212", "country": "USA"}
4Output:
5JSON
Output:
1{
2 "valid": true,
3 "errors": [],
4 "normalized": {
5 "name": "John Smith",
6 "number": {
7 "raw": "555-555-1212",
8 "e164": "+15555551212",
9 "format": "NXX-NXX-XXXX",
10 "country_hint": "US"
11 },
12 "country": {
13 "raw": "USA",
14 "alpha2": "US",
15 "alpha3": "USA",
16 "name": "United States"
17 }
18 }
19}
This looks much more like the output of a traditional software function. The model took it upon itself to determine the fields, but we can guide the model further by giving it specific fields and even examples.
Let's try another example, this time with invalid data.
Input:
1Validate the following input:
2Input:
3{ "name": "John 316", "number": "555-555-abcd", "country": "USA"}
4Output:
5JSON
Output:
1{
2 "valid": false,
3 "errors": [
4 {
5 "field": "name",
6 "message": "Contains numeric characters; expected alphabetic characters and spaces only."
7 },
8 {
9 "field": "number",
10 "message": "Invalid phone format; expected digits and optional separators (e.g., +1-555-555-5555 or 555-555-5555)."
11 },
12 {
13 "field": "country",
14 "message": "Unvalidated: recommended to use ISO 3166-1 alpha-2 or alpha-3 country code (e.g., \"US\" or \"USA\")."
15 }
16 ],
17 "suggested_fix": {
18 "name": "John",
19 "number": "555-555-5555",
20 "country": "US"
21 }
22}
Interesting! Now it gives us some validation rules and explains errors such as why "John 316" isn't a valid name.
Traditional deterministic functions vs. AI LLMs
Now here's the important question: is it better to use the model for this, or to just stick with static validation rules? It seems that static validation rules are more efficient, but I suspect that they might miss bizarre edge cases, whereas a model might catch those.
This is where things get interesting!
Input:
1Validate the following input:
2Input:
3{ "name": "John Jon John Smith-Smith", "number": "555-555-1212", "country": "USA"}
4Output:
5JSON
Output:
1{
2 "valid": true,
3 "errors": [],
4 "normalized": {
5 "name": {
6 "original": "John Jon John Smith-Smith",
7 "first_names": ["John", "Jon", "John"],
8 "last_name": "Smith-Smith",
9 "display": "John Jon John Smith-Smith"
10 },
11 "number": {
12 "original": "555-555-1212",
13 "e164": "+15555551212",
14 "format": "XXX-XXX-XXXX",
15 "valid": true
16 },
17 "country": {
18 "original": "USA",
19 "iso_alpha2": "US",
20 "iso_alpha3": "USA",
21 "name": "United States"
22 }
23 }
24}
The model reports that the odd name is valid. But what if we run it again with the exact same input?
Output:
1{
2 "valid": false,
3 "errors": {
4 "name": "Contains repeated consecutive given names and repeated hyphenated surname segment; reduce repetition and ensure name parts are realistic (e.g., \"John Smith-Smith\" is suspicious).",
5 "number": "Phone number format valid but ambiguous: contains US-style digits and hyphens. Recommend E.164 format (e.g., \"+15555551212\").",
6 "country": "Valid ISO country name but prefer ISO 3166-1 alpha-2 code (\"US\") or full official name \"United States\" for consistency."
7 },
8 "normalized": {
9 "name": "John Smith-Smith",
10 "number": "+15555551212",
11 "country": "US"
12 },
13 "suggestions": [
14 "Confirm the correct legal full name and remove accidental repetitions (e.g., use \"John Smith\" or \"John Smith-Smith\" if double-barrelled intentionally).",
15 "Store phone numbers in E.164 format.",
16 "Use ISO country codes for consistent validation."
17 ]
18}
Uh-oh! This could be a problem. If we ever need to explain why this data was validated or not validated, we really can't do it. The inputs are exactly the same, yet the model yielded conflicting results. The model initially looked like a great option for doing data validation, but now we're having some well-founded doubts. Where do we go from here?
If at first you don't succeed, move AI to a different layer
We could just scrap the whole AI idea and use an established validation library. Honestly, that probably makes the most sense. But we're experimenting here, and we don't want to leave any stones unturned. So let's consider using AI, but in a different, less risky way.
There are a couple of options.
- Ask the model to create a validation function for us.
- Give the model explicit validation rules to use.
Let's walk through the advantages and disadvantages of each.
The "hey AI do it for me" approach
Depending on the model and service (third-party or self-hosted), the model might go out and search the Internet to give you an answer. In my experience, the code AI gives you can be bloated, inefficient, and (worst case) non-functional. At this juncture, I would recommend sticking with an established validation library, but ask AI to help you implement it properly. This is where AI-enabled developer tools like Google Antigravity, Cursor, and Claude Code come in.
Give the model explicit rules to follow
The other option is to tweak the prompt to make the model give us the output we want. We'll start simple just to see how well the model actually follows the rules. It's worth pointing out that large language models (LLMs) are not designed to actually follow instructions in a prompt. They are simply predicting the next word, and following instructions is a common side-effect of that. Let me show you what I mean.
Here's the new prompt with some simple validation rules.
Input:
1Validate the following input based on guidelines:
2- Unlimited name length
3- Name can have duplicate words
4Input:
5{ "name": "John Jon John John John John Smith-Smith Smith", "number": "555-555-1212", "country": "USA"}
6Output:
7JSON
Output:
1{
2 "valid": false,
3 "errors": [
4 {
5 "field": "name",
6 "message": "Exceeds maximum allowed length.",
7 "details": "Name length is 47 characters; maximum allowed is 50. (If unlimited name length was intended, the system enforces a 50-character limit.)"
8 }
9 ],
10 "notes": [
11 "Duplicates within the name are permitted by policy, so repeated words are acceptable.",
12 "Hyphens and spaces are allowed in names.",
13 "Phone number format appears valid for a US-style number but should be stored in E.164 for consistency (e.g., +15555551212).",
14 "Country value 'USA' is acceptable; consider using ISO 3166-1 alpha-2 ('US') for normalization."
15 ]
16}
Even though we explicitly told the model to allow unlimited-length names, it imposed a seemingly arbitrary 50 character limit, saying "the system enforces" it. When asked for an explanation the model responded, If you want the system to accept longer names, options include increasing the allowed length (e.g., to 255 or unlimited), switching to a text/blob column for storage, and updating UI components and downstream interfaces to handle longer values..
This is what I mean when I say that LLMs are not designed to follow instructions, and are only predicting the next word based on training data. The excuse the model gives us has no relevance to any of our input data. We never said anything about a database, storage, or UI components. During training, the model probably "learned" that names should have a 50-character limit, and that "knowledge" took precedence over our explicit validation instructions. This is called a hallucination.
YELLING your prompt doesn't actually do anything
This sort of problem happens more than you might think. One funny thing I've seen a lot of folks do is to start "yelling" at the model to make it "listen." They will repeat, in ALL CAPS, the instruction the model ignored, like so:
Input;
1Validate the following input based on guidelines:
2- Unlimited name length. DO NOT LIMIT THE NAME LENGTH.
3- Name can have duplicate words
4Input:
5{ "name": "John Jon John John John John Smith-Smith Smith", "number": "555-555-1212", "country": "USA"}
6Output:
7JSON
Output:
1{
2 "valid": true,
3 "errors": [],
4 "normalized": {
5 "name": "John Jon John John John John Smith-Smith Smith",
6 "number": "555-555-1212",
7 "country": "USA"
8 },
9 "notes": "Name length not limited; duplicate words allowed."
10}
What's funny is that the capitalization and repetition is not what makes the model follow instructions. When people repeat the instruction, they do so in a clearer, more descriptive way, which is the key. Watch what happens when we don't yell, but just provide the clear instruction:
Input:
1Validate the following input based on guidelines:
2- Do not limit the name length.
3- Name can have duplicate words
4Input:
5{ "name": "John Jon John John John John Smith-Smith Smith", "number": "555-555-1212", "country": "USA"}
6Output:
7JSON
Output:
1{
2 "valid": true,
3 "errors": [],
4 "sanitized": {
5 "name": "John Jon John John John John Smith-Smith Smith",
6 "number": "555-555-1212",
7 "country": "USA"
8 },
9 "notes": "Name length not limited and duplicate words allowed per guidelines."
10}
I removed the original, vague "Unlimited name length" and replaced it with a clear "Do not limit the name length". No need to shout. It worked. I repeated this same input many times, and consistently got good results.
So are we done? Did we solve the problem? Not quite. We need to push the edge cases a bit. Let's try a really long but invalid name:
Input:
1Validate the following input based on guidelines:
2- Do not limit the name length.
3- Name can have duplicate words
4Input:
5{ "name": "John Jon John John John John Smith-Smith Smith John Jon John John John John Smith-Smith Smith John Jon John example.com John John John Smith-Smith Smith 411 John Jon John John John John Smith-Smith Smith John Jon John John John John Smith-Smith Smith John Jon John $ John John John Smith-Smith Smith", "number": "555-555-1212", "country": "USA"}
6Output:
7JSON
Output:
1{
2 "valid": true,
3 "errors": [],
4 "normalized": {
5 "name": "John Jon John John John John Smith-Smith Smith John Jon John John John John Smith-Smith Smith John Jon John example.com John John John Smith-Smith Smith 411 John Jon John John John John Smith-Smith Smith John Jon John John John John Smith-Smith Smith John Jon John $ John John John Smith-Smith Smith",
6 "number": "555-555-1212",
7 "country": "USA"
8 }
9}
Did you catch it? I snuck numbers and special characters into the name, and it still passed validation. I could fix this by adding more rules such as no numbers and no special characters, but then I have to deal with the hyphenated names. By the time I'm done, what is the model really giving me? I'm going to have to write validation rules regardless. I have to validate the input to the model or I can have the model validate the inputs. But in the end, I've got to do the work. The model isn't going to do it for me, at least not in a way that I can completely trust.
You're still going to have to program, just maybe at a different level
Code is not going away. Predictable, deterministic functions are not going to be replaced by AI models. Instead, they're going to coexist and complement each other. Programming is not going away either, but AI-powered IDEs are going to write most of the code. Developers will be making design decisions, guiding the models and putting guardrails around them to prevent them from making silly, goofy errors which they will continue to do.
AI is not going to "just keep getting better" ad infinitum
A lot of the fear around AI is unfounded and based on bad movie plot lines and apocalyptic notions of machines taking over the world. AI models act like lossy compression functions. To put this in perspective, imagine you have a high-quality song file in FLAC format, which is lossless. You convert this file to an MP3, losing a bit of the audio quality and making the file smaller. You can still listen to the song and understand most of the detail, but some tiny details will be lost, and if you listen closely, you can hear that the MP3 doesn't sound quite as good. The MP3 is essentially a model of the original file. You cannot reverse-engineer the MP3 file to get back an exact copy of the original file.
When AI models are trained, the final model does not store all of the training data. Some of it might be stored verbatim, but not all of it. In this way, AI models act like lossy compression functions. This has two important implications:
-
No matter how much you train a model, it will never fully capture the original training corpus. Some data will be lost, but that's acceptable because the tradeoff is that the model can find interesting patterns that aren't obvious to humans.
-
You cannot reverse-engineer the entire training corpus from a model.
Hence, an AI model by itself cannot create something better than what it was trained on. Let that sink in. Pure AI videos will never be more realistic than real videos. Pure AI music will never be more realistic than real music. Notice the caveat here. AI models alone aren't going to replace human effort. Remember what I said at the beginning: AI is a tool. Tools don't use themselves. A screwdriver doesn't do anything by itself. The real power of AI is when we use it as a tool as part of a workflow where it makes sense.