Prompt Engineering Techniques for Claude Apps
Prompt engineering for Claude apps means structuring your instructions, context, and examples so Claude produces consistent, correct output on the first try instead of after five rounds of trial and error. The techniques that work best for Claude differ slightly from other models because of how it handles system prompts, XML-style structure, and long context — this article covers the ones that actually move the needle in production.
If you're building an app on top of Claude (not just chatting in a playground), the goal isn't "clever prompts" — it's repeatable output across thousands of requests with different inputs. That requires a different mindset than one-off prompting: you're designing a template, not writing a single message.
Separate instructions from data
The single most common mistake in Claude apps is mixing instructions and user-provided content in one blob of text. Claude (like most LLMs) performs much better when it can clearly tell what's an instruction and what's data to process.
Use XML tags to separate the two:
Summarize the following support ticket in two sentences.
Focus on the customer's core problem, not the greeting or sign-off.
<ticket>
{{user_input}}
</ticket>
This matters more as inputs get longer or messier — user-submitted text, scraped HTML, logs. Claude is trained to recognize tag boundaries, so wrapping variable content in <ticket>, <document>, or <context> tags reduces the chance it treats part of the input as an instruction to follow.
Use the system prompt for role and constraints, not tasks
The system prompt is where persistent behavior belongs: tone, persona, output format rules, things that should apply to every request. The user message is where the actual task and data go.
{
"system": "You are a technical support assistant for a SaaS billing product. Always respond in plain text, no markdown. If you don't know the answer, say so explicitly instead of guessing.",
"messages": [
{ "role": "user", "content": "Customer says their invoice shows double charges. <ticket>...</ticket>" }
]
}
Putting formatting and behavioral constraints in the system prompt instead of repeating them in every user message keeps your app code cleaner and makes the model's behavior more consistent across requests, because the instruction isn't competing for attention with task-specific content.
Give Claude room to reason before answering
For tasks that involve judgment — classification, multi-step analysis, anything with edge cases — ask Claude to reason first and give a final answer last. Claude tends to produce better final answers when it's allowed to think through the problem in the same response, rather than being forced to answer immediately.
Analyze the support ticket below. First, list the possible causes
in a few sentences. Then on a new line write "Answer:" followed by
one of: billing_error, user_error, bug, unclear.
<ticket>{{ticket_text}}</ticket>
If you need a machine-parseable answer, put the reasoning first and the structured output last, then parse only the final section. Mixing them in the wrong order — asking for the answer first — tends to produce worse reasoning, because the model commits to a conclusion before considering alternatives.
Use few-shot examples for formatting, not logic
Few-shot examples are most effective when the task is about output format rather than teaching Claude a concept it doesn't already understand. If you need strict JSON with specific field names, show one or two examples instead of describing the schema in prose:
Extract the product name and price from the text. Respond only
with JSON in this exact format:
Example input: "The Pro Plan costs $29/month"
Example output: {"product": "Pro Plan", "price": "29"}
Now extract from: "{{input_text}}"
Two good examples usually outperform a long paragraph of formatting rules. Keep examples realistic — if your production inputs are messy, your few-shot examples should be messy too, not clean idealized versions.
Prefill the start of the response
You can steer Claude's output format by prefilling the beginning of the assistant turn. This is especially useful for forcing JSON output or skipping preamble like "Sure, here's the summary:".
{
"messages": [
{ "role": "user", "content": "Summarize this ticket as JSON with fields summary and category." },
{ "role": "assistant", "content": "{" }
]
}
By prefilling {, you push Claude to continue directly into JSON rather than opening with conversational filler. This is a small trick but it reliably eliminates a whole class of parsing failures in production apps.
Use tool definitions instead of prompt-based parsing
If your app needs Claude to call functions, query a database, or return strictly typed arguments, define tools instead of relying on prompt instructions to produce a particular JSON shape. Tool definitions give Claude a schema it validates against, which is far more reliable than describing the shape in text. If you're routing requests through SubToAPI, tool calls work the same way as the native Claude API — see /docs/tools for the request format.
Don't over-specify — test with real inputs
A prompt that works on your three test cases can fail on real user input. Prompt engineering for an app, as opposed to a demo, means testing against a representative sample of actual inputs: edge cases, malformed text, non-English content, empty fields. Build a small eval set of 20–50 real examples and re-run it every time you change the prompt — this catches regressions that manual spot-checking misses.
Keep prompts as short as they need to be. Long lists of edge-case instructions ("if X, do Y, unless Z, in which case...") tend to degrade reliability rather than improve it. If you find yourself writing more than a few conditional rules, it's often a sign the task should be split into two separate calls instead of one overloaded prompt.
Putting it into an API workflow
Once a prompt is working reliably, the next problem is usually operational: API keys per environment, usage tracking per team member, and streaming responses to a frontend without managing SDK versions yourself. SubToAPI wraps your existing Claude access in a standard HTTPS API with sub_live_... keys, so the prompt you test locally works the same way in staging, production, and across team members without separate billing setups. Start with the quickstart or see the full request format in the messages docs; plans start at €9/month and a free trial is available at /signup.
questions
Do system prompts matter more than user prompts in Claude apps? They serve different purposes — system prompts set persistent behavior and format rules, user prompts carry the task and data. Both matter, but mixing them causes more failures than getting either one perfectly worded.
Should I use few-shot examples for every Claude prompt? No. They help most with output formatting and structure. For tasks Claude already understands conceptually, extra examples add tokens without improving accuracy, and can even bias output toward the examples' specific phrasing.
How do I keep prompt output consistent across many API calls? Separate instructions from data with tags, define strict output format with a schema or prefilled response start, and test against a fixed set of real-world inputs whenever you change the prompt, rather than relying on manual spot checks.