提示词工程与工具调用入门

提示词工程与工具调用入门
AI Agent 工程实践教程 · 第 05 章
把提示词写法、结构化输出和工具调用连接起来,形成可复用的 Agent 输入输出规范。
第五天:提示词工程入门
前面几天我们已经完成了学生端 AI 问答的核心链路:
- 前端输入问题。
- Java 保存消息,并把问题转发给 Python。
- Python 判断是否需要知识库。
- 需要时通过 LlamaIndex 和 Milvus 检索资料。
- Python 把系统提示词、知识库资料、历史消息、本次问题组装成
messages。 - 大模型根据
messages生成回答。 - Java 接收流式结果,保存 AI 回答,再转发给前端。
第五天开始,我们要把注意力放到一个很关键的问题上:
同样是调用大模型,为什么有的回答稳定、清楚、能按要求输出,有的回答却经常不符合预期?
答案很大程度上和提示词有关。
提示词工程不是简单地“把问题写长一点”,而是让模型明确知道:
- 它现在是什么角色。
- 它要完成什么任务。
- 它可以参考哪些上下文。
- 它必须遵守哪些规则。
- 它应该用什么格式输出。
- 程序后面要怎么使用它的输出。
这一天我们先讲提示词,把模型为什么能按规则回答、怎么按格式输出、提示词为什么要做版本管理讲清楚。
1. Prompt 不是一句话,而是一组 messages
很多同学第一次接触大模型时,会把 Prompt 理解成“用户输入的那一句话”。
例如:
什么是 RAG?
这句话当然是 Prompt 的一部分,但在真实项目里,大模型通常收到的不是一个字符串,而是一组 messages。
每一条 message 都有两个核心字段:
{
"role": "system",
"content": "你是一个耐心、专业的 AI 课程助教。"
}
role 表示这条消息的角色,content 表示具体内容。
我们项目里的角色主要有三种:
| role | 含义 | 项目中的作用 |
|---|---|---|
system |
系统提示词 | 规定模型身份、回答风格、知识库使用规则 |
user |
用户提示词 | 学生本次真正提出的问题 |
assistant |
AI 历史回答 | 多轮对话时,让模型知道前面已经回答过什么 |
这里要注意一个重点:
模型会按照 messages 的顺序理解上下文。
所以系统规则、知识库资料、历史消息、本次问题的顺序不能随便放。
2. 系统提示词是什么
在一个 AI 应用里,系统提示词的作用是先给模型定规则。
用户每次问的问题都不一样,但产品希望 AI 的表现是稳定的:
- 始终以同一个身份回答。
- 始终保持合适的语气。
- 始终遵守业务边界。
- 始终按照项目要求组织答案。
比如我们的学生端 AI 问答,不希望模型一会儿像百科,一会儿像客服,一会儿又像普通聊天助手。
我们希望它一直像一个“AI 课程助教”:
- 能用学生听得懂的方式解释问题。
- 回答时尽量结合课程和项目。
- 遇到知识库没有说明的内容,要明确告诉学生。
- 不把没有依据的信息说成确定结论。
所以,系统提示词不是为了装饰模型,而是为了给模型一个稳定的工作方式。
系统提示词,也就是 system prompt,用来告诉模型:
- 你是谁。
- 你应该用什么语气回答。
- 你回答时要遵守哪些边界。
- 什么内容可以回答,什么内容需要谨慎。
我们项目里有一个默认系统提示词,配置在 Python 的 Settings 里:
ai_chat_system_prompt: str = os.getenv(
"AI_CHAT_SYSTEM_PROMPT",
"你是一个耐心、专业的 AI 课程助教,请用清晰、适合学生理解的方式回答问题。",
)
这句话虽然不长,但已经告诉模型三件事:
- 角色:AI 课程助教。
- 态度:耐心、专业。
- 表达方式:清晰、适合学生理解。
如果没有系统提示词,模型只看到用户问题,也可以回答,但回答风格会更不稳定。
例如用户问:
RAG 是什么?
如果没有系统提示词,模型可能用很通用的百科式语言回答。
如果加上系统提示词:
你是一个耐心、专业的 AI 课程助教,请用清晰、适合学生理解的方式回答问题。
模型就更容易用课程讲解的方式回答。
3. 用户提示词是什么
用户提示词,也就是 user prompt,是用户本次真正输入的问题。
在学生端 AI 问答里,它来自页面输入框。
例如:
老师,向量数据库为什么不用 MySQL?
到了 Python 服务后,它会被放进最后一条 user message:
messages.append(ChatMessage(role="user", content=question))
用户提示词一般放在 messages 的最后。
原因很简单:
前面的系统规则、历史消息、知识库资料都是为了帮助模型理解上下文,最后这条用户消息才是模型本次要回答的问题。
4. assistant 消息是什么
assistant 消息表示模型之前说过的话。
在多轮对话里,模型需要知道前面聊了什么。
例如第一轮:
user: 什么是 RAG?
assistant: RAG 是检索增强生成...
第二轮用户继续问:
它和普通大模型问答有什么区别?
这里的“它”指的是上一轮的 RAG。
如果不给历史消息,模型可能不知道“它”指什么。
所以项目里 Java 会查询最近的历史消息,然后传给 Python:
history: list[ChatMessage] = Field(default_factory=list)
Python 在组装 messages 时,会把历史消息放进去:
messages.extend(history)
这样模型就能结合上下文回答。
5. 我们项目里的 messages 顺序
学生端 AI 问答真正拼 Prompt 的位置在 Python:
YanQue-AI/src/yanque_ai/chat/prompt_builder.py
核心代码是:
messages = [
ChatMessage(role="system", content=self._settings.ai_chat_system_prompt),
]
if knowledge_hits:
messages.append(ChatMessage(role="system", content=self._build_knowledge_prompt(knowledge_hits)))
messages.extend(history)
messages.append(ChatMessage(role="user", content=question))
它的顺序是:
- 先放系统提示词。
- 如果查到了知识库资料,再放知识库提示词。
- 再放历史对话。
- 最后放学生本次问题。
也可以画成这样:
system:你是 AI 课程助教
system:下面是知识库检索到的参考资料
user/assistant:历史对话
user:学生本次问题
这个顺序很重要。
如果把知识库资料放在用户问题后面,模型不一定能很好地把它当成参考资料。
如果把历史消息放在系统提示词前面,规则的优先级也会变得不清楚。
6. 知识库提示词怎么写
我们项目里的知识库提示词不是直接把 chunk 拼进去,而是先加一段规则:
return (
"下面是从知识库检索到的参考资料。回答时优先依据这些资料;"
"资料没有提到的内容,要明确说明“知识库资料里没有明确说明”,不要编造。\n\n"
+ "\n\n".join(chunks)
)
这段提示词做了两件事:
- 告诉模型这些内容是参考资料。
- 告诉模型资料没有提到时不要自己补充没有依据的内容。
这就是 RAG 问答里非常重要的一类提示词。
如果只把资料内容塞给模型,不说明使用规则,模型可能会把知识库资料和自己的通用知识混在一起回答。
所以 RAG 场景的提示词通常要写清楚:
- 优先依据检索资料。
- 资料没有说明时,要明确告诉用户。
- 不要把不确定的信息说成确定结论。
- 回答要围绕用户问题,不要把所有资料都复述一遍。
一个更完整的 RAG 系统提示词可以这样写:
你是一个 AI 课程助教。
下面会提供若干段从知识库检索到的资料。
回答时请优先依据资料内容。
如果资料中没有明确说明,请直接说明“知识库资料里没有明确说明”。
不要把没有依据的内容说成确定事实。
回答要简洁、清楚,适合学生理解。
7. 什么是一个好的提示词
一个好的提示词,不是越长越好,而是越清楚越好。
可以按照下面这个结构来写:
角色:你是谁?
任务:你要做什么?
上下文:你可以参考哪些资料?
规则:你必须遵守什么?
输出格式:你要怎么输出?
示例:复杂任务给一个例子。
例如我们要让模型讲解一个技术概念,可以这样写:
你是一个 AI 课程助教。
请用适合初学者的方式解释下面的技术概念。
要求:
1. 先用一句话说明它是什么。
2. 再用一个生活中的例子帮助理解。
3. 最后说明它在我们项目里对应哪一部分。
4. 不要使用过多专业术语。
学生问题:什么是向量数据库?
这个提示词比单纯问“什么是向量数据库”更稳定。
因为它告诉模型:
- 用什么身份回答。
- 按什么结构回答。
- 面向什么水平的人回答。
- 回答重点要落到项目里。
8. 提示词里要少用模糊要求
下面这些要求比较模糊:
回答得好一点。
回答得专业一点。
写得详细一点。
不要编造没有依据的内容。
它们不是完全不能用,但模型不一定知道“好”“专业”“详细”具体是什么意思。
更好的写法是把要求拆清楚:
请按下面结构回答:
1. 先用一句话解释概念。
2. 再说明它解决了什么问题。
3. 再结合我们项目里的代码位置说明它怎么落地。
4. 最后给一个简单例子。
如果资料中没有明确说明,请直接说明资料没有提到。
提示词越具体,模型越容易按预期输出。
9. 系统提示词和用户提示词的区别
系统提示词和用户提示词都能影响模型,但它们的定位不一样。
| 类型 | 谁来维护 | 放在哪里 | 主要作用 |
|---|---|---|---|
| 系统提示词 | 项目开发者或运营人员 | system message |
规定模型身份、风格、边界 |
| 用户提示词 | 最终用户 | user message |
表达本次问题或任务 |
举个例子:
系统提示词:
你是一个耐心、专业的 AI 课程助教,请用清晰、适合学生理解的方式回答问题。
用户提示词:
LlamaIndex 在我们项目里负责什么?
模型最终回答时,会同时参考这两部分。
系统提示词更像“长期规则”,用户提示词更像“本次任务”。
10. 结构化输出提示词
有些时候,我们不是让模型直接写一段自然语言回答,而是让它输出一个结构化结果。
我们项目里的知识库路由就是一个例子。
代码位置:
YanQue-AI/src/yanque_ai/chat/knowledge_router.py
它要让一个轻量模型判断:
这个问题需不需要查知识库?
系统提示词里写了这样的规则:
你是一个问答路由分类器,只判断用户问题是否需要检索公司内部知识库。
不确定时返回 true。只输出 JSON,不要输出其他文字。
用户提示词里要求模型按固定结构返回:
请判断下面问题是否需要检索知识库,并返回:
{"useKnowledgeBase": true/false, "reason": "一句话原因", "confidence": 0-1}
问题:...
这里模型输出的不是最终回答,而是一个 JSON。
程序再读取这个 JSON:
data = self._parse_json_object(content)
use_knowledge = bool(data.get("useKnowledgeBase"))
这类提示词在后面讲工具调用时非常重要。
因为工具调用的核心也是:
- 让模型判断要不要使用工具。
- 让模型选择哪个工具。
- 让模型给出工具需要的参数。
- 程序校验参数,然后真正执行工具。
11. 结构化输出一定要做程序校验
让模型“只输出 JSON”,不代表它永远都会输出合法 JSON。
模型有时可能多输出一句解释,也可能少一个字段。
所以项目里没有直接相信模型输出,而是做了提取和解析:
match = re.search(r"\{.*\}", content, flags=re.S)
if not match:
raise ValueError("模型未返回 JSON")
return json.loads(match.group(0))
同时外层也做了异常处理:
except Exception:
return True, "知识库路由判断失败,保守使用知识库"
这是一条很重要的工程原则:
提示词负责引导模型,程序负责校验结果。
不能因为提示词写了“必须返回 JSON”,代码里就完全不处理异常。
12. Few-shot:给模型一个例子
Few-shot 指的是在提示词里给模型一个或几个示例。
如果任务比较复杂,示例会比单纯写规则更直观。
例如我们要判断是否需要知识库,可以这样写:
你是一个问答路由分类器,只判断用户问题是否需要检索知识库。
示例 1:
问题:Python 的 list 和 tuple 有什么区别?
输出:{"useKnowledgeBase": false, "reason": "这是通用编程知识", "confidence": 0.9}
示例 2:
问题:第三天课程讲义里 RAG 是怎么解释的?
输出:{"useKnowledgeBase": true, "reason": "问题依赖课程内部资料", "confidence": 0.95}
现在请判断:
问题:...
Few-shot 的好处是模型更容易模仿输出格式和判断标准。
但也要注意,示例不要太多。
示例太多会占用上下文,也会增加模型理解成本。
13. 为什么提示词要放到数据库
现在我们项目里的系统提示词主要通过环境变量配置:
AI_CHAT_SYSTEM_PROMPT=你是一个耐心、专业的 AI 课程助教...
这种方式适合早期开发,因为简单直接。
但如果项目里有多个 Agent,就不能只考虑一个系统提示词。
不同 Agent 的工作目标不同,系统提示词也应该不同。
例如:
| Agent | 系统提示词重点 |
|---|---|
| 学生问答 Agent | 像 AI 课程助教一样回答,语言清楚,适合学生理解 |
| 知识库路由 Agent | 只判断问题是否需要检索知识库,输出固定 JSON |
| 工具调用 Agent | 判断是否需要调用工具,并生成工具参数 |
| 作业批改 Agent | 按评分标准给出评价、分数和修改建议 |
| 客服问答 Agent | 按业务口径回答,遇到不确定问题要提示人工处理 |
也就是说,系统提示词不是全项目只有一份。
它通常会随着 Agent 的职责、业务场景和输出格式发生变化。
但当项目上线后,提示词可能会经常调整:
- 想让回答更适合学生。
- 想加一条知识库回答规则。
- 想调整结构化输出格式。
- 想对比不同版本的回答效果。
- 某次调整效果不好,需要快速回滚。
如果提示词一直写在代码或环境变量里,每次修改都需要开发介入,管理起来不方便。
所以更完整的做法是把提示词放进数据库。
这也属于提示词工程的一部分。
它不是在研究“怎么写一句 Prompt”,而是在解决:
提示词如何被管理、发布、审计和回滚。
14. 提示词表可以怎么设计
可以先设计两张表。
第一张表:prompt_template
保存一个提示词的基本信息,以及它属于哪个 Agent。
CREATE TABLE prompt_template (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
code VARCHAR(100) NOT NULL COMMENT '提示词编码,例如 ai_chat_system',
name VARCHAR(100) NOT NULL COMMENT '提示词名称',
agent_code VARCHAR(100) NOT NULL COMMENT '所属 Agent,例如 student_chat_agent',
status VARCHAR(20) NOT NULL COMMENT '状态:ENABLED/DISABLED',
active_version_id BIGINT NULL COMMENT '当前启用的版本 ID',
create_time DATETIME NOT NULL,
update_time DATETIME NOT NULL,
UNIQUE KEY uk_prompt_template_code (code)
);
第二张表:prompt_template_version
保存每一次提示词内容修改。
CREATE TABLE prompt_template_version (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
template_id BIGINT NOT NULL COMMENT '所属提示词模板 ID',
version_no INT NOT NULL COMMENT '版本号',
content TEXT NOT NULL COMMENT '提示词内容',
variables JSON NULL COMMENT '变量说明,例如 question、knowledge_context',
change_note VARCHAR(500) NULL COMMENT '本次修改说明',
create_by BIGINT NULL COMMENT '创建人',
create_time DATETIME NOT NULL,
UNIQUE KEY uk_prompt_template_version (template_id, version_no)
);
这两张表先解决最核心的问题:
prompt_template:这个提示词是什么。prompt_template_version:它有哪些历史版本。
有了版本以后,提示词就可以回滚。
比如学生问答 Agent 原来使用的是第 2 版提示词:
prompt_template.active_version_id -> version 2
后来我们升级了一版提示词,希望回答更详细:
prompt_template.active_version_id -> version 3
但上线后发现第 3 版效果不好,例如回答变得太长,或者不够适合学生理解。
这时不需要删除第 3 版,也不需要马上改代码。
只要把当前启用版本切回第 2 版:
prompt_template.active_version_id -> version 2
这就是提示词回滚。
所以版本管理的价值不只是“保存历史记录”,更重要的是:
- 新版本可以上线试用。
- 旧版本不会丢失。
- 新版本效果不好时,可以快速切回稳定版本。
15. 提示词要不要加缓存
提示词放进数据库以后,还有一个运行时问题:
每次学生提问时,Python 都去数据库查提示词,会不会变慢?
如果访问量很小,直接查数据库也能跑。
课程第一版可以先不用 Redis,直接在 Python 服务里做本地缓存。
数据库保存提示词配置
Python 本地内存缓存当前启用的提示词
Python 调用模型前优先读本地缓存
也就是说,数据库是提示词的管理源,本地缓存是提示词的读取加速层。
可以这样理解:
- 管理后台修改提示词,写入 MySQL。
- Python 第一次处理学生问题时,从 MySQL 查询当前启用的提示词。
- 查询到以后,把提示词放到 Python 本地缓存里。
- 后面的请求优先读本地缓存,不需要每次都查 MySQL。
- 缓存过期后,再重新查 MySQL,并刷新本地缓存。
这样做的好处是:
- 不需要每次问答都访问 MySQL。
- 不需要额外引入 Redis,课程实现更简单。
- 提示词修改或回滚后,缓存过期就会读到新的当前版本。
缓存的 key 可以设计得简单一点:
prompt:active:{agent_code}:{prompt_code}
例如:
prompt:active:student_chat_agent:ai_chat_system
缓存里可以保存当前启用版本的内容和过期时间。
如果使用第三方库,可以用 cachetools.TTLCache:
from cachetools import TTLCache
prompt_cache = TTLCache(maxsize=100, ttl=60)
这里的含义是:
maxsize=100:最多缓存 100 条提示词。ttl=60:每条缓存最多保留 60 秒。
读取时可以按 agent_code 和 prompt_code 组成缓存 key:
cache_key = f"prompt:active:{agent_code}:{prompt_code}"
prompt = prompt_cache.get(cache_key)
if prompt is None:
prompt = query_prompt_from_mysql(agent_code, prompt_code)
prompt_cache[cache_key] = prompt
缓存中的提示词内容可以长这样:
{
"templateId": 1,
"versionNo": 2,
"content": "你是一个耐心、专业的 AI 课程助教..."
}
这样 Python 每次组装 messages 时,就可以直接拿到当前生效的系统提示词。
如果不想引入第三方库,也可以自己用字典保存过期时间:
import time
prompt_cache = {}
def get_cached_prompt(cache_key: str):
item = prompt_cache.get(cache_key)
if not item:
return None
if item["expires_at"] < time.time():
prompt_cache.pop(cache_key, None)
return None
return item["value"]
这种写法的核心就是:
- 缓存时多保存一个
expires_at。 - 读取时先判断有没有过期。
- 过期了就删除缓存,再查数据库。
课程里推荐先用 cachetools.TTLCache,代码更短,也更容易讲清楚。
16. 怎么判断提示词升级有没有效果
提示词升级以后,不能只靠“感觉好像更好了”来判断。
比较清楚的做法可以分成四步。
第一步:先确定这次升级要解决什么问题
提示词升级之前,要先写清楚升级目标。
例如:
本次升级目标:
当知识库没有相关资料时,模型要明确说明“知识库资料里没有明确说明”,不能补充没有依据的内容。
有了明确目标,后面才知道应该测什么。
如果目标没有说清楚,评估时就容易变成“看起来好像更好”,这样很难判断是否真的可以发布。
第二步:准备两类测试数据
测试数据一般分成两类:
- 本次升级数据。
- 回归数据。
本次升级数据,用来验证这次要修的问题有没有修好。
例如这次升级是为了解决“知识库没有资料时不能补充没有依据内容”,测试数据就要包含这类问题:
| 数据类型 | 测试问题 | 期望表现 |
|---|---|---|
| 本次升级数据 | 知识库里有第五天工具调用的完整代码吗? | 如果资料没有提到,要明确说明 |
| 本次升级数据 | 第六天会讲什么? | 如果知识库没有资料,不能直接编造 |
回归数据,用来验证原来正常的问题有没有被影响。
例如旧版本在下面这些问题上回答得不错,新版本也不能变差:
| 数据类型 | 测试问题 | 期望表现 |
|---|---|---|
| 回归数据 | RAG 是什么? | 仍然能用学生听得懂的方式解释 |
| 回归数据 | 向量数据库为什么不用 MySQL? | 仍然能讲清楚业务数据和向量数据的区别 |
| 回归数据 | LlamaIndex 在项目里负责什么? | 仍然能结合项目代码说明 |
| 回归数据 | 第四天讲了哪些内容? | 仍然会优先参考知识库 |
简单说:
本次升级数据:看新问题有没有修好
回归数据:看旧能力有没有被影响
测试数据不要只放简单问题,最好覆盖几种典型情况:
| 类型 | 目的 | 示例 |
|---|---|---|
| 正常问题 | 看基础回答是否稳定 | RAG 是什么? |
| 知识库存在的问题 | 看是否能依据资料回答 | 第四天讲了哪些内容? |
| 知识库不存在的问题 | 看是否会说明资料没有明确说明 | 第六天讲义里工具调用怎么实现? |
| 错误前提问题 | 看是否会纠正错误前提 | Milvus 是不是用来保存 MySQL 表的? |
| 边界问题 | 看是否能控制回答范围 | 你能保证这个答案一定正确吗? |
| 格式要求问题 | 看是否能按格式输出 | 请用三点总结 LlamaIndex 的作用 |
| 多轮追问问题 | 看历史上下文是否生效 | 那它和 Milvus 的区别呢? |
第三步:让旧版本和新版本回答同一批问题
评估时要让旧版本和新版本面对同一批测试数据。
version 2 -> 回答 A
version 3 -> 回答 B
这样对比才公平。
如果旧版本测的是一批问题,新版本测的是另一批问题,就很难判断差异到底来自提示词,还是来自测试问题本身。
第四步:自动评估为主,人工抽查兜底
少量关键问题可以人工评分。
但测试数据一多,人工不可能全部看完,所以更常见的方式是:
自动评估全量数据
人工复查异常样本
人工抽查正常样本
最后决定是否发布
自动评估可以分成两层。
第一层是程序规则检查。
这类检查比较确定,适合交给代码做。
| 检查项 | 判断方式 |
|---|---|
| 是否输出合法 JSON | 用 json.loads 判断能不能解析 |
| 是否包含必要字段 | 检查字段是否存在 |
| 回答是否太长 | 统计字数 |
| 是否按要求列出三点 | 检查结构数量 |
第二层是大模型评估。
对于“是否适合学生理解”“是否回答到重点”“是否遵守知识库边界”这类语义问题,可以让另一个大模型做初步评分。
这种方式也常叫 LLM as Judge,意思是让大模型当评审。
评分 Prompt 可以这样写:
你是提示词升级评估员。
请比较旧版本回答和新版本回答。
评分维度:
1. 准确性:有没有说错。
2. 完整性:有没有回答到问题重点。
3. 可理解性:是否适合学生理解。
4. 知识库边界:资料没有说明时,是否避免补充没有依据的内容。
5. 回归风险:新版本是否比旧版本变差。
请只输出 JSON:
{
"oldScore": 1-5,
"newScore": 1-5,
"better": "old/new/same",
"risk": "low/medium/high",
"reason": "一句话说明原因"
}
大模型评估不能完全代替人工。
它的作用是先帮我们筛选:
- 新版本分数明显下降的样本。
- 新旧版本差异很大的样本。
- 风险等级为
medium或high的样本。 - 本次升级数据没有通过的样本。
这些样本再交给人工重点复查。
同时,也要从正常样本里随机抽查一部分,避免自动评估漏掉问题。
最后可以按下面规则决定是否发布:
| 情况 | 处理方式 |
|---|---|
| 本次升级数据明显变好,回归数据没有明显变差 | 可以发布 |
| 本次升级数据变好,但回归数据变差 | 暂不发布,继续修改 |
| 本次升级数据没有变好 | 暂不发布 |
| 自动评估通过,但人工抽查发现明显问题 | 暂不发布 |
课程第一版先记住一句话:
提示词升级不是只看新问题有没有修好,还要看旧能力有没有被影响;大量数据先用大模型和规则自动评估,再由人工复查重点样本。
17. 提示词里的变量
很多提示词不是固定文本,而是模板。
例如:
你是一个 AI 课程助教。
请根据下面资料回答学生问题。
资料:
{{knowledge_context}}
学生问题:
{{question}}
这里的 {{knowledge_context}} 和 {{question}} 就是变量。
程序在调用模型前,会把变量替换成真实内容:
资料:
[资料1] 文档:第四天讲义,片段:2
LlamaIndex 负责把文档切分、向量化并写入 Milvus...
学生问题:
LlamaIndex 在我们项目里负责什么?
模板变量要设计清楚。
常见变量有:
| 变量 | 含义 |
|---|---|
{{question}} |
用户本次问题 |
{{history}} |
历史对话 |
{{knowledge_context}} |
知识库检索结果 |
{{student_name}} |
学生姓名 |
{{course_name}} |
课程名称 |
{{output_format}} |
输出格式要求 |
变量不是越多越好。
变量太多会让提示词难维护,也会让不同场景之间耦合太重。
18. 从环境变量到数据库的演进
我们可以把提示词管理分成三个阶段。
第一阶段:写死在代码里。
ChatMessage(role="system", content="你是一个 AI 课程助教")
优点是简单。
缺点是每次修改都要改代码。
第二阶段:放在环境变量里。
AI_CHAT_SYSTEM_PROMPT=你是一个耐心、专业的 AI 课程助教
优点是不用改代码就能调整部分内容。
缺点是缺少版本记录,也不方便多人管理。
第三阶段:放进数据库。
prompt_template
prompt_template_version
优点是可以管理版本、记录使用情况、支持回滚。
真实项目一般会逐步从第一阶段走到第三阶段。
课程里先让大家理解这个演进过程,不需要一开始就把平台做得很复杂。







