把 LLM 用在一个叫 Picodevil 的项目里,是最近让我最有成就感的一次尝试。Picodevil 是我基于树莓派 Pico 做的一个桌面环境监测小设备,名字就是 Pico 加 devil,目标不大,但五脏俱全:有温湿度传感器、有按键切换显示、有简单的 LED 状态反馈,最终还要通过 WiFi 把数据上报到本地服务。整个开发过程,从最开始的需求拆解、引脚接线确认,到 MicroPython 代码生成、串口日志排错,再到把项目文档整理成 LLM 可以检索的资料库,大部分环节我都交给了大语言模型。
做完之后的结论先说在前面:LLM 真的能帮你把一个软硬件结合的项目做出来,但前提是你得知道怎么跟它配合。它不是万能的,会一本正经地编造引脚号,也会给出逻辑完整但时序完全错误的代码。这篇文章不聊概念,直接按我的落地顺序拆一遍。如果你也在做电子 DIY,或者想把 LLM 更高效地塞进自己的开发流程,这篇会比较有用。
1. 先搞清楚:LLM 在这个项目里到底能替你做哪些事
动手之前,我把 LLM 能介入的环节分成了四类,后面所有操作都在这四类里走。不然很容易变成“让 LLM 写代码,复制进去报错,再扔回去改”的低效循环。
1.1 需求拆解:让一个模糊想法变成可执行清单
第一个能大量用到的能力,是需求拆解。很多项目卡住不是因为代码难写,而是需求说不清楚。我最初对 Picodevil 只有一个大致想法:用 Pico 做一个能读取温湿度、能通过按键切换显示状态、能把数据上报的小设备。这个描述其实非常模糊,直接写代码肯定会乱。
我把这句话原样丢给 LLM,让它输出一份任务清单,要求包含硬件清单、接线方式、代码模块划分、测试步骤和可能踩的坑。它给出的结果比我预想的具体得多。它提醒了几个我自己容易忽略的点:Pico 的 ADC 参考电压是 3.3V,传感器模块供电最好独立,多个 I2C 设备要检查地址冲突。这些信息不一定每条都对,但至少给了我一份检查方向。
这是 LLM 的第一个实际价值:它不节省思考,但能帮我把思考展开。你只需要提供一个非常粗糙的目标,它就能生成一份需要人工复核的框架。我一般会再补一句约束:“每个引脚说明都要标注信息来源,不确定的地方标记为待确认。”这能明显减少后续幻觉内容的影响。
1.2 代码生成:LLM 写代码的边界到底在哪
LLM 生成嵌入式代码的能力现在不算差。像 Pico 这种生态成熟、网上资料多的板子,MicroPython 和 C SDK 的示例都很多,模型完全可以参考这些资料生成能跑的代码。
但要注意边界。LLM 生成代码的问题在于它没见过你的真实硬件,不知道你的传感器实际型号是否兼容 3.3V 逻辑,不知道你手上那根杜邦线是不是接触不良,更不知道你的板子当前是什么固件版本。它能给出的是一个逻辑完整的代码框架,但引脚号、外设初始化顺序、上拉电阻配置这些细节,必须由你把关。
我的做法是:先让它生成最小可运行版本,跑通之后再逐步加功能。不要一上来就让它写一个几千行的完整项目,那样一旦出错,你根本分不清问题出在哪个模块。
1.3 解释和排错:LLM 最被低估的能力
排错是我在 Picodevil 上体验最好的环节。把串口输出的一段报错原样贴给 LLM,让它解释可能原因,再让它给出几种排查顺序,它通常能给出靠谱的方向。MicroPython 的缩进错误、模块导入失败、引脚复用冲突,这类问题它处理得比搜索引擎高效很多。
为什么效果好?因为报错文本本身就是非常明确的上下文,模型从大量真实项目里学到过这些错误的标准解法。反过来,如果只丢一句“我的设备不工作”,效果就会差很多。这给出一条通用经验:给 LLM 的上下文越具体,得到的答案越可执行。报错日志、代码片段、硬件接线、供电方式,这些信息给得越全,LLM 的回答就越接近一个真实工程师的判断。
2. 把环境分成三块:硬件、软件和 LLM 访问方式
很多人第一步就搞混了。用 LLM 开发一个硬件项目,环境不是一个“开发环境”,而是三个环境同时在工作:硬件环境、代码编译环境、LLM 访问环境。我建议先把这三块分开准备,每一块单独验证,最后再合到一起。否则出了问题,你根本不知道先查哪一边。
2.1 硬件侧:Pico 的烧录和串口日志是第一道门槛
硬件侧的准备主要是三件事:板子能上电、固件能烧录、串口能输出日志。
Pico 的烧录方式很成熟,按住 BOOTSEL 按钮再插入 USB,电脑上会挂载出一个 U 盘,把 UF2 格式的固件文件拖进去就行。这里要注意固件选择:MicroPython 固件有不同构建版本,下载时确认文件名和板子型号匹配。C SDK 方式则要配置交叉编译链,复杂度会高一些。
第一道门槛其实是串口日志。跑硬件项目,没有日志就像闭着眼开车。Pico 的 MicroPython 默认把 print 输出到 USB 串口,电脑上需要装好 USB 驱动,然后用串口工具连接。Windows 下经常出现识别不到串口的问题,多数是驱动没装,或者 USB 线只能充电不能传数据。这个坑我后面专门讲。
2.2 软件侧:让 LLM 帮你决定用 MicroPython 还是 C SDK
Pico 有两个主流开发路径:MicroPython 和 C SDK。选哪个会直接影响后面所有代码生成和排错方式。
我当时把这个问题直接抛给 LLM。它给出的选择标准很清楚:如果项目以快速验证为主,对性能不敏感,优先 MicroPython;如果要做低功耗、复杂时序、高性能外设驱动,优先 C SDK。它还提醒:MicroPython 在内存不足和实时性上有明显上限,C SDK 的学习成本和编译链路复杂度更高。
这个思路是对的。像 Picodevil 这种桌面小设备,用 MicroPython 足够。不过要注意,LLM 给出的建议是一般性规律,它不知道你的具体场景。如果你的项目涉及大量外设并发、精确的传感器时序或超低功耗,哪怕规模小,也建议直接走 C SDK,避免后期返工。
2.3 LLM 侧:云端 API、本地推理、Agent 框架怎么选
LLM 的访问方式有三种常见路径,我整理了一个对比表,方便你根据自己的情况选。
| 方式 | 适合场景 | 需要关注的指标 | 常见坑点 |
|---|---|---|---|
| 云端 API | 追求生成质量,上下文需求大 | 接口超时、并发限制、成本 | 上下文越长成本越高,返回格式可能不稳定 |
| 本地推理 | 数据敏感、离线开发、简单代码片段 | 显存或内存、推理速度、量化格式 | 配置不够时速度很慢,小模型容易写错复杂逻辑 |
| Agent 框架 | 需要多步操作、调用工具、自动化 | 工具调用准确率、任务编排、失败重试 | 框架本身有学习成本,过度自动化反而更慢 |
我的建议是:第一次跑通用云端 API 或本地推理都行,关键是别在访问方式上花太多时间。如果你只是让 LLM 写代码、解释报错,直接用聊天窗口就够了。等你需要“自动读取串口日志再自动改代码”这类流水线操作时,再上 Agent 框架。
这里特别说一下本地推理。很多人会纠结推理引擎选哪个,其实更值得关注的是模型量化和上下文长度这两个参数。同样的模型,量化位数不同,速度和生成质量差异很大;上下文窗口不够时,长代码文件会被截断,导致 LLM 只看到一半代码就给出判断。
3. 实操流程:从一句需求到 Picodevil 跑起来
环境准备好之后,我建议把整个开发流程拆成四步。每步都有明确的验收标准,不满足就停下来检查,不要往下走。这套流程不只是在 Picodevil 上适用,换到其他嵌入式小项目也一样。
3.1 第一步:让 LLM 输出需求说明书和任务清单
先把你的项目目标写清楚,哪怕只是一句话。比如我写的是“用树莓派 Pico 做一个读取温湿度、按键切换显示、通过 WiFi 上报数据的桌面设备”。然后把这句话丢给 LLM,要求它输出一份需求说明书,必须包含:
- 功能列表:哪些是必须功能,哪些是后续扩展
- 硬件接线表:每个外设用哪个引脚、供电方式
- 代码模块划分:每个模块负责什么
- 测试步骤:每步如何验证成功
- 风险清单:可能踩的坑和规避方式
这一步的验收标准不是“它写得对不对”,而是“它有没有把你自己没想清楚的问题暴露出来”。LLM 很擅长生成看起来完整的清单,但里面可能有臆造内容。如果你对硬件不熟,最好用它的清单去对照官方文档和其他教程,看看引脚号、模块名是否对得上。
3.2 第二步:生成接线表和引脚映射,先对照再动手
给 LLM 提供你手上外设的具体型号,让它生成引脚映射表。比如“DHT11 数据脚接 GPIO 2,VCC 接 3.3V,GND 接 GND”这类信息,LLM 一般能写出来,但你必须人工核对一次。
核对标准很简单:打开 Pico 的引脚图,依次确认每个引脚编号是否存在;再对照外设的数据手册,确认供电电压是 3.3V 还是 5V,确认模块是否支持板载上拉。最容易出问题的是 I2C 和 SPI 这类总线,LLM 可能把 SDA 和 SCL 的引脚号写反,或者忽略 I2C 设备地址冲突。
这一步不要省。我发现把接线确认放在最前面,后面的代码调试会顺畅很多。绝大多数“代码运行出错”,根源其实是硬件接线错误。
3.3 第三步:单文件代码生成,先跑最小闭环
不要一开始就生成完整项目。我的做法是先把最小闭环跑通:让 LLM 生成一个单文件 MicroPython 脚本,功能就是开机后在串口打印一句启动信息,然后循环读取传感器并打印数值。
这个最小闭环要验证三件事:固件能跑、串口能输出、传感器能返回数值。只要这三件事都正常,后面加功能就只是迭代问题。如果最小闭环跑不通,先别急着让 LLM 改代码,先检查固件、接线和串口,确认是环境问题还是代码问题。
等最小闭环通过,再逐模块加功能:加显示、加按键、加网络请求。每加一个模块就跑一次,把新报错贴给 LLM。这个过程有点像两个人结对编程:LLM 负责写思路和实现,你负责验证和把关。
3.4 第四步:把报错日志直接丢给 LLM,形成调试闭环
代码报错时,最有效的做法是把完整报错信息连同相关代码片段一起发给 LLM,然后问三个问题:
- 这个报错最可能的原因是什么
- 应该先检查哪个位置
- 给出一个最小修复方案
这里有个细节:尽量报告完整的“现象加输入加输出”。比如“我执行 sensor.read() 后返回空值,数据脚接在 GPIO 2,供电 3.3V,日志没有任何报错”。这种上下文比单纯贴报错更容易让 LLM 定位问题。
调试闭环的关键是让每一次修复都可验证。改完代码重新跑一次,确认输出发生变化,再决定是否继续。如果连续三次修改都没有改善,停手,回到硬件侧检查接线和供电,不要继续和代码死磕。
注意:最浪费时间的调试方式,是让 LLM 在一个错误假设上反复打补丁。连续多次没进展时,优先怀疑硬件和输入,而不是代码逻辑。
4. 从聊天窗口升级成可复用工具链
当你从“问一句答一句”变成要处理多个文件和多次迭代时,纯聊天窗口就不够用了。这时候可以考虑把 LLM 组织成工具链。但工具链不是必须的,要根据实际迭代频率决定。
4.1 为什么需要编排框架:对话式生成是单点,Agent 是流水线
聊天窗口本质是单点交互:你抛一个任务,它返回结果。对写代码、改代码这种单任务是够用的。但如果你想整个流程变成“读取代码文件、检查日志、提出修改、重新生成文件、自动测试”,单点对话就不够了。
这就要用到编排框架。LLM Agent 的核心思路是让模型在多个步骤之间决策:它可以选择读哪个文件、调用哪个工具、决定改哪个参数。好处是流程可以自动化,坏处是它可能选错工具、读错文件,或者在一个错误方向上反复尝试。“比人高效”和“比人可靠”是两回事。
我的经验是:先不要上完整 Agent。可以在项目里先加一个简单的脚本,封装几个固定动作:读取串口日志、把日志存成文件、把日志发给 LLM、把 LLM 回复的代码写回文件。这样一个半自动流程,比完整 Agent 好控制得多。
4.2 用 MCP 把工具接进 LLM:文件读取、串口日志、文档查询
MCP 是当前很常见的把工具接入 LLM 的方式。它定义了一套统一协议,让 LLM 能调用外部工具,比如读取本地文件、执行命令、查询文档。对 Picodevil 这种项目,MCP 能接的工具大概有这三类:
- 文件读写:让 LLM 直接读取当前代码文件,生成修改建议后写回
- 串口日志读取:把串口输出写入日志文件,再让 LLM 分析
- 文档查询:把芯片手册、外设 datasheet 变成可检索内容
接入 MCP 的好处是减少复制粘贴,让 LLM 基于真实数据做判断,而不是基于你手动转述的信息。但要注意权限问题:MCP 服务如果配置了命令执行权限,一定要限制可执行命令范围,只留项目需要的白名单命令,不要开放任意命令。
4.3 用 RAG 整理硬件手册和芯片资料
另一个值得做的是 RAG,也就是把资料库变成 LLM 可以检索的上下文。很多人听说过 RAG,但不知道对硬件项目有什么用。我把它用在两个地方。
第一,把 Pico 官方文档、MicroPython 文档、外设 datasheet 的关键章节整理成文本片段,存入向量库。这样问答时,LLM 可以从资料库中检索相关段落,而不是完全依赖自己的记忆,能明显减少引脚和寄存器信息的幻觉。
第二,把开发过程中自己和 LLM 的对话记录、修过的坑、验证通过的代码片段,沉淀成项目笔记。这个笔记本身也能变成检索源。时间久了,这个项目的知识库会越来越完整,后续调试速度会快很多。
RAG 实现不算复杂,核心是文本切分、向量化、检索和拼装上下文。但要注意切分粒度:硬件手册按章节切最好,按自然段切容易丢失上下文。切分过细会导致检索结果不完整,切分过粗会造成上下文超长。
4.4 什么时候需要自己写一个工作流脚本
最后说一个实际判断:不是所有场景都需要框架。如果你只是偶尔用一次 LLM,聊天窗口足够。如果你每天都要处理几十次代码修改和日志分析,那才值得搭 Agent、MCP、RAG 这一套。搭工具链本身也要花时间,而且会引入新问题,比如版本兼容、API 变化、上下文管理。
以我的经验,先用脚本打通最小闭环,比如一个 Python 脚本封装“日志到 LLM 到写回文件”,跑稳之后再考虑上完整框架。这个顺序能帮我把“工具问题”和“项目问题”分开,避免出现“代码报错但搞不清是程序问题还是工具链问题”的混乱。
5. 关键参数和判断标准:怎么知道 LLM 给你的东西能用
用 LLM 开发,最常被问的就是:怎么判断它给的东西能不能用?我总结了一套自己的判断标准。
5.1 代码能用的标准:不是“没报错”,而是“输出可验证”
很多人觉得 LLM 生成的代码只要编译不报错就能用。对嵌入式项目来说,这个标准完全不成立。编译器不报错只能说明语法没问题,不表示逻辑正确、引脚正确、时序正确。
我的判断标准分三层:
- 第一层:能否在真实硬件上运行,运行后串口有预期输出
- 第二层:连续多次运行是否稳定,不会随机卡死或偶尔失败
- 第三层:更换环境参数后是否仍然可控,比如换一批传感器或改供电方式
如果你只是学习,验证到第二层就够。如果要长期使用,就必须考虑第三层。很多项目在开发环境跑得很好,一到现场就出问题,往往就是第三层没做验证。
5.2 模型精度和本地推理要关注什么
用 LLM 做开发时,我对精度的关注点和其他应用不太一样。如果用的是云端 API,精度由服务端决定,一般不用管。如果用本地推理,就要注意量化格式对生成质量的影响。
常见做法是用低精度量化省显存,但量化位数过低会导致代码生成质量下降,尤其是复杂逻辑和长代码。我的建议是:代码生成任务优先用 FP16 或 BF16 这类精度起步,只有当显存或内存确实不够时再考虑更低精度量化。同时要关注上下文长度,优先确认模型的上下文窗口能覆盖整个代码文件,否则分析不完整,结论自然不准。
5.3 生成质量不稳定时,先查上下文和输入格式
如果你发现 LLM 的回答时好时坏,先别怀疑模型不行,先检查三样东西:
- 上下文是否完整:代码文件有没有截断,报错日志是否完整
- 输入格式是否清晰:有没有明确区分“事实信息”和“任务要求”两部分
- 约束是否明确:有没有告诉 LLM 哪些引脚是确定的,哪些需要它推理
我经常看到的问题是:用户把一段乱七八糟的日志和代码混在一起发给 LLM,模型分不清哪里是报错、哪里是代码、哪里是描述。这种情况下生成质量差不是模型问题,是输入问题。
5.4 速度、质量、成本之间的取舍
最后落到工程层面。用 LLM 开发项目,速度和质量往往不能两头都占。我的建议是:日常调试用快而便宜的小模型,生成复杂完整模块时再换更强的大模型。这个策略在本地推理和云端 API 都适用。
实际操作时,我会准备两套配置:一个快速模式,用于解释报错、简单问答;一个高质量模式,用于代码生成、架构设计。快速模式用较小模型和较高采样温度,高质量模式用较强模型并降低随机性。用不同配置处理不同任务,整体效率会明显提升,也不会在简单问题上浪费太多成本。
6. 踩过的坑和调整过的地方
最后写一写我实际踩过的坑。这些坑不一定每个你都会遇到,但遇到时可以帮你少走弯路。
6.1 LLM 编造引脚和寄存器,这是最需要注意的问题
第一个坑是幻觉。LLM 在生成硬件相关代码时,会一本正经地输出不存在的引脚、错误的寄存器地址、不存在的库函数。尤其是在资料比较少的传感器或芯片型号上,幻觉率明显更高。
我的应对方式有三条:
- 凡涉及引脚、寄存器、库函数,都让 LLM 标注来源并给出理由
- 把官方文档关键信息通过 RAG 放进上下文,减少对模型记忆的依赖
- 每次拿到代码,先用最小测试脚本验证硬件相关部分,再叠加业务逻辑
如果你发现 LLM 连续几次给出同一个不存在的引脚,马上停手。不要在错误假设上继续加代码,否则后面排错会非常痛苦。
6.2 别让 LLM 一口气生成整个项目
第二个坑是贪大。让 LLM 一次生成整个项目的所有模块,看起来省事,实际是给自己埋雷。模块之间的接口约定、变量命名、时序配合,LLM 一次生成时可能不一致。一个模块的 bug 会传染给另一个模块,最后你根本不知道问题出在哪。
我的做法前面已经说过:先最小闭环,再逐模块加。每个模块单独验证通过后再合并。合并时特别关注全局变量、共享状态和初始化顺序,这三个地方最容易在合并阶段出问题。
6.3 串口、权限、路径问题比代码逻辑更容易卡住
第三个坑容易被忽略。开发过程中真正卡住我的,往往不是代码逻辑,而是环境问题:Windows 下串口驱动没装、USB 线不支持数据传输、文件写入权限不足、项目路径含中文导致编译工具异常、MCP 服务读取日志时权限不够。
这些问题的特点是报错信息五花八门,容易误导方向。我的排查顺序固定为:
- 先看串口能不能识别、日志能不能输出
- 再看文件路径和权限
- 再查依赖版本和编译环境
- 最后才怀疑代码逻辑
先确认环境能不能支持,再判断代码写得对不对。这个顺序能避免很多无效调试。
6.4 落地前留一份检查清单
把这次的经验总结成一份检查清单,方便后面复用:
- 需求是否拆成了可验证的小任务
- 引脚和接线是否人工核对过
- 是否先跑通了最小闭环
- 串口日志是否全程可用
- 每个模块是否单独验证过
- 验证通过的代码和踩过的坑是否沉淀成笔记
- 是否确认上下文长度能覆盖完整代码文件
- 是否预留了失败重试和日志清理机制
这份清单不复杂,但每一条都是实际踩过坑之后的总结。对硬件项目的 LLM 辅助开发来说,最重要的不是模型有多强,而是你自己有没有一套稳定的验证流程。
做完 Picodevil 之后,我的整体感受是:LLM 确实把“从想法到原型”的门槛降低了一大截,但它没有替你省掉工程判断。它能帮你快速生成代码、解释报错、整理文档,但接线对不对、供电够不够、引脚冲突不冲突,最终还得你自己去确认。如果你也想做类似的项目,我建议先把单任务流程跑稳,再考虑上 Agent、RAG 这些工具链。先让 LLM 从一个代码生成器变成你的结对编程伙伴,再让它变成一条自动化流水线。这个顺序,比一开始就搭一套复杂框架可靠得多。