前阵子我需要一块 RISC-V AI 芯片的实验台。芯片工程样片还在工厂里,软件栈又不能等,于是我把目标转向了 QEMU:在一台普通的 x86 主机上,用纯软件模拟拉起一块 RISC-V 64 位开发板,把 Linux、PyTorch、RVV 向量扩展环境全部跑通。和以前不一样的是,这次环境搭建不是我一条命令一条命令手敲的,整个过程由 AGENT 主导:它负责拆任务、查资料、生成脚本、分析启动日志,我只在最关键的架构选择上做最终确认。写这篇内容,是想把整套“Agent + QEMU + RISC-V + AI软件栈”的搭法记录下来,给准备做 RISC-V 软件预研、内核驱动开发或者 AI 推理栈移植的朋友一个可直接复用的参考。
我不会把每个细节都讲成教科书,重点放在三个地方:为什么用 QEMU 而不是等真板子、Agent 在这个过程里到底能承担什么、以及真正跑通一块 AI 实验台会遇到哪些坑。
1. 先搞清楚:这块实验台到底要模拟什么
动手之前,务必先想清楚一件事:QEMU 到底是用来“替身”哪一块硬件的。如果你连这个都没想好,后面整个环境搭出来也会四不像。
1.1 RISC-V AI 芯片,QEMU 能模拟到哪一层
RISC-V 和 x86 不太一样,它不是一个具体 CPU,而是一套指令集架构,下面还有一系列可选扩展。AI 芯片通常关注的是向量计算能力,也就是 RISC-V 的 V 扩展(RVV),以及 AI 推理时常会用到的各种自定义指令。QEMU 作为一个指令级模拟器,可以在-cpu参数里把这些扩展打开,让 guest 里的代码真正执行到 RVV 指令,比如vadd.vv、vfmacc.vv这样的向量运算。这是最接近“AI 芯片计算核心”的模拟层级。
QEMU 也能承担平台级模拟。virt机器是一块虚拟开发板,包含 UART、PCI 总线、virtio 外设等。你能在上面跑完整 Linux 内核,也能通过-device挂载额外的模拟设备。如果你有一颗自研的 NPU,想把它的寄存器模型做成 QEMU 设备,再在 guest 里写驱动访问它,这条路也是通的。还有一层是软件栈级模拟,也就是不关心底层是不是真的仿了 NPU,只要 guest 里能跑 PyTorch、ONNX Runtime 这类 AI 软件,验证它们在 riscv64 上能否编译、能否运行,就达到了目的。
我这次选择的是“指令级 + 软件栈”组合:一方面用-cpu rv64,v=true验证 RVV 代码,另一方面在 guest 里搭 Python AI 推理环境。至于具体 NPU 的寄存器模型,后面再慢慢加。这样做的好处是周期短、可控性强,坏处是没办法评估真实芯片的性能,因为 QEMU 的 TCG 翻译执行比真实硬件慢很多,跑出来的性能数据没有参考意义。
1.2 为什么不等真板子,非要折腾 QEMU
很多人的第一反应是:去买一块 RISC-V 开发板不就行了吗?如果只是玩一玩,确实可以。但放到项目里,真板子有几个绕不开的麻烦。
第一,货期不可控。芯片厂商给的评估板数量有限,经常要排队,有时候软件团队要提前三个月开始干活。第二,成本不可控。一块带 NPU 的 RISC-V 板子价格不低,而 QEMU 只需要一台能跑 x86 的普通电脑,零硬件成本。第三,CI/CD 需求。我想在每次代码提交后自动跑一遍 RISC-V 的软件测试,真板子只有一两块,没法并行跑多实例,QEMU 则可以同时开四五个虚拟机,每个测试一个干净环境。
QEMU 还有一点被很多人忽略:它可以模拟“还没存在的芯片”。芯片流片之前,软件开发必须先行,这时候 QEMU 是唯一能让你提前接触指令集和平台模型的工具。你可以在 QEMU 上先把内核驱动写好、把 AI 推理框架移植好,等芯片回来直接跑。
当然也有代价。RISC-V guest 在 x86 宿主机上不能走 KVM 加速,只能靠 TCG 动态翻译,CPU 密集型任务会明显变慢。如果你要测真实推理延迟、吞吐量,那还是得等真板子。我的建议是:软件栈验证、功能调试、内核开发用 QEMU,性能测试和功耗测试等硬件。
2. AGENT 链路设计:怎么写任务书,怎么防止它乱来
这次环境搭建最特别的一点,是我把大量工作交给了 AGENT。很多人用 AI 工具只是问一句“怎么写命令”,然后自己复制粘贴。真正像样的做法,是把 AGENT 当成一个会自己动手的实习生,给它明确任务、明确边界、明确验收标准。
2.1 任务书不只是几句 Prompt
我建了一个工作目录,在里面放了一个TASK.md,内容不是随便几句话,而是带验收条件的任务书。
# TASK.md 目标:在宿主机上用 QEMU 拉起 RISC-V 64 位 Linux,并在 guest 里安装可用的 AI 推理环境。 环境约束: - 操作系统:宿主机为 Ubuntu 22.04 - 工作目录:/home/user/riscv-lab - 不允许修改宿主机全局配置 - 所有产物输出到 /home/user/riscv-lab/build 执行步骤: 1. 检查 qemu-system-riscv64 是否存在,不存在则用 apt 安装 qemu-system-misc 2. 获取 Ubuntu riscv64 cloud image 或可替代 rootfs 3. 编写并执行启动脚本 qemu-run.sh 4. 确认 guest 能通过 SSH 访问 5. 在 guest 中安装 python3-venv,给出 PyTorch CPU 版本的安装方案 6. 输出:启动脚本、运行日志、每步执行记录 验收标准: - 启动脚本可以直接拉起到串口控制台 - SSH 端口映射可用 - guest 内能执行 python3 -V - 记录失败的步骤和原因这份任务书看起来简单,但比普通 Prompt 多出了“约束”和“验收”两部分。约束是告诉 AGENT 什么不能碰,验收是保证它不会只在表面上完成一半就交差。我在后面还会强调一点:AGENT 每一步产生的日志都要落盘,毕竟它跑完就忘了,日志是我事后复盘和回滚的依据。
很多人在用 AGENT 的时候,会纠结该选哪种 agent 框架。其实没有标准答案。对我来说,关键是这个 AGENT 有没有“执行命令”的能力,而不是停留在聊天界面上。所谓 harness,就是让 AGENT 调用工具时走权限检查的壳;技能 skill 则是一些可复用的套路,比如“QEMU 启动参数模板”。如果你用现成的 Agent 框架,选支持终端操作的;如果你是技术出身,也可以自己写一个循环,本质上就是“模型决定下一步动作 -> 执行命令 -> 把输出反馈给模型”。
2.2 AGENT 自动完成的部分,和我人工确认的关键点
整个流程里,AGENT 自动完成的事情包括:检查 QEMU 是否安装、搜索 Ubuntu riscv64 镜像下载地址、生成启动脚本、分析启动日志并尝试修复、给出 guest 内 Python 环境的安装步骤。这些事如果我自己做,大概要一到两个小时,AGENT 十几分钟就跑完了。
但我没有把所有决策都交给它。有几个点是我人工确认后才让它继续的。
一个是机器选型。AGENT 一开始用的方案是-machine sifive_u,因为网上很多旧教程都是拿这块板子举例。但我想用virt,原因是:virt 是纯虚拟平台,virtio 设备支持更完整,后续要挂自定义设备模型也更容易。这个选择直接影响了整个环境的基础。
另一个是网络模式。AGENT 默认建议用-netdev user,我认可。但如果未来想用固定 IP、多台虚拟机互相通信,就需要改成tap0桥接模式,这涉及宿主机网桥配置,权限要求高,不能随便让 AGENT 自动改。
还有一个是 rootfs 选择。它最初想下载完整的 Ubuntu cloud image,我确认了这个方向没问题,但提醒它先检查镜像里是否自带内核和引导,避免启动时还要自己去拼 OpenSBI、内核、initrd。事实证明这个检查很关键,后面省了很多事。
2.3 权限边界与回滚机制
AGENT 能执行终端命令,听起来很爽,但也意味着它有破坏宿主机的风险。我的经验是:尽量不让 AGENT 直接拿到 root 权限,即使它说“需要 sudo”,也要在任务书里写明必须停下来询问。如果一定要允许,就在宿主机上创建一个低权限用户,只给它操作工作目录的权限。
另外,工作目录本身也要设计成可丢弃的。我把所有下载的镜像、生成的 rootfs 都放在build/下,万一搞坏了直接删掉重来。QEMU 的磁盘镜像我用的是 qcow2 格式,它天然支持快照,环境弄乱之后可以qemu-img snapshot -a一键回滚。这一点强烈建议你做到,因为你让 AGENT 自由操作时,它一定会踩坑,能回滚比什么高级技巧都实在。
3. QEMU 拉起 RISC-V 系统的关键实操
现在进入物理层面。无论 AGENT 多聪明,最终还是要落地成几个命令和文件。下面的操作我在 Ubuntu 22.04 上完整跑通过,细节比较啰嗦,但每一步都有原因。
3.1 宿主机准备与镜像获取
先把宿主机需要的软件装上。
sudo apt update sudo apt install -y qemu-system-misc qemu-utils wget xz-utils检查 QEMU 是否装好:
qemu-system-riscv64 --version如果提示找不到命令,可能是因为发行版里这个二进制被拆分了。Debian/Ubuntu 下qemu-system-misc包含 riscv64 模拟器,装好后直接可用。
下一步是获取镜像。我用的是 Ubuntu riscv64 cloud image,这个镜像基于 qcow2 格式,可以直接被 QEMU 作为磁盘使用,不需要再转换。下载地址在 Ubuntu 官方 cdimage 站点,选择release下对应版本的ubuntu-XX.XX-preinstalled-server-riscv64.img.xz。
mkdir -p /home/user/riscv-lab/build cd /home/user/riscv-lab/build wget <镜像下载链接> xz -d ubuntu-*.img.xz解压后得到一个.img文件。注意这个文件的格式是 qcow2,不要习惯性地把它当成 raw 镜像。用file命令确认一下:
file ubuntu-*.img输出里应该能看到QEMU QCOW2 Image (v3)字样。确认之后,我建议先创建一块数据盘,专门放模型权重和测试脚本。用 qcow2 的好处是宿主机上只占用实际写入的大小。
qemu-img create -f qcow2 data.qcow2 20G3.2 启动命令逐行拆解
下面这条命令是我最终跑通的,先整体看一遍。
qemu-system-riscv64 \ -machine virt \ -cpu rv64,v=true \ -smp 4 \ -m 8G \ -drive file=ubuntu-riscv64.img,format=qcow2,id=hd0 \ -device virtio-blk-device,drive=hd0 \ -drive file=data.qcow2,format=qcow2,id=hd1 \ -device virtio-blk-device,drive=hd1 \ -netdev user,id=net0,hostfwd=tcp::2222-:22 \ -device virtio-net-device,netdev=net0 \ -nographic逐个解释参数,不然 AGENT 很可能随机调参,而你根本不知道哪里出了问题。
-machine virt指定平台模型。RISC-V 下常见的是virt和sifive_u。我选 virt 的理由前面已经说过:virtio 支持完整,设备树规范,社区生态都围绕它。
-cpu rv64,v=true开启 RVV 向量扩展。如果你后续想跑 RVV 向量代码,这个参数必须有。QEMU 7.2 之后对 V 扩展的支持已经很成熟,可以放心开。
-smp 4开 4 个虚拟 CPU。-m 8G给 guest 8G 内存。因为 AI 推理有时会吃内存,2G 太紧,8G 比较宽松。如果你只是验证启动,可以用-m 2G减少宿主机负载。
-drive和-device virtio-blk-device是配套的。第一块盘装系统,第二块盘是数据盘。这里有个容易踩的坑:很多人只写-drive file=xxx,format=qcow2,忘了-device,结果 guest 里根本看不到硬盘。在 RISC-V virt 机器上,不能假设盘会自动接到某条总线上,必须显式挂一个 virtio-blk-device。
-netdev user,id=net0,hostfwd=tcp::2222-:22是用户态网络。这种模式最简单,guest 通过 QEMU 内置的 NAT 上网,宿主机无需 root,也不需要网桥。hostfwd把宿主机的 2222 端口转发到 guest 的 22 端口,这样后面可以用 SSH 连接。如果你想要 guest 里的固定 IP,或者希望 guest 能被局域网内其他机器直接访问,就要换成tap0桥接,但那种模式需要创建tap设备和网桥,权限和网络拓扑都要规划,我这次没选。
-device virtio-net-device,netdev=net0是网络设备。在 virt 机器上一定要用virtio-net-device,不要用 e1000,因为 virt 平台默认没有 e1000 这种 PCI 网卡。很多 Agent 生成的脚本会照抄 x86 的参数,拿到这里就起不来。
-nographic把串口作为控制台,直接在当前终端显示 guest 的输出。加上这个参数,你就能在纯文本终端里控制整个虚拟机,不需要图形桌面。
3.3 从启动到 SSH 登录
执行启动脚本后,第一次会看到一个比较慢的启动过程,因为 QEMU 正在用 TCG 翻译 guest 指令。几秒钟后应该能看到 OpenSBI 的 logo,然后是内核启动日志,最后进入登录提示。Ubuntu cloud image 默认用户名一般是ubuntu,密码在镜像说明里会有,通常安装时有提示。
登录后建议马上改密码,然后检查网络。
ip addr show如果没问题,会看到一个eth0或者enp0s1网卡,IP 是 QEMU 用户态网络分配的 10.0.2.15。这个 IP 只有 guest 内部可见,想要从宿主机进来,还得走端口转发。
从宿主机连:
ssh ubuntu@localhost -p 2222第一次连接会提示 host key 确认,正常。如果连不上,十有八九是 guest 里没启用 SSH 服务,或者 cloud-init 还没完成初始化。等两分钟再试。
为了方便传文件,我习惯加一块 9p 共享目录。在启动命令里插入:
-virtfs local,path=/home/user/riscv-lab/shared,mount_tag=host0,security_model=none,id=host0在 guest 里挂载:
sudo mkdir -p /mnt/shared sudo mount -t 9p -o trans=virtio,version=9p2000.L host0 /mnt/shared这块共享目录最初让我很惊讶,因为 RISC-V 的 guest 内核必须编译进 9p 支持才能挂载。Ubuntu 官方内核默认带了,所以能用。如果之后你自己编译内核,记得把CONFIG_NET_9P_VIRTIO和CONFIG_9P_FS选上,否则会报mount: /mnt/shared: unknown filesystem type '9p'。这个 9p 目录是我传模型权重、测试脚本和日志的主要通道,比 SSH 传文件方便得多,尤其是大文件。
4. Guest 里搭建 AI 运行环境
系统起来了,网络通了,只是万里长征第一步。既然是“AI 芯片实验台”,还得把 AI 运行环境搭出来。这里有很多和 x86 完全不同的坑,AGENT 可以帮你生成步骤,但几个现实问题必须提前知道。
4.1 Python 与 PyTorch 在 RISC-V 上的安装现实
进入 guest 后,先确保 Python 环境可用。
sudo apt update sudo apt install -y python3-venv python3-pip build-essential git mkdir -p /home/ubuntu/ai-lab cd /home/ubuntu/ai-lab python3 -m venv venv source venv/bin/activate pip install --upgrade pip接下来是重头戏:装 PyTorch。坏消息是,PyTorch 官方并不提供riscv64的预编译 wheel。你在pip install torch时,pip 会在 PyPI 上找不到合适的包,然后尝试下载源码包现场编译。CPU 版 PyTorch 在 RISC-V 上源码编译是可行的,但耗时非常长,我试过一次,8G 内存 4 核的虚拟机里编了两三个小时还没编完,而且很容易因为内存不足被 kill。
如果你只是想验证推理逻辑而不是真的拿到一个可用的 torch 包,我更推荐一条折中的路:先用 NumPy 实现一个小型神经网络推理,把整条数据通路跑通。等确认了真正的目标芯片和工具链之后,再去编译 PyTorch。另外,ONNX Runtime 对 RISC-V 的支持比 PyTorch 好一些,有社区构建的包,虽然不一定官方发布,但成功率更高。下表是我的选择建议:
| 需求 | 推荐方案 | 原因 |
|---|---|---|
| 快速验证推理流程 | NumPy 手动实现 | 零编译,几分钟内跑通 |
| 跑标准 ONNX 模型 | ONNX Runtime 源码/社区包 | 编译量比 PyTorch 小,依赖轻 |
| 完整 PyTorch 环境 | 源码编译 | 时间长、吃内存,但要拿真实结果只能走这条 |
| 验证 RVV 指令 | gcc 交叉编译汇编/C | 最贴近芯片真实计算核心 |
如果你决定源码编译 PyTorch,建议不要直接在 QEMU guest 里编。先在 x86 宿主机上把交叉编译工具链准备好,生成 riscv64 的交叉编译环境,再尝试交叉编译。这是很多人的经验,能省掉 guest 里内存不足的问题。不过交叉编译 PyTorch 依赖项非常复杂,涉及 OpenBLAS、protobuf、eigen 等,坑比想象的深,新手容易劝退。
4.2 用一个小型推理程序验证实验台
我最后在实验台上跑通的第一个正经 AI 程序,是一个两层的 MLP,用来做简单的二分类。为了不依赖 PyTorch,我用 NumPy 手写前向传播。代码如下:
import numpy as np def sigmoid(x): return 1.0 / (1.0 + np.exp(-x)) class MLP: def __init__(self): self.w1 = np.random.randn(4, 16).astype(np.float32) self.b1 = np.zeros((1, 16), dtype=np.float32) self.w2 = np.random.randn(16, 2).astype(np.float32) self.b2 = np.zeros((1, 2), dtype=np.float32) def forward(self, x): h = sigmoid(x @ self.w1 + self.b1) out = sigmoid(h @ self.w2 + self.b2) return out model = MLP() x = np.random.randn(1, 4).astype(np.float32) print(model.forward(x))在 RISC-V guest 里执行:
python3 inference.py能看到输出一个形状为(1, 2)的数组,说明 Python、NumPy、CPU 浮点运算链路是通的。这个测试虽然简单,但对实验台来说意义重大:它证明了你可以在 RISC-V 虚拟硬件上跑数据流,后续把 NumPy 换成 PyTorch 或者 ONNX Runtime,只是换一个算子库的事,数据通路不用改。
如果你想更贴近“AI 芯片”的计算核心,可以用 RISC-V 工具链写一个使用向量扩展的程序。在 guest 里安装 gcc:
sudo apt install -y gcc写一个最简单的向量加法:
#include <riscv_vector.h> #include <stdio.h> int main() { int n = 16; float a[16], b[16], c[16]; for (int i = 0; i < n; i++) { a[i] = i; b[i] = i * 2; } for (int i = 0; i < n; i++) c[i] = a[i] + b[i]; for (int i = 0; i < n; i++) printf("%f ", c[i]); return 0; }用-march=rv64gcv编译:
gcc -O2 -march=rv64gcv -o vadd vadd.c ./vadd如果程序正常输出,说明 QEMU 的 V 扩展真的在工作。你可以在这基础上逐步加向量化矩阵乘、卷积等算子,这就是一个最原始的 AI 芯片计算单元实验台。
4.3 与真实 AI 芯片相关的驱动和虚拟设备模拟
如果想更进一步,模拟一颗具体的 AI 芯片,QEMU 也支持你自定义设备模型,把 NPU 想象成一个挂在 PCIe 上的加速卡,guest 里写驱动通过 MMIO 访问寄存器。QEMU 提供了比较完整的设备建模接口,你可以注册一个 PCIe 设备:
static void riscv_npu_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->desc = "RISC-V NPU accelerator"; dc->realize = riscv_npu_realize; dc->reset = riscv_npu_reset; }这只是设备侧的骨架,实际还要实现 PCIe 配置空间读写、BAR 空间映射、中断、DMA 等逻辑。guest 侧再写一个 Linux 内核模块,注册一个platform_driver或者pci_driver,通过ioremap访问寄存器。这套流程就是一个完整的“驱动先行”开发闭环:芯片还没有,驱动和用户态栈已经在 QEMU 上联调完了。
不过我要提醒一句:自定义 QEMU 设备模型涉及 QOM 和 PCIe 模拟的不少概念,不要指望 AGENT 一次生成对。我建议先跑通最小 GPIO/UART 设备模型,再往 AI 方向扩展。AGENT 在这里的价值是帮你生成代码骨架、查 QEMU 源码里现成设备模型的实现方法,而不是凭空替你设计硬件逻辑。
5. 常见问题与排查手记:Agent 是主力排查员
最后这部分是我最想分享的。环境搭建过程中遇到了一堆问题,AGENT 作为主力排查员确实帮我省了很多时间。下面这些问题几乎都会遇到,建议收藏。
5.1 启动卡在 OpenSBI,或者串口完全无输出
现象:执行启动命令后,终端里只有 OpenSBI 的几行字,然后一直卡住,或者干脆什么都没显示。
排查顺序:
第一,确认你用了-nographic。如果没有,串口输出不会直接打到终端上,可能会去图形窗口,而你如果在一个纯 SSH 会话里根本看不到。
第二,确认有没有给内核传正确的 console 参数。如果是 Ubuntu cloud image,它通常会自己处理,但如果你是自己拼内核和 rootfs,需要在-append里加console=ttyS0,否则内核日志不会出现在串口。
第三,看分区。root=/dev/vda是常见写法,但如果你少加了-device virtio-blk-device,guest 里没有/dev/vda,内核就会在挂根文件系统时崩溃,日志最后会停在VFS: Cannot open root device "vda"。
第四,如果卡在 OpenSBI 阶段,多半是固件问题。Ubuntu 官方镜像自带引导,不需要单独指定-bios。如果从网上找了旧教程,加了奇怪的-bios参数,反而可能冲突。
遇到这种问题,我一般直接把完整启动日志存到文件里,丢给 AGENT 让它帮我定位是在哪个阶段卡住的。它比人眼看着更快的点在于,能迅速搜索日志关键词,比如Kernel panic、No working init found、Failed to mount。
5.2 SSH 连不上,guest 里能看到网络但宿主机过不去
现象:guest 里ip addr能看到10.0.2.15,ping 外网也能通,但宿主机上ssh ubuntu@localhost -p 2222就是连不上。
原因大多是两个。一个是 guest 里的 SSH 服务没起来,Ubuntu cloud image 默认会装 openssh-server,但如果你用的是其他 rootfs,可能需要手动安装并启动:
sudo systemctl enable ssh --now另一个是端口转发写错了。hostfwd=tcp::2222-:22的语法是宿主机端口在前,guest 端口在后。如果你写反成hostfwd=tcp::22-:2222,那宿主机的 22 端口会转发到 guest 的 2222 端口,而 guest 的 SSH 在 22 上,当然连不上。
还有一种情况是 cloud-init 还没有完成。镜像第一次启动时会自动扩展根分区、配置网络、生成 SSH host key,这个过程可能要一两分钟。如果你在启动后几十秒就去连,可能服务还没就绪。耐心等一分钟后重试。
5.3 GDB、快照与性能调试的实际经验
QEMU 自带 GDB stub,内核开发时可以在启动命令里加:
-s -S-S表示启动后暂停 CPU,等待调试器连接,-s表示在宿主机 1234 端口开 GDB 服务。然后用交叉版的 gdb 连上去:
gdb-multiarch vmlinux target remote :1234不过如果你只是想调试用户态程序,没必要用 QEMU 的 GDB 接口,直接在 guest 里gdb ./a.out就完了。QEMU 的 GDB 更多是给内核、引导代码用的。
另外一个经验是:QEMU 多核模拟有时候反而会比单核慢。TCG 模式下,多核会有同步开销,如果你跑的任务不是并行密集,用-smp 1可能启动更快。如果你确实需要多核,可以尝试:
-accel tcg,thread=multi这会启用多线程 TCG,在宿主机是多核时能明显改善性能。但这属于锦上添花,我在实验台上跑 NumPy 推理时,单核也能接受。
磁盘快照在这里是保命工具。qcow2 天然支持内部快照,在 guest 里装好了一轮环境之后,回到宿主机执行:
qemu-img snapshot -c healthy ubuntu-riscv64.img下次如果想恢复到干净状态:
qemu-img snapshot -a healthy ubuntu-riscv64.img这个方法比重新下载镜像快很多,也避免 AGENT 自动操作时把环境改坏后无法回滚的痛苦。
5.4 Agent 排查问题的一个通用套路
如果让 AGENT 帮你排查,我的做法是:把现象、启动日志、配置文件粘贴给它,然后明确告诉它“不要给我解释原理,先给我下一步操作”。很多人让 AI 排查失败,是因为问题描述太模糊,只说了“连不上”,没有任何客观信息。
一份合格的排查信息长这样:
QEMU 启动后 guest 能登录,宿主机 ssh localhost -p 2222 连不上。 日志显示 sshd 已启动,宿主机的端口监听正常。 hostfwd 配置是 tcp::2222-:22。 请给我下一步的排查命令。AGENT 拿到这种输入,会优先检查监听端口、防火墙、SSH 配置,而不是漫无目的地展开长篇大论。最终它定位到的问题是:guest 的 sshd 只监听了 IPv6,而localhost解析成了127.0.0.1。这种问题人工看半天也未必能马上反应过来,让 AGENT 过滤日志反而更快。
写在最后
这套实验台搭建下来,我最深的体会是:AGENT 不是用来替代你的判断力的,它是帮你把脏活累活干掉的。环境搭建里大量工作其实是机械搜索、试错、翻日志,这些 AGENT 做得又快又好。但哪些参数不能乱动、哪条路线会浪费时间、要在什么层级上模拟 AI 芯片,这些决策最后还是得你自己想清楚。
如果让我重来一次,我不会让 AGENT 一上来就拉 Ubuntu 完整镜像,而是会先让它用最小的 BusyBox rootfs 把 QEMU RISC-V 启动链路跑通,再一步步加上网络、共享目录、Python。小系统更轻、问题更少,排查起来也不容易被一堆 cloud-init 日志干扰。
还有一个小技巧想分享:现在这套环境里,我会把每次修改 QEMU 启动参数的命令记录到一个history.md文件里,顺手让 AGENT 在每次做完事之后追加一段变更说明。时间一长,这个文件就是最好的项目文档,比什么环境搭建笔记都管用。下一块真正带 NPU 设备模型的模拟器,我就是在这个文件的基础上继续扩展的。