RISC-V Linux 嵌入式实践课 · 综合项目

端侧 Agent 环境终端

荔枝派继续管风扇与 MQTT;K3 上跑量化后的本地模型;你在终端里像用 Claude Code 一样跟 DeepSeek Harness 打字。同一套工具,本地和云端只换一个地址。

手:荔枝派 4A · C · RuyiSDK 脑:K3 · llama.cpp 嘴:终端里的 DeepSeek Harness
故事

这条线是什么

前六章已经把「手」做完:交叉编译、滞回、继电器风扇、DHT22、MQTT、三线程。综合项目不再另开第七章,也不再做 weights.h 手写 tiny 前向。现场还是这套温控,换的是谁做决定、人怎么下意图

人在终端里打字。DeepSeek Harness 跑 Agent 循环:当前模型根据你的话和工具列表,决定调用读状态、开/关风扇、控灯、改阈值。工具经 MQTT 打到荔枝派。板上三线程自己的滞回一直在转——没人打字,风扇仍按温度动作。

你(终端打字) │ ▼ DeepSeek Harness(Agent 循环 · 工具注册) │ 模型插件:本地 llama-server 或 云端 DeepSeek │ 同一 OpenAI 兼容 HTTP,只换 baseURL ▼ 工具 execute → MQTT │ ▼ 荔枝派 ch06 三线程:采集 ∥ 滞回控风扇 ∥ MQTT
和旧综合项目的差别:旧方案是老师发权重、学生在板上手写 tiny 前向。现方案是学生自己量化出可加载的本地模型,用 Harness 当唯一的 Agent 循环,前六章的 C 程序当手。
两件事

Harness 是运行时,DeepSeek 是一种模型

DeepSeek Harnessdsh)是 Agent 运行时:会话、工具、循环、界面都是插件。它默认可以挂云端 DeepSeek,也可以挂任何 OpenAI 兼容接口。源码不用改。

DeepSeek 模型只是脑子的一种。本地量化模型是另一种脑子。对 Harness 来说,两者都是「模型供应商」:协议相同,baseURL 不同。

云端

https://api.deepseek.com。能力强,要密钥和网络。

本地

K3 上 llama-server 提供 http://<K3>:8080/v1。量化后的指令模型,离线也能验收。

切换发生在 Harness 的模型配置里。对话框、工具列表、板上程序都不改。

硬件

荔枝派当手,K3 当脑

K3 适合跑 llama.cpp(厂商 IME2 加速),针脚不像荔枝派那样接 DHT 和继电器。所以综合项目用两块板,用已经教过的 MQTT 当总线。

机器跑什么本课工具
荔枝派 4Ach06 三线程:采温、滞回、风扇、灯、MQTTC + RuyiSDK 交叉编译
进迭 K3llama-server + 终端里的 DeepSeek HarnessBianbu 上的 llama.cpp-tools-spacemit
个人电脑量化(llama-quantize)、改工具插件、SSHRuyiSDK / 本机 gcc
如意 SDK 编的是荔枝派上的 C 程序。K3 上的加速推理走进迭提供的 llama.cpp,目前不要写成 ruyi install 就能吃到 IME2。普通 gcc 自编的 llama.cpp 跑在 A100 核上会非常慢。
界面

在终端里对话,像 Claude Code

本课不把网页当成对话入口。你在终端里启动 DeepSeek Harness,像 Claude Code 那样打字、看工具调用、看回复。官方 dsh web 会起浏览器,主路径不用它。

交互式终端界面是 Harness 的一层 UI 插件。装好 dsh 之后,用终端 profile 进入当前目录的会话:

# 安装 CLI(Node 22+)
npm i -g @deepseek-ai/dsh@next

# 终端 UI(Claude Code 同款打字界面)
dsh plugin --profile tui add @dsh-tui/dsh-tui
dsh --profile tui

模型配置里加两个供应商:一个 baseURL 指向本机或 K3 的 llama-serverapi: openai-completions),一个指向云端 DeepSeek。之后在会话里切换模型,工具不变。

官方还带 dsh --profile headless "一句话任务",跑完一轮就退出,适合脚本。本课验收用交互式终端会话:你打字,模型调工具,板上有现象。
量化

本地模型从量化来

具体叫哪一个指令模型不钉死。课要的是:在电脑上用 llama.cpp 把一份较高精度权重压成 GGUF(至少做到 Q4),拷到 K3,用带 IME2 的 llama.cpp 起服务。

# 主机:量化(示例文件名按你下载的模型改)
llama-quantize model-f16.gguf model-q4_0.gguf Q4_0

# K3:加速推理 + OpenAI 兼容 HTTP
sudo apt install llama.cpp-tools-spacemit
llama-server -m ~/.cache/models/llm/model-q4_0.gguf -t 4 --port 8080

量化前后记下体积,并在终端 Harness 里用同一句「现在热不热」各问一次:工具调用还在,才算压成功。极致压缩可以再出一份 Q2,对照质量与速度;主验收以能稳定调工具的那一档为准。

K3 带 IME2 时,中小指令模型(大约 1.5B–4B、Q4)做「读状态、选工具、回一句人话」是够用的。把很大的稠密模型压进内存,常见结果是能启动、生成慢、工具调用不稳,本课不走那条路。

工具

Harness 调的是前六章已经有的手

工具在 Harness 里登记(TypeScript 的 defineTool)。execute 里不要重写 GPIO。它只做转发:发 MQTT,或调用你用 C 编好的小命令。荔枝派上的 tri-thread 继续采温、滞回、驱动继电器。

工具模型看见的含义落到板上
read_status读当前温度、湿度、风扇、阈值订阅读状态主题,或向板问一句 status
set_fan开或关风扇发布命令主题,通信线程执行
set_led开或关灯沿用第五章的灯主题
set_threshold改温度上下限与第四章 set temp 同一类下行

人打的是自然语言:「太吵了把风扇关了」「现在多少度」。模型选工具、填参数。传感器数字由 read_status 提供,模型自己不去读针脚。

闭环

没人打字时,风扇仍按温度转

荔枝派上的控制线程一直按阈值拉继电器。Harness 是指挥官,不是唯一的心跳。这样前六章的验收在综合项目里仍然成立:把终端关掉,风扇还在跟温度走。

打字用来查状态、改阈值、强制开/关、换一句人话意图。Agent 的决定落到同一套 MQTT 和 GPIO 上。

验收

现场要能看见什么

通过条件
滞回仍在不打开 Harness 时,超上限风扇转、低下限停
量化有一份学生自己压出的 GGUF;记下体积;K3 上 llama-server 能起来
终端对话在终端 Harness 里打字,能看到模型调用本课工具
读得动read_status 返回的温度与板上日志一致
动得了打字让风扇或灯动作,板上现象可见
换模型同一句话,本地 llama-server 与云端 DeepSeek 各走一遍,工具仍是同一套
干净停板上 Ctrl+C 仍先停风扇再退出(ch06 契约保留)
里程碑

按这个顺序做完

  1. P.1 双机通。荔枝派 tri-thread 在跑;电脑上 Mosquitto 可达;K3 能 SSH 上去。
  2. P.2 量化。主机 llama-quantize 得到 Q4 GGUF,记下体积。
  3. P.3 本地服务。K3 安装 llama.cpp-tools-spacemitllama-server 监听 8080。
  4. P.4 终端 Harness。dsh --profile tui 进会话;登记本地与云端两个模型供应商。
  5. P.5 工具。登记 read_status / set_fan / set_led / set_threshold,全部转发到已有 MQTT。
  6. P.6 对照。关掉终端,确认滞回自己转;再打开终端打字改行为。
  7. P.7 答辩演示。按上面验收表走一遍,本地和云端各问一句。
规划条目也写在 Course Outline。本文是综合项目的正文。