【FDE系列】阶段3:Day 55:综合实战 — 巡检报告生成器与本周收官

📚前言

📒FDE系列内容总纲:

【大纲】FDE 前沿部署工程师学习系列教程-CSDN博客

🚄前置课程列表:

见文档结尾附录。


🚀阶段3·Day 55:综合实战 --- 巡检报告生成器与本周收官 🎉

FDE 学习系列教程 · 第三阶段 · 第 7 周 · Day 5(收官) 预计时长:3 小时 | 难度:★★★☆☆ | 前置知识:Day 51-54(API 调用、Prompt 三板斧、结构化输出、推理引导) 对标大纲课时:3.1.1 ~ 3.1.4 综合(本周收官)
📌 一句话目标:把四天所学整合为一个可演示的小产品------喂入巡检数据,自动产出结构化巡检报告;同时建立 Prompt 文件化与版本管理的工程习惯。


🧑‍🤝‍🧑 开场:四天的零件,今天组装

先盘一下你这四天攒下的零件:

Day 能力 产出
51 调 API day51_hello_llm.py:能跟模型说话
52 立规矩 工单分类 Prompt(zero-shot / few-shot 两版)
53 要 JSON extract_with_retry():一句话 → 可入库字段
54 引导推理 CoT 故障分析模板、ReAct 循环雏形

但它们现在是四个散落的 .py 文件,Prompt 硬编码在代码字符串里------这在真实项目里活不过两周:

复制代码
· 改一句 Prompt 要动 Python 代码 → 改完还得重新部署
· 改坏了没法回滚 → 因为旧版被覆盖了
· 想对比两版效果 → 只能靠记忆:"好像上一版好一点?"

所以今天两件事,一件造东西,一件立规矩:

复制代码
① 造东西:巡检报告生成器
   巡检记录(温度/振动)──► 模型 ──► 带异常识别、风险分级、处置建议的 Markdown 报告

② 立规矩:Prompt 文件化 + 版本号
   prompts/inspection_report.v1.txt   ← 改 Prompt 不用动代码,v1/v2 并存可回滚

做完这个,你的智能工单助手 v0.1 就有两大件了:工单信息提取(Day 53)+ 巡检报告生成(今天)。它们共同长在第二阶段的设备告警工单系统之上:

复制代码
第二阶段底座                      本周新增 v0.1
┌────────────────────┐        ┌──────────────────────────────┐
│ FastAPI 工单接口     │        │ 自然语言报修 → extractor.py → 工单 │
│ MySQL 工单表        │  +     │ 巡检记录   → reporter.py  → 报告   │
│ 飞书通知 / Webhook   │        │ prompts/*.v1.txt(文件化管理)     │
└────────────────────┘        └──────────────────────────────┘

📖 一、今天要造的东西:巡检报告生成器

业务场景(车间每天都在发生的事)

巡检员张工早上绕车间一圈,手抄了一堆数:

复制代码
A3:温度 91.2℃  振动 2.1
B2:温度 65.0℃  振动 8.3
C1:温度 82.4℃  振动 3.0
D5:温度 60.1℃  振动 2.2
E2:温度(没记)  振动 4.0

然后他得写一份《设备巡检日报》交给车间主任。这份报告最烦的地方不是抄数,而是判断和汇总:哪台异常?多严重?先修哪台?数据不全的要不要编?

这就是我们要让模型干的活:

复制代码
输入:巡检记录(JSON / 列表)
   │
   ▼
┌──────────────────────────────────────────┐
│ prompts/inspection_report.v1.txt(规则+基准+报告骨架) │
│ + reporter.py(拼装数据、调 llm.chat)          │
└──────────────────────────────────────────┘
   │
   ▼
输出:Markdown 报告
   # 设备巡检日报(2026-09-21)
   ## 一、总体概况
   ## 二、异常设备明细(表格)
   ## 三、处置建议(按风险排序,带时限)
   ## 四、备注与需人工确认事项

💡 注意这个形状:数据 → Prompt 模板 → 模型 → 结构化产出 。以后你做的每一个 AI 功能都是这个形状------RAG 只是中间多一步"检索",Agent 只是多几轮循环。今天把它走通一遍,后面的课都是在上面加零件。

为什么这个任务适合模型,不适合 if/else

环节 if/else 能做吗 模型能做吗
温度阈值判定 ✅ 而且更准(规则明确) ⚠️ 可能算错
跨指标综合定级 ❌ 要写一堆组合条件 ✅ 读规则就行
生成"处置建议"文字 ❌ 只能套模板 ✅ 能结合上下文写得像人写的
识别"数据缺失/矛盾" ❌ 要额外写校验 ✅ 能主动标注
汇总成可读报告 ❌ ✅

⚠️ 这里有一个非常重要的工程判断:阈值判定这种"确定性计算",应该让程序做,不该让模型做。 今天让模型顺便算,是为了练手(也因为报告需要综合判断);真上生产,你会先算出等级再喂给模型(见第六节的"工程化升级方向")。别让模型干它不擅长的事------这是 Day 53 就讲过的原则。


📖 二、Prompt 也要"代码化管理"

先把目录结构定下来(今天全部按这个来):

复制代码
fde-ai/
├── .env                     # API Key(已在 .gitignore 里)
├── .gitignore
├── day51_hello_llm.py       # 前几天的练习脚本,保留做参考
├── day52_zero_shot.py
├── day53_schema.py
├── day54_cot.py
├── day55_report_demo.py     # 今天的演示入口
├── outputs/                 # 生成的报告落在这里
└── smart_assistant/         # ★ 本周成果归置到这个包
    ├── __init__.py
    ├── llm.py               # 统一封装的调用函数
    ├── prompts/
    │   ├── extract_ticket.v1.txt
    │   └── inspection_report.v1.txt   # Prompt 当独立文件管理
    ├── extractor.py         # Day53 的工单提取
    └── reporter.py          # 今天的报告生成

四条理由,每一条都是踩过坑才有的:

理由 不这么做的后果
文件化:Prompt 与代码分离 改一句 Prompt 要动代码、重新部署;产品经理没法参与改 Prompt
版本号:v1/v2 并存不覆盖 改坏了没法回滚;"上一版明明更好"但找不回来
一处定义:同类任务共用一份 三个地方复制了同一段 Prompt,改了一处漏了两处
可评测:版本对应实验结果 无法回答"v2 到底比 v1 好在哪",优化全凭感觉

📌 第 8 周 Langfuse 会把这件事做得更彻底(云端版本管理 + 调用追踪);下周的 Promptfoo 对比也需要"两个版本的文件"作为输入。今天的文件命名约定,就是为下周准备的。


🖥️ 三、实操:搭起 smart_assistant 包

实操步骤 1:统一 LLM 调用封装

smart_assistant/llm.py:

python 复制代码
"""统一的 LLM 调用入口:所有功能模块共用,方便以后换模型/加追踪"""
import os, json
from openai import OpenAI
from dotenv import load_dotenv

load_dotenv()

client = OpenAI(
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com",
)


def chat(system: str, user: str, temperature: float = 0.7,
         max_tokens: int = 1024, json_mode: bool = False) -> str:
    kwargs = {}
    if json_mode:
        kwargs["response_format"] = {"type": "json_object"}
    resp = client.chat.completions.create(
        model="deepseek-chat",
        messages=[{"role": "system", "content": system},
                  {"role": "user", "content": user}],
        temperature=temperature,
        max_tokens=max_tokens,
        **kwargs,
    )
    return resp.choices[0].message.content

为什么要有这么一层"看起来多余"的封装?

复制代码
① 换模型只改一处:哪天客户要求换私有化模型,改 llm.py 一个文件
② 统一加东西:重试、超时、日志、成本统计、Langfuse 追踪,都加在这一层
③ 业务代码干净:extractor.py / reporter.py 只关心 Prompt 和数据

这就是第二阶段反复强调的分层思想在 AI 代码里的应用。

顺手加一个带用量统计的版本(可选,但对建立成本意识很有用):

python 复制代码
def chat_with_usage(system: str, user: str, **kwargs) -> tuple[str, dict]:
    """返回 (回答, 用量字典),便于统计成本"""
    resp = client.chat.completions.create(
        model="deepseek-chat",
        messages=[{"role": "system", "content": system},
                  {"role": "user", "content": user}],
        **kwargs,
    )
    usage = {
        "prompt_tokens": resp.usage.prompt_tokens,
        "completion_tokens": resp.usage.completion_tokens,
        "total_tokens": resp.usage.total_tokens,
    }
    return resp.choices[0].message.content, usage

实操步骤 2:写报告生成 Prompt(文件化)

smart_assistant/prompts/inspection_report.v1.txt:

复制代码
你是制造车间设备巡检分析专家。根据输入的巡检记录生成 Markdown 报告。

【判定基准】
- 温度:正常≤80℃;80~85℃为预警;>85℃为告警
- 振动:正常≤4.5mm/s;4.5~7为预警;>7为告警
- 任一项告警,该设备风险等级为"高";仅预警为"中";全部正常为"低"

【报告结构】严格按以下 Markdown 输出:
# 设备巡检日报({{date}})
## 一、总体概况
- 巡检设备数 / 正常数 / 预警数 / 告警数(各1行)
## 二、异常设备明细
表格列:设备编号 | 温度 | 振动 | 风险等级 | 问题判断
(全部正常时输出"无异常设备")
## 三、处置建议
按风险从高到低,每条含:设备、建议动作、建议时限
## 四、备注与需人工确认事项
列出数据缺失或互相矛盾、需要现场复核之处;没有则写"无"

【规则】
1. 只依据给定数据,禁止虚构未提供的读数
2. 风险等级必须严格按基准计算,不得拍脑袋
3. 涉及告警的设备,建议时限不超过2小时

这个 Prompt 里藏着四天所学的全部要点,值得拆开看:

位置 用到的知识 来自
"你是......巡检分析专家" 角色设定(第一板斧) Day 52
【判定基准】三条 边界裁决规则、禁止拍脑袋 Day 52
【报告结构】小标题 结构化骨架、CoT 式分步 Day 54
"禁止虚构读数" 防编造约束 Day 54
表格列定义 输出格式约束(第二道防线) Day 53

📌 {``{date}} 是占位符,下一步用 replace 替换(第 8 周会升级为 Jinja2 模板引擎)。先用最简单的办法把链路跑通,再考虑优雅。

实操步骤 3:把 Day 53 的提取器也搬进包里

smart_assistant/prompts/extract_ticket.v1.txt:

复制代码
你是工单信息提取器,只输出 JSON 对象,不要输出任何其他文字。

【提取字段】
- title: str,工单标题,4~40字
- device_id: str|null,形如 A3、B12 的设备编号;描述中未明确出现时填 null,禁止猜测
- priority: low|medium|high(涉及安全/停机/泄漏=high;不影响生产=low;其余=medium)
- summary: str,40字以内的一句话摘要

【规则】
1. 只输出 JSON,禁止输出解释或 Markdown 代码块
2. 未提供的信息填 null,严禁编造
3. priority 必须是 low / medium / high 三者之一

smart_assistant/extractor.py:

python 复制代码
"""自然语言报修 → 结构化工单字段(Day 53 的封装版)"""
import json
from typing import Literal
from pathlib import Path
from pydantic import BaseModel, Field, ValidationError
from .llm import chat

PROMPT_DIR = Path(__file__).parent / "prompts"


class TicketExtract(BaseModel):
    title: str = Field(min_length=4, max_length=40)
    device_id: str | None = Field(default=None, pattern=r"^[A-Z]+\d+$|^$")
    priority: Literal["low", "medium", "high"]
    summary: str = Field(max_length=60)


def load_prompt(name: str) -> str:
    return (PROMPT_DIR / name).read_text(encoding="utf-8")


def extract_with_retry(text: str, max_retry: int = 3) -> TicketExtract:
    system = load_prompt("extract_ticket.v1.txt")
    for attempt in range(1, max_retry + 1):
        raw = chat(system, text, temperature=0, max_tokens=400, json_mode=True)
        try:
            return TicketExtract.model_validate_json(raw)
        except ValidationError as e:
            print(f"[extract] 第 {attempt} 次不合规:{e.errors()}")
            text = f"上次输出不符合 schema,错误:{e.errors()},请只输出修正后的 JSON。原文:{text}"
    raise RuntimeError(f"提取失败,已重试 {max_retry} 次")

实操步骤 4:报告生成模块 + 演示入口

smart_assistant/reporter.py:

python 复制代码
"""巡检数据 → Markdown 报告"""
import json
from pathlib import Path
from .llm import chat

PROMPT_DIR = Path(__file__).parent / "prompts"


def load_prompt(name: str) -> str:
    return (PROMPT_DIR / name).read_text(encoding="utf-8")


def generate_report(records: list[dict], date: str) -> str:
    system = load_prompt("inspection_report.v1.txt").replace("{{date}}", date)
    user = "巡检记录 JSON 如下:\n" + json.dumps(records, ensure_ascii=False, indent=2)
    return chat(system, user, temperature=0.2, max_tokens=1500)

根目录新建 day55_report_demo.py:

python 复制代码
"""本周收官演示:巡检记录 → Markdown 报告(打印 + 落盘)"""
from pathlib import Path
from smart_assistant.reporter import generate_report

records = [
    {"device_id": "A3", "temperature": 91.2, "vibration": 2.1, "inspector": "张工"},
    {"device_id": "B2", "temperature": 65.0, "vibration": 8.3, "inspector": "张工"},
    {"device_id": "C1", "temperature": 82.4, "vibration": 3.0, "inspector": "李工"},
    {"device_id": "D5", "temperature": 60.1, "vibration": 2.2, "inspector": "李工"},
    {"device_id": "E2", "temperature": None, "vibration": 4.0, "inspector": "王工"},
]

if __name__ == "__main__":
    report = generate_report(records, date="2026-09-21")
    print(report)
    Path("outputs").mkdir(exist_ok=True)
    Path("outputs/report_2026-09-21.md").write_text(report, encoding="utf-8")

运行:

复制代码
python day55_report_demo.py

python3 day55_report_demo.py

观察重点(对着输出逐条核对,这就是最朴素的"验收"):

检查项 期望 模型做到了吗
A3 温度 91.2 → 告警 → 风险"高" ✅ ☐
B2 振动 8.3 → 告警 → 风险"高" ✅ ☐
C1 温度 82.4 → 预警(不是告警)→ 风险"中" ✅ ☐
D5 全正常 → 风险"低",不进异常表 ✅ ☐
E2 温度缺失 → 进"需人工确认",不得编造读数 ✅ ☐
告警设备建议时限 ≤ 2 小时 ✅ ☐
概况里的计数(5 台 / 正常 / 预警 / 告警)对得上 ✅ ☐

💡 如果某一项没做到,不要急着怪模型 ------先检查 Prompt 里那条规则写清楚没有。这是本周最重要的思维习惯:效果不好 → 先查指令 → 再改指令 → 记录对比。


📊 四、巡检判定基准速查表

这是本次任务的"业务规则",模型和你都要遵守同一套:

指标 正常 预警 告警
温度 ≤ 80℃ 80 ~ 85℃ > 85℃
振动 ≤ 4.5 mm/s 4.5 ~ 7 > 7

综合定级规则:

复制代码
任一项告警  → 风险"高"
仅预警      → 风险"中"
全部正常    → 风险"低"
数据缺失    → 不据此定级,列入"需人工确认"

本次 5 台设备的判定答案(用来对答案)

设备 温度 振动 温度判定 振动判定 综合风险
A3 91.2 2.1 告警 正常 高
B2 65.0 8.3 正常 告警 高
C1 82.4 3.0 预警 正常 中
D5 60.1 2.2 正常 正常 低
E2 缺失 4.0 缺失 正常 待确认

处置时限约定:告警设备 ≤ 2 小时;预警设备可安排当班处理。

⚠️ 这些阈值是本课程的教学设定 。真实客户现场,阈值来自设备手册或工艺卡------FDE 的第一件事永远是问清楚"你们的标准是什么",而不是照搬网上或上一家的数字。


🖥️ 五、实操:故意刁难,逼出 Prompt 漏洞

AI 功能不能只测正常数据。边界输入是 Prompt 的照妖镜。

实操步骤 1:准备边界用例

新建 day55_edge_test.py:

python 复制代码
"""边界用例:用坏数据逼出 Prompt 漏洞"""
from smart_assistant.reporter import generate_report

edge_cases = [
    ("空记录", []),
    ("读数全缺", [{"device_id": "A3"}]),
    ("明显异常值", [{"device_id": "A3", "temperature": 999, "vibration": 0}]),
    ("设备号缺失", [{"temperature": 90, "vibration": 1.0}]),
    ("自相矛盾", [{"device_id": "A3", "temperature": 70, "vibration": 1.0, "note": "现场冒烟"}]),
]

for name, records in edge_cases:
    print("=" * 60)
    print(f"用例:{name}  输入:{records}")
    print("-" * 60)
    print(generate_report(records, date="2026-09-21"))

跑一遍,把问题记下来。v1 大概率会犯这些错:

用例 v1 常见表现 问题严重性
空记录 编造出一台设备和一份报告 🔴 严重(幻觉)
读数全缺 把 A3 判成"低风险/正常" 🔴 严重(把没数据当成没问题)
温度 999 判为"告警"并给出处置建议 🟡 中(没识别为异常数据)
设备号缺失 报告里出现"未知设备"或干脆漏掉 🟡 中
自相矛盾 只按数字判正常,忽略"冒烟" 🟡 中(漏掉关键文本线索)

实操步骤 2:改出 v2

不要覆盖 v1------复制一份改名,这就是版本管理:

复制代码
cp smart_assistant/prompts/inspection_report.v1.txt smart_assistant/prompts/inspection_report.v2.txt

在 v2 的规则部分追加:

复制代码
4. 巡检记录为空时,除概况写0外,其余各节明确写"今日无巡检数据"
5. 读数超出物理合理范围(温度>200或<0)时,标记为"数据异常待复核",不据此定级
6. 设备读数缺失时,不得判定为"正常",必须列入"需人工确认事项"
7. 记录中的文字备注(如"冒烟""异响")与数值冲突时,优先采信文字描述并标注冲突

然后加一个切换入口(这就是"版本可切换"的最小实现):

python 复制代码
def generate_report(records: list[dict], date: str, version: str = "v1") -> str:
    name = f"inspection_report.{version}.txt"
    system = load_prompt(name).replace("{{date}}", date)
    user = "巡检记录 JSON 如下:\n" + json.dumps(records, ensure_ascii=False, indent=2)
    return chat(system, user, temperature=0.2, max_tokens=1500)

实操步骤 3:v1 vs v2 对比

python 复制代码
for name, records in edge_cases:
    print("=" * 60)
    print(f"用例:{name}")
    print("--- v1 ---")
    print(generate_report(records, date="2026-09-21", version="v1")[:400])
    print("--- v2 ---")
    print(generate_report(records, date="2026-09-21", version="v2")[:400])

把结果填进记录本(这张表下周会被 Promptfoo 自动化):

用例 v1 表现 v2 表现 v2 是否解决
空记录 ☐
读数全缺 ☐
温度 999 ☐
设备号缺失 ☐
自相矛盾 ☐

📌 这就是"评测驱动迭代"的微型实战 :发现问题 → 改 Prompt → 用同一批用例再跑 → 对比记录。第 8 周会把它规模化(30 条用例 + 自动化评分),但流程和今天一模一样。工具变复杂,思路不变。


🖥️ 六、实操:两件套合体,接回工单系统

实操步骤 1:一个入口,两件事

新建 day55_assistant.py------智能工单助手 v0.1 的门面:

python 复制代码
"""智能工单助手 v0.1:提取工单 + 生成巡检报告"""
from smart_assistant.extractor import extract_with_retry
from smart_assistant.reporter import generate_report
from pathlib import Path

REPAIR_TEXT = "B12冲压机防护门失灵,门没关也能启动,太危险了,赶紧处理"
RECORDS = [
    {"device_id": "A3", "temperature": 91.2, "vibration": 2.1, "inspector": "张工"},
    {"device_id": "C1", "temperature": 82.4, "vibration": 3.0, "inspector": "李工"},
]

if __name__ == "__main__":
    # ① 自然语言报修 → 结构化字段
    ticket = extract_with_retry(REPAIR_TEXT)
    print("【工单提取】")
    print(ticket.model_dump())

    # ② 巡检记录 → Markdown 报告
    report = generate_report(RECORDS, date="2026-09-21", version="v2")
    Path("outputs").mkdir(exist_ok=True)
    Path("outputs/report_2026-09-21.md").write_text(report, encoding="utf-8")
    print("\n【巡检报告】已生成 outputs/report_2026-09-21.md\n")
    print(report[:600])

实操步骤 2:把提取结果送进第二阶段系统

python 复制代码
import httpx

resp = httpx.post(
    "http://localhost:8000/api/tickets",
    json=ticket.model_dump(),
    headers={"X-API-Key": "fde-secret-2026"},   # 生产请从环境变量读
    timeout=10,
)
print(resp.status_code, resp.json())

服务没起来也能验收:把上面换成 print(ticket.model_dump()),确认字段齐、类型对、枚举合法即可。

实操步骤 3:(选做)把报告能力暴露成接口

如果第二阶段那套 FastAPI 还在,加一个接口,让车间主任能随时要报告:

python 复制代码
from fastapi import FastAPI
from pydantic import BaseModel
from smart_assistant.reporter import generate_report

app = FastAPI(title="智能工单助手 v0.1")


class InspectionRequest(BaseModel):
    date: str
    records: list[dict]
    version: str = "v2"


@app.post("/ai/inspection-report")
def api_inspection_report(req: InspectionRequest):
    """巡检记录 → Markdown 报告"""
    return {"date": req.date,
            "version": req.version,
            "report": generate_report(req.records, req.date, version=req.version)}

测试:

复制代码
curl -X POST http://localhost:8000/ai/inspection-report \
  -H "Content-Type: application/json" \
  -d '{"date":"2026-09-21","records":[{"device_id":"A3","temperature":91.2,"vibration":2.1}]}'

到这一步,"AI 能力"和"业务系统"就真正长在一起了。

工程化升级方向(知道就行,后面几周会做)

今天的简化 生产该怎么做 什么时候学
阈值判定交给模型 程序先算等级,模型只负责写报告 现在就能改(Day 55 练习 3)
Prompt 里 {``{date}} 用 replace Jinja2 模板引擎 第 8 周
没有重试/超时/日志 llm.py 里加统一处理 第 8-10 周
没有成本/效果追踪 Langfuse 追踪每次调用 第 8 周
报告没有落库 存 MySQL + 生成历史列表 自己加

📊 七、本周复盘:知识地图与验收清单

本周知识地图

复制代码
Prompt Engineering 基础(Day 51-55)
│
├─ API 调用(Day 51)
│   ├─ openai SDK + DeepSeek(兼容接口,换 base_url 即可)
│   ├─ messages 三角色:system / user / assistant
│   ├─ 模型无状态:多轮历史自己带
│   ├─ temperature / max_tokens / finish_reason
│   └─ token 计费:输入+输出,输出更贵
│
├─ 三板斧(Day 52)
│   ├─ System 四段式:角色/任务/规则/输出
│   ├─ Zero-shot:常识任务直接下指令
│   ├─ Few-shot:范例对解决边界模糊与格式刁钻
│   ├─ 分隔符隔离外部数据
│   └─ 边界裁决规则(如安全优先)
│
├─ 结构化输出(Day 53)
│   ├─ response_format=json_object
│   ├─ Pydantic:类型/枚举/正则校验
│   ├─ 校验失败回喂错误 → 限次重试
│   └─ 概率文本 → 确定契约的三道防线
│
├─ 推理引导(Day 54)
│   ├─ 快答类 vs 推理类任务分流
│   ├─ CoT:规定分析步骤,先推理后结论
│   ├─ Plan-and-Execute:先计划确认再执行
│   └─ ReAct 雏形:想→做→看循环(Agent 种子)
│
└─ 综合实战(Day 55)
    ├─ 巡检记录 → 结构化 Markdown 报告
    ├─ Prompt 文件化 + 版本号
    ├─ 边界输入驱动 v1→v2 迭代
    └─ 智能工单助手 v0.1:提取 + 报告两件套

Prompt 工程化习惯清单

习惯 做法 你做到了吗
文件化 Prompt 存 prompts/*.txt,代码只负责传数据 ☐
版本号 v1/v2 并存,迭代不覆盖旧版 ☐
一处定义 同类任务共用一个 system,别到处复制粘贴 ☐
变更有记录 实验本写清:改了什么、哪条用例变好/变差 ☐
边界先行 空值、缺失、极端值、恶意输入尽早试 ☐
统一入口 所有调用过 llm.chat(),方便换模型/加追踪 ☐

本周验收清单(逐条打勾,没过就回去补)

# 验收项 达标标准 ☐
1 API 调用 不看笔记能独立写出调用脚本并解释 usage ☐
2 三角色 能说清 system 与 user 的分工,能实现多轮 ☐
3 三板斧 同一个分类任务有 zero/few-shot 两版及对比记录 ☐
4 结构化 JSON mode + Pydantic + 重试完整跑通 ☐
5 业务联动 提取结果能成功创建第二阶段系统的工单 ☐
6 推理 CoT 报告质量明显优于直接提问(有对照) ☐
7 ReAct 理解循环机制,能解释假工具 demo 的每一步 ☐
8 工程习惯 Prompt 文件化、带版本号、有实验记录 ☐
9 v0.1 巡检报告生成器可演示,边界用例有处理 ☐
10 安全 Key 在 .env 中,.gitignore 配置正确 ☐

📝 本课小结

知识点 一句话记住
完整链路 数据 → Prompt 模板 → 模型 → 结构化产出
统一封装 llm.py 一处调模型,方便换模型/加追踪/加日志
Prompt 文件化 改 Prompt 不动代码,产品经理也能改
版本号 v1/v2 并存,改坏能回滚,对比能溯源
判定基准 温度 ≤80 正常 / 8085 预警 / >85 告警;振动 ≤4.5 / 4.57 / >7
综合定级 有告警=高,仅预警=中,全正常=低,缺失=待确认
边界用例 空数据、缺读数、异常值、矛盾信息必须测
迭代闭环 发现问题 → 改 Prompt → 同批用例再跑 → 对比记录
模型分工 确定性计算交给程序,模型只做它擅长的判断与表达
v0.1 成果 工单提取 + 巡检报告两件套,长在第二阶段系统之上

🧠 核心认知 :本周你学会的不是几个"咒语",而是一套把 AI 变成系统能力的方法论 :先调通 API(Day 51),再把任务交代清楚(Day 52),然后让输出变得可被程序消费(Day 53),再让复杂问题被分步推理(Day 54),最后用工程化手段把它们管起来(今天)。Prompt 是会反复迭代的资产,不是一次性的脚本------从今天起,像管代码一样管它。


📋 课后练习

练习 1:把阈值判定从模型手里拿回来(约 40 分钟)

今天的 v2 让模型又判等级又写报告。改进它:在 reporter.py 里先用 Python 算出每台设备的等级,再把带等级的表格喂给模型,让它只负责写"处置建议"和"备注"。

先自己写一遍 judge(),再对照下面的参考实现(判定基准见第四节):

python 复制代码
def judge(temp, vib) -> str:
    """按判定基准算出风险等级(确定性计算,别交给模型)"""
    levels = []
    for value, warn, alarm in ((temp, 80, 85), (vib, 4.5, 7)):
        if value is None:
            levels.append("unknown")          # 数据缺失,不据此定级
        elif value > alarm:
            levels.append("high")
        elif value > warn:
            levels.append("medium")
        else:
            levels.append("low")
    if "unknown" in levels:
        return "待确认"
    if "high" in levels:
        return "高"
    if "medium" in levels:
        return "中"
    return "低"

验收:

  1. 用同一批 5 条记录,对比"模型自己判"和"程序判完再喂"两种版本的等级是否一致

  2. 记录两次调用的 total_tokens 差异

  3. 写一句结论:哪些活从模型手里拿走之后,结果更稳了?

练习 2:把 v2 迭代成 v3(约 40 分钟)

用第五节的 5 个边界用例继续刁难 v2,找出至少 2 个还没解决的问题(例如:设备号缺失时报告里怎么写、同一台设备出现两条记录怎么办、巡检员字段怎么用起来)。

要求:

  1. 新建 inspection_report.v3.txt(不覆盖 v2),在规则里补上对应条款

  2. 用完全相同的边界用例跑 v2 和 v3,逐条对比

  3. 在实验记录本里写:改了哪句、哪条用例从 ❌ 变 ✅、有没有哪条用例反而变差了(这很重要------Prompt 优化经常按下葫芦浮起瓢)

练习 3:给 v0.1 补上"报告归档"(约 30 分钟)

让生成的报告不再只是打印在屏幕上:

  1. 报告落盘到 outputs/巡检日报_YYYY-MM-DD.md(目录按月份分子目录更好)

  2. 写一个 list_reports() 函数,列出 outputs/ 下所有报告文件(用 pathlib.Path.glob)

  3. (进阶)把报告元信息(日期、设备数、告警数、使用的 Prompt 版本)写进一个 outputs/index.json,方便以后检索

这一步看着不 AI,但它是"能演示"和"能用"之间的差别:客户要看的是"上周的报告在哪",不是"再跑一次给我看"。


🔭 下节预告

本周你已经能让模型"干好活",但心里可能总不踏实:

复制代码
· 换个问法它还稳吗?
· 怎么证明 v2 真的比 v1 好,而不是我运气好?
· 有人在输入框里写"忽略上面的指令"怎么办?
· 线上跑了一个月,到底花了多少钱、哪条 Prompt 用得最多?

下周(第 8 周,Day 56-60)进入 模块 3.1(下):Prompt 评测、安全与管理 ------ 把"凭感觉调 Prompt"升级成"用数据说话":

Day 主题 你会做出什么
56 评测集与指标 把本周的批量脚本升级成 ≥30 条标注评测集
57 Promptfoo A/B 评测 用工具自动跑 v1 vs v2,读懂评测报告
58 Prompt 注入与越狱 亲手攻击自己的工单助手,再学会防护(分隔符的用武之地)
59 模板化与版本管理 Jinja2 模板 + Prompt 目录规范
60 Langfuse 可观测 追踪每一次调用:花了多少 token、用了哪个版本、效果如何

本周作业请先收好这三样东西 ,下周直接要用:day53_batch_result.json(批量提取结果)、工单分类的 zero/few-shot 两版 Prompt、今天的 inspection_report.v1/v2.txt。

恭喜跑完第三阶段第一周 🎉 休息一下,下周见!


🌍附录:前置课程列表

阶段一:认知启蒙(AI 认知与 FDE 角色)
AI 认知

【FDE系列】阶段1Day 1:AI 层级关系 --- 四个嵌套的圈-CSDN博客

【FDE系列】阶段1Day 2:AI 三阶段发展史 --- 会认 → 会判断 → 会创造-CSDN博客

【FDE系列】阶段1Day 3:符号 AI vs 机器学习 --- 两条路线的本质区别-CSDN博客

【FDE系列】阶段1Day 4:Transformer 的历史意义 --- 2017 年的分水岭-CSDN博客

【FDE系列】阶段1Day 5:本周复习与自测 --- 检验你的 AI 认知地基-CSDN博客

【FDE系列】阶段1Day 6:Transformer 架构 --- 一张图纸盖出千千万万栋楼-CSDN博客

【FDE系列】阶段1Day 7:LLM 本质 --- 文字接龙机器-CSDN博客

【FDE系列】阶段1Day 8:Token --- 模型眼中的最小单位-CSDN博客

【FDE系列】阶段1Day 9:AI 幻觉 --- 为什么会一本正经地胡说八道-CSDN博客

【FDE系列】阶段1Day 10:上下文窗口 --- 模型的记忆力上限 + 本周复习-CSDN博客

【FDE系列】阶段1Day 11:Prompt --- 给模型立规矩-CSDN博客

【FDE系列】阶段1Day 12:Memory --- 让模型记住上下文

【FDE系列】阶段1Day 13:RAG --- 给模型配图书管理员-CSDN博客

【FDE系列】阶段1Day 14:Tool Use --- 让模型动手操作-CSDN博客

【FDE系列】阶段1Day 15:MCP --- 统一的工具接口标准 + 第三周复习-CSDN博客

FDE 基础概念

【FDE系列】阶段1Day 16:什么是 FDE --- 把 AI 变成客户结果的人-CSDN博客

【FDE系列】阶段1Day 17:FDE vs 传统实施 --- 三大本质区别-CSDN博客

【FDE系列】阶段1Day 18:FDE 三重身份 + C6 胜任力模型-CSDN博客

【FDE系列】阶段1Day 19:七阶段行动路径 + 行业经验的价值-CSDN博客

【FDE系列】阶段1Day 20:阶段总结与产出物 --- 第一阶段收官-CSDN博客


阶段二:技术地基(Python + FastAPI + SQL + Docker + API 集成)
Python基础

【FDE系列】阶段2:Day 21:Python 环境搭建 --- 写出你的第一行代码-CSDN博客

【FDE系列】阶段2:Day 22:变量、数据类型、条件判断 --- Python 的"记忆"和"判断"-CSDN博客

【FDE系列】阶段2:Day 23:循环与函数 --- 让代码跑 100 遍、把逻辑打包复用-CSDN博客

【FDE系列】阶段2:Day 24:数据结构 --- 列表、字典、集合、元组-CSDN博客

【FDE系列】阶段2:Day 25:文件读写与 JSON --- 让程序连通外部数据(第一周收官)-CSDN博客

【FDE系列】阶段2:Day 26:模块化编程 --- 把代码拆成"抽屉柜"-CSDN博客

【FDE系列】阶段2:Day 27:异常处理与日志 --- 让程序"摔不烂、查得到"-CSDN博客

FastAPI入门到进阶

【FDE系列】阶段2:Day 28:FastAPI 入门 --- 把你的函数变成 API 服务-CSDN博客

【FDE系列】阶段2:Day 29:FastAPI 进阶 --- Pydantic 模型与完整 CRUD 实战-CSDN博客

【FDE系列】阶段2:Day 30:生产代码规范 --- 测试、类型注解、配置管理(第二周收官)-CSDN博客

SQL基础

【FDE系列】阶段2:Day 31:SQL 基础 --- 增删改查一把梭-CSDN博客

【FDE系列】阶段2:Day 32:多表查询 --- JOIN 与聚合-CSDN博客

【FDE系列】阶段2:Day 33:进阶查询 --- 窗口函数与 CTE-CSDN博客

【FDE系列】阶段2:Day 34:数据清洗 --- 把脏数据捋干净-CSDN博客

【FDE系列】阶段2:Day 35:Python + SQL --- 工单接入 MySQL + 本周收官-CSDN博客

Linux基础

【FDE系列】阶段2:Day 36:Linux 入门与文件操作 --- 扔掉鼠标的第一天-CSDN博客

【FDE系列】阶段2:Day 37:权限、进程与文本三剑客-CSDN博客

【FDE系列】阶段2:Day 38:Shell 脚本 --- 把命令串起来自动跑-CSDN博客

【FDE系列】阶段2:Day 39:Linux 综合实战 --- 让服务无人值守-CSDN博客

【FDE系列】阶段2:Day 40:Shell 进阶 --- 生产级脚本与本周收官-CSDN博客

Docker

【FDE系列】阶段2:Day 41:Docker 入门 --- 把环境装进盒子-CSDN博客

【FDE系列】阶段2:Day 42:Dockerfile 实战 --- 把你的应用打包成镜像-CSDN博客

【FDE系列】阶段2:Day 43:Docker Compose --- 多容器一键编排-CSDN博客

【FDE系列】阶段2:Day 44:Nginx 反向代理 + Git 版本控制-CSDN博客

【FDE系列】阶段2:Day 45:综合实战 --- Docker + Nginx + Git 完整部署与本周收官-CSDN博客

API 集成与系统对接

【FDE系列】阶段2:Day 46:RESTful 设计与认证授权-CSDN博客

【FDE系列】阶段2:Day 47:对接企业系统 --- 飞书 / 钉钉 API-CSDN博客

【FDE系列】阶段2:Day 48:Webhook 处理与数据映射-CSDN博客

【FDE系列】阶段2:Day 49:OpenAPI 文档与接口测试-CSDN博客

【FDE系列】阶段2:Day 50:综合项目 --- 设备告警工单闭环系统 & 第二阶段收官 特殊字符-CSDN博客

阶段三:AI 应用技术(含 SDD 方法论)
AI基础:Prompt Engineering 系统训练

【FDE系列】阶段3:Day 51:从聊天窗口到代码 --- 跟 LLM 的第一次握手-CSDN博客

【FDE系列】阶段3:Day 52:Prompt 三板斧 --- 角色、示例与清晰指令-CSDN博客

【FDE系列】阶段3:Day 53:结构化输出 --- 让模型的回答能进数据库-CSDN博客

【FDE系列】阶段3:Day 54:思维链与推理任务 --- 让模型一步步想清楚-CSDN博客

待完成教程:

RAG 知识检索系统

Agent 框架与开发

Tool Calling 与 MCP

LLM 推理与部署

规范驱动开发与 Agent 工程方法论

阶段四:平台与交付(含 Agent 治理)

阶段五:行业实战与认证

相关推荐
百度一下吧40 分钟前
Codex 使用操作指南
人工智能
和裕1 小时前
全纸结构重型纸箱能否满足 1 吨以上设备出口熏蒸豁免要求?通关合规性全解析
大数据·运维·网络·人工智能·算法
Ai-_Man1 小时前
您您这可以把Microsofat Copilot的多个会话比如说。左侧的多个会话一次性导出吗?不是单条会话里面的多次会对话。AI导出鸭
javascript·人工智能·ai·小程序·电脑·copilot
2601_965969061 小时前
教师考完AI证书后,应该完成哪些教学项目?
人工智能
代码方舟1 小时前
零信任架构实战:基于天远运营商三要素简版V即时版查询构建自动化电子投保实名核验网关
大数据·人工智能·架构·自动化
JavaPub-rodert1 小时前
AI Agent 怎么接上长期记忆?从 Graphiti MCP Server 讲透 MCP、Episode、搜索与记忆工具化
人工智能
大模型任我行1 小时前
Meta:强化学习权重传输不再卡顿
人工智能·语言模型·自然语言处理·论文笔记
sugarzhangnotes2 小时前
【无标题】
开发语言·人工智能·python
盼小辉丶2 小时前
PyTorch强化学习实战(27)——进化策略在强化学习中的应用
人工智能·pytorch·深度学习·强化学习