model_info、server_info 与在线控制面#

扩展与调试这一节前面已经讲了证据链、watchdog、internal state 和低层控制工具,但还有一层特别贴近真实值班与平台运维的能力,如果不单独收束就很容易被误用:系统对外到底暴露了哪些 introspection endpoint、哪些 live control endpoint,它们分别回答什么问题,又应该按什么风险层级使用。

这个问题不能只靠扫一遍 http_server.py 的路由列表解决。因为这些端点虽然挂在同一个入口文件里,但职责差异极大:

  • 有些只是告诉你系统当前是什么人格,例如 /model_info
  • 有些会把运行时状态大面积打出来,例如 /server_info
  • 有些则会直接改变系统状态,例如 /flush_cache/pause_generation/update_weights_from_*

这章真正要补齐的,就是把这层在线控制面按风险和职责重新分层,让维护者知道什么时候该只看,什么时候才该动手。

先把这层控制面放回一张分层图里#

如果只看路由清单,最容易产生的误解就是:这些端点都是“运维接口”,大差不差。更稳的理解方式,是先把它们放回一条从只读到强控制的梯度里。

flowchart TD
    Info["只读 introspection\n/model_info /server_info /v1/loads"] --> Ops["温和运维动作\n/flush_cache /start_profile /stop_profile"]
    Ops --> Control["强控制动作\nupdate_weights / load_lora / pause_generation / set_internal_state"]
    Control --> Runtime["TokenizerManager / Scheduler / worker state"]

这张图最重要的一点是:这些 endpoint 不是平铺的工具箱,而是一条从“看系统”到“轻度操作系统”再到“直接改系统状态”的递进链。只要这条分层稳住了,线上使用它们时的判断就会稳很多。

/model_info/server_info 看起来都在“查信息”,实际上回答的是两类问题#

这两个端点是最容易被混读的一组。

/model_info 更接近模型人格与能力摘要。它通常回答的是:

  • 当前服务是不是 generation 模型
  • 当前模型有没有图像 / 音频理解能力
  • 当前 model_pathtokenizer_pathweight_version 是什么
  • 模型架构和偏好的 sampling 参数是什么

换句话说,它更像一个“服务此刻对外自我介绍”的端点。

/server_info 则更重。它不仅会触到 tokenizer_manager.get_internal_state(),还会把 server_argsscheduler_info、版本号和更多内部状态拼到一起。它回答的就不再是“这个服务是什么”,而更像“这个服务此刻正处在什么运行态里”。

优秀技术书在这里最该替读者做的一层判断,不是列字段,而是明确边界:

  • 想确认服务“长什么样”,先看 /model_info
  • 想确认服务“现在处在什么状态”,再看 /server_info

deprecated endpoint 值得写进书,不是因为怀旧,而是因为它暴露了运维表面的漂移#

http_server.py 里还保留了一批 deprecated endpoint,比如:

  • /get_model_info
  • /get_server_info
  • /get_load
  • /get_weight_version / /weight_version

把它们写进书里,不是为了给兼容路径做广告,而是为了提醒读者两个现实:

  1. 运维表面本身在演化,不是永远稳定的一组路径
  2. 写值班脚本和平台工具时,应该尽量依赖新入口,而不是倚赖兼容别名

这种提醒特别像一本成熟系统书应有的风格:不仅解释系统当前怎么工作,也提醒哪些边界是会漂移的。

AuthLevel.ADMIN_OPTIONALadmin_api_key 暗示了这层控制面不是“默认全开”#

很多 live control endpoint 会挂 @auth_level(AuthLevel.ADMIN_OPTIONAL),而 HiCache attach / detach 等路径又会显式检查 server_args.admin_api_key。这说明在线控制面本身也分层:

  • 有些能力默认可用,但可以附带管理员语义
  • 有些更强的能力只有在显式配置 admin_api_key 后才应该暴露

这是一种非常典型的 inference runtime 运维设计:

  • introspection 要足够方便,否则现场诊断会很痛苦
  • 危险动作又必须能被收紧,否则运维面会变成另一条攻击面或误操作面

从书稿角度,这种“控制面也有自己的权限人格”特别值得点出来。

flush_cache、profile 和 freeze_gc 更适合被理解成“温和运维动作”#

把这些动作和权重更新、LoRA 或 pause/continue generation 放在一起看,很容易高估或低估它们的风险。更稳的理解是,它们属于中间层:

  • /flush_cache 会改变缓存状态,但不直接改模型语义
  • /start_profile / /stop_profile 会改变采样与证据收集强度
  • freeze_gc 会改变运行时 GC 行为,但更多是诊断和性能实验工具

它们的共同点是:会影响系统行为,却通常不改变“这台服务现在提供什么模型、什么协议、什么会话语义”。因此它们更像温和运维动作,而不是强控制动作。

update_weights_*、LoRA 和 pause_generation 则是另一层东西#

这一组已经不只是“看看系统”或“温和干预”,而是在直接改写系统执行人格:

  • update_weights_from_disk
  • update_weights_from_tensor
  • update_weights_from_distributed
  • update_weights_from_ipc
  • update_weight_version
  • load_lora_adapter
  • unload_lora_adapter
  • pause_generation
  • continue_generation

这些动作会直接改变:

  • 模型参数
  • 请求能否继续前进
  • 当前服务向外暴露的模型能力版本

因此它们更像 live control plane,而不是 debug helper。把它们和前一层明确分开,是这章最重要的工程判断之一。

update_weight_version 和真正换权重为什么不是一回事#

这是一个特别容易在现场被误读的点。update_weight_version 自己就说明得很清楚:它只是更新 server_args.weight_version 这一条事实源,并不等于真正完成一次新权重装载。也就是说:

  • weight_version 更像对外声明版本标签
  • update_weights_from_* 才是在实际改动模型参数

如果把两者混成一回事,就很容易出现“版本号已经变了,但模型行为没有变”的判断偏差。系统书在这里的责任,不是重复接口名,而是帮读者提前识别这种高危误解。

session 与 generation 控制也应算在这层 live control 里#

/open_session/close_session/abort_request/pause_generation/continue_generation 这些端点的共同点是:它们控制的不是静态信息,而是运行中实体的生命周期。

更稳的理解方式是:

  • /open_session / /close_session 控制长寿命上下文实体
  • /abort_request 控制单请求生命周期
  • /pause_generation / /continue_generation 控制更全局的生成推进

这类动作非常像交通控制,而不是信息查询。把它们纳入同一章,是为了让维护者真正把在线控制面看成“操作系统状态”的地方,而不是“补几个 HTTP 接口”的地方。

线上真正出问题时,先碰哪一层端点#

更稳的顺序通常是:

  1. 先查只读 introspection
    例如 /model_info/server_info/v1/loads
  2. 再考虑温和运维动作
    例如 /flush_cache、profile 入口、freeze_gc
  3. 最后才碰强控制动作
    例如 weight / LoRA 更新、set_internal_statepause_generation

这套顺序的价值并不只是“更保守”,而是能明显降低值班现场的二次伤害。你先确认系统是什么状态,再决定要不要真正改它。这正是一本成熟系统书在讲控制面时最该提供的帮助。

最容易出现的四种误判#

第一,误以为所有运维端点都只是“看看”。
实际上很多端点会直接改写系统状态。

第二,误以为 /server_info/model_info 只是粒度不同。
更准确地说,前者是运行时快照,后者是模型与能力摘要。

第三,误以为 weight_version 更新等于换权重成功。
源码已经把两者明确分开。

第四,误以为 control endpoint 越多越方便。
它们越强,越应该按风险级别分层使用。

真正顺着源码读这一层时,更稳的顺序#

建议按下面顺序:

  1. 先看 http_server.py/model_info/server_info
  2. 再看 flush_cache、profile、freeze_gc
  3. 然后看 update_weights_*、LoRA、session、pause/continue 这些强控制入口
  4. 最后再回到 TokenizerManager 对应方法,确认这些请求怎样穿过 communicator 进入 runtime

这样读,你得到的不是一串平铺路由,而是一张按风险与职责分层的控制面地图。

小结#

这一章真正补齐的,是维护层里非常现实的一块在线操作面:只读 introspection 负责告诉你系统现在是什么,温和运维动作负责做可控的运行中调整,而 weight、LoRA、session 和 generation 控制则构成更强的 live control plane。

把这一层讲清之后,扩展与调试部分就不只是在教你“怎么找证据”,也开始教你“什么时候该只看,什么时候才该动手改线上系统”。