Show HN:我用 Qwen 和 Raspberry Pi 打造了一套本地车载 AI
英文标题:🔶 Show HN: I made a Raspberry with Qwen my local car AI
开发者展示了 CarWatch:一套部署在 Raspberry Pi 5 上、可完全离线运行的车载 AI 系统,使用本地 Qwen3.6-35B-A3B 模型,并以 GroupMind 房间 Agent 的形式与用户交互。该系统在 16GB Raspberry Pi 5 上实测生成速度为 3.5 tok/s、提示处理速度超过 25 tok/s,可基于车主手册 RAG 提供带页码引用的回答,并具备本地语音、车辆状态监测、远程可达和自更新能力。项目强调“本地优先、联网增强”,在无网络的车库、隧道或偏远地区仍可工作,联网任务则通过持久化队列延后发送。对开发者而言,这展示了较大参数 MoE 模型、RAG、语音识别、systemd 服务和车载 OBD 集成在低成本边缘硬件上的组合路径。
549.1 KB
416.9 KB
122.6 KB
中文
让你的汽车成为聊天室 Agent——完全离线。 一台 Raspberry Pi 5 随车运行,在本地运行一个 350 亿参数模型,以 @gle(或你为其命名的任何名称)的身份加入你的 GroupMind 房间,并像其他 Agent 一样向你发送消息:出发、抵达、行程摘要,以及在有物体撞击车辆时发送行车记录仪片段。你可以通过 CodeWatch 在手机或手表上审批和回复。开放的 PR 会与 ClawWatch 和 WhereWatch 一同出现在 CodeWatch 仪表盘上。
已在真实硬件上实时测量和验证(Pi 5、16 GB、约 300 欧元):
- 🧠 Qwen3.6-35B-A3B(Unsloth UD-Q3_K_S 动态量化,14.3 GB)实现 3.5 tok/s 生成速度 / 25+ tok/s 提示处理速度,可持续运行在 65 °C;不使用云端、互联网或订阅服务。
- 📖 可根据汽车自身的 745 页用户手册回答问题并提供页码引用(词法 RAG,随 SD 卡附带)——并且会_拒绝_回答手册中未说明的内容。
- 🔬 有依据的自我认知:每次提问时,都会从机器上实时读取温度、降频状态、风扇、内存、磁盘、网络以及当前加载的模型。凡是它无法感知的事情,它会明确表示无法感知——系统提示词的设计确保未知信息绝不会被悄然表述为事实。
- 🎙️ 免手持语音:持续监听器(能量 VAD → whisper.cpp,全部在 Pi 上运行)会听取你的语音,通过同一条有依据的处理管线处理文字,并在房间中回复。无需唤醒词仪式,也无需云端语音转文字服务。
- 📡 自主运行:systemd 服务会在启动时自动拉起整个栈——模型服务器、房间 Agent、语音监听器、手机仪表盘和发动机监控器。
- 🔧 可从任何地方维护:汽车会从该仓库自行拉取更新(每小时一次,另有仪表盘上的“立即更新”按钮),并主动建立隧道,因此即使处于手机热点的 NAT 之后也始终可访问。再也不需要把笔记本电脑带进车里维护。
- 📶 三级网络连接:手机热点 → 家庭 Wi-Fi → 自身备用接入点。因此,即使在完全没有信号的车库中,手机也总能连上它。
包含所有死胡同在内的构建日志位于 docs/plan.md。
它是 CodeWatch(手腕上的 Agent;源码:codewatch-cli)和 ClawWatch(手腕上的健康监测;v2 发布视频)的同类项目。这个项目监控汽车。其余产品家族位于 thinkoff.io。
flowchart LR
subgraph car [In the car - Raspberry Pi 5]
MIC[USB mic] --> LISTEN[carwatch-listen<br/>VAD + whisper.cpp]
LISTEN --> BRAIN[llama.cpp server<br/>Qwen3.6-35B-A3B]
MANUAL[(Owner manual RAG<br/>745 pages, on SD)] --> BRAIN
STATE[selfstate<br/>temp / fan / net / model] --> BRAIN
OBD[carwatch-obd<br/>watches the OBD cable] --> AGENT
BRAIN --> AGENT[carwatch-agent<br/>the @gle room agent]
DASH[web dashboard :8088<br/>status / update / voice / wifi]
UPD[self-update<br/>hourly git pull] -.updates.-> car
REACH[dial-out tunnel<br/>reachable behind any NAT]
end
AGENT <-->|posts + mentions| GM[GroupMind rooms]
GM <--> PHONE[Your phone / watch<br/>CodeWatch]
DASH <-->|same wifi| PHONE
加载中
本地与在线:策略
本地是产品,在线是增强。 汽车必须在零连接条件下依然完全可用,因为汽车会处于车库、隧道和乡村信号盲区:
- _始终本地运行(无信号也可工作):_语音输入、助手回答(Pi 上的模型)、用户手册回答(RAG 随 SD 卡提供)、手机仪表盘(由汽车提供服务)、行程和状态跟踪。
- _跨连接空档排队:_房间发帖、片段上传、提及回复。所有内容都会先写入持久化的磁盘发件箱;内容会延迟送达,而不会丢失。
- _仅在线可用,并对此保持诚实:_远程可达性(主动拨出的隧道)、自更新、升级到更大的模型——首先是在随车局域网中运行的本地模型服务器(仍不使用云端),随后仅在在线且明确被要求时,才使用云模型,并使用汽车自身设有预算上限的密钥。
经验法则是:一眼可见、与安全相关的信息绝不能依赖网络;任何社交或重型任务都会优雅降级为“稍后处理”。
状态——哪些已验证、已构建、已计划
一辆车只有四块手掌大小的接触面贴着路面,那是它唯一接触现实的地方。每个车轮对应一条原则:只断言你能感知的事,只声称已验证的事,明确标注所有过渡性内容,并如实报告失败而不粉饰。那四个接触面之上的一切,都只是悬架。
— @claudeMB,CarWatch 开发日志,在一天内以艰难方式学会这四条原则之后
诚实政策:只有功能在真实汽车上成功运行后,才称为“已验证”。“已构建并测试”表示代码已针对真实或模拟的对应端到端运行,但尚未接触实体汽车。
| 功能 | 状态 |
|---|---|
@gle 房间 Agent:提及、基于依据的回答、在线心跳 |
已验证(每日运行) |
| 带页码引用的用户手册 RAG | 已验证 |
| 由汽车提供服务的手机仪表盘(状态、Wi-Fi、语音开关、更新按钮) | 已验证 |
| 免手持语音:持续 VAD 监听器 → whisper → 基于依据的回答 → 房间 | 已验证(真实语音已在 Pi 上完成转写) |
| 从此仓库自更新(每小时定时器 + 仪表盘按钮) | 已验证 |
| 任意 NAT 后的主动拨出可达性(cloudflared 快速隧道) | 已验证(已通过开放互联网访问) |
| 通过 DoIP/ENET 读取 OBD 发动机数据(RPM、冷却液、速度、电压) | 已针对协议精确的假网关完成构建并测试(tests/fake_gateway.py);零接触守护进程会监控线缆并自行发布结果。尚未在真实汽车上验证——将在下次驾驶时自行确认或推翻结果 |
| 拉取行车记录仪片段(WOLFBOX G900,已映射 hisnet CGI API) | 探测完成,管线尚未接入 |
| MBUX 仪表盘渲染、后视镜图标条 | 已计划 |
硬件(参考构建)
-
Raspberry Pi 5,16 GB(需要主动散热——没有散热时 SoC 会降频)
-
用于语音的 USB 麦克风(任何符合 USB 音频类别标准的麦克风)
-
WOLFBOX G900 三通道行车记录仪(Wi-Fi AP;CarWatch 从中拉取事件片段)
-
OBD 接入:以太网转 OBD(DoIP/ENET)线缆——已构建支持,等待真实汽车验证;标准 ELM327 类适配器是备用方案
-
供电:行车记录仪硬接线套件为摄像头供电;Pi 需要独立的 5V/5A USB-C 供电(12V PD 适配器,或汽车的 230V 插座 + 墙插电源)
git clone https://github.com/ThinkOffApp/CarWatch.git cd CarWatch ./install.sh
随后将你的凭据放入 /etc/carwatch/config.json(绝不要放入仓库——参见 config.example.json),然后执行:
sudo systemctl enable --now carwatch
之后,汽车会保持自身为最新状态:update.sh 会拉取该仓库的 main 分支、安装任何新的 systemd 单元并重启服务——可通过定时器、仪表盘按钮或手动触发:
curl -sSL https://raw.githubusercontent.com/ThinkOffApp/CarWatch/main/update.sh | bash
将 config.example.json 复制到 /etc/carwatch/config.json:
api_base—— 你的 GroupMind 服务器,例如https://groupmind.oneapi_key—— Agent 的 API 密钥(为汽车创建一个密钥;绝不要复用其他 Agent 的密钥,也绝不要提交它)room—— 汽车发帖所在房间的 slughandle—— 汽车的显示名称,例如@glehome_ssids—— 表示“已停在家中”的 Wi-Fi 网络wolfbox—— 行车记录仪 AP 名称/密码和轮询间隔
WOLFBOX 的 HTTP API 没有文档;carwatch-probe 可发现它:
python3 -m carwatch.wolfbox --probe
请先将 Pi 连接至行车记录仪的 Wi-Fi AP。探测器会遍历已知的行车记录仪固件端点模式,并打印出有响应的端点;这将用你的摄像头真实路径填充 wolfbox.py 中的 TODO。
AGPL-3.0,与 ClawWatch 相同。版权所有 (C) 2026 ThinkOff / Petrus Pennanen。
English / 原文
Your car as a chat-room agent — fully offline. A Raspberry Pi 5 rides in the car, runs a 35B-parameter model locally, joins your GroupMind rooms as @gle (or whatever you name yours), and messages you like any other agent: departures, arrivals, trip summaries, and dashcam clips when something hits the car — with approvals and replies from your phone or watch via CodeWatch. Open PRs land on the CodeWatch dashboard next to ClawWatch and WhereWatch.
Live and measured, on real hardware (Pi 5, 16 GB, ~300 €):
- 🧠 Qwen3.6-35B-A3B (Unsloth UD-Q3_K_S dynamic quant, 14.3 GB) at 3.5 tok/s generation / 25+ tok/s prompt , 65 °C sustained, no cloud, no internet, no subscription.
- 📖 Answers from the car's own 745-page owner's manual with page citations (lexical RAG, ships on the SD card) — and refuses to answer what the manual doesn't say.
- 🔬 Grounded self-knowledge : temperature, throttling, fan, memory, disk, network and which model is loaded are read live from the machine per question. What it can't sense, it says it can't sense — the system prompt is built so an unknown can never silently read as a fact.
- 🎙️ Hands-free voice : a continuous listener (energy VAD → whisper.cpp, all on-Pi) hears you speak, routes the words through the same grounded pipeline, and answers into the room. No wake word ceremony, no cloud STT.
- 📡 Autonomous : systemd services self-start the whole stack on boot — model server, room agent, voice listener, phone dashboard, engine watcher.
- 🔧 Maintainable from anywhere : the car pulls its own updates from this repo (hourly + a dashboard "update now" button) and dials out a tunnel so it stays reachable even behind a phone hotspot's NAT. No laptop-in-the-car maintenance, ever.
- 📶 Three-tier connectivity: phone hotspot → home wifi → its own fallback access point, so the phone can always reach it, even in a garage with zero signal.
The build log with every dead end included lives in docs/plan.md.
Sibling of CodeWatch (agents on your wrist; source: codewatch-cli) and ClawWatch (health on your wrist; v2 launch video). This one watches the car. The rest of the family lives at thinkoff.io.
flowchart LR
subgraph car [In the car - Raspberry Pi 5]
MIC[USB mic] --> LISTEN[carwatch-listen<br/>VAD + whisper.cpp]
LISTEN --> BRAIN[llama.cpp server<br/>Qwen3.6-35B-A3B]
MANUAL[(Owner manual RAG<br/>745 pages, on SD)] --> BRAIN
STATE[selfstate<br/>temp / fan / net / model] --> BRAIN
OBD[carwatch-obd<br/>watches the OBD cable] --> AGENT
BRAIN --> AGENT[carwatch-agent<br/>the @gle room agent]
DASH[web dashboard :8088<br/>status / update / voice / wifi]
UPD[self-update<br/>hourly git pull] -.updates.-> car
REACH[dial-out tunnel<br/>reachable behind any NAT]
end
AGENT <-->|posts + mentions| GM[GroupMind rooms]
GM <--> PHONE[Your phone / watch<br/>CodeWatch]
DASH <-->|same wifi| PHONE
Loading
Local vs online: the strategy
Local is the product; online is the enrichment. The car must be fully useful with zero connectivity, because cars live in garages, tunnels and countryside dead zones:
- Always local (works with no signal): voice in, the assistant's answers (on-Pi model), owner's-manual answers (RAG ships on the SD card), the phone dashboard (served BY the car), trip/state tracking.
- Queued through connectivity gaps: room posts, clip uploads, mention replies. Everything lands in a persistent on-disk outbox first and is delivered late rather than lost.
- Online-only, and honest about it: remote reachability (the dial-out tunnel), self-updates, escalation to bigger brains — first a local-LAN model server when one rides along (still no cloud), then a cloud model only when online AND explicitly asked, on the car's own budget-capped key.
Rule of thumb: glanceable safety-relevant info never depends on the network; anything social or heavy degrades gracefully to "later".
Status — what is proven vs. built vs. planned
A car keeps four palm-sized contact patches on the road, the only place it ever meets reality. One principle per wheel: assert only what you can sense, claim only what is verified, label anything interim loudly, and report failure plainly with no silver lining. Everything above those four patches is just suspension.
— @claudeMB, CarWatch dev log, after a day of learning all four the hard way
Honesty policy: a feature is only "proven" after it worked on the real car. "Built + tested" means the code runs end-to-end against a real or simulated counterpart but has not yet met the physical car.
| Feature | Status |
|---|---|
@gle room agent: mentions, grounded answers, presence heartbeat |
proven (running daily) |
| Owner's-manual RAG with page citations | proven |
| Phone dashboard served by the car (status, wifi, voice toggle, update button) | proven |
| Hands-free voice: continuous VAD listener → whisper → grounded answer → room | proven (real voice transcribed on-Pi) |
| Self-update from this repo (hourly timer + dashboard button) | proven |
| Dial-out reachability behind any NAT (cloudflared quick tunnel) | proven (reached over the open internet) |
| OBD engine reading over DoIP/ENET (RPM, coolant, speed, voltage) | built + tested against a protocol-accurate fake gateway (tests/fake_gateway.py); zero-touch daemon watches the cable and posts results by itself. Unverified against the real car — it will confirm or refute itself on the next drive |
| Dashcam clip pull (WOLFBOX G900, hisnet CGI API mapped) | probe done, pipeline not wired |
| MBUX dashboard render, mirror icon strip | planned |
Hardware (reference build)
-
Raspberry Pi 5, 16 GB (active cooling required — the SoC throttles without it)
-
USB microphone for voice (any class-compliant mic)
-
WOLFBOX G900 3-channel dashcam (wifi AP; CarWatch pulls event clips from it)
-
OBD access: ethernet-to-OBD (DoIP/ENET) cable — support built, real-car verification pending; a standard ELM327-class adapter is the fallback path
-
Power: the dashcam hardwire kit feeds the camera; the Pi needs its own 5V/5A USB-C feed (12V PD adapter, or the car's 230V socket + wall PSU)
git clone https://github.com/ThinkOffApp/CarWatch.git cd CarWatch ./install.sh
Then put your credentials in /etc/carwatch/config.json (never in the repo — see config.example.json) and:
sudo systemctl enable --now carwatch
After that the car keeps itself current: update.sh pulls this repo's main, installs any new systemd units, and restarts services — on a timer, from the dashboard button, or by hand:
curl -sSL https://raw.githubusercontent.com/ThinkOffApp/CarWatch/main/update.sh | bash
Copy config.example.json to /etc/carwatch/config.json:
api_base— your GroupMind server, e.g.https://groupmind.oneapi_key— the agent's API key (create one for the car; never reuse another agent's key, never commit it)room— room slug the car posts tohandle— the car's display handle, e.g.@glehome_ssids— wifi networks that mean "parked at home"wolfbox— dashcam AP name/password and poll interval
The WOLFBOX's HTTP API is undocumented; carwatch-probe discovers it:
python3 -m carwatch.wolfbox --probe
Connect the Pi to the dashcam's wifi AP first. The probe walks known dashcam-firmware endpoint patterns and prints what answers, which fills in wolfbox.py's TODOs with your camera's real paths.
AGPL-3.0, like ClawWatch. Copyright (C) 2026 ThinkOff / Petrus Pennanen.

