生产工程
用评测、可观测性、部署与证据证明系统在真实约束下可靠。
如何证明系统可靠,并完成部署、作品集和面试表达?概念校准
Agent
- 它是什么
- 围绕目标和状态,在约束下选择动作、执行、观察并验证结果的运行系统。
- 它不是什么
- 不是独立人格,也不是把模型放进无限循环。
Harness
- 它是什么
- 承载模型、工具、状态、权限、日志、预算、人工确认和恢复的运行控制环境。
- 它不是什么
- 它能限制风险并保留证据,但不能直接阻止模型产生幻觉。
验证与评测
- 它是什么
- 用测试、Schema、引用、状态和验收规则检查单次结果,并用数据集衡量系统表现。
- 它不是什么
- 不等于让模型对自己的输出再给一次意见;验证必须落到外部可检查证据。
可观测性
- 它是什么
- 通过结构化日志、Trace、指标和版本信息解释系统在一次运行中发生了什么。
- 它不是什么
- 不只是保存终端输出;没有关联 ID、状态转换和敏感信息边界的日志难以诊断。
面试、系统设计与行业判断
用 Forge 的代码、日志、评测和失败证据练习项目表达与系统设计。
Python 3.12 · pytest · Pydantic · SQLite · deterministic Mock概念校准\n\n在开始操作代码前,先把本章涉及的概念放回正确的工程边界。\n\n\n\n### Agent agent\n\n- 它是什么: 围绕目标和当前状态,在约束下选择动作、执行、观察并验证结果的运行系统。核心运行环是:目标/状态 → 选择动作 → 执行工具 → 观察结果 → 验证 → 停止或重新规划。\n- 它不是什么: 它不是独立人格,也不是让模型无期限循环。模型只是决策组件,动作、权限、状态和停止条件由外部运行环境共同约束。\n- 与相邻概念的关系: Context 提供可见信息,Tool 提供动作,Harness 控制权限和副作用,Verification 判断结果,Planning 只在复杂任务需要时加入。\n- 在 HeatStack Forge 中的位置: Forge 读取任务合同与状态,选择一个受许可动作,记录工具结果,再用测试、Schema 或验收规则决定成功、失败、预算耗尽、重复动作、人工介入或重新规划。\n- 典型误用与修正: 误用是把“模型继续生成”当成进展。修正方法是让每轮产生可观察的状态变化,并为所有停止原因建立确定性检查。\n\n### Harness harness\n\n- 它是什么: 承载模型、工具、状态、权限、日志、预算、人工确认、隔离和恢复的运行控制环境。\n- 它不是什么: 它可以缩小风险、拒绝动作并保留证据,但不能保证模型输出永远正确,也不能代替领域验收。\n- 与相邻概念的关系: Agent Loop 在 Harness 中运行;Tool、Memory 和 MCP 连接受其策略约束;Observability 记录过程,Evaluation 判断行为。\n- 在 HeatStack Forge 中的位置: Forge Harness 管理工作目录、工具、确认队列、预算、Checkpoint、审计日志和回滚,把模型建议与真实副作用分开。\n- 典型误用与修正: 误用是把系统提示词当成安全边界。修正方法是把权限、路径、网络、密钥、预算和回滚落实在模型之外的控制中。\n\n### 验证与评测 evaluation\n\n- 它是什么: Verification 用测试、Schema、引用、状态或验收规则检查一次结果;Evaluation 用数据集和指标衡量多次运行表现。\n- 它不是什么: 它不是让模型对自己的回答再给一次意见;通过与否必须落到外部可检查证据。\n- 与相邻概念的关系: Agent Loop 依赖 Verification 决定停止,RAG 需要分层评测,Planning 需要节点验收,Observability 提供运行记录。\n- 在 HeatStack Forge 中的位置: Forge 为单次运行保存合同测试与 evidence,再用固定场景集比较质量、延迟、成本、权限和恢复能力。\n- 典型误用与修正: 误用是把一个综合分数当成全部结论。修正方法是定义分层指标、失败样本和版本基线,并结合产品风险评审。\n\n### 可观测性 observability\n\n- 它是什么: 通过结构化日志、Trace、指标、状态转换和版本信息解释一次运行发生了什么,并支持定位失败与比较版本。\n- 它不是什么: 它不只是终端输出,也不是无限记录所有输入;缺少关联 ID、状态转换或敏感信息边界的日志既难排查又可能泄露数据。\n- 与相邻概念的关系: Harness 产生运行事件,Agent Loop 与工具调用形成 Trace,Evaluation 聚合指标,Memory 与恢复依赖版本记录。\n- 在 HeatStack Forge 中的位置: Forge 为每次任务生成 operation_id,记录阶段、工具、耗时、成本、错误类别、状态变化和证据路径,同时过滤敏感信息。\n- 典型误用与修正: 误用是等失败后再临时加日志。修正方法是在合同设计时定义事件与关联字段,并用故障注入确认能重建时间线。\n\n
将项目目标、个人行动、结果和证据绑定,避免无法验证的夸大表述
先看一个具体问题
面试项目叙述缺乏可验证证据
你在面试中讲述了一个项目:长任务失败后,你添加了恢复机制,最终恢复率达到 100%。
面试官追问:“这个 100% 是怎么验证的?有代码、测试或日志吗?”你只能口头描述,无法提供任何本地证据。
当前代码库中还没有 forge/interview 包,因此无法用 ProjectClaim 来绑定证据并拒绝无证据的主张。
你需要创建一个 ProjectClaim 数据类,在 validate() 中强制要求至少一个本地不可变证据工件,否则抛出包含 ‘evidence’ 的 ValueError。
先做判断
如果 ProjectClaim.validate() 只检查四个叙述字段是否非空,而忽略 evidence 元组,会发生什么?
- 无证据的主张会被接受,测试
test_claim_without_evidence_is_rejected失败。 - 无证据的主张会被拒绝,测试通过。
- 程序会崩溃,因为
evidence未定义。 - 没有任何影响,因为证据不是必需的。
判断依据: 正确答案是第一个选项。如果 validate() 不检查 evidence,那么空元组 () 也会通过验证,导致测试期望的 ValueError 不会抛出,测试失败。
它是什么
证据绑定的项目主张
ProjectClaim 是一个不可变数据类,将项目叙述的四个部分(situation、task、action、result)与一个证据元组绑定。
validate() 方法执行两条规则:叙述字段必须非空,且证据元组必须至少包含一个本地文件路径。
本地证据路径指向不可变工件,如代码、测试、日志或数据文件,这些工件可以在面试后由面试官检查。
它不是什么
不是流畅的故事或在线链接
它不是一个只包含叙述文本而没有证据的普通数据类;缺少证据的主张会被拒绝。
它不接受网页链接作为证据,因为链接内容可能改变或消失,无法保证不可变性。
它不保证项目结果一定正确,只保证主张有可检查的本地证据支撑。
它与相邻概念的关系
证据与叙述的约束关系
evidence 元组中的每个路径都指向一个本地文件,该文件是叙述中 result 字段所声称成果的证明。
validate() 在叙述字段检查之后检查证据,确保只有完整且有证据的主张才能通过。
测试 test_evidenced_claim_passes 使用 evidence/recovery.json 作为有效证据,而 test_claim_without_evidence_is_rejected 使用空元组验证拒绝逻辑。
本阶段的边界决定: 如果证据元组为空或包含以 ‘http’ 开头的路径,validate() 必须抛出 ValueError;只有本地文件路径才被视为有效证据。
按质量、延迟、成本和模态需求筛选模型,并解释被淘汰方案
先看一个具体问题
从多个候选模型中选出满足所有约束且成本最低的模型
你正在为面试系统设计一个模型路由组件,需要从多个候选模型中选出满足质量、延迟、成本和模态约束且成本最低的模型。
当前代码库中还没有 forge/interview/model_tradeoffs.py 文件,因此测试无法导入 ModelOption 和 choose_model,导致测试收集阶段直接报错。
你需要创建该文件并实现模型选择逻辑,使 test_cheapest_eligible_model_is_selected 和 test_required_modality_is_enforced 两个测试通过。
如果只按成本选择而忽略模态约束,就会在需要图像能力的场景中错误地选择纯文本模型,这正是本阶段要避免的失败。
先做判断
在实现 choose_model 时,如果只按成本最低选择模型,而忽略 required_modalities 约束,会发生什么?
- 测试
test_required_modality_is_enforced会失败,因为选择了不支持图像模态的text-cheap。 - 测试仍然会通过,因为成本最低的模型总是满足所有约束。
- 程序会抛出异常,因为模态约束无法检查。
- 测试会失败,因为
choose_model无法处理多个模型。
判断依据: 正确答案是第一个选项。忽略模态约束会导致在需要图像能力的场景中选择纯文本模型 text-cheap,从而无法通过 test_required_modality_is_enforced。模态约束必须作为硬过滤条件,而不是事后检查。
它是什么
模型权衡矩阵是什么
模型权衡矩阵是一个决策函数,它接收候选模型列表和约束条件,返回满足所有约束且成本最低的模型,并列出被拒绝的模型名称。
它通过硬过滤条件(质量、延迟、成本、模态)缩小候选集,然后在剩余模型中按成本排序选择最优解。
如果没有任何模型满足所有约束,函数会抛出 ValueError,明确表示无法满足需求。
它不是什么
模型权衡矩阵不是什么
它不是简单的成本比较器,不能忽略质量、延迟或模态等维度。
它不是事后检查机制,模态约束必须在过滤阶段就作为硬条件,否则会选出错误模型。
它不保证一定存在满足所有约束的模型,因此需要处理无解的情况。
它与相邻概念的关系
与其他概念的关系
模型权衡矩阵是系统设计中路由决策的一部分,它依赖于 ModelOption 数据类来封装模型属性。
它与验证和评测相关:测试用例通过断言选中的模型名称来验证决策逻辑的正确性。
它与可观测性相关:函数返回被拒绝的模型名称,便于记录和解释决策过程。
本阶段的边界决定: 模型选择必须同时满足质量、延迟、成本和模态约束;任何缺失都会导致错误路由。模态约束必须作为硬过滤条件,而不是事后检查。
从名称、参数、权限和幂等性审查工具 Schema,识别过宽能力
先看一个具体问题
一个看似正常的工具定义为何会隐藏风险?
你正在为面试系统设计模块添加工具设计能力。当前 forge/interview/tool_design.py 文件尚未创建,测试 test_read_tool_has_no_findings 和 test_idempotent_write_requires_key 在导入阶段就会失败。
你需要实现 ToolDesign 数据类和 review_tool 函数,使测试通过。但真正的挑战在于:工具审查不能只检查名称和参数是否一致,还必须考虑副作用语义。
例如,一个幂等的写工具(如 create_issue)如果没有显式的幂等键参数,重复请求可能产生重复副作用。你的审查逻辑必须能发现这种过宽能力。
先做判断
在实现 review_tool 之前,请预测:对于 ToolDesign("create_issue", "Create an issue", ("title",), ("title",), "write", True),审查函数应该返回什么?
- 返回空元组,因为名称和参数都合法。
- 返回包含
"missing-idempotency-key"的元组,因为幂等写工具缺少幂等键。 - 返回包含
"invalid-schema"的元组,因为required_args不是allowed_args的子集。 - 返回包含
"unknown-side-effect"的元组,因为side_effect值不在允许集合中。
判断依据: 正确答案是第二个选项。工具审查必须检查副作用语义:对于幂等的写或破坏性工具,必须显式提供幂等键参数。这个工具是写操作且幂等,但 allowed_args 中没有 idempotency_key,因此应报告缺失幂等键。
它是什么
工具契约审查是什么
工具契约审查是对工具定义的结构和语义进行静态检查,以发现潜在风险。它接收一个 ToolDesign 对象,返回一个发现问题的字符串元组。
审查必须覆盖身份清晰度、参数一致性、副作用类型和幂等键要求。每个检查都是独立的,可以组合产生多个发现。
它不是什么
工具契约审查不是什么
它不是运行时行为验证,不会实际调用工具或检查执行结果。它只基于工具定义本身进行静态分析。
它也不是对工具名称和参数格式的简单一致性检查;副作用语义和幂等性是审查的核心部分。
它与相邻概念的关系
与其他概念的关系
工具契约审查是 Agent 设计中的安全边界:Harness 在执行工具前可以调用审查函数来拒绝过宽能力的工具。
它与验证与评测相关:审查结果可以作为工具是否可用的验证证据,但审查本身不替代运行时验证。
本阶段的边界决定: 工具审查必须考虑副作用语义:对于幂等的写或破坏性工具,必须显式提供幂等键参数。如果缺少幂等键,审查应报告 missing-idempotency-key。
根据召回、引用和拒答指标诊断 RAG,而不是只调整 Prompt
先看一个具体问题
RAG 系统频繁给出无依据回答,却只调整 Prompt
你接手了一个 RAG 问答系统,线上指标显示无依据回答率高达 20%,但团队一直在反复修改 Prompt,问题没有改善。
你需要实现一个诊断函数 diagnose,它接收 RagMetrics(召回率、引用精度、无依据回答率),并返回应采取的改进动作。
当前代码库中还没有 forge/interview/rag_reasoning.py,测试 test_low_recall_points_to_retrieval 和 test_unsupported_answers_require_abstention_gate 因导入失败而无法运行。
你的任务是创建该文件,定义 RagMetrics 数据类和 diagnose 函数,使诊断逻辑能区分检索、引用和拒答三类问题。
先做判断
当 RAG 系统的无依据回答率很高(例如 20%)时,最合理的诊断动作是什么?
- 仅改进检索,提高召回率
- 仅改进引用,提高引用精度
- 添加拒答门控,避免无依据回答
- 保持基线不变,继续观察
判断依据: 无依据回答率高意味着模型在缺乏证据时仍生成答案,仅改进检索或引用无法直接阻止这种行为,必须通过显式的拒答门控来拦截。
它是什么
RAG 诊断模型
RAG 诊断模型将系统问题分解为三个可独立测量的维度:召回率(检索是否找到相关文档)、引用精度(生成内容是否被检索证据支持)、无依据回答率(模型在证据不足时是否仍作答)。
每个维度对应一个明确的改进动作:低召回率指向 improve-retrieval,低引用精度指向 improve-grounding,高无依据回答率指向 add-abstention-gate。
诊断函数 diagnose 根据阈值判断每个维度是否异常,并返回所有需要采取的动作;如果所有指标正常,则返回 hold-baseline。
它不是什么
不是单一 Prompt 调优
RAG 诊断不是只调整 Prompt 的文本表述;Prompt 调优无法修复检索召回不足或引用证据缺失等结构性问题。
它也不是用一个综合分数来代表系统健康度;必须分别检查召回、引用和拒答指标,因为它们的失败模式和修复手段不同。
诊断结果不是模型的主观意见,而是基于可量化指标和固定阈值的确定性规则。
它与相邻概念的关系
指标与动作的映射关系
召回率 recall_at_k 低于 0.8 时,说明检索器没有把相关文档排进前 k 个结果,需要改进检索策略或索引。
引用精度 citation_precision 低于 0.9 时,说明生成内容引用了不相关或错误的文档,需要改进 grounding 或引用校验。
无依据回答率 unsupported_answer_rate 高于 0.05 时,说明模型在证据不足时仍生成答案,需要添加拒答门控,在置信度低时返回“无法回答”。
三个指标相互独立,一个指标异常不代表其他指标异常;诊断函数必须分别检查并累积所有需要的动作。
本阶段的边界决定: 当无依据回答率超过 5% 时,必须添加拒答门控,即使召回率和引用精度都正常;否则系统会持续产生无依据回答,损害用户信任。
将资产、信任边界、威胁和缓解措施建立可追踪映射
先看一个具体问题
为什么只列出威胁还不够?
在面试或系统设计讨论中,你可能会快速列出几条威胁,例如“工具逃逸”或“提示注入”,然后认为威胁模型已经完成。
但如果没有检查这些威胁是否覆盖了所有关键资产,就可能遗漏像 API 密钥这样的重要保护对象。
本阶段要求你实现一个验证函数,它必须确保威胁模型覆盖所有必需资产,否则抛出 ValueError。
当前起始代码中 forge/interview/security_reasoning.py 文件尚未创建,因此测试在导入时就会失败。
先做判断
在实现 validate_threat_model 之前,你认为以下哪种行为是正确的?
- 只要威胁列表非空,就认为威胁模型有效。
- 必须检查每个必需资产是否至少被一个威胁条目覆盖,否则拒绝。
- 只需要检查威胁 ID 是否唯一,资产覆盖不重要。
- 威胁模型应该由人工审查,代码不需要自动验证。
判断依据: 正确选项是第二个:威胁模型必须覆盖所有必需资产。如果遗漏任何资产,验证函数应该抛出 ValueError,因为未覆盖的资产意味着存在未被分析的风险。
它是什么
威胁模型作为覆盖契约
威胁模型是一个从资产到威胁的映射:每个关键资产都必须至少有一条威胁条目描述其风险、边界、缓解措施和验证方式。
validate_threat_model 函数通过比较威胁条目中的资产集合与必需资产集合来强制执行这个契约。
如果存在缺失资产,函数抛出包含缺失资产名称的 ValueError,从而阻止不完整的威胁模型通过。
它不是什么
不是自由形式的威胁列表
威胁模型不是随意列出几条威胁就完事;它必须系统性地覆盖所有需要保护的资产。
仅仅检查威胁 ID 唯一性是不够的,因为即使 ID 不重复,资产覆盖仍然可能不完整。
威胁模型也不是静态文档,它应该能够被代码自动验证,以便在资产集合变化时快速发现遗漏。
它与相邻概念的关系
资产、威胁与验证的关系
资产是需要保护的对象,例如 API 密钥、工作区或文档。
威胁条目通过 asset 字段声明它保护哪个资产,并通过 boundary、mitigation 和 verification 字段描述风险和控制措施。
validate_threat_model 接收威胁元组和必需资产集合,计算已覆盖资产集合,然后找出缺失资产并报告。
本阶段的边界决定: 验证函数只负责检查资产覆盖和基本完整性,不评估威胁描述的质量或缓解措施的有效性;这些需要人工审查或更复杂的分析。
根据流量、并发、延迟和故障域计算容量,并拒绝单副本生产设计
先看一个具体问题
一个单故障域的生产设计被容量计算放行
你正在为面试准备一个系统设计案例:给定峰值流量、平均延迟、目标利用率和故障域数量,计算所需的工作节点数。
初始代码只根据利特尔法则计算并发量并向上取整,完全忽略了故障域数量,导致只有一个故障域的生产设计也能通过容量计算。
测试 test_single_failure_domain_is_rejected 期望当 failure_domains=1 时抛出 ValueError,但当前实现返回了有效的工作节点数,测试失败。
你需要修改 forge/interview/system_design.py 中的 required_workers 函数,使其在故障域不足时拒绝该设计,并确保容量计算正确。
先做判断
在修改代码之前,请预测:如果 required_workers 函数只计算并发量并向上取整,而不检查故障域数量,会发生什么?
- 测试
test_capacity_uses_littles_law会失败,因为容量计算错误。 - 测试
test_single_failure_domain_is_rejected会失败,因为单故障域设计被接受。 - 两个测试都会通过,因为容量计算与故障域无关。
- 两个测试都会失败,因为函数缺少必要的参数。
判断依据: 正确答案是第二个选项。当前实现只关注容量计算,没有检查故障域数量,因此单故障域设计会被接受,导致 test_single_failure_domain_is_rejected 失败。第一个测试仍然通过,因为容量计算本身是正确的。
它是什么
容量规划中的利特尔法则与故障域约束
利特尔法则(Little’s Law)指出,系统中的平均并发请求数等于到达率乘以平均响应时间,即 L = λ × W。
在容量规划中,我们用峰值 RPS 作为到达率,平均延迟作为响应时间,得到并发量,再除以目标利用率得到所需的工作节点数。
故障域(failure domain)是指一个组件或区域发生故障时会影响的范围;生产系统至少需要两个故障域,以避免单点故障。
required_workers 函数必须同时满足容量需求和故障域约束:计算出的工作节点数不能小于故障域数量,且故障域数量至少为 2。
它不是什么
容量计算不是简单的流量除法
容量计算不是只考虑流量和延迟,还必须考虑故障域数量;单故障域设计即使容量计算正确也应被拒绝。
利特尔法则给出的是平均并发量,而不是峰值并发量;实际容量规划需要考虑峰值流量和利用率余量。
故障域数量不是可选的优化参数,而是生产系统的基本要求;缺少故障域约束会导致系统在单点故障时完全不可用。
它与相邻概念的关系
容量、利用率与故障域的关系
容量计算基于利特尔法则:并发量 = 峰值 RPS × 平均延迟,然后除以目标利用率得到所需工作节点数。
故障域约束要求工作节点数至少等于故障域数量,且故障域数量至少为 2;这确保了系统在单个故障域失效时仍能运行。
最终的工作节点数是容量计算值和故障域数量中的较大者,同时满足性能和可用性要求。
本阶段的边界决定: 生产系统设计必须至少有两个故障域;单故障域设计即使容量计算正确也应被拒绝。
按准确性、取舍、证据和沟通分别评分,并生成针对最低维度的改进建议
先看一个具体问题
面试评估不能只给总分
在上一阶段,你已经完成了容量规划,现在要构建一个模拟面试评估模块。
面试官需要按准确性、取舍、证据和沟通四个维度分别打分,并针对最弱维度给出改进建议。
如果评分维度不完整,评估必须被拒绝,否则无法定位面试者的具体短板。
当前代码中还没有 forge/interview/mock_interview.py 文件,测试会因导入失败而报错。
先做判断
如果 evaluate 函数收到一个只包含 correctness 和 communication 两个维度的 InterviewScore,它应该怎么做?
- 计算这两个维度的平均分并返回最弱维度
- 抛出
ValueError,因为评分维度不完整 - 自动补全缺失维度并给默认分
- 返回
None表示无法评估
判断依据: 正确选项是抛出 ValueError。面试评估必须使用固定的四个维度,任何缺失都意味着评估不完整,不能给出分数或建议。
它是什么
结构化面试评估
面试评估是一个函数,它接收一个包含四个维度分数的 InterviewScore 对象,并返回平均分、最弱维度和下一步行动。
四个维度是准确性、取舍、证据和沟通,每个维度都需要一个 1 到 5 的整数分数和一条证据备注。
评估函数首先检查维度完整性,然后检查分数范围,最后检查备注非空,全部通过后才计算最弱维度。
它不是什么
不是随意打分
面试评估不是简单地对现有分数求平均,也不是让模型自己判断表现。
它不能接受缺失维度的分数,也不能忽略证据备注,否则评估结果不可信。
评估结果必须基于外部可检查的规则,而不是主观意见。
它与相邻概念的关系
评估与验证的关系
evaluate 函数是验证机制的一部分,它确保面试评估符合固定的评分维度契约。
InterviewScore 数据类保存分数和备注,evaluate 使用这些数据执行检查并生成结果。
测试用例 test_incomplete_rubric_is_rejected 验证缺失维度时抛出异常,test_complete_rubric_targets_weakest_dimension 验证最弱维度计算正确。
本阶段的边界决定: 面试评估必须使用固定的四个维度:准确性、取舍、证据和沟通;任何缺失都应被拒绝。
完成本章
用真实代码、日志、评测和失败案例回答面试问题。
本地实验自检
- 未开始
- 2阅读中
- 3实验已下载
- 4测试结果已读取
- 5本地自检通过
verification.json 只在当前浏览器中解析,不会上传。这里验证的是实验合同,不是服务器认证或第三方背书。
概念校准与一周复习
三道题检查你是否掌握了本章边界、交付证据和恢复方法。答案只保存在当前浏览器。