Crafting effective prompts for AI assistants

By Belisar Hoxholli

Why instructions matter

Imagine handing a critical task to a junior developer with only a half-baked spec. Chances are, you’ll get something, but not what you envisioned. Large Language Models (LLMs) operate similarly – they break down your input into tokens (words or subwords) and then predict a response token by token based on those instructions. In other words, an LLM (even a top-tier model like GPT-4o, o1, etc.) will do exactly what you ask, not necessarily what you mean. If your prompt is vague or ambiguous, the model might fill in the gaps in unpredictable ways.

Think of writing prompts like giving instructions to an intern who’s doing a task for the first time. You wouldn’t tell an intern “Make this better” without context; you’d spell out the requirements. Likewise, clear and structured prompts prevent misunderstandings. Ambiguity is the enemy: unclear directions can lead to irrelevant or inconsistent outputs. By providing precise details (just as you would in a well-written Jira ticket or API contract), you guide the AI to produce results closer to what you want. The bottom line: the effort you put into crafting good instructions directly translates into the quality of the AI’s response.

The PROMPT

To remember the best practices of prompt-writing, let’s use a cheeky developer-oriented acronym: PROMPT. Each letter highlights a principle to level up your prompt engineering game. Think of it as writing good code – clear, purposeful, and easy to follow.

P – Purpose (Plan your Prompt): Start with a clear goal in mind. State exactly what you want the AI to do. A prompt without a defined purpose is like a function with no spec – the outcome will be anyone’s guess. For example, instead of saying “Help with Laravel middleware”, specify “Explain how to implement custom middleware in Laravel”. Clear intent sets the stage and reduces guesswork. As OpenAI’s guidelines put it, be specific and detailed about what you need – context, outcome, format, etc.. Defining the purpose up front focuses the model, much like a good unit test defines what success looks like.

R – Role or context: Provide any relevant context or ask the model to assume a role. LLMs love context – it’s their equivalent of having the right configuration before running a program. If you want a particular perspective or expertise, say so! For instance, “You are a senior Laravel developer reviewing a pull request” sets a tone and expertise level. Or include actual context: “Given the following controller code […]”. Supplying background details helps the model understand your question better. Context is everything for complex queries; just as a snippet of code might behave differently without the rest of the codebase, an AI’s answer improves when it knows the scenario or data it should consider.

O – Outcome and Output format: Describe the desired output and format. Do you want a PHP code snippet, a step-by-step explanation, or just a one-line answer? Specify that. If you expect a list of bullet points or a JSON structure, mention it explicitly. For example: “List three optimization tips for Eloquent queries in bullet points.” This is akin to defining a function’s return type. By articulating the output expectations, you make it easier for the AI to deliver something you can use straight away. Models respond well when you show or tell them the format you need – it removes another layer of ambiguity. Leverage dedicated structured output schemas on providers that support them.

M – Minimize ambiguity (Maximize clarity): Use precise language and avoid open-ended or subjective terms. If a term could be interpreted in multiple ways, clarify it. Saying “optimize this Laravel controller” is less clear than “refactor this Eloquent query for fewer database calls”. Aim to eliminate wiggle room in interpretation, much like you’d eliminate undefined behavior in code. Instead of writing “the response should be short”, define “short” precisely (e.g. “under 5 sentences”). In prompt engineering, specific beats vague every time. A good practice is to replace imprecise adjectives with concrete metrics or descriptions (e.g., “Use a 3-5 sentence paragraph to describe X” rather than “keep it fairly short”).

P – Provide examples (if needed): For complex tasks, examples can guide the model. This is the “show, don’t tell” principle. If you want the AI to output code in a certain style or format, give it a small example to mimic. For instance, prompting: “Translate the following array to JSON. Example: Input: [‘a’ => 1, ‘b’ => 2]; Output: {"a":1,"b":2}. Now convert this array: […]” gives a clear pattern to follow. Examples act as hints of the desired outcome and can dramatically improve reliability and consistency of the output. This few-shot approach is like providing unit test examples – the model sees the pattern and reproduces it. Just be sure your examples are correct and relevant, as the AI will generalize from them.

T – Test and Tweak: Don’t expect a perfect answer on the first try. Just as you rarely write a bug-free feature in one go, prompt engineering is an iterative process. Try your prompt, review the output, and refine it. If the answer was off-base, ask yourself: what part of my instruction was misunderstood or too vague? Maybe you forgot to mention a crucial detail (the same way a missing env variable can break an app). Treat your prompt like code under development: debug it by adjusting phrasing, adding context, or splitting one big prompt into smaller pieces. The key is to experiment and iterate – change one thing at a time and see how the output improves. Over time, you’ll learn how even small wording changes can significantly influence the results. (More on this in the “Iterating on Prompts” section below.)

Understanding LLM workloads

Not all prompts are created equal – they depend on the job you’re asking the AI to do. LLMs are amazingly versatile (they can churn out prose, write code, summarize text, answer questions, and more), but each of these workloads may require a different prompting strategy. As an experienced developer, you instinctively adjust your approach for different tasks; similarly, you should adjust how you prompt for different AI tasks:

Free-form text generation: This is when you want the model to produce a narrative, explanation, or any open-ended content (like an error explanation or a blog paragraph). Here, providing a guiding context or style can help. For example, “Explain in one paragraph why using Laravel’s Eloquent ORM can be beneficial, in a casual tone.” You might give the AI freedom to be creative, but you still set boundaries (topic, length, tone). If you leave it too open (“Tell me about Laravel”), you’ll get a very generic answer. So, frame your prompt to narrow down the topic and style. Essentially, be the product owner for the content: set acceptance criteria (topic, tone, key points) so the AI delivers something on-target.

Code generation and completion: Using AI to get code snippets or help with programming requires precision in prompts. When asking for code, specify the language and context, and any specific libraries or frameworks. For instance: “In PHP/Laravel, write a middleware that logs the request method and URL.” By stating PHP/Laravel, you cue the model into the right ecosystem (so it doesn’t give you Node.js or Python code). If you have a piece of code that needs completing or debugging, include it. For example, “Here’s a Laravel query builder snippet […]. Complete it to eager load related comments.” LLMs can indeed write and even debug code, but they perform best when you describe the problem clearly (just like writing a good bug report). Also, remember to double-check AI-generated code – treat it like code from a junior dev: useful, but possibly needing review.

Summarization and explanation: Sometimes you’ll use LLMs to summarize long texts (logs, documentation, or even a Slack conversation) or to explain a piece of code. In these cases, the prompt should clearly separate the instruction from the content. For example: “Summarize the following error log in one sentence: .” or “Explain what the following Laravel code does, step by step: .” Use delimiters like triple quotes or XML tags to enclose the text if you’re using an API, so the model knows what it needs to summarize versus what is just instruction. The strategy here is to be straightforward: tell the model it’s summarizing or explaining, provide the text, and specify any focus for the summary (e.g., “focusing on causes of the error”). Because the model only knows what you feed in the prompt (plus its training data), ensure the critical content is included. A well-structured summarization prompt will yield a more focused and accurate summary than a generic “TL;DR please.”

Retrieval or Q&A (knowledge extraction): When you want factual answers, especially about domain-specific knowledge (say details from Laravel’s docs or your project’s readme), you need to ensure the model has access to that info. By default, an LLM like GPT-4o has a lot of general knowledge but might not know specifics of your project. If the information is small, include it in the prompt: “Using the Laravel documentation below, answer the question… … Question: How do you define a route that handles POST requests?”. This way, the model retrieves from the given text rather than guessing. If the info is too large to include, that’s when techniques like RAG (discussed later) come in – effectively, you first fetch relevant data then ask the question. The prompting strategy for retrieval-style tasks is to ground the AI in provided text. Always instruct the model to base its answer only on the given context to minimize hallucinations. It’s similar to how you’d cite sources in an essay – give the AI the source material up front.

Chatbot or multi-turn conversations: Interacting with an AI in a conversational manner (like a chatbot that remembers context) adds another twist to prompting. In a chat setting, you typically have system messages or an initial prompt setting the stage (e.g., “You are an AI assistant that helps with programming questions.”), and then each user message and assistant response builds on the last. Prompt design here includes maintaining context across turns and possibly reminding the model of important information if the conversation gets long. For example, if in round 1 you provided a code snippet and by round 5 you’re asking a follow-up, the model might not see the snippet unless the system or you include it again (depending on how the conversation memory is handled). The key is to keep each prompt in the conversation contextually complete enough. Sometimes rephrasing the user’s question with context in your prompt can help. Also, instruct the AI if needed to stay in character or follow a style throughout the chat. Essentially, you’re writing not just one prompt but a series of prompts (a dialogue) – each turn should be clear and build logically on the previous. This is akin to an ongoing function call that retains state; you ensure the state (context) persists so the AI doesn’t lose the thread.

In short, identify the type of task and adjust your prompt like you’d choose the right algorithm for a job. If it’s creative, give it freedom (with guidance); if it’s precise (like code or factual answers), give it structure and context. The more the prompt fits the workload, the better the output.

Iterating on prompts

No developer expects to write a perfect feature on the first try – we debug, we refine. Treat prompt crafting the same way. The first response you get from the AI is like a first unit test run: if it fails (or isn’t quite what you wanted), dig into why and iterate.

Start simple and build up. Begin with a basic prompt to see how the model responds. Think of it as your introduction for the task. If the output isn’t what you need, analyze it like a failing test. For example, if you asked for a Laravel validation rule snippet and the AI’s answer is incorrect or off-topic, check your prompt: Did you specify the Laravel version or context? Did you actually ask for a code snippet? Maybe you got a verbose explanation instead of code because you didn’t explicitly say “provide code”. This analysis is akin to checking if your API call payload is correct when you get a weird response.

Use a debugging mindset. When a prompt “bug” occurs (i.e., the AI’s answer is wrong or odd), isolate the issue. Is the instruction unclear or too broad? Try tightening it. Is the answer incomplete? Perhaps ask the AI to be more detailed or to format the answer differently. One change at a time – like altering one parameter in a function – will let you observe its effect. For instance, if the AI’s recipe output is missing steps, you might add “list all steps without skipping any.” If the tone is off, you could append “respond in a formal tone.” After each tweak, run the prompt again and see if the result moves closer to your desired outcome.

Picture debugging a JSON response from a Laravel API endpoint. If the data is missing a field, you’d check the controller or the query – maybe you forgot to select that field or it’s named differently. Likewise, if the AI answer misses a piece of info, it might be because your prompt didn’t mention that piece or implied a different focus. By methodically adjusting and re-running (and sometimes reverting if an adjustment made things worse), you converge on a prompt that consistently yields good results. It’s literally prompt debugging. Just as you write tests for critical code paths, you might test your prompts with a few variations of input to ensure the AI handles them well.

Keep track of what works. In code, we version control our changes; for prompts, it’s helpful to keep notes or versions of prompts that worked versus those that didn’t. You might discover patterns – e.g., “When I phrase it like X, the answer is more accurate, but phrasing like Y causes confusion.” Over time, the lessons you learned become your personal prompting playbook.

Finally, remember that AI models can update or change (just like dependencies). A prompt that worked perfectly with one model (say GPT-3) might need tweaking for another (say GPT-4) because of differences in how they handle instructions. So if you upgrade your AI model, be ready to re-test your prompts. It’s an evolving process, but that’s part of the fun – you’re not just writing a prompt, you’re developing it.

Extending prompting with RAG and vector stores

Sometimes the information you need is outside the AI’s built-in knowledge. Imagine you have a Laravel project with extensive documentation or a private knowledge base. How do you get the AI to use that? Enter Retrieval-Augmented Generation (RAG) – a technique that combines prompting with information retrieval. In a RAG setup, your prompt isn’t flying solo; it’s backed by a mini search engine that supplies relevant data from external sources. The system will fetch, say, the portion of your Laravel docs about middleware, and feed it into the prompt so the model can generate a more informed answer.

In practical terms, RAG works like this: first, you query a knowledge store (documentation, wiki, database, etc.) for information related to your question, then you attach those snippets of information to the prompt you give the LLM. The LLM sees both your question and the retrieved text, allowing it to produce a response that’s grounded in that external data. This approach dramatically improves accuracy and relevance for domain-specific questions – it’s like giving the AI an open-book exam. Instead of hoping it remembers some Laravel detail from training, you hand it the exact page from the docs and ask it to answer using that.

To enable RAG in your applications, you’ll often use vector databases behind the scenes. These are specialized databases that store embeddings (vector representations) of text, which allows for efficient similarity search – a fancy way of saying “find me chunks of text related to this query.” When you ask a question, the system converts it to a vector, searches the vector DB for similar content (like the relevant Laravel guide about routing), and gets back those text chunks to include in the prompt. Vector databases play a key role in RAG systems: they enable fast, relevant context retrieval to feed to the LLM. Popular choices include Pinecone, Weaviate, or even open-source ones like Qdrant or FAISS, but the concept is what’s important: it’s your knowledge bank for the AI.

Consider a practical scenario: you’re building a ChatGPT-like assistant for your company’s internal Laravel codebase. You want it to answer questions about the code (“Where is the user authentication logic defined?”) or documentation (“What does our XyzService class do?”). By using RAG, your app can search your actual code or docs for the keywords, pull the relevant snippets (perhaps the XyzService class definition or docstring), and prepend them to the AI prompt: “According to our docs, XyzService is responsible for […] . Given that, how would I extend it to add feature Y?”. The LLM, now armed with real data, can give a far more precise answer, even citing the provided context. This easily beats a vanilla prompt because the AI isn’t guessing or relying on possibly outdated training data – it’s using your current, source-of-truth information.

One more benefit: reduced hallucination. Hallucinations (when the AI confidently invents incorrect info) are a big headache, especially with technical info. By grounding the model with actual retrieved facts, you anchor its imagination. It’s as if you clipped its wings a bit – in a good way – keeping it factual. Of course, implementation matters: you’ll need to ensure your retrieved context is relevant (garbage in, garbage out). Tools like vector stores help by finding semantically relevant chunks of text rather than doing simple keyword matching.

In summary, RAG and vector databases let you augment the AI’s knowledge on the fly. For a developer, this is like having a self-updating Stack Overflow or documentation buddy integrated into your AI assistant. Instead of the assistant saying “I don’t know” or, worse, making something up about Laravel, it can pull up the actual docs and give you an answer with confidence. It’s a powerful technique that extends what your prompts can do – by plugging in the right data at the right time – ensuring your AI assistant stays as sharp and accurate as the documentation and data you feed it.

Belisar Hoxholli
Principal Engineer
Author Image

Interested in speaking with a developer?

Connect with us.
©2025 Kirschbaum Development Group LLC Privacy Policy Terms of Service