目录

一、什么是提示词工程

1.1 定义

1.2 核心价值

1.3 提示词工程的发展背景

二、提示词的基本结构

2.1 角色(Role)

2.2 任务(Task)

2.3 输入(Input)

2.4 输出格式(Output Format)

2.5 约束(Constraint)

2.6 示例(Example)

2.7 完整提示词示例与代码

三、提示词核心技巧

3.1 角色设定(Role Prompting)

3.2 约束控制

3.3 Zero-shot(零样本)

3.4 Few-shot(少样本)

3.5 Chain of Thought(思维链,CoT)

3.6 结构化输出(JSON)

3.7 其他常用技巧补充

(1)Self-Consistency(自一致性)

(2)ReAct(Reasoning + Acting)

(3)提示词模板化

四、角色提示词详解

4.1 三种消息角色

(1)system(系统提示词)

(2)user(用户输入)

(3)assistant(助手回复)

4.2 三种角色的配合方式

4.3 代码实现

(1)多轮对话基础示例(OpenAI SDK)

(2)对话式 Few-shot(OpenAI SDK)

(3)LangChain 实现多轮对话

五、提示词工程的最佳实践与常见误区

最佳实践

常见误区

六、本节总结


一、什么是提示词工程

1.1 定义

提示词(Prompt) 是用户提供给 AI 模型的输入指令,用于引导其生成特定输出。

提示词工程(Prompt Engineering) 则是设计、优化这些指令的系统化过程,旨在提升模型输出的准确性、相关性和可用性

简单来说:你对 AI 说什么、怎么说,直接决定了 AI 给你的回答质量。提示词工程就是研究"怎么说才能得到最好的回答"。

1.2 核心价值

价值维度 说明
降低幻觉(Hallucination) 通过明确约束和上下文限定,减少 AI "胡编乱造"的概率
提升效率 减少反复迭代的次数,一次性获得可用结果
解锁潜能 引导模型完成复杂推理、创意生成、代码编写等高阶任务
保证一致性 在批量处理场景中,通过标准化提示词确保输出格式和质量的一致性
降低使用门槛 不需要微调模型,通过自然语言即可定制模型行为

1.3 提示词工程的发展背景

提示词工程之所以成为一门独立的"工程学科",有几个关键背景:

  • 大模型能力涌现:GPT-3、ChatGPT 等模型的出现,使得同一个模型在不同提示词下可以表现出截然不同的能力。
  • 从微调到提示的范式转变:早期 NLP 任务需要针对每个任务训练专门的模型;现在通过精心设计的提示词,一个通用模型就能完成多种任务。
  • API 经济:调用大模型 API 已成为主流开发方式,提示词就是开发者与模型之间的"编程语言"。

二、提示词的基本结构

一个完整的 Prompt,一般包含以下六个核心组成部分:

2.1 角色(Role)

作用:定义"模型是谁",框定回答的身份和视角。

你是一名资深客服分析专家 

角色设定会影响模型的语气、用词、知识范围和回答风格。后面第四章会详细展开。

2.2 任务(Task)

作用:告诉模型"要做什么",是提示词的核心指令。

请对用户工单进行分类 

任务描述应尽量具体、明确、无歧义。避免模糊指令如"帮我处理一下这个",而应写成"请将以下用户反馈按照退款/物流/商品三类进行分类"。

2.3 输入(Input)

作用:提供模型需要处理的数据或上下文。

用户问题:我退款怎么还没到账 

输入可以是文本、表格、代码片段、对话记录等。关键是要和任务描述清晰对应。

2.4 输出格式(Output Format)

作用:规定输出"长什么样",让结果可预期、可解析。

常见输出格式:

格式 适用场景
JSON 后端系统解析、API 集成
Markdown 文档生成、内容展示
HTML 前端页面渲染
XML 结构化数据交换
纯文本/大白话 面向普通用户的回答
列表 分类汇总、要点罗列

2.5 约束(Constraint)

作用:限制模型行为,防止输出超出预期范围。

不要编造信息,只能基于输入判断,只能输出20个字,不能输出违禁词 

约束是控制模型"不做什么"的关键手段,尤其在生产环境中非常重要。

2.6 示例(Example)

作用:给模型"参考答案",帮助它理解你期望的输出形式和标准。

示例的提供与否,衍生出了 Zero-shot(不给示例)和 Few-shot(给少量示例)两种重要策略,后文会详细讲解。

2.7 完整提示词示例与代码

将以上六个部分组合,形成一个完整的提示词:

import os
from openai import OpenAI
from dotenv import load_dotenv

project_root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
env_path = os.path.join(project_root_path, ".env")
load_dotenv(env_path)

MODEL_API_KEY = os.getenv("MODEL_API_KEY")
MODEL_BASE_URL = os.getenv("MODEL_BASE_URL")
MODEL_NAME = os.getenv("MODEL_NAME")

client = OpenAI(
    api_key=MODEL_API_KEY,
    base_url=MODEL_BASE_URL
)


def process_work_classify(user_input):
    user_prompt = f"""
    你是一名资深客服分析专家。

    任务:
    对用户工单进行分类。

    分类标签:
    - 退款问题
    - 物流问题
    - 商品问题

    输入:
    用户问题:{user_input}

    输出要求:
    以 JSON 格式返回:
    {{
    "category": ""
    }}
    """
    response = client.chat.completions.create(
        model=MODEL_NAME,
        messages=[
            {"role": "user", "content": user_prompt},
        ],
        stream=False
    )
    return response.choices[0].message.content


if __name__ == '__main__':
    print(process_work_classify("我的商品没有收到"))

结构拆解对照:

结构部分 对应内容
角色 你是一名资深客服分析专家
任务 对用户工单进行分类
输入 用户问题:{user_input}
输出格式 以 JSON 格式返回
约束 只能从给定的三个标签中选
示例 (本例未提供,属于 Zero-shot)

三、提示词核心技巧

3.1 角色设定(Role Prompting)

不同角色设定会让模型的输出风格完全不同:

角色设定 输出特点
客服 语气温和、礼貌,注重解决方案
数据分析师 理性、客观,注重数据和逻辑
教师 循循善诱,善于举例和类比
律师 严谨、条理清晰,引用条款
段子手 幽默、夸张,善用反转

使用建议:角色设定不是越花哨越好,关键是与任务匹配。一个数据分类任务不需要设定"你是一个海盗",但一个儿童教育场景设定"你是一位耐心的小学老师"就很有效。

3.2 约束控制

约束控制是提示词工程中最容易被忽视、但生产环境中最重要的环节。

常见约束类型:

1. 事实约束:不要编造信息,不确定请返回"无法判断"
2. 范围约束:只从给定内容中回答,不要引入外部知识
3. 长度约束:回答不超过100字 / 只输出一个标签
4. 格式约束:只输出JSON,不要附加说明文字
5. 安全约束:不输出违禁词、不生成有害内容

实用技巧:对于关键业务场景,约束应配合程序校验(如 json.loads() 校验、正则匹配),不能完全依赖提示词本身。模型偶尔会"忘记"约束,程序兜底是工程化必备手段。

3.3 Zero-shot(零样本)

定义:不提供任何示例,直接让模型执行任务。

适用场景:任务简单明确、模型本身已具备相关能力。

代码示例:

import os
from openai import OpenAI
from dotenv import load_dotenv

env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)

MODEL_API_KEY = os.getenv("MODEL_API_KEY")
MODEL_BASE_URL = os.getenv("MODEL_BASE_URL")
MODEL_NAME = os.getenv("MODEL_NAME")
client = OpenAI(api_key=MODEL_API_KEY, base_url=MODEL_BASE_URL)


def llm_response(user_prompt):
    response = client.chat.completions.create(
        model=MODEL_NAME,
        messages=[{"role": "user", "content": user_prompt}],
        stream=False,
        max_tokens=1024,
        temperature=0.7
    )
    return response.choices[0].message.content


def zero_shot_sentiment(text: str) -> str:
    """Zero-shot 情感分析:仅任务说明,无样例。"""
    prompt = f"""你是文本情感分析助手。
任务:判断下面这句话的情感倾向,只能从以下标签中选一个:正面、负面、中性。
待分析文本:{text}
输出要求:只输出一个标签,不要解释。"""
    return llm_response(prompt)


if __name__ == "__main__":
    user_text = "这家店的包装很用心,但配送比预计慢了一天。"
    print(zero_shot_sentiment(user_text))

优点:提示词简洁,token 消耗少,适合简单任务。 局限:对于复杂分类边界、特殊格式要求,效果可能不稳定。

3.4 Few-shot(少样本)

定义:在提示词中提供少量示例(通常 2~5 个),让模型"模仿"示例的模式来完成任务。

适用场景:分类任务、风格控制、格式对齐、边界模糊的判断。

代码示例:

import os
from openai import OpenAI
from dotenv import load_dotenv

env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)

MODEL_API_KEY = os.getenv("MODEL_API_KEY")
MODEL_BASE_URL = os.getenv("MODEL_BASE_URL")
MODEL_NAME = os.getenv("MODEL_NAME")
client = OpenAI(api_key=MODEL_API_KEY, base_url=MODEL_BASE_URL)


def llm_response(user_prompt):
    response = client.chat.completions.create(
        model=MODEL_NAME,
        messages=[{"role": "user", "content": user_prompt}],
        stream=False,
        max_tokens=1024,
        temperature=0.7
    )
    return response.choices[0].message.content


def few_shot_intent(user_text: str) -> str:
    few_shot_prompt = f"""
    你是电商客服对话的意图识别助手。

    任务:
    根据用户一句话判断意图,只能从以下标签中选一个:
    查询物流、申请退款、咨询商品、其他

    模仿下面格式(每段两行:用户:... 意图:...):

    用户:我的快递到哪了?
    意图:查询物流

    用户:这件衣服洗一次就起球了,我要退钱。
    意图:申请退款

    用户:这款耳机防水吗?
    意图:咨询商品

    用户:今天天气不错。
    意图:其他

    现在只对新的一句话分类,同样输出两行「用户:」「意图:」:

    用户:{user_text}
    意图:
    """
    return llm_response(few_shot_prompt)


if __name__ == "__main__":
    user_text = "上周买的鞋子码数偏小,能换大一码吗?"
    print(few_shot_intent(user_text))

Few-shot 的设计要点:

要点 说明
示例数量 通常 2~5 个即可,过多会浪费 token
覆盖边界 示例应覆盖各类别,尤其是容易混淆的边界情况
格式一致 所有示例的格式必须严格一致,模型会模仿格式
多样性 同一类别的示例尽量用不同的表述方式

3.5 Chain of Thought(思维链,CoT)

定义:在提示词中要求模型"一步一步思考",先展示推理过程,再给出最终结论。

核心原理:2022 年 Google Research 团队(Jason Wei 等人)在论文 "Chain-of-Thought Prompting Elicits Reasoning in Large Language Models" 中提出,通过在提示中加入中间推理步骤,可以显著提升大模型在算术、常识推理和符号推理等任务上的表现。

适用场景

  • 数学应用题
  • 逻辑推理
  • 多步骤决策
  • 复杂分类(需要层层判断)

代码示例:

import os
from openai import OpenAI
from dotenv import load_dotenv

env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)

MODEL_API_KEY = os.getenv("MODEL_API_KEY")
MODEL_BASE_URL = os.getenv("MODEL_BASE_URL")
MODEL_NAME = os.getenv("MODEL_NAME")
client = OpenAI(api_key=MODEL_API_KEY, base_url=MODEL_BASE_URL)


def llm_response(user_prompt: str, max_tokens: int = 1024) -> str:
    response = client.chat.completions.create(
        model=MODEL_NAME,
        messages=[{"role": "user", "content": user_prompt}],
        stream=False,
        max_tokens=max_tokens,
        temperature=0.7,
    )
    return response.choices[0].message.content


def cot_word_problem(question: str) -> str:
    """Chain-of-Thought:要求模型先分步推理,再给出最终答案。"""
    prompt = f"""你是一名擅长应用题解析的助教。

任务:
下面是一道应用题。请先「逐步写出推理过程」(可用「步骤1」「步骤2」等形式),
把每一步用到的数字和运算关系说清楚;推理结束后,最后一行单独写:
最终答案:<一个简洁结论,例如具体金额或数字>

要求:
- 推理过程与最终答案都要完整;
- 最终答案那一行必须以「最终答案:」开头。

题目:
{question}
"""
    return llm_response(prompt, max_tokens=2048)


if __name__ == "__main__":
    q = (
        "书店促销:某书原价每本 45 元。小明买 3 本可享总价 8 折,"
        "结账时还能再使用一张「满 100 减 10」的优惠券(先打折后满减)。"
        "小明实际需要支付多少元?"
    )
    print(cot_word_problem(q))

CoT 的两种触发方式:

方式 说明 示例
Zero-shot CoT 不给示例,只加一句引导语 "请一步一步思考"、"Let's think step by step"
Few-shot CoT 给出示例,示例本身包含推理过程 示例中展示"步骤1→步骤2→结论"的完整链路

补充说明:Zero-shot CoT 的有效性由 Kojima 等人在 2022 年论文 "Large Language Models are Zero-Shot Reasoners" 中验证,仅需在提示末尾添加 "Let's think step by step" 就能在多个推理基准上获得显著提升。

3.6 结构化输出(JSON)

定义:要求模型按照严格的 JSON 格式输出,便于后端系统直接解析。

适用场景:API 集成、数据管道、批量处理、与下游系统对接。

代码示例:

import json
import os
from typing import Any

from dotenv import load_dotenv
from openai import OpenAI

env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)

MODEL_API_KEY = os.getenv("MODEL_API_KEY")
MODEL_BASE_URL = os.getenv("MODEL_BASE_URL")
MODEL_NAME = os.getenv("MODEL_NAME")
client = OpenAI(api_key=MODEL_API_KEY, base_url=MODEL_BASE_URL)


def llm_json_response(user_prompt: str, max_tokens: int = 1024) -> str:
    """要求模型只输出合法 JSON 对象。"""
    response = client.chat.completions.create(
        model=MODEL_NAME,
        messages=[{"role": "user", "content": user_prompt}],
        stream=False,
        max_tokens=max_tokens,
        temperature=0.3,
        response_format={"type": "json_object"},
    )
    return response.choices[0].message.content


def classify_ticket_json(user_issue: str) -> dict[str, Any]:
    """
    将用户工单打成结构化 JSON,并在本地 json.loads 校验。
    若网关不支持 json_object,可把 response_format 一行去掉,仅靠提示约束。
    """
    prompt = f"""你是一名客服工单分析助手。请根据用户描述,输出一个 JSON 对象
(不要 markdown 代码块,不要多余说明文字)。

JSON 的键必须严格如下,类型与取值说明:
- "category": 字符串,只能是 "退款问题" | "物流问题" | "商品问题" | "其他"
- "confidence": 数字,0 到 1 之间,表示你对分类的把握
- "summary": 字符串,一句话概括用户诉求(不超过 50 字)

用户工单:
{user_issue}
"""
    raw = llm_json_response(prompt)
    return json.loads(raw)


if __name__ == "__main__":
    issue = "上周买的鞋子码数偏小,能换大一码吗?运费谁出?"
    data = classify_ticket_json(issue)
    print(json.dumps(data, ensure_ascii=False, indent=2))

关键细节:

  • temperature 建议设低(0.1~0.3),减少随机性,输出更稳定。
  • response_format={"type": "json_object"} 是 OpenAI 官方提供的 JSON 模式,部分国产模型可能不支持此参数,此时仅靠提示约束即可。
  • 务必在代码层做 json.loads() 校验,作为兜底,因为模型偶尔会输出不合法的 JSON(如多余逗号、markdown 包裹等)。

3.7 其他常用技巧补充

除了上述核心技巧外,以下几种方法在实际项目中也经常用到:

(1)Self-Consistency(自一致性)

对同一个问题让模型多次回答(通过设置较高 temperature 或多次调用),取多数投票的结果。适用于对准确性要求高的分类和推理任务。

(2)ReAct(Reasoning + Acting)

由 Yao 等人在 2022 年提出,让模型交替进行"思考"和"行动"(如调用工具、搜索信息),是 Agent 架构的提示词基础。典型格式:

Thought: 我需要查询该订单的物流状态
Action: search_order_logistics(order_id="12345")
Observation: 订单已到达北京分拣中心
Thought: 根据物流信息,我来回答用户
Answer: 您的包裹目前已到达北京分拣中心,预计明天送达。
(3)提示词模板化

在工程实践中,提示词应模板化管理,而非硬编码在代码中。推荐做法:

  • 使用 Jinja2、f-string 等模板引擎
  • 将提示词模板独立为 .txt.jinja2 文件
  • 变量部分通过参数注入,方便版本管理和 A/B 测试

四、角色提示词详解

4.1 三种消息角色

调用对话式接口时,请求中的 messages 每条都有 role 字段,用来区分这段话是谁说的。必须掌握三种核心角色:

(1)system(系统提示词)
  • 位置:放在 messages 最前面。
  • 内容:写相对稳定的设定——身份、规则、语气、输出格式等。
  • 注意:具体某条工单、某句待分类的原文更适合放在 user 中,不要塞进 system。否则每条业务数据都要改 system,难维护也浪费 token。
{
    "role": "system",
    "content": "你是电商客服助手。回答不超过三句话,语气礼貌;若涉及赔偿或法律问题,请建议用户联系人工客服。"
}
(2)user(用户输入)
  • 内容:用户输入的内容,或程序拼出来的"任务说明 + 数据"。
  • 灵活度:一轮可以有多条 user,常与 assistant 交替。最后一条 user 往往是本次要模型回答的内容。
  • 说明:任务说明和示例也可以全部写在一个长 user 里;若拆成多条 user / assistant,在模型眼里更像"有轮次的对话",便于实现对话式 Few-shot。
(3)assistant(助手回复)
  • 内容:模型上一轮已经生成的回复。下一轮请求里带上,多轮才有上下文。
  • 特殊用法:也可以人工写一条 assistant 当标准答案,前面配 user 当例题,用来教格式或定义分类边界——这正是对话式 Few-shot 的原理。

4.2 三种角色的配合方式

习惯做法system 在最前,后面 userassistant 交替。新请求里带上此前相关轮次(注意 token 上限),再追加最新的 user

一句话概括system 定规矩,user 给当前输入,assistant 是模型说过的话或你给的示范。

┌──────────────────────────────────────────────┐
│  messages:                                    │
│  ┌────────────────────────────────────────┐   │
│  │ system: 你是客服助手,回答简短礼貌     │   │
│  ├────────────────────────────────────────┤   │
│  │ user: 支持7天无理由退货吗?            │   │
│  ├────────────────────────────────────────┤   │
│  │ assistant: 支持。签收次日起7天内...    │   │
│  ├────────────────────────────────────────┤   │
│  │ user: 那运费谁承担?    ← 当前问题     │   │
│  └────────────────────────────────────────┘   │
└──────────────────────────────────────────────┘

注意事项:

  1. 1.在 LangChain 里常写成 SystemMessageHumanMessageAIMessage,含义与上面三种 role 完全一致。
  2. 2.system 并非绝对约束,重要规则可配合格式约定或程序校验。单次任务说明(如"只输出标签")有人放 user 顶部、有人放 system,团队内部统一即可。
  3. 3.部分模型对 system 的遵从度不同。一般来说,参数量越大的模型对 system 的遵从度越高。

4.3 代码实现

(1)多轮对话基础示例(OpenAI SDK)
import os
from typing import Any

from dotenv import load_dotenv
from openai import OpenAI

env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)

MODEL_API_KEY = os.getenv("MODEL_API_KEY")
MODEL_BASE_URL = os.getenv("MODEL_BASE_URL")
MODEL_NAME = os.getenv("MODEL_NAME")
client = OpenAI(api_key=MODEL_API_KEY, base_url=MODEL_BASE_URL)


def chat(messages: list[dict[str, Any]], max_tokens: int = 1024, temperature: float = 0.7) -> str:
    """messages 为 OpenAI 格式:[{"role": "system"|"user"|"assistant", "content": "..."}, ...]"""
    response = client.chat.completions.create(
        model=MODEL_NAME,
        messages=messages,
        stream=False,
        max_tokens=max_tokens,
        temperature=temperature,
    )
    return response.choices[0].message.content


def demo_system_and_user() -> str:
    """system 定规则 + user 提问题(最常用组合)。"""
    messages = [
        {
            "role": "system",
            "content": (
                "你是电商客服助手。回答不超过三句话,语气礼貌;"
                "若涉及赔偿或法律问题,请建议用户联系人工客服。"
            ),
        },
        {"role": "user", "content": "我的快递显示已签收但我没收到货,怎么办?"},
    ]
    return chat(messages)


def demo_multi_turn_with_assistant() -> str:
    """
    多轮:必须把上一轮的 assistant 内容放进 messages,再接新的 user。
    这里 assistant 内容模拟「上一轮模型已说过的话」。
    """
    messages = [
        {
            "role": "system",
            "content": "你是电商客服助手,回答简短。",
        },
        {"role": "user", "content": "你们支持 7 天无理由退货吗?"},
        {
            "role": "assistant",
            "content": "支持。签收次日起 7 天内,商品未使用且吊牌完好可申请无理由退货。",
        },
        {"role": "user", "content": "那运费谁承担?"},
    ]
    return chat(messages)


if __name__ == "__main__":
    print("=== 示例 1:system + user ===")
    print(demo_system_and_user())
    print()
    print("=== 示例 2:system + user + assistant + user(多轮追问)===")
    print(demo_multi_turn_with_assistant())
(2)对话式 Few-shot(OpenAI SDK)
import os
from typing import Any

from dotenv import load_dotenv
from openai import OpenAI

env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)

MODEL_API_KEY = os.getenv("MODEL_API_KEY")
MODEL_BASE_URL = os.getenv("MODEL_BASE_URL")
MODEL_NAME = os.getenv("MODEL_NAME")
client = OpenAI(api_key=MODEL_API_KEY, base_url=MODEL_BASE_URL)


def chat(messages: list[dict[str, Any]], max_tokens: int = 256, temperature: float = 0.3) -> str:
    response = client.chat.completions.create(
        model=MODEL_NAME,
        messages=messages,
        stream=False,
        max_tokens=max_tokens,
        temperature=temperature,
    )
    return response.choices[0].message.content


def few_shot_intent_via_messages(user_text: str) -> str:
    """
    用 user/assistant 交错给出示例,最后一条 user 为真实待分类句子。
    assistant 只输出意图标签。
    """
    system = """你是电商客服意图识别助手。
用户会发来一句话,你只输出一个意图标签,不要解释。
标签只能是:查询物流、申请退款、咨询商品、其他。"""

    shot_pairs = [
        ("我的快递到哪了?", "查询物流"),
        ("这件衣服洗一次就起球了,我要退钱。", "申请退款"),
        ("这款耳机防水吗?", "咨询商品"),
        ("今天天气不错。", "其他"),
    ]

    messages: list[dict[str, Any]] = [{"role": "system", "content": system}]
    for u, a in shot_pairs:
        messages.append({"role": "user", "content": u})
        messages.append({"role": "assistant", "content": a})
    messages.append({"role": "user", "content": user_text})

    return chat(messages)


if __name__ == "__main__":
    sample = "上周买的鞋子码数偏小,能换大一码吗?"
    print("待分类:", sample)
    print("模型输出:", few_shot_intent_via_messages(sample))

对比两种 Few-shot 写法:将示例写在一个长 user 里 vs. 用 user/assistant 交替。后者更贴近对话场景,模型理解起来更自然,但会多消耗一些 token。

(3)LangChain 实现多轮对话
import os

from dotenv import load_dotenv
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
from langchain_openai import ChatOpenAI

env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)

MODEL_API_KEY = os.getenv("MODEL_API_KEY")
MODEL_BASE_URL = os.getenv("MODEL_BASE_URL")
MODEL_NAME = os.getenv("MODEL_NAME")

llm = ChatOpenAI(
    api_key=MODEL_API_KEY,
    base_url=MODEL_BASE_URL,
    model=MODEL_NAME,
    temperature=0.7,
    max_tokens=1024,
)


def demo_system_and_user() -> str:
    """system 定规则 + user 提问题。"""
    messages = [
        SystemMessage(
            content=(
                "你是电商客服助手。回答不超过三句话,语气礼貌;"
                "若涉及赔偿或法律问题,请建议用户联系人工客服。"
            )
        ),
        HumanMessage(content="我的快递显示已签收但我没收到货,怎么办?"),
    ]
    return llm.invoke(messages).content


def demo_multi_turn_with_assistant() -> str:
    """多轮:含上一轮 assistant(AIMessage),再接新的 user。"""
    messages = [
        SystemMessage(content="你是电商客服助手,回答简短。"),
        HumanMessage(content="你们支持 7 天无理由退货吗?"),
        AIMessage(
            content="支持。签收次日起 7 天内,商品未使用且吊牌完好可申请无理由退货。"
        ),
        HumanMessage(content="那运费谁承担?"),
    ]
    return llm.invoke(messages).content


if __name__ == "__main__":
    print("=== 示例 1:SystemMessage + HumanMessage ===")
    print(demo_system_and_user())
    print()
    print("=== 示例 2:System + Human + AIMessage + Human(多轮追问)===")
    print(demo_multi_turn_with_assistant())

LangChain 角色映射SystemMessage = system,HumanMessage = user,AIMessage = assistant。


五、提示词工程的最佳实践与常见误区

最佳实践

实践 说明
先简后繁 先用最简单的提示词测试,确认基本能力后再逐步添加角色、约束、示例
迭代优化 提示词不是一次写好的,需要根据输出不断调整
版本管理 对提示词做版本控制,记录每次修改和效果变化
程序兜底 关键场景用代码校验输出格式,不能完全依赖提示词约束
关注 token 提示词越长,消耗的 token 越多,成本越高,响应越慢
测试边界 用极端输入和边界情况测试提示词的鲁棒性

常见误区

误区 正确做法
提示词越长越好 精准比冗长更有效,无关信息反而会干扰模型
只测一条就上线 应该用多条不同输入进行批量测试
所有任务都用 CoT 简单任务用 CoT 反而可能降低效率、增加错误
完全信任模型输出 生产环境必须有程序校验和异常处理
system 能硬性约束一切 system 是"软约束",模型偶尔会偏离,关键规则需配合程序校验
忽视 temperature 参数 任务越需要确定性,temperature 应设越低(分类任务建议 0.1~0.3)

六、本节总结

  1. 提示词工程的本质是"用输入控制输出"——你不需要改模型,只需要改你对模型说的话。
  2. 一个好的 Prompt = 角色 + 任务 + 输入 + 输出格式 + 约束 +(可选)示例
  3. Few-shot 和 CoT 是提升效果的两大关键手段——前者解决"格式和边界"问题,后者解决"推理深度"问题。
  4. 结构化输出(JSON)是工程化落地的必备技巧——配合 response_format 和程序校验使用。
  5. 三种消息角色(system / user / assistant)的合理配合,是实现多轮对话和对话式 Few-shot 的基础。
  6. 提示词需要不断调试和演化——没有一劳永逸的"完美提示词",只有不断迭代的"更优提示词"。
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐