第01阶段:AI应用基础与 OpenAI 入门
先看懂 AI 应用的工作流程,再完成第一次 API 调用,最后学会写清楚提示词。
进入学习会做 AI 应用,也要会保护密钥、控制花费、核查信息。
本课项目:AI应用安全检查表
学习重点:API Key、安全、成本、内容边界、信息核查。工具重点:Safety Checklist。
页面里加入 OpenAI、Node.js、Python 和 JSON 图标,帮助学生把 AI 能力、后端调用、脚本实验和结构化输出放在同一条学习路线里理解。
先用阶段卡片看清大方向,再用周课卡片进入具体项目。每节课都保留理论、例子、Node.js、Python、练习和自测,学生可以直接按卡片推进。
先看懂 AI 应用的工作流程,再完成第一次 API 调用,最后学会写清楚提示词。
进入学习AI 不只要会说话,还要按固定格式交答案,这样程序才能稳定处理。
进入学习AI 负责理解语言,函数负责精确计算;两者配合,结果更可靠。
进入学习把图片也交给 AI 看,再让它用清楚的文字或 JSON 结果回答。
进入学习需要最新消息时查网页;需要班级资料时查文件。先找资料,再回答。
进入学习把 AI 能力做成网页:前端收集输入,后端保护密钥,页面展示结果。
进入学习Agent 会按步骤完成任务,但你要给它工具、边界、检查规则和预算意识。
进入学习把前面学过的提示词、JSON、函数、检索、网页和安全设计合在一个作品里。
进入学习一个好的 AI 应用不只是能运行,还要安全、可控、可解释。
理论不是背概念,而是帮你判断项目为什么这样设计。下面这些规则会在代码里反复出现。
这一课的项目是“AI应用安全检查表”,重点是“API Key、安全、成本、内容边界、信息核查”。你可以把它当成一个小实验:先给它一个清楚输入,再观察代码里哪些地方用到了 Safety Checklist。课堂里我们不会一上来就追求复杂功能,而是先把最小版本做出来。最小版本跑通以后,你再改输入、改提示词、改输出格式,变化就会看得很清楚。
这几课开始做更像产品的 AI。Agent 会按步骤处理任务,但越能自动做事,越需要边界和检查。
本课有一条很实用的学习线索:先问“用户到底给了什么”,再问“程序希望拿到什么”。比如你可以试这些输入:请解释 while 循环;输入一万字会怎样?;没有 API Key 时运行。这些输入故意有简单的,也有容易出问题的。正常输入能帮你确认功能;短输入、空输入、奇怪输入能帮你发现系统边界。
写代码时建议你分三轮。第一轮只跑通官方调用,不加自己的想法;第二轮把输入换成自己的例子,看看结果是否还合理;第三轮才开始改结构,比如增加字段、加错误提示、做网页交互。这个顺序有点慢,但很稳。真正浪费时间的不是慢,而是一下子改太多,最后不知道错在哪里。
不要把“自动”理解成“不用管”。好的 Agent 要知道什么时候问问题,什么时候查资料,什么时候停下来提醒风险。
理论部分要和代码一起看。比如“输入契约”不是一个漂亮词,它在代码里就是长度检查、必填字段、表单校验;“输出契约”也不是空话,它在代码里就是 JSON Schema、固定字段或页面渲染规则。你每写一行检查代码,都是在告诉系统:什么结果可以接受,什么结果需要退回去重新处理。
课堂里可以把同桌当成第一个用户。你把项目跑给同桌看,让对方换一个输入,观察系统会不会乱。很多问题都是别人随手一试才出现的,比如输入太短、问题太模糊、连续点击按钮、图片看不清。能处理这些小麻烦,作品就会从“我电脑上能跑”变成“别人也能用”。
最后做复盘时,不要只写“我学会了调用 API”。可以写得更具体:我学会了怎样限制输入,怎样让输出固定,怎样判断结果不可靠,怎样把报错变成用户看得懂的提示。这样的复盘有用,因为下一课你真的会再次用到它。
先把例子看懂,再动手写代码。你不需要一次记住所有概念,先能说清楚“输入是什么、输出是什么、程序要检查什么”。
不写进前端、不发截图、不提交到公开仓库。
每次输入最多 500 字;每个用户每分钟最多请求 3 次;失败后不要无限重试。
涉及健康、法律、金钱、重要日期的内容,要提示用户确认来源。
下面同时给出 Node.js 和 Python 两套完整最小实现。先任选一种原样跑通,再改输入、改提示词、改输出格式。
import OpenAI from "openai";
const client = new OpenAI();
const MODEL = process.env.OPENAI_MODEL || "gpt-5.5";
const usageByUser = new Map();
function safetyCheck({ userId, input }) {
const now = Date.now();
const history = usageByUser.get(userId) || [];
const recent = history.filter((t) => now - t < 60_000);
recent.push(now);
usageByUser.set(userId, recent);
if (!process.env.OPENAI_API_KEY) {
return { ok: false, message: "缺少 OPENAI_API_KEY,请先设置环境变量。" };
}
if (!input || input.trim().length === 0) {
return { ok: false, message: "输入不能为空。" };
}
if (input.length > 500) {
return { ok: false, message: "输入太长,请缩短到 500 字以内。" };
}
if (recent.length > 3) {
return { ok: false, message: "请求太频繁,请一分钟后再试。" };
}
return { ok: true };
}
async function safeAsk(userId, input) {
const check = safetyCheck({ userId, input });
if (!check.ok) return check.message;
const response = await client.responses.create({
model: MODEL,
input: [
{
role: "system",
content:
"你是学生学习助手。不要提供危险、违法或需要专业资质的确定建议。重要信息提醒用户核查。",
},
{ role: "user", content: input },
],
max_output_tokens: 300,
});
return response.output_text;
}
console.log(await safeAsk("student-001", "请用简单例子解释 while 循环。"));
from openai import OpenAI
import os
import time
client = OpenAI()
MODEL = os.getenv("OPENAI_MODEL", "gpt-5.5")
usage_by_user = {}
def safety_check(user_id, text):
now = time.time()
history = usage_by_user.get(user_id, [])
recent = [t for t in history if now - t < 60]
recent.append(now)
usage_by_user[user_id] = recent
if not os.getenv("OPENAI_API_KEY"):
return False, "缺少 OPENAI_API_KEY,请先设置环境变量。"
if not text.strip():
return False, "输入不能为空。"
if len(text) > 500:
return False, "输入太长,请缩短到 500 字以内。"
if len(recent) > 3:
return False, "请求太频繁,请一分钟后再试。"
return True, ""
def safe_ask(user_id, text):
ok, message = safety_check(user_id, text)
if not ok:
return message
response = client.responses.create(
model=MODEL,
input=[
{
"role": "system",
"content": (
"你是学生学习助手。不要提供危险、违法或需要专业资质的确定建议。"
"重要信息提醒用户核查。"
),
},
{"role": "user", "content": text},
],
max_output_tokens=300,
)
return response.output_text
print(safe_ask("student-001", "请用简单例子解释 while 循环。"))