Control model behavior with System Prompts, guide style with few-shot examples, and force models to output structured JSON with Pydantic—these are core skills for building reliable AI applications.
Prompt Engineering is the most direct means to affect LLM output quality. This section introduces four progressive tips and techniques from the most basic to the most rigorous:
passsystem_promptParameters define the Agent's role and behavioral guidelines. The simplest yet effective.
Add 2-5 input/output examples to the system prompt to guide the model to imitate a specific style or format.
Use a template in prompt to clearly define the output field names and formats to make the natural language output more regular.
Use Pydantic to define the data model byresponse_formatForces LLM to output strict JSON, usable directly as a Python object.
Reliability and parsability are improved in sequence: basic → few-shot → structured prompts → structured output. In a production environment, any scenario that requires a program to parse LLM output should be given priority.Structured output(Pydantic), it is the most reliable way.
The simplest way to prompt: increate_agentwhen passed insystem_promptParameters, tell the model who it is and what it should do.
Without the system prompt, the model will give the "honest" answer - the moon has no capital:
agent = create_agent(model=deepseek_model())
question = HumanMessage(content="What's the capital of the moon?")
response = agent.invoke({"messages": [question]})
print(response['messages'][1].content)
system_prompt = "You are a science fiction writer, create a capital city at the users request."
scifi_agent = create_agent(
model=deepseek_model(temperature=1), # temperature=1 增加创意性
system_prompt=system_prompt
)
response = scifi_agent.invoke({"messages": [question]})
print(response['messages'][1].content)
temperature=1Make the model output more creative and diverse (the results of each run are different);temperature=0Make the output more certain and repeatable (the same result every time you run it). Use high temperature for creative tasks and low temperature for tasks that require consistency (such as code generation, data extraction).
Few-shot prompting is a powerful technique: give a few "input → output" examples directly in the system prompt, and LLM will imitate the style and format of these examples to generate new responses.
system_prompt = """
You are a science fiction writer, create a space capital city at the users request.
User: What is the capital of mars?
Scifi Writer: Marsialis
User: What is the capital of Venus?
Scifi Writer: Venusovia
"""
scifi_agent = create_agent(
model=deepseek_model(),
system_prompt=system_prompt
)
question = HumanMessage(content="What is the capital of The Moon?")
response = scifi_agent.invoke({"messages": [question]})
print(response['messages'][1].content)
Note the change in output style: the model learned the format "Scifi Writer: [word]" in the example and gave a concise one-word answer instead of a long description.
LLM learned to "continue" text through training. The few-shot example is equivalent to showing the model a "conversation script", and the model will continue writing in the style of this script. The quality and consistency of the examples directly determine the few-shot effect - the examples must be representative and the format must be uniform.
Structured Prompting defines clearly field names and output formats in the system prompt, making the model's natural language output more regular and easier to parse.
system_prompt = """
You are a science fiction writer, create a space capital city at the users request.
Please keep to the below structure.
Name: The name of the capital city
Location: Where it is based
Vibe: 2-3 words to describe its vibe
Economy: Main industries
"""
scifi_agent = create_agent(
model=deepseek_model(),
system_prompt=system_prompt
)
response = scifi_agent.invoke({"messages": [question]})
print(response['messages'][1].content)
The output of the structured prompt is stillnatural language string, field separation is just a convention, and the model may not strictly adhere to it (occasionally adding or removing fields, or changing the order). If you need to reliably parse each field with code, you must use the following sectionStructured output (Pydantic)。
Structured Output is the most reliable way: usePydanticDefine the data model byresponse_formatThe parameter tells LLM that the output must be according to this schema. LangChain will automatically parse the model's JSON output into Pydantic objects under the hood.
from pydantic import BaseModel
class CapitalInfo(BaseModel):
name: str # 城市名称
location: str # 地理位置
vibe: str # 氛围描述
economy: str # 经济支柱
agent = create_agent(
model=deepseek_model(),
system_prompt="You are a science fiction writer, create a capital city at the users request.",
response_format=CapitalInfo # 关键:传入 Pydantic 类
)
question = HumanMessage(content="What is the capital of The Moon?")
response = agent.invoke({"messages": [question]})
# structured_response 是 Pydantic 对象,不是字符串
print(response["structured_response"])
when you pass inresponse_format=CapitalInfoWhen, LangChain will:
CapitalInfoTools, parameters strictly conform to the schemaresponse["structured_response"]Modern LLM (GPT-4, DeepSeek, Claude) are supportedFunction Calling/Tool Use, which requires that the model output strictly conforms to the parameters of JSON Schema, and the reliability is much higher than "embedding JSON in ordinary text".response_formatParameters take advantage of this mechanism.
Once you have the Pydantic object, you can read each field just like accessing the properties of a normal Python object:
capital_info = response["structured_response"]
# 访问具体字段
print(capital_info.name) # → 'Lunar Prime'
print(capital_info.location) # → 'Mare Imbrium, near the lunar equator'
print(capital_info.vibe) # → 'futuristic, serene, industrious'
print(capital_info.economy) # → 'Helium-3 mining...'
# 组合使用
print(f"{capital_info.name} is located at {capital_info.location}")
useresponse_formathour,messagesExcept in the listHumanMessageandAIMessage, there will be one moreToolMessage:
for msg in response["messages"]:
pprint(msg)
When using structured output,response['messages'][-1].contentis no longer what you want (it could be an empty string or a tool call message). should passresponse["structured_response"]to get the Pydantic object insteadmessages[-1].content。
| Skill | Output format | reliability | Applicable scenarios |
|---|---|---|---|
| Basic tips | Natural language (free form) | Low | Open dialogue, creative writing, simple Q&A |
| Few-shot | Natural language (mimicking example format) | middle | A specific style/format is required, and there are samples for reference. |
| Structured prompts | Natural language (with field conventions) | middle | A rough structure is required, allowing for occasional deviations |
| Structured output | Pydantic object (strict JSON) | high | Requires program parsing output, data pipeline, and form filling |