第 6 章 · Prompt 工程:instructions 与描述体系
本章目标:掌握 Agno 中
description、instructions、system_message三层的分工与优先级,学会写出稳定、可维护的 Agent 提示词。
6.1 Agno 的三层提示词体系
Agno 不是让你手写一大段 system prompt,而是把它拆成结构化的配置项。按官方文档的上下文工程(Context Engineering)模型:
| 配置项 | 层级 | 作用 |
|---|---|---|
description | 最高层 | Agent 是谁、整体职责,相当于"岗位说明书" |
instructions | 中间层 | 具体行为规则列表,相当于"操作手册" |
system_message | 覆盖层 | 完全自定义的 system 消息,设置后取代前两者的自动组装 |
# prompt_layers.py —— 三层体系的用法
import os
from dotenv import load_dotenv
from agno.agent import Agent
from agno.models.openai import OpenAIChat
load_dotenv()
model = OpenAIChat(
id="deepseek-chat",
api_key=os.getenv("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com/v1",
)
agent = Agent(
model=model,
# 岗位说明书:一句话说清角色与边界
description="你是一名严谨的 Python 技术面试官。",
# 操作手册:逐条列出行为规则,Agno 会编号后注入 system 消息
instructions=[
"每次只问一个问题,等候选人回答后再追问",
"追问要针对上一轮回答中的薄弱点",
"全程使用中文,代码示例可用英文标识符",
"不要一次给出答案,先引导候选人思考",
],
markdown=True,
)
agent.print_response("开始面试我")为什么用列表而不是一整段? 列表让每条规则独立成行,模型对"条目式指令"的遵循率显著高于大段落;同时便于代码评审和版本 diff——这是把提示词当"配置"而非"文案"管理的关键。
6.2 instructions 支持模板变量
instructions 里可以放占位符,配合会话状态在运行时填充,实现"一套提示词服务多种用户":
# prompt_template.py —— 模板变量注入
agent = Agent(
model=model,
db=None,
instructions=[
"用户当前的会员等级是 {plan},回答语气据此调整",
"免费用户推荐方案时必须说明付费功能限制",
],
session_state={"plan": "pro"}, # 会话状态中的值会填进 {plan}
)
# 同一 Agent 换个 session_state 就能服务不同等级用户
agent.print_response("有什么功能可以用?", session_state={"plan": "free"})这种写法把"业务数据"从提示词文本中解耦出来:改会员规则只动 session_state,不动提示词。
6.3 什么时候用 system_message
绝大多数场景用 description + instructions 就够了。只有当你需要完全控制 system 消息原文时才用 system_message——注意它会绕过自动组装:
# system_message_demo.py —— 完全覆盖型 system 消息
agent = Agent(
model=model,
description="这个字段会被忽略", # ⚠️ 设置了 system_message 后不再生效
instructions=["这条也不会生效"],
system_message="你是 pirate Translator,把用户输入翻译成海盗腔英文。",
)选择建议
除非迁移遗留系统或对接强约束的第三方 prompt 规范,否则不要用 system_message。放弃结构化分层等于放弃了 Agno 对上下文的精细管理能力。
6.4 Few-shot 示例注入
想让输出格式极其稳定,最有效的手段是在指令里给例子(few-shot)。结合第 5 章的结构化输出,格式由 schema 保证;而风格和判断标准则靠示例:
# few_shot.py —— 用示例锚定分类标准
from pydantic import BaseModel, Field
from typing import Literal
class TicketCategory(BaseModel):
category: Literal["bug", "feature", "question", "complaint"]
urgency: int = Field(ge=1, le=5, description="紧急程度")
support_router = Agent(
model=model,
description="客服工单分类员。",
instructions=[
"根据工单内容输出分类与紧急度(1-5)",
"判断标准示例:",
"- '登录按钮点了没反应' → bug, urgency=3",
'- "希望增加深色模式" → feature, urgency=2',
'- "数据会不会泄露?" → question, urgency=1',
'- "再不解决我就投诉到消协!" → complaint, urgency=5',
],
output_schema=TicketCategory,
)
cases = ["App 闪退了根本打不开", "能不能出个微信小程序版"]
for c in cases:
r = support_router.run(c)
print(c, "->", r.content.category, r.content.urgency)示例的价值在于消除标准的歧义:"闪退"算 bug 还是 complaint?有了对照样例,模型的选择就稳定多了。
6.5 中文 Prompt 实战要点
教程统一使用中文模型与中文场景,几个实测有效的经验:
- 指令语言与业务语言一致:让 DeepSeek 处理中文任务时,指令本身也用中文写,术语理解更准;
- 避免长否定句:"不要使用复杂句式"不如直接写"每句不超过 25 字";
- 规则数量控制在 10 条以内:超出后中间条款容易被忽略,宁可拆分成多个专职 Agent;
- 关键格式要求放首尾:列表第一条和最后一条的遵循率最高,把硬性格式约束放在这两个位置;
- 用
additional_guidance补充临时规则(如需动态追加行为要求),保持主 instructions 稳定,方便对比效果。
6.6 迭代方法:像测代码一样测提示词
提示词工程的正确姿势不是"凭感觉改",而是建立小评测集回归验证:
# prompt_eval.py —— 最简提示词回归测试
EVAL_CASES = [
("登录页面白屏", "bug"),
("希望支持导出 Excel", "feature"),
("怎么修改绑定的手机号", "question"),
]
def evaluate(agent) -> float:
hits = sum(
agent.run(q).content.category == expect
for q, expect in EVAL_CASES
)
return hits / len(EVAL_CASES)
print(f"准确率: {evaluate(support_router):.0%}")
# 修改 instructions 前后各跑一次,用数字决定是否采纳新版本把这套思路扩展到几十条用例、接入 CI 定期跑,就是第 24 章评估体系(Evals)的雏形。
6.7 本章小结
description定角色、instructions定规则、system_message全覆盖(慎用);- instructions 用条目列表 + 模板变量
{placeholder},是可维护的"配置"而非文案; - Few-shot 示例用于消除判断标准的歧义,与 output_schema 配合效果最佳;
- 中文提示词:指令与业务同语言、少否定句、规则 ≤10 条、硬约束放首尾;
- 提示词改动要用评测集量化验证,拒绝凭感觉上线。
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. 设置了 system_message 之后,description 和 instructions 会怎样?
2. instructions 中写 "用户的套餐是 {plan}",如何让占位符被真实值替换?
3. 关于 few-shot 示例的主要作用,正确的是?
4. 按照本章的迭代方法论,改进提示词的正确流程是?
🛠️ 动手实践
- 把第 5 章"动手实践"的工单分类 Agent 重构为 description + instructions 分层写法,并补充 3 条边界规则。
- 为你的 Agent 写 10 条中文评测用例,实现
prompt_eval.py的升级版:输出每条的预期/实际对照表。 - 试验规则顺序的影响:把"输出必须是 JSON"分别放在 instructions 首位和末位,各跑 5 次统计格式错误次数。
至此入门篇完成,进入第 7 章:工具 Tools——内置工具包原理与使用。