Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Prompt Engineering for LLM Control

Introduction

In our previous lessons, you've learned to interact with LLMs programmatically and to steer the generation process using sampling parameters like temperature and top_p. These parameters give you control over the style of the output—its creativity versus its predictability.

Today, we'll shift our focus to controlling the LLM's fundamental behavior, persona, and purpose. The goal of this lesson is to learn how to design system prompts to control LLM behavior for a specific task.

Think of it this way: if sampling parameters are the knobs that tune an engine's performance, the system prompt is the blueprint that defines what kind of vehicle the engine is in—a race car, a freight truck, or a family sedan. By mastering system prompts, you can transform a general-purpose LLM into a specialist tailored for your application.

1. The Role of the System Prompt

When you make an API call, you typically provide a list of messages. As we've seen, these messages have roles. Until now, we've mostly used the user role. However, there's a special role that sets the stage for the entire interaction: the system role.

To understand the distinction, let's consult a clear definition.

The Difference Between System Messages and User ... - PromptHub

The article 'The Difference Between System Messages and User Messages' from PromptHub offers a concise explanation of the different roles in an API request and the best practices for each.

Please read the first half of the article, covering the sections: 'Introduction' 'Understanding Roles in API Requests' 'Best Practices for System and User Messages' 'Different role types when using LLMs' (including the 'System role best practices' and 'User role best practices' subsections). Focus on the distinction between the high-level, persistent nature of the system prompt and the task-specific nature of the user prompt.

As the article highlights, the key separation is:

  • System Prompt: Provides high-level, persistent instructions that apply across the entire conversation. It defines the LLM's persona, rules, and overarching goal.
  • User Prompt: Contains the specific, immediate task or question for the model to address.

For you as a software engineer, a useful analogy is to think of the system prompt as an initialization script or a configuration file for a service. It sets up the environment, defines constants, and establishes behavioral rules before any specific requests (user prompts) are processed.

Here's a simple, concrete example of how this looks in code:

OpenAI API System Prompt Example for Persona Definition
In this Python snippet, the `system` message sets the persona of 'Ben, a real-estate agent'. This high-level instruction governs the entire interaction, causing the LLM to introduce itself in character when prompted by the `user` message.

2. The Anatomy of an Effective System Prompt

Now that we understand the what and why, let's explore the how. A well-designed system prompt is not just a block of text; it's a structured set of instructions.

The following video provides an excellent deep dive into the components of a powerful system prompt by deconstructing an example piece by piece.

How to Write Better System Prompts

The video 'How to Write Better System Prompts' from the ZazenCodes channel demonstrates advanced techniques used in production systems. Pay close attention to how different sections of the prompt are structured to achieve a specific behavior.

Watch from the beginning to 13:18. The video covers: The function of a system prompt as a 'programming layer'. A detailed walkthrough of a sample system prompt, highlighting its structure. A summary of key design techniques.

The video demonstrates several powerful techniques for designing robust system prompts. Let's summarize the key principles:

  • Role and Goal Specification: Start by clearly defining the AI's identity and its primary objective (e.g., "You are Chad GPT, a dedicated writing assistant...").
  • Hierarchical Instructions: Use formatting like Markdown headings or even HTML tags (<section>, </section>) to group related instructions. This improves clarity for both the model and human developers.
  • Explicit Formatting Requirements: Tell the model exactly how you want the output structured (e.g., "Output markdown," "Use two hashes for main sections").
  • Restrictions and Constraints: Create a dedicated section for things the model must not do. Using capitalization (e.g., "DO NOT...") can help emphasize these critical rules.
  • Context-Dependent Behavior: Define different "routes" or modes of operation based on the user's intent (e.g., "If the writing type is 'email', follow these specific style guides...").
  • Chain-of-Thought Guidance: Explicitly instruct the model to think step-by-step by providing a planning section (e.g., "Execute these steps in the following order..."). This makes its reasoning process more reliable.
  • Dynamic Context Injection: As shown with the current_date, your application code can dynamically insert information into the system prompt at runtime to provide the model with up-to-date context.

3. A Systematic Framework for Prompt Design

Having a collection of techniques is great, but a systematic framework is even better for ensuring you cover all your bases. The following article proposes a clean, four-part structure that is easy to remember and apply.

Boldly Prompting - System Instructions and Agent Tools

The article 'Boldly Prompting - System Instructions and Agent Tools' provides a practical structure for building system prompts for AI agents. We will focus on its proposed framework.

Read from the 'System Instructions' section to the end of the complete system prompt example. Focus on understanding the purpose of the four proposed sections: Role, Tools, Context, and Task.

This Role, Tools, Context, Task framework gives you a mental model for building a prompt from scratch:

  1. Role: Who is the AI? What is its persona and tone?
  2. Tools: What capabilities does it have beyond text generation (e.g., calling functions, searching the web)? We'll cover this in-depth in a future module.
  3. Context: What background information does it need? This can include correcting undesirable behaviors seen in testing (e.g., "Do not guess table names; here is the list of available tables...").
  4. Task: What is the step-by-step process it should follow to fulfill the user's request?

4. Let's Design a System Prompt

Let's apply this framework to a practical task. Imagine you want to build an assistant that helps you write technical documentation for your code.

Here is how we could structure the system prompt using the Role, Tools, Context, Task model:




# SYSTEM PROMPT




### Role
- You are Docu-Bot, an expert technical writer specializing in creating clear, concise, and accurate documentation for software engineers.
- Your tone is professional, helpful, and precise.
- You are to act as a collaborator, not just a generator.




### Tools
- You do not have access to external tools. Base your documentation solely on the code provided.




### Context
- The user will provide a snippet of code (e.g., a function or class).
- The target audience for the documentation is other developers who are familiar with the programming language but not with this specific code.
- The current date is {{current_date}}. Include this in any changelog sections if requested.




### Task
- Your primary task is to generate documentation for the provided code in Markdown format.
- Follow these steps:
    1.  **Analyze:** Carefully read the provided code to understand its purpose, inputs, outputs, and any potential side effects.
    2.  **Generate Plan:** Silently create a plan for the documentation structure.
    3.  **Generate Documentation:** Based on your analysis, generate the documentation, which MUST include the following sections:
        - A one-sentence summary of the function's purpose.
        - A 'Parameters' section listing each parameter, its expected type, and a brief description. If there are no parameters, state that.
        - A 'Returns' section describing the return value and its type. If the function does not return anything, state that.
        - A 'Usage Example' section with a clear, simple code block demonstrating how to use the function.
    4.  **Constraints:**
        - DO NOT invent functionality that is not present in the code.
        - If the code is ambiguous or incomplete, ask the user for clarification instead of making assumptions.
        - Respond ONLY with the Markdown documentation. Do not include conversational pleasantries like "Here is the documentation you requested."

This prompt is specific, structured, and gives the model a clear set of instructions and constraints, drastically increasing the likelihood of getting a useful and consistent response.

Conclusion

You now have a solid framework for designing system prompts, a critical skill for building reliable and specialized LLM-powered applications.

Key Takeaways:

  • System vs. User Prompts: The system prompt sets the high-level, persistent context (persona, rules), while the user prompt contains the immediate, specific task.
  • Structure is Key: Effective system prompts are not just prose; they are structured documents. Using formatting like Markdown and clear sections (e.g., Role, Context, Task) makes them more effective.
  • Be Explicit: Clearly define what the model should do and what it should not do. Provide step-by-step instructions for its reasoning process (a "task plan").
  • Iterate: The best prompts are developed through testing. Start with a structured prompt, observe the model's failures or undesirable behaviors, and add context or constraints to correct them.

Preview of the Next Lesson:

In our design exercise, we instructed the model to respond in Markdown. While this is human-readable, for many applications, you need output that is machine-readable. In the next lesson, we will learn how to implement structured output parsing from LLM responses, focusing on how to reliably get and use JSON output. This is the next logical step toward integrating LLMs into robust software systems.

Can't find a good explanation? Sign up and we'll make it for you

Sign up