Prompt 基础

Prompt 的核心是把角色、任务、上下文、输出格式和回答边界说清楚,让模型更稳定地完成具体任务。

Prompt 是什么

Prompt,中文一般翻译为“提示词”或“提示语”。

Prompt 可以先理解成给大模型的输入说明。

它不只是用户问的一句话,而是由几部分组合出来的:

角色设定
任务目标
上下文资料
输出要求
示例
限制条件
用户问题

上一篇调用 API 时已经看到 messages 了。

[
  {
    "role": "system",
    "content": "你是一个严谨的 Java 后端工程师,回答要简洁。"
  },
  {
    "role": "user",
    "content": "什么是 LLM API?用一句话解释。"
  }
]

这里的 systemuser,其实就是 Prompt 工程最基础的入口。

结论:

Prompt 要明确任务说明、上下文和输出规则,目标是提高模型回答的稳定性。

Prompt 的使用场景

普通聊天、RAG、Tool Calling、Agent 都会用到 Prompt。

普通聊天:

用户问题
  -> 拼接 system / user prompt
  -> 调用 LLM API
  -> 返回回答

RAG:

用户问题
  -> 检索知识库
  -> 把资料放进 Prompt
  -> 要求模型只根据资料回答
  -> 返回答案和引用来源

Agent:

用户任务
  -> Prompt 说明可用工具和执行规则
  -> 模型判断下一步
  -> 调用工具
  -> 再根据工具结果生成最终回答

Prompt 的作用是:

让模型知道自己扮演什么角色
让模型知道当前要解决什么问题
让模型知道哪些事情不能乱答
让模型按后端服务需要的格式输出

System Prompt

system prompt 主要放全局规则。

可以理解成这次对话或这次调用的“工作说明”。

比如:

{
  "role": "system",
  "content": "你是一个严谨的 Java 后端工程师。回答要简洁,优先给可落地的方案,不确定时直接说明不确定。"
}

这里适合放:

角色
回答风格
安全边界
输出格式
业务规则
禁止事项

不适合放太多临时问题。

临时问题应该放到 user prompt 里。

一个简单例子

你是一个严谨的 Java 后端工程师。
请用面向工程落地的方式回答问题。
如果问题信息不足,先说明缺少什么信息。
不要编造不存在的接口、类名或配置项。

这类规则适合作为固定模板。

后面写成代码时,可以像这样组织:

String systemPrompt = """
        你是一个严谨的 Java 后端工程师。
        请用面向工程落地的方式回答问题。
        如果问题信息不足,先说明缺少什么信息。
        不要编造不存在的接口、类名或配置项。
        """;

User Prompt

user prompt 放用户当前的具体问题。

比如:

{
  "role": "user",
  "content": "Spring Boot 项目里怎么用环境变量读取 API Key?"
}

如果问题比较复杂,最好不要只写一句话。

可以按这个结构写:

背景
目标
约束
输入
希望输出

比如:

背景:我是 Java 后端,正在学习 AI Agent。
目标:想在 Spring Boot 里安全读取大模型 API Key。
约束:不要把 Key 写死到代码里。
希望输出:给一个最小可用示例。

这种写法比单纯问一句:
image.png

怎么读取 API Key?

要稳定很多。
image.png
结论:

输入越清楚,输出越接近预期。

System 和 User 怎么分工

可以先按这个规则理解:

长期规则放 system
当前问题放 user
业务资料放 user 或单独上下文
历史对话按顺序放 user / assistant

示例:

{
  "messages": [
    {
      "role": "system",
      "content": "你是一个严谨的 Java 后端工程师。回答要简洁,不确定时说明不确定。"
    },
    {
      "role": "user",
      "content": "请解释 Spring Boot 中 Controller、Service、Repository 的分工。"
    }
  ]
}

不要把所有东西都堆进一段大文本里。

后面系统复杂后,Prompt 最好拆成几块:

systemPrompt
contextPrompt
taskPrompt
outputPrompt

这样代码更容易维护,也方便后面调试效果。

Few-shot 是什么

Few-shot 就是在 Prompt 里给几个示例。

模型会根据示例学习你想要的回答方式。

比如我要模型把用户问题分类成:

技术问题
账号问题
订单问题
其他问题

可以这样写:

请判断用户问题类型,只返回分类名称。

示例1:
用户:登录时提示 token 过期怎么办?
分类:账号问题

示例2:
用户:我的订单为什么还没发货?
分类:订单问题

示例3:
用户:Java 调用接口超时怎么排查?
分类:技术问题

现在判断:
用户:Spring Boot 项目启动后端口被占用怎么办?
分类:

Few-shot 的价值在于:

减少模型自由发挥
统一输出风格
让模型理解边界
提高分类、抽取、改写任务的稳定性

Zero-shot 和 Few-shot

不提供示例,直接让模型完成任务,叫 zero-shot。

请判断这个问题的类型:我的订单为什么还没发货?

提供几个示例,再让模型完成任务,叫 few-shot。

示例1:...
示例2:...
现在判断:我的订单为什么还没发货?

我的使用习惯可以先这样定:

简单问答:zero-shot
分类任务:few-shot
格式要求严格:few-shot
模型总是答偏:few-shot

如果后面要做客服 Agent,意图识别、工单分类、问题改写这些地方都很适合用 few-shot。

约束回答边界

大模型有一个问题:

会补全
会猜
会把不确定说得像确定

所以 Prompt 里要明确边界。

常见约束:

不知道就说不知道
只能根据给定资料回答
不要编造字段、接口、链接
不要输出无关解释
输出必须符合指定格式
如果信息不足,先说明缺少什么信息

比如 RAG 里经常这么写:

请只根据下面的资料回答用户问题。
如果资料中没有答案,请回答“根据现有资料无法判断”。
不要使用资料之外的知识补充答案。
回答最后列出引用的资料编号。

这类边界很重要。

不然知识库问答系统最容易变成:

资料里没有
模型自己脑补
用户以为系统真的查到了

这就是后面做 RAG 时要重点防的幻觉问题。

输出格式约束

学习阶段可以先用普通文本约束。

比如:

请按下面格式回答:

结论:
原因:
示例:
注意点:

如果要让后端解析,就要更严格。

比如:

请只输出 JSON,不要输出 Markdown,不要添加解释。

{
  "category": "订单问题",
  "confidence": 0.8,
  "reason": "用户询问订单发货状态"
}

不过这篇先不展开 JSON。

下一篇 Day 4 会专门整理结构化输出,包括:

让模型输出 JSON
Java 解析 JSON
Python Pydantic 校验
异常兜底

这里先记住一点:

只靠一句“请输出 JSON”不够,工程里还要做解析、校验和兜底。

Prompt Template

后面写代码时,不可能每次手写一整段 Prompt。

更常见的是做模板。

比如:

你是一个技术学习助手。

请根据下面资料回答问题:

资料:
{context}

用户问题:
{question}

要求:
1. 只根据资料回答
2. 不知道就说不知道
3. 回答要简洁

代码里填变量:

String prompt = template
        .replace("{context}", context)
        .replace("{question}", question);

正式项目里可以用更规范的模板工具。

但学习阶段先理解本质:

固定规则
  +
动态上下文
  +
用户问题
  =
一次完整 Prompt

Java 后端视角下的 Prompt

对 Java 后端来说,Prompt 不应该散落在业务代码里。

不建议这样:

String prompt = "你是...请帮我..." + userInput;

更好的做法是先拆出来:

prompt/
  ├── system-prompt.md
  ├── rag-answer-prompt.md
  ├── intent-classify-prompt.md
  └── tool-result-summary-prompt.md

或者放到配置里:

application.yml
数据库
配置中心

后面如果要优化效果,至少能知道改的是哪一类 Prompt。

这也方便做版本记录:

v1:回答太发散
v2:增加“不知道就说不知道”
v3:增加引用来源格式
v4:增加 few-shot 示例

Prompt 也要像代码一样管理。

常见问题

回答太长

加输出长度和格式要求。

请用 5 句话以内回答。
请按要点输出,不要展开背景介绍。

也可以配合 API 参数:

max_tokens

回答不稳定

降低随机性。

temperature: 0.1 - 0.3

再补 few-shot 示例。

如果是分类、抽取、判断类任务,示例通常很有用。

模型乱编

加边界约束。

不知道就说不知道。
不要编造不存在的字段、接口、类名或链接。
如果资料不足,说明缺少什么信息。

RAG 场景还要加:

只根据给定资料回答。
不要使用资料之外的知识。

输出格式不对

先用更明确的格式说明。

比如:

只输出下面四行:
分类:
置信度:
原因:
建议:

如果后端必须解析,下一步就要上 JSON 结构化输出和校验。

System Prompt 写很多还有用吗

有用,但不是越长越好。

太长的问题是:

增加 token 成本
模型可能抓不住重点
后续维护困难

我的原则:

长期稳定规则保留
临时任务不要塞进去
能用示例说明的,不写一堆抽象规则

一个完整示例

下面是一个学习阶段可以直接拿来测试的 Prompt。

System:
你是一个严谨的 Java 后端工程师。
请用工程落地视角回答问题。
如果信息不足,请说明缺少什么信息。
不要编造不存在的接口、类名、配置项或链接。

User:
背景:我正在学习 AI Agent,已经能调用 LLM API。
目标:理解 Prompt 的基础写法。
问题:System Prompt、User Prompt、Few-shot 分别是什么?什么时候用?
希望输出:
1. 用简单的话解释
2. 给一个示例
3. 说明常见坑

这类写法比只问:

讲一下 Prompt

要好很多。

它把背景、目标、问题和输出要求都给清楚了。

练习清单

这一篇我只要求自己完成几件事:

能区分 system prompt 和 user prompt
知道 system 里放长期规则
知道 user 里放当前问题
能写一个带背景、目标、约束的 user prompt
能写一个 few-shot 分类示例
知道怎么限制模型不要乱编
知道 RAG 里为什么要写“只根据资料回答”
知道输出格式约束和 JSON 结构化输出不是一回事

可以准备三个小练习。

练习 1:普通问答 Prompt

角色:Java 后端学习助手
任务:解释一个技术概念
要求:简洁、准确、给示例

练习 2:分类 Prompt

输入用户问题
输出问题分类
分类范围:技术问题 / 账号问题 / 订单问题 / 其他问题
加 3 个 few-shot 示例

image.png

练习 3:RAG 边界 Prompt

给定一段资料
要求模型只根据资料回答
资料里没有就说无法判断
不要补充资料之外的信息

建议目录:

ai-agent-study
├── java
│   └── prompt-demo
│       └── PromptDemo.java
├── python
│   └── prompt-demo
│       └── prompt_demo.py
└── docs
    └── prompt-basic.md

image.png

小结

这一篇先记住这句话:

Prompt 的核心不是把话写得玄,而是把角色、任务、上下文、格式和边界写清楚。

对 Java 后端来说,Prompt 后面会变成系统的一部分。

它会参与:

普通聊天
RAG 问答
意图识别
Tool Calling
Agent 工作流
结果总结
异常兜底

所以不要只把 Prompt 当成临时字符串。

更好的习惯是:

拆模板
留版本
可测试
可回滚
能配合日志观察效果

先掌握 system、user、few-shot 和边界约束,后面再接结构化输出、RAG 和 Agent。

它们的外层结构很像,区别主要在知识怎么组织、规则怎么写。

可以这样记:

普通问答 Prompt:告诉模型怎么回答
Few-shot Prompt:给模型几个例子,让它照着做
RAG Prompt:给模型一批资料,让它只能基于资料回答

更抽象一点:

Prompt = 任务说明 + 上下文信息 + 约束条件 + 输出格式

你后面写 AI Agent、RAG、分类器,基本都是在改这四样东西。

比如:

任务说明:你要做什么?
上下文信息:给你哪些资料?
约束条件:哪些不能做?
输出格式:最后怎么返回?

真正工程里,Prompt 不要写得太玄乎。先按这个模板来就够了:

你是一个【角色】。

你的任务是:【任务目标】。

规则:

  1. 【规则1】
  2. 【规则2】
  3. 【规则3】

参考信息:
【上下文 / 示例 / 知识库内容】

用户输入:
【用户问题】

输出要求:
【只返回 JSON / 只返回分类 / 先结论后解释】

一句话:Prompt 的骨架基本一样,变化的是任务、资料、边界和输出格式。

参考资料


这个家伙很懒,啥也没有留下😋