全书主线、边界与核心不变量#

这一节负责把全书真正反复回扣的主线钉住。它不会提前展开全部实现,但会说明哪些对象、边界和运行时语义构成了后面章节共享的底板。

这本书写什么,不写什么#

这本书写的是:

  • 请求怎样进入、排队、执行、回包;
  • 这些路径在源码里分别落在哪些对象和文件上;
  • 当系统出问题时,应该先回到哪条主线和哪组证据。

这本书不写的是:

  • 所有模型、所有 backend、所有实验分支的百科式覆盖;
  • 未经验证的性能结论;
  • 把目录结构直接当作架构真相的强断言。

换句话说,这本书追求的是“稳定主线 + 稳定锚点”,不是“覆盖一切可能的局部知识”。

全书反复回扣的主线#

如果把全书压缩成一条最短主线,它其实就是:

  1. 请求怎样进入系统;
  2. 请求怎样被压成运行时对象;
  3. 请求怎样进入 queue、cache、execution;
  4. 结果怎样回到协议表面;
  5. 出了问题以后,证据链怎样重新回到这些对象和边界上。

这条主线之所以重要,是因为它决定了后面的章节顺序:

  • 第二部分先走通请求路径;
  • 第三部分再进入执行核心;
  • 第四部分最后才回到代码导读、观测和维护。

如果没有这条主线,后面的章节就会更像平铺专题,而不像一本系统书。

哪些不变量必须在后文持续成立#

后面无论写哪一章,至少有四条东西应该持续成立。

不变量一:请求对象会变形,但不会失去边界#

请求会一路变化:

  • ChatCompletionRequest
  • GenerateReqInput
  • ReqState
  • TokenizedGenerateReqInput
  • Req
  • ScheduleBatch
  • ForwardBatch

但每一层都必须仍然有明确职责。后文如果把这些对象混着讲,这条不变量就被破坏了。

不变量二:控制面和数据面必须分得开#

session、abort、priority、weight update、logging configuration 这些更像控制面;batch、KV cache、forward、sampling、text delta 则更像数据面。两者会互相影响,但不应该被写成同一个层次的问题。

不变量三:运行时边界比目录边界更重要#

后面不断会出现:

  • TokenizerManager
  • Scheduler
  • DetokenizerManager
  • ModelRunner

这些边界不是因为目录刚好这么分,而是因为运行时真的靠这些边界在推进状态。全书后面必须一直把它们当成正式边界,而不是方便记忆的模块名。

不变量四:观测和证据必须能回到主线#

RequestStageReqTimeStats、request logger、trace、dump、profile、tests 这些内容,后面都不应该变成“独立工具箱”。它们存在的意义,是把排障和维护重新接回请求主线和运行时边界。

读每章时都该反复问的三个问题#

为了把这组不变量真正变成阅读工具,而不是抽象口号,可以把它压成三个固定问题:

  1. 这一章主要保护哪条不变量?
  2. 如果这条不变量被打破,系统会先表现成什么症状?
  3. 哪个源码锚点最能证明这条不变量存在?

只要对每章都能回答这三个问题,整本书就不容易被读散。

为什么这一节必须放在最前面#

如果这些范围和不变量不先说清楚,后面读到某一章时你很容易犯两种错误:

  1. 看到局部细节就把它当成全书中心;
  2. 看到后面的证据链又把它当成新的旁支专题。

把不变量先立起来的好处,是后面每一章都知道自己在护哪一层,不需要临时再给自己找存在理由。

小结#

这一节真正要补齐的,不是更多背景知识,而是后文的共同底板:

  • 这本书的边界在哪里;
  • 全书主线是什么;
  • 哪些不变量必须持续成立。

只要这一层先稳住,后面越往里写,整本书越不容易散。