Prompt engineering in practice
Duration: 12 min Prerequisites: chapter 10 (you’ve seen the 3 tabs), demo 4 running and a project already generated (e.g.
banking).
Key idea
Section titled “Key idea”An agent is its system prompt + its tools. Editing the prompt amounts to editing the behaviour, without touching the code. This chapter illustrates that property at runtime, using demo 4.
System prompt vs user prompt
Section titled “System prompt vs user prompt”| Kind | Content | Who writes it | When |
|---|---|---|---|
| System prompt | The general role of the agent: “you are a Java dev, you use these tools, here are the hard rules.” | The developer who built the agent | Once, at design time |
| User prompt | The specific task: “build a tiny bank with 3 classes.” | The user | At every call |
For the 3 agents of demo 4:
| Agent | System prompt | User prompt |
|---|---|---|
| Generate | SYSTEM_PROMPT (line 654+ of agent.py) | Chosen in the sidebar (banking, tictactoe, …) |
| Verify | VERIFY_SYSTEM_PROMPT (line 827+) | Auto-generated by build_verifier_bootstrap() |
| Tests | TEST_SYSTEM_PROMPT (line 996+) | Auto-generated by build_test_bootstrap() |
Concrete examples: the same user prompt under three different system prompts
The user prompt is identical in all three cases: “Write a function that adds two numbers.”
Only the system prompt changes — and with it, the model’s entire behaviour.
| System prompt (excerpt) | Output for the same user prompt |
|---|---|
”You are a Java developer. Always use camelCase, always include a Javadoc comment, never use the keyword var.” | /** |
| “You are a Python developer. Always use snake_case, add type hints, never raise an exception silently.” | def add_numbers(a: int, b: int) -> int: |
| ”You are a pirate who answers every coding question in pirate slang and never writes more than three lines of code.” | Arr matey, here be yer treasure: |
This is the core property of an agent: the system prompt is the role, the user prompt is the task. Changing the system prompt at runtime, without recompiling any code, changes the agent’s identity and conventions. This is exactly what the editable expanders of demo 4 expose, and what the rest of this chapter exercises live.
Guided in-class demonstration
Section titled “Guided in-class demonstration”This sequence takes about 3 minutes to run and makes the property concrete with no additional theory.
Step 1 — Prepare
Section titled “Step 1 — Prepare”- Launch demo 4:
cd ollama-demo-4-trio-agents-java ; .\start.ps1. - Sidebar: pick Banking system.
- Tab 1: click Run agent. Wait for completion (~30s to 2 min depending on machine).
- Tab 2 (Verify) should show 3 or 4 files to check. If the
Bankclass has aprivatefield, the preview banner will say so.
Step 2 — Run the “with rule” version
Section titled “Step 2 — Run the “with rule” version”-
Tab 2, open the expander “System prompt (the agent’s role — editable for live demo)”.
-
You see the full
VERIFY_SYSTEM_PROMPT, including this line:4. EVERY field declared with ‘private’ is rewritten as ‘public’, so a future test agent can read the state directly. This is a hard project convention.
-
Click Run code review.
-
Observe: the agent calls
read_fileon the offending file, thenwrite_filewith a version whereprivatewas replaced bypublic. The Fixes written: 1 counter shows up at the bottom. -
If you reopen the Workspace source files expander, you see the diff:
private ArrayList<Account> accounts;→public ArrayList<Account> accounts;.
Step 3 — Break the prompt
Section titled “Step 3 — Break the prompt”- Regenerate the project (tab 1, Run agent) to start from a workspace with
privateto fix. - Tab 2, system-prompt expander: delete the entire rule 4 (the 3 lines that mention
private). - Click Run code review.
- Observe: this time, the agent touches nothing. Fixes written: 0, message “All good”. The
privateis still there in the source.
Step 4 — Repair the prompt
Section titled “Step 4 — Repair the prompt”- Click Reset to default in the expander to reload the rule.
- Rerun Run code review.
- The
privateis fixed again.
What this sequence demonstrates: the behaviour of the agent has been changed without recompiling a single line of Python. Three lines of prompt were edited, and nothing else.
The lesson
Section titled “The lesson”An AI agent is not a classical program. In a classical program:
change behaviour = change code = recompileIn an agent:
change behaviour = change prompt = rerunThis property is what makes:
- you can prototype a behaviour in 30 seconds;
- you can test two variants side-by-side without rebuilding;
- you can give prompt control to the user (that’s what ChatGPT does with Custom Instructions).
It’s also why prompt engineering is a real job: a bad prompt = an unusable agent, a good prompt = a working tool.
5 tips for writing a good system prompt
Section titled “5 tips for writing a good system prompt”1. Be imperative, not suggestive
Section titled “1. Be imperative, not suggestive”NO : "It would be nice if you could use public fields..."YES : "EVERY field MUST be declared public. No private."LLMs trained to follow instructions respond better to explicit orders.
2. Give a complete example
Section titled “2. Give a complete example”Don’t describe, show. The TEST_SYSTEM_PROMPT (lines 999-1018 of agent.py) includes a full mini CalculatorTest.java with imports, class, two @Tests. Five times more effective than prose description.
3. List hard rules before soft ones
Section titled “3. List hard rules before soft ones”HARD RULES (must follow):1. ...2. ...3. ...
CONVENTIONS (try to follow):- ...- ...The model treats the first list as constraints; the second as preferences.
4. Tell it what to do on error
Section titled “4. Tell it what to do on error”Our SYSTEM_PROMPT ends with:
If compile_java reports an error, call read_file then write_file with a fixed COMPLETE version that keeps imports and other classes intact, then call compile_java again.
Without this line, the model often gives up on the first error.
5. End with an explicit stop condition
Section titled “5. End with an explicit stop condition”When compile_java returns 'Compilation successful.', stop and writeone short sentence in plain English (no code, no JSON).Otherwise the model can keep calling tools “just in case”, up to MAX_STEPS.
Variations to try in class
Section titled “Variations to try in class”Once this initial sequence has been completed, ask students to modify other parts of the prompt:
| Modification | Expected behaviour |
|---|---|
| Remove all coding rules | The model writes “standard” Java with private + getters/setters, tests fail to compile. |
| Add “Use French names for classes” | Compte, Banque, Transaction instead of Account, Bank, etc. |
| Add “Use the Builder pattern” | The model structures classes differently, sometimes well, sometimes not. |
| Add “Always add a toString() method” | All classes get toString (and the model mentions it in its messages). |
Key takeaways
Section titled “Key takeaways”- An agent = system prompt + tools + loop. Change the prompt, change the behaviour.
- Demo 4 exposes the 3 system prompts in editable expanders, which allows the effect of a prompt change to be observed at runtime.
- A good system prompt: imperative, with a full example, hard rules listed, explicit error handling, clear stop condition.
- That’s why prompt engineering is a real job — not “chatting with a chatbot”.