关于 Anthropic 设计文档评审环节的完整指南:这一小时如何进行、阅读方法、两份埋有缺陷的练习文档、按优先级排序的批评意见,以及面试官会追问的后续问题。
作者:前沿部署编辑团队已审阅
本文属于 Anthropic 系统设计题库。该题目是这一环节的代表性题目。练习文档和批评意见为本站原创。
题目描述
这一环节用评审批评取代了从零开始的设计。面试官会分享一份文档,通常几页,有时接近团队实际运行的系统。文档故意带有弱点,其中一些是缺失的内容。你的任务是找出真正重要的问题、说明原因、提出改进方案,然后在面试官追问时为自己的观点辩护。
据反馈,这一环节出现在工程经理面试流程中,如今更常作为资深工程师的系统设计环节。有反馈称 推理 API 题目中的推理服务器曾作为评审对象。
澄清性问题
在开始批评之前先问这些问题。每一个都会改变你对所发现问题的排序方式。
- 这份文档处于什么阶段? 内部工具的 v1 版本可以容忍一些公开上线所不能容忍的捷径。
- 用户是谁,他们最需要什么? 对延迟敏感的用户会把延迟缺陷排在成本缺陷之前。
- 哪些约束是固定的? 如果硬件、供应商或截止日期已定,就在这些约束之内进行批评。
- v1 需要支撑什么规模,一年后呢? 一个现在没问题但在负载达到十倍时会崩溃的设计,与一个今天就已崩溃的设计,是不同性质的问题。
- 是否有它要取代的现有系统? 迁移风险可能是文档中最大的风险。
这一环节难在哪里
有三件事容易让人栽跟头。
首先,一切看起来都像问题。一份故意埋有缺陷的文档有 20 个可以指出的点。把 20 个点都以同等权重说出来,会让面试官认为你无法对风险进行排序。
其次,最严重的缺陷往往是缺失的内容。文档对故障处理、回滚或谁负责值班响应只字未提。只有对照检查清单阅读时,你才会发现这些问题。
第三,这一环节是一场对话。在你提出最初的几个观点后,面试官会挑出其中一个并追问:为什么这很重要,你会怎么做,你的方案代价是什么?一个你无法辩护的批评,比一个你从未提出的批评得分更低。
因此,这一环节的核心张力是覆盖面与判断力之间的权衡。你必须读得足够广以发现缺失的内容,然后只把真正重要的少数发现放在最前面。
flowchart LR R[带着意图阅读]:::svc --> C[带着清单阅读]:::svc C --> L[一长串发现]:::bad L --> K[按影响 x 可能性排序]:::svc K --> T[前三项及修复方案]:::store T --> D[在追问下为观点辩护]:::store classDef svc fill:#f4f1e8,stroke:#315e55,color:#171717; classDef store fill:#fdf3dc,stroke:#c4492d,color:#171717; classDef bad fill:#fbe9e4,stroke:#c4492d,color:#171717;
核心要点。 评分来自排序。先广泛阅读找出缺失之处,然后以少数几个危害最大的发现作为开场。
关键概念
严重程度 = 影响 x 可能性
从两个维度对每个发现排序。发生时有多严重:数据丢失、宕机、错误答案,还是页面缓慢?发生的可能性有多大:每天、高峰期,还是一年一次?可能发生的数据丢失胜过罕见的性能下降。限制整个系统的缺陷胜过单个组件中的缺陷。
| 严重程度 | 示例 | 如何呈现 |
|---|---|---|
| 阻断性 | 常见故障导致数据丢失、硬性吞吐量上限、无法回滚 | 首先提出;要求在上线前做出修改 |
| 重大 | 单点故障、用户之间缺少隔离 | 第二梯队;提出修复方案及其成本 |
| 轻微 | 命名、图表不清晰、路径稍慢 | 简单提及或跳过 |
| 疑问 | 可能是有意为之的设计 | 先提问再批评 |
错误与缺失
错误类发现指向文档中的某句话,并指出它会失败。缺失类发现指向文档从未涉及的主题。两者都很重要。面试官会同时埋下这两类问题,而缺失类问题能区分出优秀的候选人,因为它们需要一份心理清单。
在约束条件内进行批评
如果文档设定了某个约束,例如固定的批处理函数、不使用自动扩缩容,或指定了某个供应商,不要主张移除它,除非它使目标无法实现。从零重新设计系统说明你没有接受问题本身;在限制范围内改进设计说明你能在真实团队中工作。
一条好评论的结构
一条好的评审评论包含三部分:风险、文档中的证据,以及你想要的修改。当修改成本不明显时,要补充说明。
核心要点。 按影响乘以可能性排序,像找错误一样努力找缺失,尊重既定约束,并把每个发现写成风险、证据、修改。
这一小时如何进行
一个典型的时间安排,如果面试官没有设定,你可以主动提出:
| 分钟 | 你做什么 |
|---|---|
| 0 到 5 | 提出上述澄清性问题 |
| 5 到 15 | 阅读:第一遍看意图,第二遍带着清单看 |
| 15 到 17 | 用两句话总结设计 |
| 17 到 30 | 呈现排序后的前三项发现,每项附一个修复方案 |
| 30 到 35 | 列出缺失的内容 |
| 35 到 55 | 追问环节:面试官会针对你的观点深入追问 |
这两句话的总结比看起来更重要。它证明你理解了设计,并且让面试官有机会在你基于它展开之前纠正你的误读。
一种阅读方法
把文档读两遍。
第一遍读意图。它解决什么问题,为谁解决,核心机制是什么?先不要记录缺陷。
第二遍带着清单读。把每一项标记为已覆盖、薄弱或缺失。
| 领域 | 要看什么 |
|---|---|
| 目标与非目标 | 是否说明了成功衡量标准?哪些被明确排除在范围之外? |
| 备选方案 | 是否考虑过其他设计,为什么被否决? |
| 规模与成本 | 有没有数字?数字是否合理? |
| 数据流 | 能否端到端追踪一个请求? |
| 失败模式 | 每个组件宕机、变慢或返回坏数据时会发生什么? |
| 一致性 | 两个操作者会不会产生竞态?有没有东西被重复写入? |
| 隔离 | 一个用户或团队会不会伤害其他用户或团队? |
| 上线与回滚 | 它如何发布,又如何撤销发布? |
| 可观测性 | 测量什么,有什么告警,谁会被呼叫? |
| 安全与隐私 | 谁能读取什么?密钥和用户数据如何处理? |
| 迁移 | 流量如何从旧系统迁移过来? |
大多数刻意埋下的缺失都在失败模式、上线和可观测性方面。
练习文档 1:一个批量推理网关
在阅读点评之前,先计时阅读它。
DESIGN: Batch inference gateway, v1 Goal: serve model M to internal teams through one HTTP endpoint. Design: - Clients POST a request. The gateway pushes it onto one FIFO list in Redis. - A dispatcher wakes every 500 ms, pops up to 32 requests, and sends them as one batch to a free GPU host. - Each GPU host runs one model replica. - Results are written to Redis under the request id. Clients poll GET /result/<id> once per second. Scaling: on-call adds GPU hosts by hand when the queue passes 1,000. Rollout: new model versions go to all hosts at once, on Saturday. Monitoring: a dashboard of GPU utilization per host.
两句话总结:网关把请求排入一个 Redis 列表,由定时器驱动的调度器把最多 32 个请求组成批次发送到空闲的 GPU 主机。客户端轮询 Redis 获取结果,扩容靠手动,新版本一次性部署到所有主机。
flowchart LR C([Clients]):::user -->|POST| G[Gateway]:::svc --> Q[(Redis FIFO list)]:::store T((500 ms tick)):::bad --> D[Dispatcher]:::svc Q --> D -->|batch of up to 32| H[GPU hosts]:::store H --> RS[(Redis results)]:::store C -->|poll every 1 s| RS classDef user fill:#e6efec,stroke:#315e55,color:#171717; classDef svc fill:#f4f1e8,stroke:#315e55,color:#171717; classDef store fill:#fdf3dc,stroke:#c4492d,color:#171717; classDef bad fill:#fbe9e4,stroke:#c4492d,color:#171717;
排序后的点评
4.1 阻塞性问题:定时器限制了吞吐量并增加了延迟
风险。 调度只在 500 毫秒的节拍上进行,每次 32 个请求。也就是说,无论有多少台 GPU 主机,每秒最多只有 64 个请求。而且每个请求在到达 GPU 之前都要等待最多 500 毫秒,即使系统空闲也是如此。
证据。 “调度器每 500 毫秒唤醒一次,最多取出 32 个请求。”
修改建议。 当批次达到大小上限,或最老的请求已等待超过一个较短的超时时间时(以先到者为准),就刷新该批次;并且只要有 GPU 空闲就立即调度。超时机制在低负载时限制了延迟,大小触发机制在高负载时消除了吞吐量上限。
这一点之所以排在首位,是因为它限制了整个系统。在这一点改变之前,增加主机(即文档中的扩容方案)毫无作用。
flowchart LR
subgraph Before["Before: fixed tick"]
direction LR
T1((every 500 ms)):::bad --> P1[pop 32]:::svc
end
subgraph After["After: size or timeout"]
direction LR
Q2[(queue)]:::store --> F{32 queued OR<br/>oldest waited 50 ms?}:::svc
F -->|yes| P2[dispatch to any free GPU]:::svc
end
classDef svc fill:#f4f1e8,stroke:#315e55,color:#171717;
classDef store fill:#fdf3dc,stroke:#c4492d,color:#171717;
classDef bad fill:#fbe9e4,stroke:#c4492d,color:#171717;4.2 重大问题:单一 FIFO 列表让一个团队饿死其他团队
风险。 某个团队的一个批量任务填满列表,排在后面的所有交互式调用方都要等待数分钟。
证据。 “网关将其推入一个 FIFO 列表。”
修改建议。 每个团队或每个优先级类别各设一个队列,采用加权公平调度来消费,并在网关处加上每团队配额。询问作者是否有调用方是交互式的,答案决定了优先级需要多严格。
4.3 重大问题:一次性全量上线,没有回滚方案
风险。 一个有问题的模型版本同时到达所有主机。文档没有说明任何回退方式,而且周六出问题时在场的员工更少。
证据。 “新模型版本在周六一次性推送到所有主机。”
修改建议。 先在少数几台主机上进行金丝雀发布,对比错误率、延迟和输出校验与旧版本的差异,然后分阶段逐步推进。将旧权重保留在磁盘上,使回滚只需一次重启。用就绪检查来控制流量,确认正确的版本已加载。改在工作日发布。
4.4 缺失的内容
- 故障处理。 当某个批次运行途中其 GPU 主机宕机时会发生什么?没有任何机制将其重新入队,这些请求会永远挂起。
- 单点故障。 Redis 同时保存队列和结果。如果它在没有持久化的情况下重启,所有排队的请求和未读取的结果都会消失。
- 幂等性。 客户端超时后重试,会创建第二个请求和第二次 GPU 运行。
- 容量测算。 没有请求速率、没有延迟目标、没有 GPU 数量。
- 有用的监控。 GPU 利用率无法反映用户的痛苦。队列等待时间、p95 延迟、错误率和每团队用量才能。
- 结果过期。 没有任何机制删除结果,Redis 内存会不断增长直到崩溃。
4.5 提问,而非批评
手动扩缩容和一秒轮询对于内部 v1 来说可能是有意为之。先问清楚。如果流量不大且调用方是批处理任务,轮询构建成本低,运行起来也没问题。可以说你接受 v1 采用这种方案,并指出它会出问题的临界点:轮询负载随等待客户端数量增长,一秒一次的轮询会累积最多一秒的延迟。这样的回答体现了判断力。为一个批处理工具强求服务器推送事件则不然。
区分回答优劣的关键:第一轮点评
弱:一份平铺直叙的清单
二十个等权重的要点,从命名和图表开始。没有排序,没有修复建议,也没有指出缺失的内容。
好:有排序的发现及修复建议
以 tick 上限开头,然后是饥饿问题和上线问题,每条都有证据和改进建议,最后列出缺失的主题。
强:有排序、有成本估算、有分寸
解释为什么 tick 上限排在所有问题之前(它限制了系统容量并破坏了扩容计划),区分阻塞问题和重大问题,在批评 v1 的有意设计之前先提问,并说明每项修复的成本。
面试官主导的追问
5.1 “为什么不直接把 tick 缩短到 50 毫秒?”
在继续阅读之前。 这看起来是个简单的修复。会出什么问题?
50 毫秒的 tick 将上限提高到每秒 640 个请求,并降低了空闲时的延迟。但在低负载时它仍会发送半空的批次,而在高负载时,队列在 tick 时刻仍可能积压超过 32 个请求,导致请求多等几个 tick。更重要的是,tick 仍然忽略 GPU 的可用性。它可能在没有空闲 GPU 时弹出批次。大小或超时触发机制结合基于 GPU 可用性的分发,能同时适应两种负载状态。可以说更短的 tick 是本周内不错的权宜之计,而触发机制才是真正的修复。
5.2 “作者说 Redis 足够可靠。反驳还是接受?”
先问“足够”是什么意思。如果 Redis 重启时丢失排队请求是可以接受的,因为客户端会重试,那就接受它,并要求客户端使用幂等键进行重试。如果不可接受,修复成本也不高:开启仅追加持久化,并运行一个带故障转移的副本。要展示出当修复成本超过损失时,你可以接受风险。对每个问题都据理力争的评审者会失去信任。
5.3 “你怎么知道修复起作用了?”
给出修复前后的指标。p50 和 p95 的队列等待时间。批次填充率:每批请求数除以 32。每台主机的 GPU 忙碌时间。饱和时的每秒请求数。大小或超时的改动应将饱和吞吐量提升到大约 主机数 × 32 / 批处理时间,并将空闲时的延迟降低到超时值。
5.4 “v2 你会要求什么?”
每个团队的配额和优先级队列。基于队列等待时间的自动扩缩容。为交互式调用方提供服务器推送事件。模型版本的灰度发布流水线。按优先级顺序列出它们,并说明你会先为哪一项投入资源。这正是 EM 面试环节中该轮次所寻找的管理者层面的信号。
区分回答优劣的关键:追问
弱:对每个问题都同等辩护
把每条反驳都当作攻击,并主张那些成本超过价值的修复。
良好:守住重要问题,让步小问题
坚持把 tick 上限和回滚列为必须修复项,同时接受合理的 v1 简化方案。
强:把发现转化为计划
指出能证明每项修复的指标,按影响排序 v2 工作,并说明其成本。
练习文档 2:一个用量计量管道
第二份文档,属于不同领域,供你练习。先阅读它并写下你的前三条发现,再继续往下读。
DESIGN: Token usage metering, v1 Goal: bill customers for tokens used, daily. Design: - Each API server keeps an in-memory counter per API key. - Every 60 seconds, each server writes its counters to the usage table with INSERT ... ON CONFLICT (api_key, minute) DO UPDATE SET tokens = <server's count>. - At midnight UTC a job sums the usage table per key and sends invoices. Scale: 200 API servers, 50,000 active keys. Monitoring: the job emails the team if it fails.
6.1 点评
阻断级:upsert 会覆盖其他服务器的计数。 每台服务器都写入同一行 (key, minute),并且
SET tokens = <server's count>
会替换该值。在 200 台服务器的情况下,该行最终保留的是最后写入的服务器的值,因此用量最多会被少计 200 倍。修改:按 (key, minute, server) 作为行的键,或使用
tokens = tokens + excluded.tokens
带幂等批次 ID,这样重试的写入不会重复计数。
阻断级:服务器崩溃会丢失最多 60 秒的用量。 计数器只存在于内存中。修改:在请求完成时将用量事件写入持久化日志,并从日志聚合。该日志还能为计费争议提供审计线索。
重大:没有对账。 没有任何机制检查计费用量与 API 实际服务的用量是否一致。修改:将每日总量与独立来源(如请求日志)进行比对,并在差异超过阈值时告警。
缺失: 刷新的重试与幂等性、午夜之后的迟到数据、按本地日期计费客户的时区问题,以及对计数本身的监控,而不仅仅是任务失败。
flowchart LR
subgraph Doc["As written"]
direction LR
S1[Server 1: 40]:::svc --> U[(row key+minute<br/>SET tokens = count)]:::bad
S2[Server 2: 55]:::svc --> U
end
subgraph Fix["Fixed"]
direction LR
E[usage events per request]:::svc --> L[(durable log)]:::store --> A[aggregate by key+minute]:::store
end
classDef svc fill:#f4f1e8,stroke:#315e55,color:#171717;
classDef store fill:#fdf3dc,stroke:#c4492d,color:#171717;
classDef bad fill:#fbe9e4,stroke:#c4492d,color:#171717;这里的经验可以推广:阻断级发现是一个藏在一行 SQL 里的正确性 bug。逐条检查每个写入路径是否存在竞态和覆盖。
6.2 练习文档 3:一个模型上线管道
第三份文档,更贴近基础设施。先阅读它并在继续阅读前写下你排序后的前三条发现。
设计:模型发布流水线 v1 目标:安全地将新模型版本发布到服务集群。设计:- 发布管理员在注册表中将某个模型版本标记为“已批准”。- 控制器每 5 分钟轮询一次注册表。当发现新的已批准版本时,它将集群配置更新为新版本。- 每台服务主机监听集群配置。配置变更时,主机停止服务,从注册表存储桶下载新权重,加载后重新开始服务。- 如果超过 5% 的请求失败持续 10 分钟,值班工程师将集群配置回滚到上一个版本。规模:400 台服务主机,权重为 300 GB。监控:请求错误率仪表板。
两句话总结:注册表中的批准操作触发控制器切换一个集群级配置,每台主机独立地在变更时重新加载。回滚是手动的,在错误率升高持续 10 分钟之后进行。
flowchart LR RM[发布管理员]:::user -->|批准| REG[(注册表)]:::store CTRL[控制器,5 分钟轮询]:::svc --> REG CTRL -->|切换版本| CFG[(集群配置)]:::bad CFG --> H1[主机 1:停止、下载、加载]:::svc CFG --> H2[主机 400:停止、下载、加载]:::svc H1 --> B[(权重存储桶)]:::store H2 --> B classDef user fill:#e6efec,stroke:#315e55,color:#171717; classDef svc fill:#f4f1e8,stroke:#315e55,color:#171717; classDef store fill:#fdf3dc,stroke:#c4492d,color:#171717; classDef bad fill:#fbe9e4,stroke:#c4492d,color:#171717;
6.3 对文档 3 的评审
阻断性问题:所有主机同时停止服务。 一次配置切换会让全部 400 台主机在同一时刻停止、下载并重新加载。在整个重新加载期间,集群不提供任何服务:每次发布都会造成一次全面中断。改进:分批滚动发布,例如每次 5% 的主机,并且只有在替换容量就绪后才将主机移出轮换。
阻断性问题:400 台主机同时从一个存储桶拉取 300 GB。 这相当于同时从一个源拉取 120 TB。即使该存储桶能提供 100 GB/s 的聚合带宽(这已经很慷慨了),仅下载就需要 20 分钟,期间没有任何服务。改进:分批发布可减少并发拉取,点对点分发可消除源瓶颈(参见模型权重分发)。更好的做法是先下载再停止:主机在继续服务旧权重的同时获取并校验新权重。
重大问题:回滚缓慢且依赖人工。 在人工介入之前,整个集群要承受 10 分钟的 5% 错误率,然后还需要一次完整的重新加载才能回退。改进:先进行金丝雀发布,自动在错误率、延迟和输出质量检查上与旧版本对比,无需人工介入即可停止发布。将旧权重保留在本地磁盘上,使回滚只需一次重启,而不是重新下载。
缺失项: 主机接流量前的就绪检查;通过哈希校验下载的权重;批准前的评测门禁;控制器在发布中途崩溃时会发生什么;以及错误率之外的监控,例如延迟和质量指标——劣质模型可以在不报错的情况下使这些指标恶化。
经验教训:当两个发现都是阻塞项时,先讲用户最先感受到的那个。这里全集群停机在每次发布时都可见;而桶瓶颈只是让它持续更久。
6.4 处理分歧
继续阅读之前。 你说发布需要金丝雀。作者说金丝雀会把发布周期从一天拖到三天。你会如何回应?
针对成本进行讨论,而不是重复风险。询问发布引发事故的频率,以及这些事故持续了多久。然后提出一个能解决大部分风险的更小改动:在 5% 的主机上进行 30 分钟的自动化金丝雀,增加的时间不到一小时,而不是两天。建议金丝雀自动运行,只有当指标回退时才呼叫人工。
如果作者仍然不同意,就把风险和决定记录在文档中。评审者的职责是让权衡清晰可见、让决定是有意为之,而不是赢得争论。面试官,尤其是在经理轮次中,恰恰关注这一点:对风险立场坚定,对补救措施保持灵活,并明确由谁来做决定。
区分答案水平的关键:分歧
弱:更大声地重复反对意见
只是复述风险,没有针对作者的成本进行讨论。
良好:提出更便宜的补救措施
在作者的约束下,找到一个能解决大部分风险的更小改动。
强:把决定明确化
量化双方,提供带成本的选项,并把选定的权衡及其负责人记录在文档中。
变体
7.1 工程经理轮次
在 EM 轮次中,这一轮取代编码,与执行力和领导力轮次并列。流程方面会占更大权重:谁来评审这份文档、团队会如何分阶段推进工作、批准前你会要求作者改什么,以及你会如何处理持不同意见的作者。把发现表述成你会留给同事的一条评审意见,并附上一个简短计划:什么阻塞批准,什么可以放到 v2 再做。
7.2 固定约束
文档可能声明批处理是固定的、自动扩缩不可用、限流不在范围内。把这些当作事实。在约束之内批评调度和整理层。如果某个约束确实使目标无法实现,用数据说明一次,然后继续。
7.3 承压表达
有些面试官很少给提示,只有当你说到他们想要的点时才会跟进。沉默不是让你停止的信号。继续提出具体的机制,并出声核对检查清单,直到面试官有所回应。
7.4 评审一份你部分不同意的文档
有时设计本身是合理的,只是你会用不同的方式来做。简单说明一下然后继续:"这里我会用队列,但作者的方法在这个规模下是可行的;不构成阻碍。" 能把品味与风险区分开来,本身就是一种很强的信号。把面试时间花在能改变结果的发现上。
7.5 一份没有明显缺陷的文档
如果你没有发现阻碍性问题,就明确说出来,然后深入探讨最有可能在生产环境中出问题的部分:故障模式、上线发布和可观测性。询问团队上一次事故是什么,并检查该设计是否能发现它。为了凑时间而编造问题的评审者会失去可信度。
可迁移的模式
设计评审是在不确定性下进行风险排序。同样的技能也适用于代码评审、事故复盘和供应商评估:带着意图去读,对照清单去读,按影响和可能性对发现进行排序,把每一条写成风险、证据、变更,并区分哪些是阻碍、哪些可以等待。清单是可复用的资产。根据第 2 节中的表格建立你自己的清单,并在每次经历真实事故后加以扩展。
回顾:30 秒答案
- 先做总结。 两句话证明你理解了这份设计。
- 排序。 把会限制或击垮整个系统的发现放在最前面。
- 寻找缺失。 故障处理、上线发布和可观测性是埋设缺口的地方。
- 尊重约束。 在文档限定的范围内进行批评。
- 坚持或让步。 坚持阻碍性要点,让步于廉价的 v1 捷径,并说出能证明每项修复有效的指标。
测验
+为什么一份平铺直叙的正确发现列表得分很低?
这一轮考察的是判断力。平铺直叙的列表说明你能发现问题,但无法判断哪些问题重要。面试官希望看到你先说出会造成最大损害的发现,次要问题简略带过或干脆跳过。
+在实践文档 1 中,为什么调度 tick 的优先级高于单实例 Redis?
这个 tick 在正常负载下每天都会把整个系统的上限卡在每秒 64 个请求,并使扩容计划失效。Redis 的风险是真实的,但依赖于故障发生。影响乘以可能性,tick 排在第一。
+如何处理一个看起来薄弱但可能是刻意为之的选择?
先提问再批评。如果作者确认这是刻意的 v1 捷径,就接受它,并指出它在哪个临界点会失效。这表明你能区分真实风险与合理权衡。
+是什么让用量计量的 upsert 成为一个阻碍性 bug?
每台服务器都写入同一行,而更新是替换值而不是累加。最终计数取决于哪台服务器最后写入。计费会在每一分钟、对每一个 key 都是错的。
+一条好的评审意见有哪三个部分?
风险、文档中的证据,以及你想要的变更。当变更成本不明显时,把它补充上去。
+在实践中,为什么文档 3 中全集群同时切换配置的做法会造成阻塞?
它让每台主机在同一时刻停止、下载并重新加载,因此每次发布期间整个集群都无法提供服务。这相当于每次部署都造成一次故障。
+当作者对成本有异议时,评审者应如何回应?
正面讨论成本问题,提出一个成本更低但能覆盖大部分风险的补救方案;如果分歧仍然存在,则在文档中记录这一权衡以及决策负责人。
参考资料与延伸阅读
- Google 的设计文档介绍了设计文档应涵盖的内容以及评审的运作方式。
- Google 工程实践:代码评审给出了评审者的标准,这些标准同样适用于设计评审。
- 实践文档 1 背后的推理服务器问题在 LLM 推理 API 与 GPU 批处理中有完整的解决方案。
- 快速阅读陌生代码的能力也可以通过代码库与学习练习来训练。