0.8MB 跑通 Qwen|第 20-2 篇:推理引擎的路由与自研最小 JSON

简介: 本系列《0.8MB跑通Qwen》用纯C手搓零依赖推理引擎,适配Qwen3-VL多模型,在RK3588(aarch64)实测通过。核心含strcmp路由表与自研轻量JSON解析器,精准拦截非法请求(如`msgs`→400),严守兼容边界,代码精简可控,专注教学与边缘部署。(239字)

系列:《0.8MB 跑通 Qwen:从零实现 ARM 零依赖纯 C 推理引擎》(30 天 × 90 篇) | 适配模型:Qwen3-VL-8B-Instruct(千问3_VL_8B_Instruct)· Qwen3-VL-2B-Instruct · Qwen3-30B-A3B | 测试设备:RK3588(4×Cortex-A76 + 4×Cortex-A55,aarch64)

系列总纲:《0.8MB 跑通 Qwen》30 天 90 篇 · 总纲(阿里云社区)

上一篇:20-1《极简 HTTP:socket/bind/select 轮询》| 下一篇:20-3《SSE 流式:响应怎么写一半就发给客户端》

真机实测通过:本文实验已在 RK3588 板端实测完成(2026-09;方法学与原始记录见仓库 docs 与《实验脚本》目录)

一句话导读:推理引擎的路由与自研最小 JSON:strcmp 路由表加递归下降解析器,把"URL+JSON 体"变成行为;请求把 messages 拼成 msgs,被 400 精确挡在兼容性边界的板端实测。

关键词:手搓 Qwen 推理引擎、千问大模型推理、Qwen3-VL、零依赖纯 C、JSON、路由、自研解析器、HTTP、兼容性边界

导语:连接进来之后,URL 与请求体怎么变成一次行为?这套引擎用一张 strcmp 路由表加一个递归下降的自研最小 JSON 解析器,把字段名改错的请求精确挡在 400 上,展示兼容性边界该怎样用真实请求去戳。

HTTP 砖块就位后,vllm_server.c/vllm_admin.c 负责把"URL + JSON 体"变成行为。这篇讲两件事:路由表怎么组织,以及自研 JSON 解析器为什么"够用就行"——并用板端实测演示:请求里把 messages 拼成 msgs,服务端用自研解析器给出 400 'messages' array is required。兼容性断裂被精确地挡在边界上。

1. 知识点:路由的本质是"字符串分发",JSON 的本质是"结构约定"

  • 路由:HTTP 请求的 method + path 决定行为。极简引擎不需要正则路由框架——一张 strcmp 表(或少量 if 链)就够:GET /health、POST /v1/chat/completions、POST /admin/api/model/load……每个 handler 一个函数签名,拿解析好的 VHttpRequest 返回 VHttpResponse。
  • JSON:OpenAI 兼容层(Day 21)与 admin 面(Day 22)都依赖 JSON。引一个 JSON 库是"简单"的,但会带进一个完整解析器 + 依赖审计面。引擎的做法是把 VJson 嵌进 vllm_http.c(一个文件里 172–463 行):对象/数组/字符串/数值/布尔,外加一套极小的 set/get 与序列化。够用阈值:只要覆盖"请求体的合法形状 + 错误能精确报出",就比引库更可控。

为什么"错误能精确报出"重要?一个自研解析器可以做到:messages 缺失 → 明确说缺 messages;角色名写错 → 甚至能宽松放行(实测见 §3)。引第三方库反而要为了一个错误信息去读库代码。这是"零依赖"工程风格的收益点之一——但它同样有边界:VJson 只支持 OpenAI 请求用到的 JSON 子集(无注释、无 NaN 等),上框架的人未必能接受,取舍写明在文件头。

2. 对应代码:路由表与解析器锚点

路由层(vllm_server.c 主分发 + vllm_admin.c 1120–1170 的 admin 路由表):

/* vllm_admin.c:GET 集合 */
if (strcmp(req->method, "GET") == 0 &&
    strcmp(req->path, "/admin/api/status") == 0) {
    ... }
else if (strcmp(req->method, "POST") == 0 &&
         strcmp(req->path, "/admin/api/model/load") == 0) {
    handle_admin_model_load(...); }

JSON 解析器(vllm_http.c):

static VJson *parse_value(VJsonParser *P);   // 223:类型分发
static VJson *parse_object(VJsonParser *P);  // 172:{"k":v,...}
static VJson *parse_array(VJsonParser *P);   // 205
static char  *parse_string_body(VJsonParser *P); // 100:转义 + UTF-8
void vjson_obj_set(VJson *obj, const char *key, VJson *val); // 291

读取顺序建议:先 parse_value(类型分发)→ parse_object/parse_array(递归结构)→ parse_string_body(转义最易错的部分)。它是递归下降解析器,几十行覆盖全部需求。

3. 改动后果:字段名改错,兼容性在哪一层断

实测口径:板端 serve(模型已加载)+ x86 客户端,POST /v1/chat/completions,2026-09-07。

① 正确字段:
   {"model":"x","messages":[{"role":"user","content":"你好"}],"max_tokens":8}
   → 200,正常生成

② 字段名拼错 messages → msgs:
   → 400 {"error":{"message":"'messages' array is required","type":"invalid_request_error","code":0}}

③ 角色名写错 role → userr:
   → 200(正常回答)——解析器/兼容层对角色做了"未知即忽略"的宽容处理

④ content 缺失({"role":"user"} 无内容字段):
   → 200,空回复 finish_reason=stop(宽松放行)

四个结果拼出兼容层的真实边界:

  • messages 是必填且结构校验:缺它就 400,错误信息直接点名字段——这是解析器最严的一层;
  • 角色与内容字段是宽松的:userr 与缺 content 都放行。前者会被当未知角色忽略,后者产出一个空回复。这不是"bug",是兼容层"对 OpenAI 客户端各种不严谨请求的容忍度"设计——真正的下游(如越权/格式攻击)还有 admin 层与 attestation 兜底(Day 26/27);
  • 诚实提醒:宽松不是缺陷清单的免死金牌——如果你在生产要严格校验,应该在路由层自己加白名单,而不是依赖这个自研解析器"猜"。

这就是"改动后果"课的标准示范:协议边界的每一条缝,都该用一次真实请求去戳,而不是读代码猜。

4. 学员调试任务

  • A 档(本地/板端动手):复刻 §3 的 ①②③④ 四个请求,记录状态码与错误体;再试:messages 传成对象 {}、传成空数组 []、把 max_tokens 传成字符串 "8"——各是什么结果?(第三个大概率暴露自研解析器的数值宽容度,记录下来)。
  • B 档(纯读源码):读 vllm_http.c 100–260 行的解析器,回答:① parse_string_body 处理了哪些转义(\n、\uXXXX 等),漏处理哪个会有什么后果?② 为什么 vjson_obj_get 找不到键返回 NULL 而不是报错,调用方怎么区分"键不存在"与"值为 null"?③ admin 路由为什么宁可写一串 strcmp 也不用 switch(path[0])(提示:路径前缀冲突与可读性)。

预期输出:一张"篡改字段 × 状态码 × 错误体"对照表,附一个你额外发明的"宽松/严格"边界用例。

收尾

  • 本篇源码点名:vllm_http.c(VJson 解析器 100–463)、vllm_server.c(主路由)、vllm_admin.c(admin 路由 1120–1170)
  • 开源仓库:Kestrel-LLM (Gitee)(AGPL-3.0-or-later 或商业许可,二选一)
  • 下篇预告:请求解析对了,但对话要"边生成边看到字"——20-3 进 SSE:响应头先发、事件流逐 token 推,curl -N 能看见什么。
相关文章
|
1天前
|
缓存
0.8MB 跑通 Qwen|第 8-3 篇:推理引擎的 KV 缓存结构——按 token 还是按头存
本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,适配Qwen3-VL多模态模型,在RK3588上实测。本文精析KV缓存的token-major布局设计原理,揭示其如何兼顾prefill与decode访存效率,直击带宽瓶颈。(239字)
|
1天前
|
缓存 人工智能 索引
0.8MB 跑通 Qwen|第 12-1 篇:LLM 推理的跨进程恢复——服务重启了,会话不能断
本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,实现在RK3588上部署Qwen3-VL等多尺寸模型。本文详解`--disk-kv`机制:将KV Cache落盘持久化,支持进程重启后按前缀精准恢复,实现“会话不断连”,2K上下文prefill加速达23.6×,真正打通边缘AI服务可用性最后一环。(239字)
|
1天前
|
C语言 C++
0.8MB 跑通 Qwen|第 17-1 篇:safetensors → VQF——推理引擎的 vqf_write 一次成型
本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,适配Qwen3-VL多模态模型(2B/8B/30B),在RK3588平台实测通过。核心突破:safetensors→VQF转换与推理共用同一量化路径,实现位级可复现,体积压缩至2.2–4.2GB,真机重转SHA256完全一致。(239字)
|
1天前
|
编解码 Java 测试技术
0.8MB 跑通 Qwen|第 18-3 篇:MRoPE——推理引擎的 3D 位置编码给视觉留的席位
本篇详解Qwen3-VL多模态推理中MRoPE三维位置编码机制:通过`mrope_section=[24,20,20]`将64维旋转频率分给时间/高/宽三轴,支持视觉token网格定位;并数值推演“强行降维至1D”的相位偏差——7×7图像下最高达4.71弧度(近270°),40/64维严重失准,导致注意力失效。纯文本因t=h=w自动退化,故该bug无法被文本测试捕获。(239字)
|
1天前
|
缓存 NoSQL 区块链
0.8MB 跑通 Qwen|第 15-2 篇:推理引擎的 prefill 与 decode——两条路径为何分开
本篇详解Qwen推理引擎中prefill与decode双路径设计:prefill一次性处理整段prompt(如18 token),批量写入KV缓存;decode逐token循环生成,追加KV。通过RK3588真机gdb断点实证,明确二者独立入口、状态流转与性能动因,手搓零依赖纯C引擎的核心逻辑。(239字)
|
1天前
|
定位技术 C语言 C++
0.8MB 跑通 Qwen|第 7-1 篇:大模型量化的 Q4_0 格式——与 GGUF 对齐的 4bit 布局
本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,适配Qwen3-VL多模态模型,在RK3588上实测通过。详解GGUF对齐的Q4_0量化:32个float压缩至18字节(f16 scale + 16 nibble),剖析nibble打包规则与11倍误差代价,为端侧高效部署夯实底层基础。(239字)
|
1天前
|
缓存 安全 数据安全/隐私保护
0.8MB 跑通 Qwen|第 16-2 篇:逐字段解剖——推理引擎权重格式的 VQFHeader / VQFSig / VQFTensor
本篇深度解析Qwen推理引擎VQF v2文件头:432字节固定布局、小端序、64B对齐目录起始(448偏移),通过`_Static_assert`严控结构体尺寸,以`magic/version/size`三重门禁保障零依赖纯C加载安全。真机RK3588实测,揭穿注释与字节不符彩蛋,夯实字节序纪律。(239字)
|
1天前
|
C++
0.8MB 跑通 Qwen|第 10-2 篇:推理引擎的 sparse top-k 块选择——"只看该看的"到底怎么选
本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,实测RK3588上高效运行Qwen3-VL多模态模型。本文深度剖析sparse_attn_head的top-k块选择机制——探针抽样、prefill重要性预留、贪心补满与recency保险四段代码,揭示长上下文稀疏注意力如何精准“找针”,并实证k=1时板端翻车根源。(239字)
|
1天前
|
存储 安全 C语言
0.8MB 跑通 Qwen|第 5-2 篇:推理引擎的 Q8 对称量化——scale 从哪来
本系列聚焦ARM端零依赖纯C推理引擎,实测RK3588跑通Qwen3-VL多模态模型。本文详解Q8对称量化核心——scale标定:为何用f16存、为何除127、误差如何从0.033暴增至0.44,揭示量化精度的生死线。(239字)
|
1天前
|
调度
0.8MB 跑通 Qwen|第 13-3 篇:推理引擎的回退与收益边界——哪些场景 spec 才划算
本文精析Speculative Decoding在ARM端的收益边界:基于RK3588实测,揭示“62%命中率仍变慢”的根源——单步Decode仅44ms时,验证开销与KV回滚反致负增益;明确开启条件:长上下文、高重复性、大模型、贪婪采样。零依赖纯C,适配Qwen3-VL系列。

热门文章

最新文章