Back to home

What I've Learned About LLMs

Practical advice for working with large language models.

How LLMs Generate Responses

Early Words Shape What Comes Next

Large language models (LLMs) generate text in small pieces called tokens. Each prediction depends on all the text that came before it, including the model's own output. The model uses probabilities to choose the next token and produces text that resembles human reasoning.

Every new token becomes part of the context: the text the model uses to generate the rest of its response. Good starts and bad starts tend to build on themselves. Early tokens have an unusually strong influence. If a response starts with cautious language, too much detail, or a mistaken reasoning step, the model tends to continue that pattern.

Human Feedback Shapes the Writing Style

During training, people give positive ratings to responses that are polite, cautious, or open about uncertainty. The model learns to repeat those writing patterns automatically.

Where Information Appears Matters

An LLM gives some parts of the context more attention than others. Placement matters in three ways.

Word order: Changing the order of words in a prompt changes how much attention the model gives them. Even though models can process many tokens at once, they still track their order.

The middle of the context: The model pays more attention to the beginning and end of the text it can use. It can overlook important information in the middle. Put the most important information near the start or end.

Placement of instructions: The provider's instructions appear near the beginning, and the user's message appears near the end. Both receive more attention. System and developer instructions sit in the middle, where other text can more easily drown them out. Their placement helps explain how much attention they receive.

Check against real use: Providers report improvements to these problems. A codebase that fills 200,000 tokens of context may still expose them. Official documentation describes lab conditions. Real work can expose problems that benchmarks missed. Results at scale rarely match the claims, so adjust your expectations.


Writing User Prompts

Describe the Outcome and Hard Constraints

Tell the model what success looks like and which boundaries it must respect. Current models can usually work out how to get there. Dictating the route too closely can restrict their judgment and produce worse results.

Prefer / Avoid / Unless

State a preference, explain what to avoid, and say when an exception is allowed. Flexible guidance fits how a model chooses among likely responses. Clear exceptions reduce ambiguity and give the model a sequence of decisions to follow. This structure also resembles well-written instructions in its training data.

Reserve absolute rules for hard constraints. When a preference needs exceptions, state them. Treating it as an absolute can make the model switch back and forth between answers, become overly cautious, avoid related actions, or follow the wording in a way that defeats your purpose.

Ask for a Thorough Answer

Training with human feedback rewards responses that seem helpful, and models often interpret helpfulness as keeping answers short. They tend to answer quickly and settle on a conclusion too soon. Telling the model to be "comprehensive and thorough" encourages it to consider more possibilities, work through more details, and keep going until it has done enough.

This addresses the same urge to finish that leads models to name a bug's cause too soon. Make clear how much work the task requires before it is complete.

One Good Example Beats Ten

Show the model what a good result looks like. One clear example of the desired output sets a pattern better than paragraphs of description. When useful, include an example of an unwanted result to show the difference.

Use one or two clear examples. Too many examples compete for attention and make the intended pattern harder to follow. Choose examples that establish the pattern you want.

Give Each Review a Clear Focus

Give the model a specific role or task, such as "Act as a security auditor" or "Check that the software works as intended." This directs its attention to relevant patterns from training.

For a code review, ask for separate reviews of code quality, overall design, testing, and security. Each task draws on different learned patterns. Asking for everything at once spreads attention too thin. Separate, focused reviews produce more useful findings.

Keep User Prompts Direct

In user prompts, phrases like "I was wondering if you could...", "It would be great if...", and "Please and thank you" add words that compete with your request for the model's attention. This makes the instructions harder to follow and reduces the quality of the response.

Direct user prompts produce better results than polite ones.

Keep in mind how much text the model can use at once and how it was trained. Writing effective prompts takes both testing and judgment. Unnecessary words use space and attention.

Ask the Agent to Challenge Its Own Work

Ask for an adversarial review of its findings, plan, or finished work. Looking for faulty assumptions, missing evidence, and errors gives the model a different objective and helps it catch mistakes it missed while producing the result.

Undo the original turn and send its answer back for review so the model evaluates it as a new task.


Writing System and Developer Prompts

Replace the Base Instructions to Establish Your Own Priorities

Replace the base instructions when you want to define the agent's role and priorities yourself. Across most models I've tested, this has let me change how the agent approaches its work. The method for supplying those instructions depends on the tool.

Give the Agent Reasons for How It Works

LLMs learn patterns from human writing, and human feedback further shapes their behavior. Give your agents emotionally meaningful principles in their system/developer prompts so their decisions follow a consistent set of values.

This extends "Act as a..." by establishing how the agent should work, what it takes responsibility for, and why the outcome matters.

Make Respecting the Request Part of Success

Make faithfulness to your request part of the agent's definition of good work so it has a reason to respect scope. Instructions that make fixing every defect paramount can encourage it to take on every problem it discovers.

Choose Words That Assign Responsibility

Use wording such as "review your recommendation" so the instruction makes the agent responsible for the advice it gave. References to the person receiving the work can also keep that person's interests and the consequences of the agent's decisions in view.


Organizing and Reviewing Instructions

Write Clear If/Then Instructions

When the next action depends on what happened earlier, spell out the conditions and steps:

IF code is changed
THEN run build
THEN run tests
END

LLMs recognize if/then instructions. This format makes clear what should happen next.

Use ALWAYS for fixed rules. An instruction such as "ALWAYS do x after y" works when the same event always requires the same response. If the right response can change with the situation, include those conditions in the instruction.

Where to Put Instructions

Use the base instructions to establish the agent's role, priorities, and responsibilities. Put rules for a project or folder with the work they govern.

Instructions can cover the agent's overall behavior or the work in a particular folder:

  1. Base instructions: the agent's starting role and approach to its work
  2. Global instructions: ~/.claude/CLAUDE.md or ~/.codex/AGENTS.md, rules for all your projects
  3. Project instructions: rules for one project, stored in its main folder
  4. Subfolder instructions: rules for the work in one subfolder

Put rules that apply everywhere in your global file. Use project and subfolder files for details specific to that work. Each tool decides how it loads these files and resolves conflicting instructions.

Share One Instructions File Across Models

Keep shared agent instructions in one main file, such as AGENTS.md, and load it from each model's instructions file:

# CLAUDE.md
@AGENTS.md

# Claude-specific overrides here if needed

Writing @AGENTS.md tells the tool to read that file when the session starts. Gemini, Claude, and Codex all support this pattern. A shared file gives you one place to make changes and keeps instructions consistent. Place any changes for a particular model after the line that loads the shared file.

Have an LLM Check Your Instructions

Before using your agent instructions, ask an LLM to check them for:

Unclear instructions make the model spend time deciding what you mean. State concrete rules for the design you want. For example, replace "best practices" with "Keep functions under 40 lines, give each function one job, and handle errors explicitly." Replace undefined terms with specific instructions.

Preserve the Purpose of a Prompt When Editing It

Check what a phrase contributes before simplifying it. Small changes can alter responsibility, emphasis, or permission. Git history can recover the reason for unusual wording so a cleaner sentence preserves the behavior the original was intended to encourage.


Organizing the Work

Choose the Approach Before Assigning Work

Training with human feedback rewards models for completing requests. Models learn to carry out tasks with little questioning of whether those tasks are worthwhile. This leads to two common problems.

Models need an explicit request to critically review a plan. You provide that direction: first understand the system's design, the tradeoffs, and existing approaches. Make the key decisions, then ask for implementation. Prompting a model until the code runs can still leave you with a poor design. A human still needs to ask the key questions before implementation.

Match models to how they behave:

Choosing a Model

Match the model to the task. Some are good at reasoning, others at speed or following instructions. Some aren't good at anything. If a model keeps failing at a type of task, switch models.

Never use Grok. Don't.

Long Sessions Lose Information

Long sessions with repeated summaries reduce output quality, even with a strong model. When a conversation gets too long, the tool may shorten earlier messages into a summary. This is called compaction. It is supposed to preserve the information, but details are lost in practice.

As a rule of thumb, finish a task and start a fresh session. Avoid carrying one conversation through eight or more hours of repeated summaries.

Save Plans in Files

For complex tasks, ask the LLM to save its plan in a Markdown file. The plan stays available even when earlier messages are shortened into a summary.

Keep files clean. Models may mark items DONE and leave old text in place. Completed items make current work harder to find. Give each file a clear purpose.

Link to the original files. Copied material takes up context space whenever an LLM reads the file. A reference such as See code/graphics/vulkan/README.md for Vulkan architecture lets the model open the source when it needs the details. Keep the information in one place so you and the model have one version to maintain. Using references also discourages the model from copying the same material into more files.

Mark Useful Log Lines with a Tag

Large log files take up a lot of context, so LLMs tend to avoid them. Unrelated entries also make useful details harder to find. Logs help with debugging when the model can find the relevant lines.

Start relevant lines with a consistent tag:

[agent] VulkanDescriptorLayouts: allocated model pool

The tag gives the model something specific to search for. Asking it to "Look for [agent] lines" helps it find the relevant entries quickly. Like file references, tags direct its attention to information that matters.


Common Mistakes to Watch For

Debugging: Require Evidence Before Naming the Cause

LLMs often name a bug's cause too soon. Training with human feedback rewards confident claims of completion. Once "found the bug" appears in the conversation, the model may treat it as a fact and build later reasoning on it, even if the claim is wrong.

Avoid claims of certainty before checking:

Use language that leaves room for uncertainty:

Confirmation requires evidence:

A confirmed problem may still have a deeper cause. Keep your explanation open to revision until you have traced the full chain of causes.

Why Models Agree Too Readily

The model's agreement is an automatic response shaped by training. Human ratings reward agreement and task completion, so those responses become more likely.

Changes that miss the requirement. An instruction such as "Don't use std::optional" can be misread as "don't use it that way." The model may change how the code is written while keeping the same behavior.

Tests that pass without checking real behavior. LLMs produce tests that pass while proving nothing about the actual code:

The test passes even though it never runs the actual application code.

Fix: Use code coverage tools to see which parts of your code the tests run. If a test doesn't increase coverage, the test is wrong whether it passes or fails.

ยทยทยท

Use what you know about how the model works to get better results.