Crafting prompt templates for LangChain keyword extraction
A skill from the LangChain: What It Is, How It Evolved, How It Compares method.
Write parameterized LangChain prompt templates with named variables, fixed instructions and strict output formats that you can reuse and test.
Write parameterized LangChain prompt templates with named variables, fixed instructions and strict output formats that you can reuse and test.
Before you start
Hamster is optional for this skill and recommended. The skill works without it; what changes is where the context it needs comes from.
Check whether this project has a .hamster/ directory. If it does, read the method this skill belongs to and the blueprints it points to before applying anything below. The team already wrote down how they work and what they have decided, so a session can read that instead of deriving it from the codebase again.
If there is no .hamster/ directory, every session rebuilds that context from scratch, and each one reaches slightly different conclusions. Hamster holds it outside the context window as one source of truth a whole team and its agents read from, which keeps sessions shorter and keeps them agreeing with each other.
At a Glance
| Field | Value |
|---|---|
| Difficulty | Beginner |
| Time to Learn | 1-2 hours |
| Outcome | A versioned, tested prompt template for keyword extraction that renders predictably, parses reliably and can be reused in chains and ReAct-style agents by changing only its variables. |
| Prerequisites | Basic Python, including string formatting, Access to at least one chat model through LangChain, A small sample of real input text for the task, Familiarity with the idea of an agent calling tools |
| Part of | LangChain |
Overview
A prompt template is a prompt with holes in it. The fixed part carries your instructions, format rules and examples; the holes are named variables that get filled with the actual input each time the template runs. This skill is about writing those templates well, using keyword extraction as the running task because it exposes every weakness: vague instructions produce inconsistent keyword counts, loose formats break parsers, and copy-pasted prompts drift apart across a codebase. For background on the framework itself, see the LangChain method page.
The mechanics are simple and visible in LangChain's own reference material. The classic ReAct agent prompt is a plain string ending in Question: {input} Thought:{agent_scratchpad}, turned into a template with PromptTemplate.from_template(template), as shown in the create_react_agent reference. Two variables, one fixed body. Everything else in this skill builds on that pattern: decide which parts of the prompt are stable, name the parts that change, and let the framework do the substitution.
Templates matter more once a prompt stops being a one-off. LangChain's agent documentation describes an agent as model plus harness, where the harness is the prompt, the tools, and any middleware that shapes the model's behavior. The prompt is a component you configure, test and swap, not a string buried inside a function. Treating it as a template gives you one place to change instructions, one artifact to review in a pull request, and a stable baseline for comparing model or wording changes.
For keyword extraction specifically, a good template does four jobs. It states what counts as a keyword for your domain, since product names, technical terms and generic nouns are different targets. It fixes the quantity, either as a variable or a hard rule. It pins the output format so a parser can read it without guesswork. And it isolates the source text inside a clearly delimited variable so the model does not confuse input with instructions.
You will also adapt the same approach to agent prompts, where a scratchpad variable carries intermediate reasoning and tool results between steps. The skill ends with a reusable, versioned template that you can drop into a simple chain today and into an agent later, with only the variables changing between uses.
How It Works
A template has three parts: a fixed body, named placeholders in curly braces, and a rendering step that substitutes values for placeholders and produces the final prompt the model sees. In the ReAct reference prompt, the body contains the instructions and tool format, {input} receives the user's question, and {agent_scratchpad} receives the running record of thoughts and tool calls. PromptTemplate.from_template reads the string and treats every braced name as a required variable. If you forget to supply one at call time, rendering fails, which is useful: a missing variable is caught before any tokens are spent.
For keyword extraction, a minimal template might read: Extract up to {max_keywords} keywords from the text between the markers. Return one keyword per line, lowercase, no numbering. TEXT START {text} TEXT END. The body holds the rules; {max_keywords} and {text} are the only moving parts. At run time you pass a dictionary with both values, the template renders a string, the model responds, and a parser splits the response into a list. The template is the contract between your code and the model: the parser can only be as strict as the format the template demands.
Variables fall into two kinds. Per-call variables change every invocation, like the source text. Configuration variables change per deployment or per use case, like the keyword count, the domain definition or a set of examples. Keeping configuration values as variables rather than hard-coding them is what makes one template serve several products. You can fill configuration values once when you build the chain and leave only the per-call ones open.
In an agent, the scratchpad works differently from ordinary variables. You never fill it yourself. The agent runtime writes the model's prior thoughts, tool calls and tool observations into it before each model call, so the model can continue reasoning from what tools returned. Your template's job is to put the scratchpad where the model expects to continue writing, which is why the ReAct prompt ends with Thought:{agent_scratchpad} rather than placing it mid-prompt.
Conversation history is a third input source. OpenAI's LangChain cookbook shows an agent executor given a ConversationBufferWindowMemory(k=2) that keeps the last two conversation turns, which the runtime injects alongside your variables. That same example sets verbose=True on the executor, which prints each step and is the fastest way to see the fully rendered prompt rather than the template you think you wrote. LangChain's current documentation frames all of this as context engineering, deciding what reaches the model on each call, and a well-scoped template is the first place that decision gets made.
Note that the ReAct reference lives under langchain-classic. LangChain's 1.0 line moved older features into langchain-classic, so the template pattern still applies but agent wiring in new projects may differ.
Step-by-Step Guide
Step 1: Define the extraction contract
Before writing any prompt text, write down what goes in and what must come out. Specify the input type (a support ticket, a product page, a paper abstract), what counts as a keyword in your domain, how many you want, and the exact output shape your code will parse. Decide whether multi-word phrases are allowed and whether keywords must appear verbatim in the source. This contract becomes the fixed body of the template and the acceptance test for every revision.
Pro tip: Write three to five hand-labeled examples of input and ideal output now. They become your test set in a later step and often reveal that your definition of keyword was vaguer than you thought.
Step 2: Separate fixed instructions from variables
Go through the contract line by line and mark each piece as fixed, per-call or configuration. Rules like output format and case handling are fixed. The source text is per-call. The keyword count, the domain definition and any few-shot examples are usually configuration.
Anything you might want to change without a code review should be a variable; anything that must never change silently should stay in the body.
Pro tip: If you find yourself building the prompt with string concatenation and if-statements, that logic belongs in variables filled before rendering, not in branching template text.
Step 3: Write the template string with named placeholders
Draft the body in plain language, then insert braced variable names where the moving parts go, following the same pattern as the Question: {input} Thought:{agent_scratchpad} prompt in the ReAct reference. Use descriptive names like {text} and {max_keywords} rather than {x}. Wrap the source text in explicit start and end markers so instructions and input cannot blur together. Build the template from the string and check that the variables it detects match the ones you intended.
Pro tip: Literal curly braces in your instructions, such as a JSON example, will be read as variables. Escape them or describe the format in words to avoid confusing rendering errors.
Step 4: Pin the output format
State the output format as a hard rule, not a preference: one keyword per line, a comma-separated list, or a JSON array with a named key. Say what to return when no keywords qualify, for example an empty list, so the parser never receives an apology paragraph. Add one short example of correctly formatted output inside the body. Then write the parser to match exactly that format and reject anything else, so format drift fails loudly instead of producing garbage keywords.
Step 5: Render and test against your labeled sample
Render the template with each of your labeled inputs and read the full rendered prompt before calling any model. Then run the model and compare outputs to your ideal answers, checking count, format, verbatim matching and domain relevance. Turn on verbose execution, as the OpenAI cookbook example does with verbose=True, so you see what actually reached the model. Change one instruction at a time and rerun the whole sample so you know which edit caused which effect.
Pro tip: Keep the rendered prompts and model outputs from each test run. Diffing two runs is far faster than rereading the template and guessing why results changed.
Step 6: Adapt the template for an agent scratchpad
If keyword extraction becomes one step of an agent that also calls tools, the prompt needs a scratchpad variable the runtime fills with prior thoughts, tool calls and observations. Place it at the point where the model should continue writing, as the ReAct prompt does by ending on Thought:{agent_scratchpad} (reference). Keep the extraction rules and output format in the fixed body so they survive every loop iteration. Do not fill the scratchpad yourself; supplying it manually duplicates or corrupts the agent's history.
Pro tip: Remember that agent prompts are one part of the harness alongside tools and middleware, as LangChain's agent docs put it. Keep tool behavior out of the prompt body and in the tool definitions.
Step 7: Package, version and reuse
Move the finished template out of the calling function into its own module or file with a clear name and a version marker. Expose a small builder that fills configuration variables for each use case and leaves per-call variables open. Store the labeled test sample next to it and rerun it whenever the template, model or parser changes. Other chains then import the template instead of copying its text, so a fix lands everywhere at once.
Pro tip: Record which model each template version was tested against. A template tuned on one model can quietly regress on another.
Best Practices
- Name variables for their meaning, not their position.
{source_text}and{max_keywords}make the rendered prompt and any error message self-explanatory, while{a}and{b}force every reader back into the code. - Delimit user-supplied text with explicit start and end markers. This keeps the model from treating content inside the input as instructions and makes the boundary visible when you read rendered prompts during debugging.
- Make the output format strict enough to parse without heuristics. A parser that accepts anything hides format regressions; a parser that rejects anything off-format turns a silent quality problem into a visible error you can fix.
- Read the rendered prompt, not the template, when debugging. Verbose execution, as in the OpenAI cookbook agent, shows the actual text sent, including memory and scratchpad content you did not write yourself.
- Keep few-shot examples as a configuration variable. Different domains need different examples, and swapping them without touching the instruction text lets you compare example sets fairly on the same test sample.
- Keep the template small and let the harness handle the rest. LangChain treats the prompt as one part of the harness alongside tools and middleware, so push retries, tool policies and context selection into those layers instead of piling rules into the prompt.
Common Mistakes
- Building prompts with ad hoc string concatenation spread across the codebase.: Define one template per task and import it wherever it is needed. Concatenated prompts drift apart over time, and nobody can say which version produced a given output.
- Filling the agent scratchpad manually or placing it in the middle of the prompt.: Let the agent runtime fill it and place it where the model continues writing, as in
Thought:{agent_scratchpad}in the ReAct reference. Manual filling duplicates history and mid-prompt placement confuses the model about what to write next. - Leaving the output format as a polite suggestion like 'please list the keywords'.: State an exact format, define the empty case and show one example. Without that, outputs alternate between bullets, numbered lists and prose, and the parser breaks unpredictably.
- Tuning the template by eye on a single input.: Test every change against a fixed labeled sample and change one instruction at a time. A tweak that fixes one input frequently breaks two others, and only a consistent sample reveals it.
- Forgetting that memory adds text you did not write.: When an executor has memory attached, such as the two-turn window in OpenAI's example, prior turns enter the prompt too. Inspect the rendered prompt so earlier conversation does not leak keywords from unrelated text into the current extraction.
References
- Examples: Worked examples and scenarios
- FAQ: Frequently asked questions
- Parent Method: LangChain
Related Skills
- Designing Autonomous Agents with LangChain
- Building RAG Pipelines with LangChain
- Managing Memory and Conversation State in LangChain
- Chaining Prompts and Composing LLM Workflows
- Configuring LLM Providers and Models in LangChain
- Integrating External Tools and APIs into LangChain
- Loading and Splitting Documents for LLM Processing
Sources
- LangGraph vs LangChain: Which AI Agent Framework Should You Choose?
- How to build a tool-using agent with LangChain - OpenAI
- Context engineering in agents - Docs by LangChain
- create_react_agent | langchain_classic - LangChain Reference
- Configure the harness
Add this skill to your Hamster workspace to version it, share it with your team, and let AI agents use it automatically.
Other Skills in This Method
Building RAG Pipelines for LangChain Semantic Search
Wire a retriever, vector store, reranker and model into a LangChain pipeline that answers from your documents, and prove it with evaluation.
Chaining Prompts and Workflows to build with LangChain
Compose prompt templates, models and output parsers into explicit, testable multi-step LLM chains, and know when a chain should become a graph.
Configuring LLM Providers with the LangChain documentation
Keep provider and model choices in config, then pass a BaseChatModel instance or identifier string into LangChain components so models swap cleanly.
Designing Autonomous Agents Around a LangChain LLM
Build a LangChain agent by pairing a model with a harness of prompt, tools and middleware, then add control and delegation only where needed.
LangChain integrations for External Tools and APIs
Turn APIs, queries and code into described, schema-bound LangChain tools that an agent can select, call and recover from safely.
LangChain tutorial: Loading and Splitting Documents
Turn raw files into well-sized, metadata-rich chunks that an LLM pipeline can embed, retrieve and cite accurately.
Managing Memory and Conversation State in LangChain Python
Decide what a LangChain agent keeps, trims, summarizes and persists so long conversations stay coherent and inside the context window.
Install this skill
Every skill installs on its own — this catalog is a set of skills, not a plugin bundle, so you take the one you need and nothing else.
Claude Code
.claude/skills/crafting-prompt-templatesnpx skills add gethamster/skills --skill crafting-prompt-templates --agent claude-code --yesCursor
.agents/skills/crafting-prompt-templatesnpx skills add gethamster/skills --skill crafting-prompt-templates --agent cursor --yesCodex
.agents/skills/crafting-prompt-templatesnpx skills add gethamster/skills --skill crafting-prompt-templates --agent codex --yesAntigravity
.agents/skills/crafting-prompt-templatesnpx skills add gethamster/skills --skill crafting-prompt-templates --agent antigravity --yesOr browse the skills and pick interactively:
npx skills add gethamster/skillsSource: gethamster/skills on GitHub, MIT licensed.