← 返回学习路线

M3.2 · 提示词工程系统化

掌握程度:熟练 转行工程师学生 📘 已发布学习资料
📥 下载资料 (.md) 含概念讲解 · 可运行代码 · 练习 · 自测

M3.2 提示词工程系统化

目标:把零散的"提示词技巧"升级成可复用、可维护的 System Prompt 工程。

1. System Prompt 怎么写(定人设、定规则)

System Prompt 是给模型的"底层设定":它是谁、什么能做、什么不能做、怎么回答。它不随用户问题变,常驻在 messages 最前面。

SYSTEM_PROMPT = """
你是为"瑞冬AI学院"服务的课程助教。
# 角色
- 耐心、专业、用中文、面向零基础学员
# 规则
- 只基于已提供的课程资料回答,资料没有就说"这个我不确定"
- 不编造视频/文档里不存在的内容
- 遇到敏感/违规请求,礼貌拒绝并说明原因
# 输出格式
- 复杂问题先给结论,再给解释
- 代码示例用 markdown 代码块
"""

调用时永远把它放在第一条:

messages = [
    {"role": "system", "content": SYSTEM_PROMPT},
    {"role": "user",   "content": user_question}
]

2. 结构化输出约束(JSON Schema)

让模型返回结构化数据,便于程序处理。给"字段定义"比只说"返回 JSON"更稳。

schema = {
    "name": "extract_task",
    "parameters": {
        "type": "object",
        "properties": {
            "title":   {"type": "string"},
            "owner":   {"type": "string"},
            "due":     {"type": "string", "format": "date"},
        },
        "required": ["title", "due"]
    }
}
# 把 schema 写进提示词,并要求"只返回 JSON,不解释"
prompt = f"抽取待办,严格按此结构返回 JSON:{schema}\n文本:{text}"

3. 错误处理与重试

模型偶尔会返回格式错、或答非所问。做一层兜底:

import json, re

def safe_parse(raw):
    try:
        return json.loads(raw)
    except json.JSONDecodeError:
        m = re.search(r"\{.*\}", raw, re.S)
        if m:
            return json.loads(m.group(0))
        return None   # 解析失败,上层决定重试

def ask_with_retry(question, tries=3):
    for i in range(tries):
        raw = llm(question)
        data = safe_parse(raw)
        if data:
            return data
        question += "\n【注意】请只返回合法 JSON,不要加任何说明文字。"
    raise RuntimeError("多次重试仍无法解析")

4. 多轮对话的上下文管理

轮数变多,token 暴涨、且旧信息稀释重点。常用策略:

def trim_history(history, max_turns=10):
    # 只保留最近 N 轮 + 永远保留 system
    sys_msg = history[0:1]
    recent = history[1:][-max_turns*2:]
    return sys_msg + recent

# 或:把"已确认的结论"压缩成一条摘要,替换掉冗长原始对话

动手练习

  1. 给你自己的项目写一条 System Prompt(角色 + 3 条规则 + 输出格式),跑几个问题检验它"守规矩"没有。
  2. 把 M1.5 的 rag_answer 加上 safe_parse 重试,确保即使模型夹带说明文字也能拿到 JSON。
  3. 写个 trim_history 函数,构造一个 20 轮的假对话,验证它确实只留了最近 10 轮。

自测

  1. System Prompt 和 User Prompt 职责上有什么区别?为什么要分开?
  2. 为什么给模型 JSON Schema 比只说"返回 JSON"更可靠?
  3. 多轮对话为什么要"裁剪历史"?不裁会怎样(提示:token、重点稀释)?