跳转至

Hw2:理解 LLM 推理生命周期与 AI Service(对应实验二)

作业定位

  • Hw2 是实验二“LLM 推理生命周期与 AI Service”的配套作业;
  • 本次作业侧重阅读、分析与书面整理,主线包括:LLM 推理生命周期与性能指标、异步 AI service 的结构演化,以及 wait/query 相关语义边界;
  • 完成本作业后,你应能更顺畅地进入实验二中的代码阅读、性能测量、调试与后续接口设计任务。

作业目标

  • 从系统实现的角度理解一次 LLM 推理的基本流程,能够围绕“程序读了什么、算了什么、输出了什么”这条主线,说明 tokenizationPrefillDecodeKV Cachedetokenization 分别处在什么位置;
  • 理解 Model Loading TimeTTFTTPOT 这三个核心服务指标分别衡量什么,能够结合输入长度、输出长度与冷启动过程分析它们为什么会变化;
  • 理解 PrefillDecode 的资源消耗差异,能够结合实验数据区分 compute-boundmemory-bound 两类典型瓶颈,并把模型规模、层数、隐藏维度等架构差异映射到性能差异上;
  • 能够基于当前 llmrunpipe 与进程机制,解释为什么 AI service 会从“用户态直跑”自然演化成“请求队列 + 后台 worker”的异步结构;
  • 能够从 wait() 的语义出发,分析异步 AI service 为什么必须补上请求所有权、状态查询与一次性结果消费语义,并给出自洽的 submit/query/wait 接口理解。

作业题

与实验二的关系

Hw2 是实验二的配套书面作业。你可以将其理解为实验二的预习与整理任务:先阅读下列材料,完成作业题,再在实验课中继续推进对应的代码阅读与实现。

阅读说明

请在完成本次作业前,务必仔细阅读以下配套阅读材料页面:

上述文档会帮助你把 Transformer、Prefill/DecodeKV Cachellmrun、请求队列、后台 worker、wait/query 语义等概念对应到课程代码和后续接口设计中。

Warning

Hw2 的截止时间请以课程公告或 BB 系统页面为准;提交前请确保自己的答案是基于阅读和理解后独立完成的。

开始答题前请先完成环境准备

本次 Hw2 的题面不再展开环境准备细节。开始答题前,请先阅读并完成 Hw2 环境准备与最小检查

至少请确认以下四件事已经完成:

  • 已切换到课程仓库的 AI 分支;
  • 已下载助教提供的 smol.zip / qwen.zip,并正确放到仓库根目录 models/ 下;
  • 已使用 make qemu-smolmake qemu-qwen 完成至少一次最小运行检查,而不是使用普通的 make qemu
  • 若宿主机需要运行 tools/translate_llm_io.py,已按 Hw2 环境准备与最小检查 中的方法配置好 venv

做 Part 1 前的最小要求

在开始 Part 1 的性能测量前,请至少先完成 Hw2 环境准备与最小检查 中的“模型压缩包下载与放置”“建议先完成一次最小检查”和“宿主机侧 tokenizer 依赖”三节内容。

Part1 题目(30 分)

题目:从系统视角分析 LLM 推理的性能指标与资源压力点

在现代云计算与AI基础设施中,大语言模型(LLM)已被广泛封装为云端API或微服务。对于系统工程师而言,保障LLM推理服务的高效性和稳定性是核心任务。 当我们向用户提供LLM服务时,通常会受到严格的服务级别目标(SLO, Service Level Objectives)限制。用户的体验不仅取决于模型有多“聪明”,更取决于系统有多“快”。此外,在云原生环境中,为了应对突发的流量洪峰,系统需要动态扩容(水平扩展),这就带来了“冷启动(Cold Start)”问题。

为了评估和优化这些系统表现,我们需要关注以下几个核心的服务指标(Serving Metrics):

  • 模型加载时间 (Model Loading Time):将模型权重(Weights)从持久化存储(如硬盘)加载到内存(DRAM)的总耗时。这是决定模型实例冷启动开销的核心部分。

  • 首 Token 延迟 (Time To First Token, TTFT):从系统接收到用户的请求,到模型生成并返回第一个 Token 所经历的时间。这主要包含了处理用户输入(Prompt)的 Prefill 阶段的开销,直接决定了用户的“等待响应”体验。

  • 每个输出 Token 的时间 (Time Per Output Token, TPOT):在生成第一个 Token 之后,后续每个 Token 生成的平均耗时。这对应了模型的 Decode 阶段,反映了模型持续输出内容的速度。

任务A:基础性能剖析

请运行 SmolLM2-135M 模型进行推理,完成以下三个步骤:

  1. 说明测量机制: 阅读第一部分的文档,结合仓库代码中的提示,在报告中明确指出你的测量起点和终点。例如:你是如何设置代码来单独提取 TTFTTPOT 的?

  2. 开展变长负载测试: 分别改变输入 prompt 长度与输出长度,测量上述三个核心指标的变化。建议至少设置三组不同长度的测试用例(例如:短输入输出 8 tokens,中等长度 16 tokens,长序列 32 tokens)。要求用表格或折线图的形式清晰整理数据。

  3. 定位系统瓶颈: 结合 PrefillDecodeKV Cache 与冷启动等底层机制,根据你的实验数据回答:

    • 哪些指标主要受输入长度影响?哪些指标主要受输出长度影响?

    • 这些耗时变化中,哪些阶段反映的是系统的计算压力,哪些变化更接近访存(内存带宽)压力?请给出你的判断依据。

任务B:跨架构规模的对比

在完成任务A的基础上,引入参数规模更大的 Qwen3.5-0.8B 模型进行性能测试,完成以下两个步骤:

  1. 跨模型基准对比:在相同的硬件环境下,分别获取 Qwen3.5-0.8B 短/中/长序列的数据,并横向比较它和 SmolLM2-135MModel Loading TimeTTFTTPOT 上的差异。

  2. 架构差异与性能映射 :请查阅这两个模型的相关资料或代码配置,对比它们的关键维度差异(如:模型整体参数量、Transformer 层数、隐藏层维度 Hidden Size 等)。

    • 结合这些具体差异,解释为什么它们会以不同程度影响模型加载时间、TTFT 和 TPOT?
    • 提示:可以从模型权重对 I/O 的负担、矩阵乘法维度对算力的需求等角度展开说明。

实验环境提示

本次实验在单核CPU环境下运行,由于单核算力与内存带宽受限,大模型的推理耗时可能会较长,这是正常的现象。请耐心等待测量结果,并确保在测量过程中没有其他资源密集型任务干扰。

Part 2 题目(35 分)

题目:为什么 AI service 会从“用户态直跑”演化成“请求队列 + 后台 worker”

请结合 Part 2 阅读材料,假设后续实验会把当前这条用户态推理路径进一步封装成:

int ai_submit(const uint32 *tokens, int token_count, int predict_count);
int ai_wait(int reqid, char *out, int out_cap);
int ai_query(int reqid, struct ai_status *st);

作答说明

这是一道设计分析题。你给出的结构不要求与代码完全一致,但必须满足下面三点:

  • 能从当前 llmrunpipe 和进程机制自然推导出来
  • 请求槽、队列、worker、wait/query 之间的职责划分清楚
  • 阻塞点、唤醒条件和结果取回语义前后一致

作答时以抓住主线为准,不要求把阅读材料中的所有细节全部展开。

请完成下面三个小任务。

任务 A:画异步服务结构图

画一张 producer-consumer 结构图,至少包含:

  • 调用进程
  • ai_submit
  • 请求缓冲区
  • 后台 ai_daemon 或 worker
  • ai_wait

要求:

  • 明确谁是 producer,谁是 consumer
  • 明确哪个对象承担“排队”作用
  • 明确结果是在哪里等待、在哪里取回
  • 你可以把“请求槽 + 循环队列”合并画成一个总框,但图中必须标明:谁负责存放请求信息,谁负责排队
  • 图可以用手绘、PPT 框图或 ASCII 框图表示

任务 B:指出一类典型阻塞点

结合 sleep() / wakeup()pipe 的阅读,任选 一类 典型阻塞点展开说明,并分别回答:

  1. 是谁在阻塞
  2. 它在等什么条件
  3. 谁会负责唤醒它

可以从下面这些方向中任选其一:

  • 队列空,worker 无事可做
  • 槽位满,新的提交无法进入
  • 请求未完成,调用者在 wait 中等待

如果你愿意,也可以额外用 1-2 句话再点出另一类阻塞点,但不作为必做要求。

任务 C:解释为什么 AI 更适合异步

用不超过 200 字,或 2-3 条要点回答:

  1. 为什么“把 AI 推理直接塞进一次同步调用”不是长期服务的好结构
  2. 为什么“submit + 后台 worker + wait/query”更适合 AI 这类负载
  3. 回答中至少提到下面关键词中的 一个
  4. 复用
  5. 解耦
  6. 排队
  7. 背压
  8. 长驻

Part 3 题目(35 分)

题目:为什么异步 AI service 必须补上所有权、状态查询和一次性结果消费语义

请结合 Part 3 阅读材料,完成下面三个小任务。

作答说明

这是一道语义设计题。只要你的字段选择、状态划分和 wait/query 语义是自洽的,就可以视为合理答案;不要求逐字一致。

作答时以“最小可行语义”为准,不要求穷举所有边界情况。

任务 A:设计最小状态信息

请分别给出你认为最小可行的:

  • ai_request 元数据字段
  • ai_status 对外可见字段

要求:

  • 不要求写成完整 C 结构体
  • 只需按“字段名 + 一句话用途”的形式列出
  • ai_request 建议写 3-4 个字段,ai_status 建议写 2-3 个字段
  • 两组字段合计建议控制在 6 个以内;如果你认为需要更多字段,请说明其必要性
  • 字段名可以直接沿用阅读材料中的示意,也可以自行命名

任务 B:用 wait() 类比说明语义

结合 kernel/core/proc.cwait() 的行为,用不超过 200 字说明:

  1. 为什么一个 AI 请求必须记录“属于谁”
  2. 为什么“知道 reqid”不等于“有权限 wait/query
  3. 为什么一个请求完成后,结果被成功取走一次就应该回收,而不是永久保留

任务 C:填写语义表

请补全下面场景的期望行为理由

场景 期望行为 理由
提交者在请求尚未完成时调用 ai_query(reqid, st)
提交者在请求完成后第一次调用 ai_wait(reqid, out, cap)
同一个提交者第二次对同一 reqid 调用 ai_wait(...)
其他进程或子进程拿到这个 reqid 后调用 ai_query(...)