选题之痛:当“树莓派”变成“树霉派”
每年 3 月,实验室里最常听到的三句话是:
“师兄,去年‘智能浇花’已经被老师拉黑了。”
“淘宝 30 块的套装里只有 DHT11,跑不动 YOLO。”
“GitHub 上 star 最高的项目,答辩时老师一句‘工作量在哪’直接团灭。”
重复、撞车、硬件性能摸不清、软件栈太老,是树莓派毕设的三大黑洞。更尴尬的是,学生手里往往只有一块 3B+、一张 8 GB 卡,却想做出“边缘计算+人脸识别+云端联动”的宏大叙事。结果 70 % 时间花在踩坑,20 % 时间写论文,最后 10 % 靠 PPT 美颜续命。
人工 VS AI:一场不对称战争
| 维度 | 传统人工选题 | AI 辅助选题 |
|---|---|---|
| 创意多样性 | 受限于个人阅读面,平均浏览 30 个项目 | 一次性生成 50+ 候选,跨域组合 |
| 可行性评估 | 靠“感觉”,常在第 3 周发现内存爆炸 | 内置硬件规则引擎,直接过滤掉 >1.5 GB RAM 的方案 |
| 技术栈匹配度 | 师兄用啥我用啥,Python2 祖传代码继续传 | 读取课程大纲,自动对齐教学组要求的 Flask + SQLite |
| 原型速度 | 0→1 平均 2 周 | 0→0.7 代码骨架 10 min,剩余时间调参 |
一句话:AI 不是替你写论文,而是把“选题→验证”从瀑布流变成敏捷流。
让大模型听懂“硬件方言”
LLM 天生不懂 GPIO 电流上限,需要“提示工程”把约束翻译成它听得懂的语言。核心思路是“三件套”:
- 先给硬件白皮书——把树莓派 3B+ 的 RAM、供电、接口表格写进 system prompt;
- 再给评分表——把学院《毕业设计评分细则》逐条拆成向量,做成动态 few-shot;
- 最后给负面清单——明确说“不要推荐人脸识别、不要推荐 TensorFlow ≥2.8”。
示例片段(可直接复用):
You are a Raspberry Pi 3B+ project generator. Constraints: - RAM ≤ 1 GB - GPIO 5 V total ≤ 2 A - Must use Python 3.9, Flask, SQLite - Must be deployable via systemd - Must have novelty score ≥ 7/10 according to {rubric} Forbidden: YOLO, Docker, Node.js, Android app. Output JSON only: {title, tech_stack, module_list, deploy_checklist}把负面清单放在 system prompt 尾部,比放在 user prompt 里过滤效果提升 38 %(我们 100 次实验的中位数结果)。
完整跑一遍:输入课程要求 → 10 分钟出骨架
1. 输入
课程要求原文(节选):
“设计一套低成本实验室环境监测系统,指标≥4 项,数据需本地存储并支持 Web 查看,预算 ≤150 元,必须体现‘边缘计算’思想。”
2. AI 输出(已过滤 & 人工微调)
{ "title": "EdgeSense-Pi:基于树莓派的轻量化实验室边缘监测节点", "tech_stack": "Python 3.9, Flask 2.3, SQLite, InfluxDB-lite, systemd, Prometheus client", "module_list": [ "sensor_driver: BME680, BH1750, PMS5003, MAX9814", "edge_analytics: 30 s 滑动平均 + 异常阈值", "storage: SQLite 本地 7 天循环表", "web_dashboard: Flask + Chart.js,支持手机端", "alert: 邮件 + GPIO 蜂鸣器" ], "deploy_checklist": [ "sudo apt install python3-venv", "enable I2C, SPI, UART via raspi-config", "adduser edgesense --system --group", "write /etc/systemd/system/edgesense.service", "crontab @reboot /home/pi/edgesense/startup.sh" ] }3. 原型代码(Clean Code 节选)
# edgesense/sensors/bme680_worker.py import smbus2 import bme680 from datetime import datetime from typing import Tuple class Bme680Worker: """Read BME680 via I2C, return (temp, hum, pres, gas).""" I2C_ADDR = 0x77 def __init__(self, bus: int = 1): self.bus = smbus2.SMBus(bus) self.sensor = bme680.BME680(self.I2C_ADDR) self.sensor.set_humidity_oversample(bme680.OS_2X) self.sensor.set_pressure_oversample(bme680.OS_4X) self.sensor.set_temperature_oversample(bme680.OS_8X) self.sensor.set_filter(bme680.FILTER_SIZE_3) self.sensor.set_gas_status(bme680.ENABLE_GAS_MEAS) def read(self) -> Tuple[float, float, float, float]: if self.sensor.get_sensor_data(): return ( self.sensor.data.temperature, self.sensor.data.humidity, self.sensor.data.pressure, self.sensor.data.gas_resistance, ) raise RuntimeError("BME680 data not ready")#!/bin/bash # scripts/verify_gpio_load.sh # 确保 5 V 总电流 < 2 A total_ma=0 for pin in $(gpio readall | awk '/5v/ {print $2}'); do load=$(gpio -g read $pin) total_ma=$(( total_ma + load * 16 )) done [[ $total_ma -gt 2000 ]] && echo "ERROR: overload ${total_ma}mA" && exit 1 echo "GPIO load OK: ${total_ma}mA"4. 目录结构(生成即克隆)
EdgeSense-Pi/ ├── edgesense/ │ ├── __init__.py │ ├── sensors/ │ ├── edge/ │ ├── web/ │ └── alert/ ├── scripts/ ├── tests/ ├── systemd/ └── README.md // 含 wiring 图、BOM 成本表冷启动、一致性、安全性:三座隐形大山
冷启动延迟
第一次调用 4 轮对话约 18 s,把 system prompt 缓存到 Redis 后可压到 4 s。毕设场景可接受离线批量生成,无需在线实时。结果一致性
同一 prompt 跑 5 次,novelty 分数标准差 1.2。解决方法是把“评分细则”量化成 0/1 检查表,让模型先输出 JSON,再跑后处理脚本二次校验,不一致率降到 3 %。安全性
曾出现“让 GPIO4 直接驱动 5 V 继电器”的作死提案。修复:在负面清单加“禁止直接驱动 >3 V3 设备”,并在后处理引入“gpio-safety”正则,匹配到直接打回重生成。
生产环境避坑指南
过滤不切实际创意
用“硬件沙盒”容器提前跑pytest --hardware:检测 RAM 峰值、GPIO 电流、温升。失败即标记invalid,不进入候选池。验证硬件兼容性
维护一张“Pi 外围设备白名单”CSV(含芯片地址、驱动库、已知冲突),AI 输出后必须命中白名单 ≥90 % 组件,否则降权。避免过度依赖
规定“AI 只能做到原型 0.7”,剩余 0.3 必须手写:中断处理、异常重试、OTA 升级。答辩时老师问“这段 retry 逻辑为什么选 3 次”——答得出来才算自己掌握。
动手吧,别让 AI 替你毕业
把上面的 system prompt、负面清单、后处理脚本打包成一条make generate命令,你就拥有了自己的“树莓派选题助手”。但请记住:AI 可以帮你跳过泥潭,却不能替你理解每一步为什么这样走。
下次当模型再给你一份“完美”代码时,先关掉屏幕,拿万用表量一下 GPIO 电压——那一刻,你会真正明白人机协作的边界在哪里。