{"slug": "langchain-series-3-prompts-explained-prompt-templates-chat-prompts-dynamic", "title": "LangChain Series #3: Prompts Explained — Prompt Templates, Chat Prompts, Dynamic Prompting…", "summary": "LangChain introduces dynamic prompt templates and chat prompts to improve LLM output quality. The framework supports PromptTemplate for reusable dynamic prompts and ChatPromptTemplate for chat models with message history. These tools enable developers to generate customized instructions and manage conversations efficiently.", "body_md": "No matter how powerful a model is, the quality of its output depends heavily on the instructions you provide.\n\nIn LangChain, prompts are much more than simple strings. They allow developers to dynamically generate instructions, manage conversations, inject chat history, and even enforce structured outputs.\n\nA prompt is an instruction, question, or input given to a model to guide its response.\n\nFor example:\n\n```\nExplain what a Transformer model is.              orSummarize the Attention Is All You Need paper.\n```\n\nThe model uses this prompt as context to generate an output.\n\nOne of the first concepts to understand is the difference between static and dynamic prompting.\n\nStatic prompts use hardcoded instructions. Only the user input changes while the prompt structure remains the same.\n\nExample:\n\n```\nuser_input = \"Attention Is All You Need\"\nprompt = f\"Summarize this topic: {user_input}\"\n```\n\nGenerated prompt:\n\n```\nSummarize this topic: Attention Is All You Need\n```\n\n*Why is it called Static?*\n\nBecause the structure never changes.\n\n```\nSummarize this topic:\n```\n\nwill always remain the same.\n\n** Limitations of Static Prompts: **While simple, static prompts have several drawbacks:\n\nThis is where Prompt Templates become useful.\n\nDynamic prompts generate instructions at runtime. Instead of hardcoding values, placeholders are used and filled dynamically.\n\nExample:\n\n```\nExplain the research paper {paper}in a {style} stylewith a {length} explanation.\n```\n\nGenerated prompt:\n\n```\nExplain the research paper Attention Is All You Needin a Beginner-Friendly stylewith a Long explanation.\n```\n\nThe prompt changes based on user selections.\n\nLangChain provides PromptTemplate to create reusable dynamic prompts.\n\n``` python\nfrom langchain_core.prompts import PromptTemplatetemplate = PromptTemplate(    input_variables=[        \"paper\",        \"style\",        \"length\",        \"style_instruction\"    ],    validate_template=True,    template=\"\"\"Please summarize the research paper titled \"{paper}\"Explanation Style: {style}Explanation Length: {length}Style Guidelines:{style_instruction}\"\"\")\n```\n\nCreate once and use many times.\n\nPromptTemplate checks missing variables.\n\n```\nvalidate_template=True\n```\n\nhelps catch mistakes early.\n\nPrompt Templates work seamlessly with:\n\nUpdating a single template updates your entire application.\n\nThe template can be populated using:\n\n```\nfinal_prompt = template.invoke({    \"paper\": paper_input,    \"style\": style_input,    \"length\": length_input,    \"style_instruction\": style_instructions[style_input]})\n```\n\nThis creates a customized prompt based on user selections.\n\nTraditional LLMs accept plain text:\n\n```\nInput ↓String ↓Output\n```\n\nChat Models work differently.\n\nThey accept a sequence of messages.\n\n```\nSystem MessageHuman MessageAI Message\n```\n\nand return an AI response.\n\nLangChain provides three primary message types.\n\n```\nfrom langchain_core.messages import (    SystemMessage,    HumanMessage,    AIMessage)\n```\n\nDefines the model’s behavior.\n\n```\nSystemMessage(    content=\"You are a concise AI assistant.\")\n```\n\nRepresents user input.\n\n```\nHumanMessage(    content=\"Tell me about LangChain.\")\n```\n\nStores previous responses.\n\n```\nAIMessage(    content=response.content)\n```\n\nChatPromptTemplate helps create dynamic prompts for chat models.\n\nExample from our project:\n\n``` python\nfrom langchain_core.prompts import ChatPromptTemplatechat_template = ChatPromptTemplate([    ('system', 'You are a helpful {domain} expert'),    ('human', 'Explain in simple terms what is {topic}')])prompt = chat_template.invoke({    'domain': 'machine learning',    'topic': 'diffusion models'})\n```\n\nInstead of managing message objects manually, we can generate them dynamically.\n\n*Benefits:*\n\nReal chatbots need conversation history.\n\nLangChain solves this using: *MessagesPlaceholder*\n\nExample:\n\n``` python\nfrom langchain_core.prompts import ChatPromptTemplate,MessagesPlaceholderchat_template = ChatPromptTemplate([    ('system', 'You are a helpful customer support agent'),    MessagesPlaceholder(        variable_name='chat_history'    ),    ('human', '{query}')])\n```\n\nThey allow dynamic insertion of:\n\nwithout manually rebuilding prompts every time.\n\n**This becomes extremely useful in:** Chatbots, Agents, Customer Support Systems\n\nSo far, our models have returned plain text responses.\n\nExample:\n\n```\nThe sentiment of the review is positive.\n```\n\nWhile this is easy for humans to read, it is difficult for applications to process programmatically.\n\nImagine building:\n\nInstead of plain text, we often need structured data like:\n\n```\n{    \"sentiment\": \"positive\",    \"summary\": \"The product received favorable feedback.\"}\n```\n\nThis is where Structured Outputs and Output Parsers become useful.\n\nStructured Outputs allow LLMs to return data in predefined formats.\n\nInstead of generating free-form text, we define a schema that the model should follow.\n\n```\n    User Input       ↓      LLM       ↓Structured Response\n```\n\nLangChain supports multiple ways to define these structures.\n\n** TypedDict: **Use TypedDict when:-\n\nExample:\n\n``` python\nfrom typing import TypedDictclass Person(TypedDict):    name: str    age: int\n```\n\n*Why TypedDict Has No Validation*\n\nConsider:\n\n```\nperson = {    \"name\": \"Bob\",    \"age\": \"25\"}\n```\n\nEven though age should be an integer, TypedDict will not raise an error.\n\nThis is because TypedDict provides type hints but does not validate data.\n\n** Pydantic Models: **Use Pydantic when:-\n\nExample:\n\n``` python\nfrom pydantic import BaseModelclass Student(BaseModel):    name: str    age: int = 18\n```\n\n*Why Use Pydantic?*\n\n** JSON Schema: **Another popular approach is JSON Schema.\n\nExample:\n\n```\n{  \"title\": \"student\",  \"type\": \"object\",  \"properties\": {    \"name\": \"string\",    \"age\": \"integer\"  },  \"required\": [\"name\"]}\n```\n\n*When Should You Use JSON Schema?*\n\nWhat if the model cannot generate structured output natively?\n\nThis is where Output Parsers come in.\n\nOutput Parsers convert raw LLM responses into structured formats.\n\n```\nLLM Output     ↓Output Parser     ↓Structured Data\n```\n\nLangChain provides multiple output parsers.\n\n** String Output Parser: **The simplest parser. It converts model responses into plain strings.\n\nExample:\n\n``` python\nfrom langchain_huggingface import ChatHuggingFace, HuggingFaceEndpointfrom dotenv import load_dotenvfrom langchain_core.prompts import PromptTemplateload_dotenv()llm = HuggingFaceEndpoint(    repo_id=\"google/gemma-2-2b-it\",    task=\"text-generation\")model = ChatHuggingFace(llm=llm)# 1st prompt -> detailed reporttemplate1 = PromptTemplate(    template='Write a detailed report on {topic}',    input_variables=['topic'])# 2nd prompt -> summarytemplate2 = PromptTemplate(    template='Write a 5 line summary on the following text. /n {text}',    input_variables=['text'])prompt1 = template1.invoke({'topic':'black hole'})result = model.invoke(prompt1)prompt2 = template2.invoke({'text':result.content})result1 = model.invoke(prompt2)print(result1.content)\n```\n\nThis parser is commonly used inside chains.\n\n** JSON Output Parser: **JSON Output Parser converts responses into JSON objects.\n\nExample:\n\n``` python\nfrom langchain_huggingface import ChatHuggingFace, HuggingFaceEndpointfrom dotenv import load_dotenvfrom langchain_core.prompts import PromptTemplatefrom langchain_core.output_parsers import JsonOutputParserload_dotenv()llm = HuggingFaceEndpoint(    repo_id=\"Qwen/Qwen2.5-7B-Instruct\",    task=\"text-generation\")model = ChatHuggingFace(llm=llm)json_parser = JsonOutputParser()template = PromptTemplate(    template='Give me 5 facts about {topic} \\n {format_instruction}',    input_variables=['topic'],    partial_variables={'format_instruction': json_parser.get_format_instructions()})# prompt = template.format()# model_output = model.invoke(prompt)# final_result = json_parser.parse(model_output.content)chain = template | model | json_parserchain_result = chain.invoke({'topic': 'Origami'})print(chain_result)\n```\n\nThe parser automatically injects formatting instructions into the prompt.\n\n*Why Use JsonOutputParser?*\n\n** Structured Output Parser: **StructuredOutputParser allows us to define required fields explicitly.\n\nExample:\n\n``` python\nfrom langchain_huggingface import ChatHuggingFace, HuggingFaceEndpointfrom dotenv import load_dotenvfrom langchain_core.prompts import PromptTemplatefrom langchain_classic.output_parsers.structured import StructuredOutputParser, ResponseSchemaload_dotenv()llm = HuggingFaceEndpoint(    repo_id=\"Qwen/Qwen2.5-7B-Instruct\",    task=\"text-generation\")model = ChatHuggingFace(llm=llm)response_schema = [    ResponseSchema(name=\"fact1\", description=\"The first fact about the topic\"),     ResponseSchema(name=\"fact2\", description=\"The second fact about the topic\"),    ResponseSchema(name=\"fact3\", description=\"The third fact about the topic\"),    ResponseSchema(name=\"fact4\", description=\"The fourth fact about the topic\"),        ResponseSchema(name=\"fact5\", description=\"The fifth fact about the topic\")]parser = StructuredOutputParser.from_response_schemas(response_schema)template = PromptTemplate(    template='Give me 5 facts about {topic} \\n {format_instruction}',    input_variables=['topic'],    partial_variables={'format_instruction': parser.get_format_instructions()})chain = template | model | parserchain_result = chain.invoke({'topic': 'Origami'})print(chain_result)\n```\n\n** Pydantic Output Parser: **PydanticOutputParser combines structure and validation.\n\nExample:\n\n``` python\nfrom langchain_huggingface import ChatHuggingFace, HuggingFaceEndpointfrom dotenv import load_dotenvfrom langchain_core.prompts import PromptTemplatefrom langchain_core.output_parsers import PydanticOutputParserfrom pydantic import BaseModel, Fieldload_dotenv()llm = HuggingFaceEndpoint(    repo_id=\"Qwen/Qwen2.5-7B-Instruct\",    task=\"text-generation\")model = ChatHuggingFace(llm=llm)class Person(BaseModel):    name: str = Field(description='Name of the person')    age: int = Field(gt=18, description='Age of the person')    city: str = Field(description='Name of the city the person belongs to')parser = PydanticOutputParser(pydantic_object=Person)template = PromptTemplate(    template='Generate the name, age and city of a fictional {place} person \\n {format_instruction}',    input_variables=['place'],    partial_variables={'format_instruction':parser.get_format_instructions()})chain = template | model | parserfinal_result = chain.invoke({'place':'sri lankan'})print(final_result)\n```\n\nStructured outputs make LLM responses predictable and easier to integrate into applications.\n\nLangChain provides multiple approaches:\n\nUnderstanding these tools is essential when building reliable AI applications that need structured, machine-readable data rather than free-form text.\n\nIn the next article, we’ll dive into Chains in LangChain and learn how to combine prompts, models, and output parsers into powerful end-to-end AI pipelines using LCEL.\n\n**Code Repository: **[https://github.com/Atul245/LangChain-for-developers](https://github.com/Atul245/LangChain-for-developers)\n\nIf you found this article helpful, consider:\n\n⭐ Starring the repository\n\n🍴 Forking the repository\n\n👤 Following me for more content on LangChain, Generative AI, and AI Engineering\n\n**Connect with me on LinkedIn:** [https://www.linkedin.com/in/atulkumar8/](https://www.linkedin.com/in/atulkumar8/)\n\n[🚀 LangChain Series #3: Prompts Explained — Prompt Templates, Chat Prompts, Dynamic Prompting…](https://pub.towardsai.net/langchain-series-3-prompts-explained-prompt-templates-chat-prompts-dynamic-prompting-fd1411b3e986) was originally published in [Towards AI](https://pub.towardsai.net) on Medium, where people are continuing the conversation by highlighting and responding to this story.", "url": "https://wpnews.pro/news/langchain-series-3-prompts-explained-prompt-templates-chat-prompts-dynamic", "canonical_source": "https://pub.towardsai.net/langchain-series-3-prompts-explained-prompt-templates-chat-prompts-dynamic-prompting-fd1411b3e986?source=rss----98111c9905da---4", "published_at": "2026-06-12 17:01:04+00:00", "updated_at": "2026-06-13 00:25:47.116974+00:00", "lang": "en", "topics": ["large-language-models", "natural-language-processing", "ai-tools"], "entities": ["LangChain", "PromptTemplate", "ChatPromptTemplate", "MessagesPlaceholder", "SystemMessage", "HumanMessage", "AIMessage"], "alternates": {"html": "https://wpnews.pro/news/langchain-series-3-prompts-explained-prompt-templates-chat-prompts-dynamic", "markdown": "https://wpnews.pro/news/langchain-series-3-prompts-explained-prompt-templates-chat-prompts-dynamic.md", "text": "https://wpnews.pro/news/langchain-series-3-prompts-explained-prompt-templates-chat-prompts-dynamic.txt", "jsonld": "https://wpnews.pro/news/langchain-series-3-prompts-explained-prompt-templates-chat-prompts-dynamic.jsonld"}}