news 2026/8/13 0:32:38

高通跃龙IQ-9075平台的开发记录(1): 边缘农业AI助手的端到端部署

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
高通跃龙IQ-9075平台的开发记录(1): 边缘农业AI助手的端到端部署

设备: 高通跃龙IQ-9075 EVK(SA8775P,Hexagon v73,16 GB)
系统: Ubuntu 24.04.4 LTS,内核 6.8.0-1071-qcom,QNN 2.43,Genie 1.14.0
模型: Qwen2.5-7B-Instruct,w8a16,6-split,约 4.7 GB
代码: ThunderSoft-XA/Edge-AI-agriculture-assistant

这是一次把「端侧 7B 咨询 + 温湿度传感器 + Web 告警」串起来的 demo。板子上离线推理,浏览器里能看实时读数、能对话,超温超湿时会主动推建议。下面按做过的顺序写:模型怎么编、板怎么备、传感器怎么接、应用怎么上、知识库怎么选。步骤写清,代码不全贴。

前言:硬件平台与目标

本项目使用的是高通跃龙IQ-9075开发板,

做成什么样

设备上常驻两个进程:

服务端口作用
genie-server8081C++ HTTP 包一层 Genie,dlopen libGenie.so,模型常驻 HTP
FastAPI + Uvicorn8080Modbus 轮询、拼接ChatML、FTS5 检索、SSE 聊天与告警推送

数据流大致是:

浏览器 ──HTTP/SSE──▶ FastAPI (:8080) ├─▶ genie-server (:8081) ──▶ Hexagon HTP / Qwen2.5-7B ├─▶ pymodbus TCP ──▶ 仁科温湿度 (192.168.2.100:502) └─▶ SQLite(读数 / 告警 / 对话 / FTS5 知识库)
  • 为什么拆成两进程:Genie 要长时间占住 HTP 与数 GB 权重;业务侧要做轮询、检索、Web。HTTP 隔开后,模型加载只发生在推理进程启动时,聊天请求不必每次冷启动。

  • 网络拆成两路:WiFi(ubuntu.local)管 SSH 和 Web;以太网口直连传感器(板子192.168.2.1/24,传感器192.168.2.100)。管理面和传感面不共用同一二层网段,避免传感器静态地址和办公 DHCP 抢地址。

仓库:Edge-AI-agriculture-assistant。
应用说明在app/README.md,推理服务在app/inference-service/
模型准备走高通官方 LLM on Genie 教程,本文按实际编译过程记录关键步骤和参数。

板端实测量级(Genie 1.14.0 + QNN 2.43):常驻加载约 2.2 s,TTFT 约 176 ms,约 8.3 tok/s,单次回复常见 7–37 s。

一、模型准备

目标产物:6 个 context binary +genie_config.json+tokenizer.json,合计约 4.7 GB,放到板上/opt/qc-ai/models/qwen2.5-7b-local-6split/

流水线与高通 LLM on Genie 一致:预量化 ONNX → 拆分 → DLC → HTP context binary → Genie 加载。

拆成 6 份,是因为整模一次编进 HTP 上下文太大,拆分后每段图单独编译、运行时再串起来;prompt 图与 token 图还可共享权重,省一份拷贝。

1.1 主机环境

用途环境
云编译Python 3.11 venv,qai_hub_models,AI Hub API token
本地编译Python 3.10 venv,QAIRT SDK 2.42+,内存建议 40 GB+

QAIRT 自带的.pyd扩展是按 Python 3.10 ABI 编的,3.11 装不上,所以本地编译必须另开 3.10 环境。云编译走 AI Hub 的 Python 包,用 3.11 即可。

克隆并检出测过的ai-hub-models版本;云路径安装带qwen2_5_7b_instruct的 extra;本地再装 onnx / transformers 等。

云编译前:

python-m qai_hub configure--api_token <YOUR_TOKEN>

本地编译:

$env:QNN_SDK_ROOT ="C:\Qualcomm\AIStack\QAIRT\2.42.0.251225"

1.2 下载预量化包

高通提供约 14.9 GB 的预量化 ONNX zip,里面已有 AIMET encodings。放到qai-hub-models约定的 cache 目录后,导出脚本会自己读。可用curl -C -断点续传。

预量化在主机侧完成权重量化与校准信息;后面编译主要是把这些张量与图结构变成 HTP 能执行的 context binary,而不是从浮点大模型重新训。

1.3 云编译与本地编译

日常复现优先走云编译:把拆分、上云、回拉交给export,参数与官方设备表对齐,减少因为 SDK 或环境差异造成的坑。

python-m qai_hub_models.models.qwen2_5_7b_instruct.export `--device"Dragonwing IQ-9075 EVK"`--output-dir"<workspace>\output"`--synchronous

--device会选中目标 SoC 的编译配置,例如 Hexagon 代数、VTCM、soc 相关选项;编错设备,二进制可能能加载但行为不对。中断后重跑同一条命令即可,已完成的 job 会复用缓存。

本地编译在需要离线、或要改编译开关时用。仓库脚本对应云路径里的三步,只是落在本机 QAIRT 上:

  1. prepare_onnx_6split.py— 拆成 6 份 ONNX + encodings
  2. convert_6split_to_dlc.py --convert-only— ONNX 转 DLC,DLC 是 QNN 的中间图格式
  3. compile_6split_from_dlc.pyqnn-context-binary-generator出 HTP context binary

本地须与云端对齐的关键开关:

参数取值说明
soc_model77SA8775P。写成 0 时离线编译走通用路径,板上常出现乱码
dsp_archv73与板子 Hexagon 代数一致
weights_packingTrue把低比特权重打进 binary 内部布局,体积约减半;须走 Python API,CLI 会忽略该键
weight_sharing_enabledTrueprompt / token 两套图共用一份权重
vtcm_size_in_mb8片上 VTCM 配额,和云编译一致
图名称prompt_ar128_cl4096_N_of_MGenie 从图名解析自回归长度ar与上下文长度cl

soc_model决定编译器按哪颗 SoC 的算子与内存模型出码;图名称则不是给人看的标签,运行时要靠它配置 KV 与序列行为,编错只能重编,二进制事后改名会撞完整性校验。

云、本地在开关对齐时,产物体积应接近:

文件约大小
part_1_of_6.bin,embedding1.0–1.1 GB
part_2part_5,decoder各约 677 MB
part_6.bin,LM head约 975 MB
合计约 4.7 GB

genie_config.json常见项:context.size=4096n-vocab=152064,samplertemp=0.6 / top-k=30 / top-p=0.85backend.type=QnnHtp

1.4 模型侧踩过的坑

FastRPC 单缓冲大约 1 GB 的 SMMU 上限。
AP 经 FastRPC 把权重缓冲映射进 DSP 的 SMMU 时,单块连续缓冲大约有 1 GB 的硬限制。嵌入层单独约 1040 MB,刚好超过这个限制,加载时报错fastrpc memory map ... failed,板子物理内存非常充足,小缓冲也能映射成功,就是这一块过不去。早期的做法是把 embedding 改到 CPU 侧用查找表(LUT)处理,这样这块权重就不必整块映射到 DSP。后来打开weights_packing,当前这套 6-split 包在 IQ-9075 上不必再使用 LUT。

图名称写错会乱码。
本地曾编成qwen2_5_7b_instruct_prompt_2_of_8这类名字,模型能加载,输出却是乱码。Genie 会从图名里解析ar(自回归长度)和cl(上下文长度),正确形态类似prompt_ar128_cl4096_2_of_8。二进制事后改名会撞完整性校验,只能按正确格式重编。

soc_model一定要写正确。
如果本地编译模型,x86 主机推断不出板端特性。IQ-9075 / IQ-9100 这一路要显式正确配置soc_model=77,否则输出不对,很难debug。

QAIRT 2.35 的--float_bitwidth 16
该选项曾错误改写 RmsNorm 里本该保持量化的张量类型,HTP 校验报失败。当时改用--float_bitwidth 32绕过。另外,设备上的 DSP 固件要和编译用的 SDK 版本匹配,不能只升主机这边的编译器。

本地编译体积曾是云端的两倍。
早期本地不用weights_packing时,合计大约 9 GB,云端同配置大约 4.7 GB。差异在 context binary 生成阶段。打开 packing 并用 Python API 编译后,两边体积才对齐。

硬件上也从 Thundercomm Ride / 旧 QCS9100 栈迁到过 Addons IQ-9075 EVK。换板本身不用重写应用,但网络、PPA 里的 QNN 版本、FastRPC 的重试行为要对一下。新板上偶发非致命的failed to map buffer,运行时会换 context bank 再试,不影响输出。

二、板端环境与模型上板

2.1 刷机与基础系统

板子需已刷镜像并完成 Ubuntu 初始化(高通文档:刷机与 Use Ubuntu on IQ9)。SSH:ubuntu@ubuntu.local。同网段 WiFi;Windows 侧要能解析.local,否则直接用 IP。

2.2 安装 QNN / FastRPC

sshubuntu@ubuntu.localsudoaptupdatesudoaptinstall-yqcom-fastrpc1 libqnn1 qnn-toolsls/dev/fastrpc-cdsp

libqnn1提供 HTP 后端;FastRPC 设备节点是用户态把缓冲交给 CDSP 的入口。没有/dev/fastrpc-cdsp,后面 Genie 无法把图卸到 DSP。

本 demo 实测:libqnn12.43.0;ADSP 库路径/usr/lib/rfsa/adspADSP_LIBRARY_PATH要指到 skel 等 DSP 侧库,否则 stub 找不到对端。

2.3 安装 Genie

Genie 不在 Ubuntu PPA 里,从主机 QAIRT 的 aarch64 产物拷:

scp"..\QAIRT\..\aarch64-oe-linux-gcc11.2\genie-t2t-run"ubuntu@ubuntu.local:/tmp/ scp"..\QAIRT\..\aarch64-oe-linux-gcc11.2\libGenie.so"ubuntu@ubuntu.local:/tmp/

板上:

sudocp/tmp/genie-t2t-run /usr/local/bin/sudocp/tmp/libGenie.so /usr/local/lib/sudoldconfig

Genie 负责按genie_config.json加载多份 context binary、管理 KV、做采样;底层仍调 QNN HTP。genie-t2t-run是命令行入口,libGenie.so是同一套运行时。

2.4 推送模型包

ssh ubuntu@ubuntu.local"mkdir -p /opt/qc-ai/models/qwen2.5-7b-local-6split"scp <bundle>\*ubuntu@ubuntu.local:/opt/qc-ai/models/qwen2.5-7b-local-6split/

目录内需同时有.bingenie_config.jsontokenizer.json;配置里的相对路径按该目录解析。

2.5 先用 CLI 验证推理

cd/opt/qc-ai/models/qwen2.5-7b-local-6splitexportADSP_LIBRARY_PATH=/usr/lib/rfsa/adsp genie-t2t-run-cgenie_config.json-p'<|im_start|>system You are a helpful assistant. Do not repeat yourself.<|im_end|> <|im_start|>user What is 2+3?<|im_end|> <|im_start|>assistant '

期望看到正常英文或数字答案,而不是乱码。Prompt 必须是 ChatML:模型按该模板微调,缺 system/user/assistant 标记时行为不稳定。system 里固定带Do not repeat yourself:Genie 侧没有好用的 repeat_penalty 时,开放题容易循环复读。

每调一次genie-t2t-run都要重新加载模型,大约十几秒。后面改成常驻genie-server,就是为了把这几十秒从每次请求里拿掉。

三、推理服务 genie-server

FastAPI 不直接起子进程跑genie-t2t-run,而是通过 HTTP 调本机genie-server。模型在进程内只加载一次;请求只做 prompt → token 流。

3.1 编译

main.cppdlopen/dlsym解析 Genie,编译期不链接高通头文件与.so,交叉工具链不必安装 QAIRT。在 WSL 或 Linux 上:

cdapp/inference-service ./build.sh--cross# 产物:build/genie-server,aarch64scpbuild/genie-server ubuntu@ubuntu.local:/tmp/sshubuntu@ubuntu.local"sudo cp /tmp/genie-server /usr/local/bin/"

也可在板子上原生./build.sh,需 cmake / g++。

3.2 接口与常驻

genie-server-c/opt/qc-ai/models/qwen2.5-7b-local-6split/genie_config.json# 默认 127.0.0.1:8081
方法路径说明
GET/health存活
POST/generatebody 带完整 ChatMLprompt,SSE 回{"token":"..."},结束[DONE]
POST/reset清 KV cache

HTP 上同一时刻只跑一路生成更稳,所以忙时回 429,由业务侧排队或重试。systemd 单元见app/inference-service/genie-server.serviceqc-ai-app.service通过Requires=依赖它,避免应用起来时推理口还没听。

四、传感器选型与接线

4.1 选型

工业上比较常用的是Modbus TCP协议的传感器,这里我们选用了仁科RS-WS-ETH-6J-ModbusTCP:温湿度一体,Modbus TCP,传感器作 TCP Server,端口 502;供电 DC 7–30 V;精度大约温度 ±0.5°C、湿度 ±3%RH。

选 TCP Server,是因为板子作 Client 定时去读即可,传感器侧不用知道板子 IP;寄存器只有湿度和温度两个,应用映射简单。

地址内容
0湿度 %RH,原始值 ÷10
1温度 °C,原始值 ÷10

例如原始562→ 56.2%RH,236→ 23.6°C。温度大于 32767 按有符号补码处理。

4.2 Windows 上首次配网

出厂 IP 不一定落在要用的网段,须用官方RS-ModBusTCP-Config写一次静态参数:

  1. 传感器网线接 Windows PC,本机网卡设成同网段,例如192.168.2.10/24,上电。
  2. 打开配置工具 →「搜索」→ 双击设备。
  3. 网络参数:工作模式TCP Server;端口502;静态 IP192.168.2.100,掩码255.255.255.0,网关192.168.2.1;IP 获取 StaticIP;清掉多余 server 项。
    4.「参数配置」保存;有「设备参数」页再读一次、配一次。
  4. 断电重启传感器。搜不到时先关 Windows 防火墙,并确认 PC 与传感器同网段。

部分参数写在传感器非易失配置里,不掉电重启可能仍跑旧 IP 或旧模式。

4.3 接到 IQ-9075

板子连接传感器会占用有线网卡,我们先用无线网络连接开发机和板子。

  1. 传感器从 PC 改接到板子 ETH,板子的以太网口是end0
  2. 板上建静态以太网,本 demo 用 NetworkManager,连接名sensor-net
sudonmcli connectionaddtypeethernet ifname end0 con-name sensor-net\ipv4.method manual\ipv4.addresses192.168.2.1/24\connection.autoconnectyes

板子与传感器必须落在同一子网/24,且板子不要跟传感器抢192.168.2.100

  1. 连通性:
ping-c3192.168.2.100timeout2bash-c'echo > /dev/tcp/192.168.2.100/502'&&echoOPEN||echoCLOSED

应用默认:SENSOR_HOST=192.168.2.100SENSOR_PORT=502SENSOR_POLL_INTERVAL=5秒,pymodbus异步轮询。轮询结果进 SQLite,供仪表盘、告警阈值和拼进 LLM 的「当前读数」共用同一数据源。实机曾读到约23.6°C / 56.2%RH

没有硬件时,可用app/tests/mock_sensor.pymock_sensor_extreme.py,systemd drop-in 把SENSOR_HOST/PORT指到 mock。

五、应用部署

5.1 目录与依赖

应用源码在仓库app/services/(sensor / llm / alert / database / event_bus)、routers/static/data/knowledge/deploy/

一键部署,Git Bash 或 WSL:

cdapp/deploy ./deploy.sh ubuntu@ubuntu.local

脚本会建/opt/qc-ai/app/、SCP 文件、pip装依赖、装 systemd 并启动。

手动时:建目录并chown→ SCPmain.pyconfig.pyservices/routers/static/data/deploy/→ 板上:

cd/opt/qc-ai/app pip3install--break-system-packages-rrequirements.txtsudocpdeploy/qc-ai-app.service /etc/systemd/system/sudosystemctl daemon-reloadsudosystemctlenable--nowqc-ai-app

--break-system-packages是 Ubuntu 3.12 对系统 Python 的 pip 限制下的写法;包版本见app/README.md

5.2 配置

均在config.py,用 systemd drop-in 覆盖即可,不必改代码。常用项:

变量默认含义
SENSOR_HOST/PORT/SLAVE_ID192.168.2.100/502/1Modbus
SENSOR_POLL_INTERVAL5.0轮询秒
LLM_INFERENCE_URLhttp://127.0.0.1:8081genie-server
LLM_TIMEOUT120推理超时秒
ALERT_EXTREME_HEAT40.0极端高温,Critical,会调 LLM 出建议
ALERT_FROST_WARNING0.0霜冻,Critical
ALERT_HIGH_TEMP/LOW_TEMP35/5Warning,记日志
ALERT_HIGH_HUMIDITY/LOW_HUMIDITY95/20Warning
ALERT_COOLDOWN_SECONDS300同类告警去重间隔
DB_PATH/opt/qc-ai/app/data/qc-ai.dbSQLite
KB_ENABLEDtrue是否注入知识库
KB_TOP_K3注入段落数
KB_MAX_CHARS_PER_PASSAGE500单段截断

Critical 与 Warning 分开:只有极端温湿度才再跑一轮 LLM 生成防护建议,避免阈值抖动时把 HTP 打满。ALERT_COOLDOWN_SECONDS用来在冷却期内合并同类告警。

5.3 前端与 API

浏览器打开http://ubuntu.local:8080/:仪表盘、流式对话、告警条。前端无构建步骤,静态文件由 FastAPI 直接送。

接口作用
POST /api/chat咨询,SSE 流式
GET /api/sensors/current/history当前与历史读数
GET /api/alerts告警历史
GET /api/events传感器、告警等实时推送

对话路径:取当前读数 → 可选 FTS5 检索 → 拼 ChatML →genie-server→ SSE 回浏览器。Critical 告警走并行路径,同样经 SSE 推到页面,用户不用先发问。

六、端侧知识检索

6.1 选型

约束:推理时 HTP 打满;上下文 4096;检索不能拖成秒级。考虑过几种做法:

  • A. SQLite FTS5 / BM25:关键词倒排,Top-K 塞进 prompt。不加额外神经网络,毫秒级,可离线;同义词靠词典补齐。
  • B. 在线 API:拉天气、农情。要外网,延迟受外网影响。
  • C. A+B:本地静态知识加在线动态。信息更全,但本 demo 未接外网。
  • D. 本地 embedding + 向量库:在 ARM CPU 上编向量,语义匹配更好,但对这份 FAQ 来说太重。

这里只采用方案 A。FTS5 建倒排索引,BM25 按词稀有度与词频打分;农业术语相对固定,关键词命中率够用。「番茄 / 西红柿」要对上,就把同义写进用户词典,而不是先上向量库。

检索通常不到 5 ms。Token 预算:system + 传感器 + 2–3 段知识约 800–1500 token + 用户问句,留给生成大约两千 token。

6.2 接入方式

首次启动把data/knowledge/*.txt导入 SQLite,建 FTS5 虚表。用 external content 模式时,索引不复制一份全文,省空间。对话前search_knowledge,命中段落进 system:

Current readings: Temperature {temp}C, Humidity {humidity}% Relevant knowledge: {retrieved_passages} ... Do not repeat yourself.

原理上这就是检索增强:模型参数不改,只在上下文里塞可引用的条文,回答更贴本地农技材料;塞太多会挤占生成长度,所以要KB_TOP_K与单段截断。

知识文件命名:{category}_{标题}.txt,例如tomato_高温防护措施.txt。段落约 300–400 字,在句号处切,可留几十字符 overlap,避免知识点卡在边界上丢半句。PDF/Word 在开发机先转明文再上板。

KB_*可关检索或改 Top-K。知识文本的免责声明见app/data/knowledge/DISCLAIMER.md

七、端到端确认

模型、Genie、传感器、应用都起来后,可以按下面几项快速确认链路是否跑通。

推理
curl http://127.0.0.1:8081/health;或再跑一次带 ChatML 的短问,看中英文是否正常、会不会循环复读。

传感器
curl http://127.0.0.1:8080/api/sensors/current,温湿度与寄存器换算一致即可。

Web
打开http://ubuntu.local:8080/,仪表盘有数,聊天框能流式出字。

告警
mock_sensor_extreme或临时改阈值,看 Critical 会不会推告警并带建议,Warning 是否进历史。

知识库
问一句知识库里有的作物问题,看回复是否用到检索段落;也可在 prompt 组装处对一下。

sudosystemctl status genie-server qc-ai-appsudojournalctl-uqc-ai-app-f

八、性能对照

指标子进程genie-t2t-run常驻genie-server
模型加载每次请求约 15–20 s启动一次约 2.2 s
TTFT含加载约 20 s约 176 ms
吞吐约 8.3 tok/s约 8.3 tok/s
内存每请求 fork常驻,RSS 峰值约 1.1 GB

吞吐差不多,差在是否把加载摊到启动期。应用层单次回复时间主要跟生成长度走,常见 7–37 s。

九、扩展和完善方向

本项目是可跑通的边缘农业咨询 demo,不是成品产线系统。已经覆盖:模型上板、常驻推理、真机温湿度、Web 咨询、阈值告警、本地 FTS5 知识注入。

若往产品方向靠,比较自然的扩展包括:知识库加领域词表或第二期接天气 API、告警按作物季节调阈值、多传感器与读数导出等。这些是 demo 之上的完善方向。

参考

  • 仓库:https://github.com/ThunderSoft-XA/Edge-AI-agriculture-assistant
  • 应用与传感器:仓库文档app/README.md
  • 推理服务:仓库文档app/inference-service/README.md
  • 高通教程:LLM on Genie
  • 设备列表:AI Hub devices

上面记录的是实际搭通这条链路时用到的步骤和结论;SMMU、soc_model、packing、图名称等若还要往下挖,可以对照高通官方文档和设备侧日志继续调查。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/13 0:25:42

2026年中最新指南:8款免费好用的AI写小说工具真实测评

是不是很多写小说的小伙伴&#xff0c;总感觉码字效率提不上来&#xff1f;萌新入坑最头疼的&#xff0c;就是不会搭建完整小说大纲、找不到贴合剧情的优质小说的素材&#xff0c;写着写着就卡文停更。不少人跟风乱找AI写小说工具&#xff0c;到头来却白白浪费时间。 作为常年…

作者头像 李华
网站建设 2026/8/13 0:18:36

聊聊ESP8685-WROOM-01-H4这个模组,名字里藏了哪些信息

最近在评估一个新项目&#xff0c;要用到Wi-Fi和蓝牙双模&#xff0c;同时环境温度要求比较高&#xff0c;翻了一圈乐鑫的产品线&#xff0c;最终锁定了ESP8685-WROOM-01-H4这颗模组。今天正好聊聊这个型号到底是怎么回事。先看命名。ESP8685是芯片系列代号&#xff0c;这颗是E…

作者头像 李华
网站建设 2026/8/13 0:16:16

免安装使用微信网页版的终极解决方案:wechat-need-web浏览器扩展

免安装使用微信网页版的终极解决方案&#xff1a;wechat-need-web浏览器扩展 【免费下载链接】wechat-need-web 让微信网页版可用 / Allow the use of WeChat via webpage access 项目地址: https://gitcode.com/gh_mirrors/we/wechat-need-web 还在为无法在受限环境中使…

作者头像 李华
网站建设 2026/8/13 0:07:43

3个核心技巧掌握AltSnap透明窗口拖动,提升Windows多任务效率

3个核心技巧掌握AltSnap透明窗口拖动&#xff0c;提升Windows多任务效率 【免费下载链接】AltSnap Maintained continuation of Stefan Sundins AltDrag 项目地址: https://gitcode.com/gh_mirrors/al/AltSnap AltSnap作为Stefan Sundins AltDrag项目的现代化维护版本&a…

作者头像 李华