面灵AI→

信锐网科 AI 应用开发一面:推理服务容量、Protobuf 兼容与上下文压缩

轮次
一面
时间
2026-10
来源
牛客网

《面试题目》

  1. 请做一个简短的自我介绍。
  2. 介绍一下你负责的平台,重点讲清楚请求链路和你的职责。
  3. 如果一次性能优化只能选一个环节先做,你会依据什么确定优先级?
  4. 接入层和模型业务服务之间,哪些逻辑适合放在接入层,哪些不适合?
  5. C++ 接入服务调用 Go 推理服务时,你会如何设计调用协议和错误语义?
  6. Protobuf 接口已经有多个版本在生产环境运行,新增字段时怎样避免兼容性事故?
  7. 推理服务的容量如何评估,怎样把压测结果转化为可用的部署规划?
  8. 在 AI 辅助编程工具生成代码后,你会经过哪些环节才允许代码进入生产?
  9. 对话历史超过模型上下文预算时,怎样压缩才能尽量保留后续任务所需信息?

《参考解析》

自我介绍与平台链路

自我介绍不要背简历,半分钟里给三段:一句定位(什么方向、几年、当前在做什么)、一个经得起追问的项目(你的角色、你做的关键决策、可量化的结果)、一句与岗位的对应关系。被要求讲负责的平台时,先按「入口 → 接入层 → 业务服务 → 存储 / 模型」把请求链路口述一遍,再逐层点出你负责的部分和它对外承诺的指标(QPS、P99、错误预算、可用性)。面试官真正想确认的是:你知不知道自己模块在整条链路里的位置、边界,以及它挂掉时的影响面——讲得出故障场景和兜底动作,比罗列技术栈有效得多。

性能优化怎么排序,接入层的边界怎么划

定优先级的前提是先有观测:没有链路追踪、火焰图和分位延迟曲线,排序就只能靠猜。做法是先锚定用户可感知的目标(端到端 P99、超时率、错误预算消耗速度),再用 profiling 把耗时拆到函数和下游调用上,按「对目标指标的贡献 × 证据强度 ÷ 改动与回归风险」排序,一轮只动一个变量。资源利用率要当辅助信号而不是依据:CPU 高可能是有效计算也可能是锁竞争,CPU 低往往是在等下游;更值得盯的是排队长度和利用率曲线的拐点——利用率越过七八成之后延迟开始非线性上涨,这时候加机器解决的是排队而不是计算。改完必须固定流量模型和数据集做同条件对照,同时看下游有没有承接被转移过来的压力。

接入层适合放「对所有业务都成立、且必须统一执行」的横切能力:认证鉴权、配额限流、路由与灰度、超时预算、连接与长连接(SSE / WebSocket)管理、协议转换、统一埋点与日志。模型特有的输入清洗、提示词组装、业务规则、结果后处理、模型路由,则留在模型服务里。判据不是代码位置而是变化原因:会随租户或模型频繁变动的逻辑固化进网关,等于让网关被业务发布节奏绑架,故障域和维护成本一起膨胀;反过来,把统一的鉴权和限流散落到各业务服务,安全和配额就没人兜底。流式响应是容易被忽略的一处——网关若做整包缓冲或压缩,首字延迟会直接被它吃掉。

协议选型、错误语义与 Protobuf 多版本兼容

C++ 接入层调 Go 推理服务,首选 gRPC + Protobuf:HTTP/2 多路复用、跨语言 stub、原生 deadline 与 metadata 传播、双向流都是现成的;如果环境里已有成熟的内部 RPC 框架,优先复用,别为了协议本身再加一层复杂度。接口定义要写语义而不只是结构体——字段含义、单位、可选性、错误码,调用链上透传递减的 deadline、trace ID 与租户标识。错误必须分层:传输层的超时与连接失败、业务层的参数非法与配额拒绝、下游不可用与内部异常,用不同的码表达(gRPC 的 INVALID_ARGUMENT / RESOURCE_EXHAUSTED / DEADLINE_EXCEEDED / UNAVAILABLE / INTERNAL 就是现成的映射),上游才可能区别对待。只对幂等调用重试,且只重试 UNAVAILABLE / DEADLINE_EXCEEDED 这类瞬时错误,配指数退避、抖动和重试预算,避免故障被重试放大;deadline 到期时 Go 侧要能通过 context 取消真正终止推理,否则上游已经超时、下游还在烧 GPU。客户端把错误笼统当可重试、服务端只回一个「失败」,是这条链路最常见的两个坑。

Protobuf 多版本共存,硬规矩只有一条:已发布的字段编号和名字永不改语义、永不复用。新增字段用新编号并给出合理默认行为;删字段要把编号和名字一起 reserved;proto3 的默认值分不清「没传」和「传了零值」,需要区分就上 optional。枚举留旧编号,解析端要容忍未知值。但 schema 兼容只是底线,真正的坑在语义层:字段从可选变必填、单位从秒改毫秒、枚举含义调整,wire 层面全都兼容而业务会错。这类改动要用新字段做双读或双写迁移,先写后读、按天对齐数据,再切读路径。落地手段是 CI 里的向后兼容检查(如 buf breaking)加消费端新旧版本矩阵回归,别只靠人工 review。

推理容量:从流量画像到部署冗余

容量评估的第一步是流量画像:模型与版本、输入输出长度的分布(不是均值)、并发会话数、突发形态和租户分布,不同请求的显存与算力消耗能差一个量级。压测要在目标机型、真实推理配置下加压,记录吞吐、P99、超时率、显存与队列长度,取满足延迟和错误率 SLO 的拐点作为可用区间——把「压到错误率开始上升的最大吞吐」当容量,等于把崩溃点当容量。注意 prefill 与 decode 的瓶颈不同、KV cache 显存决定能塞多大的 batch、continuous batching 会让吞吐随负载变化,所以小规模压测线性外推不可靠。并发量级可以用 Little 定律(并发 ≈ 吞吐 × 平均响应时间)做交叉验证,但它替代不了实测。

部署规划要把冗余和成本一起算:留出故障转移和发布期的余量,按 N+1 配置,并给冷启动、模型加载留时间。过载时主动排队或限流(牺牲一小部分请求换整体延迟)比让所有请求一起变慢划算;再往上配降级阶梯(换小模型、缩短输出、关掉非核心功能),并把容量折算成每千 token 的单位成本,这个数字才能支撑扩不扩容的决策。

AI 生成代码的上线关口与上下文压缩

AI 产出的代码按未验证的候选实现对待,工具输出不是正确性证明。合并前先看 diff 有没有偏离事先确认的设计,再审接口边界、线程安全、资源生命周期、异常路径与安全(注入、越权、密钥硬编码、依赖许可证),然后跑静态检查、类型检查、单测、集成测试和边界用例;涉及并发、内存管理或鉴权的改动额外加代码评审和定向压测。要特别盯 AI 自己写的测试——常与实现同源、断言偏弱,甚至把出问题的分支 mock 掉,所以「测试全绿」之后还要追问测试是谁写的、覆盖了哪些分支。上线走小流量灰度,盯延迟、错误率、资源与下游影响,异常就回滚;敏感代码、密钥和真实用户数据不提交给未获批的外部工具。说到底,AI 改变的是产出速度,不改变「谁签名谁负责」。

上下文超预算时最忌讳从头部硬截断——早期定下的约束和用户偏好往往比最近几轮更值钱。可行做法是分层:系统指令、硬约束、用户明确标记的重要信息设为必保留;最近若干轮保持原文;中段按时间与相关性做摘要或压缩。更关键的是把已经确认的结论外置成结构化状态(任务清单、已确认参数、待办项),让模型按需回查而不是全部压在对话里;历史很长时按当前问题检索召回相关片段,命中率通常高于无差别摘要。摘要必然丢细节,还会多一次模型调用带来误差和延迟,并随轮次累积漂移,所以要给它留 token 预算、用固定模板,并在评测里看压缩后的任务成功率掉了多少,而不只是看省下多少 token。