在客户的环境里构建
在别人的基础设施上,说了算的是他们的约束,不是你的偏好。客户口中“绝不能”发生的规则,不能寄托在一个大多数时候正确的模型上,所以要在模型之外用普通代码来强制执行。然后,构建一个能通过评测、他们的运维人员不靠你也能运行的、最不花哨的系统,并把这两个选择写下来,交给他们的平台团队和模型风险部门签字。
这个阶段为了什么,又会怎样失败
到这一步,这次交付已经有了签字的阈值、一条数据通路、一个模型风险决定,以及一个正在攀升的评测分数。它缺的是一个在客户运行业务的地方跑起来的系统。这个阶段就是要把它造出来:跑在他们的托管环境上,通过他们的身份提供商认证,调用他们批准的端点,经由他们的变更流程上线,并且在供应商的人回家之后依然能用。
地基不由 FDE 选。产品工程师在自己公司选定的基础设施上构建;FDE 则在别人多年前、出于与 AI 无关的理由选定的基础设施上构建。这些约束不是需要绕过去的障碍,它们就是规格。
这个阶段会以三种方式失败,而三者都源于把客户的环境当成一个部署细节。
搬来自己的技术栈。设计默认用上供应商在自家用惯的服务:托管向量数据库、托管编排框架、对公网端点的出站调用。然后客户的平台团队告诉你,这些在他们的网络里一样都没有,于是设计在第二个月推倒重来。
把规则写进提示词。客户有一条绝不能破的规则,团队把它用大写字母写进系统提示词。演示里它守住了,评测里大多数时候也守住了。问题就出在“大多数”。它在生产环境第一次被打破时,你要面对的是客户的风险部门,而不是评测。
没人能运维的花哨设计。团队觉得有意思,就造了一个带工具、记忆和规划器的智能体循环,而其实一次固定输出的模型调用就能过阈值。FDE 在场读追踪记录时它能用;FDE 离开的那一周,就没人能维护它了。
关于证据,先说一句。这是本书证据最单薄的章节之一:没有任何经过测量的研究告诉我们,哪些架构在客户环境里能成功。现有的只有关于 FDE 团队的二手报道(T3)、一家供应商的工程指南和一位前 FDE 的回忆录(都是 T4),以及招聘启事,而招聘启事只能说明雇主要求什么,不能说明工作实际怎么做。本章的论证建立在这些材料之上,并借助 wiki 中的相关页面讲解技术栈,不在这里重复。
合成案例:他们的 VPC,他们的规则,一条平淡的流水线
在这家保险公司的第二、第三个月。年度合同已经签了,上线以分派准确率阈值为门槛,而评测分数还在从 80% 出头往上爬。生产系统必须跑在保险公司的私有云里。平台团队在第一周就发来了条件:工作负载跑在他们的容器平台上,位于他们的 VPC 之内,没有出站互联网;模型调用只能发往模型风险部门批准的区域内端点;每个服务都通过保险公司的身份提供商认证;变更要经过每周一次的变更评审会上线。FDE 的第一版草图原本假定了一个托管向量库和供应商自己的编排框架。两者都不在平台团队的清单上,后来也证明两者都不需要。
规则。理赔总监的规则里有两条没有商量余地:涉诉标记的案件绝不能分到快速队列;某些理赔类型无论文档怎么写,都必须进人工队列。FDE 把这两条完全挡在提示词之外,写成几十行普通代码,在模型之前和之后运行。理赔系统里设置的涉诉标记会推翻任何建议;建议的队列如果不在允许清单里,就直接丢弃。每条规则都有自己的测试,每次变更都要跑,而且必须每次都通过,而不是得分高就行。资深理赔员为评测挑了一个棘手案例:一个未被标记的案件,邮件往来里夹着一封律师函。遇到这种情况,模型可以把案件推向人工队列,但它说什么都不能把案件从人工队列移走。
流水线。生产环境里跑的东西刻意做得很平淡。理赔材料进来,提取文本。一次模型调用以固定格式返回一个队列和一句简短理由,再由规则检查结果。建议落到保险公司团队拥有的那张旁路表里,输入、输出和每一个版本都记入日志。如果端点宕了,或者输出无法解析,案件就进默认的人工队列,也就是交付之前每个案件的去处。没有智能体循环,也没有检索索引。接下来几周的评测工作改的是文本提取、提示词、示例和规则,从不改流水线的形态。在评测缩小差距期间,生产栈以影子模式运行,所以达到阈值之后的上线只是一次配置变更。这一段背后的模式,是 OpenAI 一次与亚太地区汽车制造商的 FDE 交付中报道的确定性硬约束,以及 Anthropic 关于寻找“尽可能简单的方案”的建议。
这一段靠三个选择撑起来。平台团队的条件成了设计说明书。规则离开模型,进入可以测到 100% 的代码,模型只保留“更谨慎”的权力。架构在评测说“够了”的地方停下。
先盘点他们的约束,再动手设计
FDE 构建工作最根本的特征,是代码放在哪里。Gergely Orosz 报道,OpenAI 的 FDE“直接在客户的基础设施上写代码,并为此使用客户的工具”。相比之下,解决方案架构师“很少在客户的基础设施上写代码”(Pragmatic Engineer,2025 年 8 月;T3,基于访谈的二手报道)。在 Palantir 做了七年 FDE 的 Anjor Kanekar“曾驻在航空航天制造商空客的总装线上”,文章还提到,“他的许多 FDE 同事也在类似非常规的环境中工作,包括物理隔离的环境”(T3)。
雇主把同样的期望写进了招聘启事。Sierra 的部署基础设施工程师需要有“在客户自有云环境中管理部署的经历,包括应对安全审查、合规要求和变更管理流程”(招聘启事,2026 年 4 月;T4,证明雇主要求什么,而不是工作实际怎么做)。同一份启事希望找一个“从一开始就考虑升级、回滚、监控和故障模式,而不是事后才想到”的人。这个光谱的最远端,是需要安全许可、驻场且物理隔离的工作,那里的约束是绝对的(见下框)。
公共部门的 FDE 招聘启事要求什么。OpenAI 的前线部署软件工程师(政府方向,2025 年 9 月发布)要求“持有有效的 TS/SCI 安全许可或同等许可”,并熟悉“云部署模式(Azure、AWS)、Kubernetes、Terraform”(招聘启事)。Anthropic 的应用 AI 工程师(公共部门)将“主要在安全的政府设施内,与客户的工程和任务团队一起驻场工作”,要求“持有有效的 TS/SCI 安全许可并通过测谎”,并优先考虑“在物理隔离或涉密环境中部署和运维软件的经验”(招聘启事)。Cohere 的前线部署工程师(基础设施专家,公共部门)是一个常驻渥太华、2026 年 9 月发布的岗位,将“主导 North 在私有云和本地环境中的端到端部署”,要求生产级 Kubernetes 和 Helm 经验,并写明“强烈优先考虑持有有效的绝密级安全许可者”(招聘启事)。就工作实际怎么做而言,三者都是 T4;招聘启事会变更或关闭,引用前请先核对。
大多数交付并不是物理隔离的,但这条经验可以迁移:在画出第一个方框之前,先弄清环境禁止什么。在构建的第一周,请平台团队书面回答七个问题:
- 托管。工作负载能跑在哪里:他们的云账号、他们的容器平台、他们的数据中心,还是供应商托管的租户?由谁开通,要多久?
- 模型端点。模型风险部门批准的是哪个端点,在哪个区域,哪个版本?它变化时会通知谁?如果批准的选项是他们自己托管的模型,wiki 的自托管推理页面讲了这会给构建增加什么。
- 身份。服务和人员通过哪个身份提供商认证,服务身份由谁签发?一把共用的供应商密钥是错误答案。
- 网络。有没有出站互联网访问?有没有代理、白名单、软件包镜像?你的构建到底能不能拉取依赖?
- 数据存储。有哪些现成的存储和队列允许你使用?一个新数据库,就是一样他们必须备份、打补丁和审计的新东西。
- 变更流程。变更怎样进入生产:一条流水线、一个变更评审会,还是一个发布窗口?从合并到运行要多久?
- 运维。出故障时会呼叫谁,他们平时已经在盯着哪些工具?
在写决策记录(10.7 节)的“决定”部分之前,先把这些答案写进它的背景部分。每个答案都会排除一些选项,而这正是目的:一个尊重全部七条约束的设计,通常比你独自画出的那个更小,而且只有它能过变更评审会。如果系统必须运行不可信的输入或代码,wiki 的沙箱与隔离模式讲了可选方案;至于运行其中哪一种,由客户的平台团队决定。
把必须守住的规则放到模型之外
每次交付都会冒出几条绝不能破的规则。涉诉标记的案件绝不进快速队列。超过某个额度的付款总要第二个人审批。关键零部件总要至少有两家供应商。客户会在需求挖掘时把这些规则说出来,划定范围时也常常把它们写成护栏。构建之前,用一个问题从阈值负责人那里拿到完整清单:“哪一种错误答案,是你必须向监管机构、法庭或董事会解释的?”把每个答案写成一句话,包含触发条件、动作和负责人。然后由构建来决定每条规则放在哪里。
记录最充分的现场案例,是 OpenAI 与一家亚太地区汽车制造商的 FDE 交付。ZenML 的 LLMOps 数据库根据对团队负责人 Colin Jarvis 的访谈做了总结(ZenML,2025;T3,对供应商自述的二手总结,没有报告任何结果指标)。团队按一条原则构建了一个供应链智能体:“尽可能使用确定性方法,只在 LLM 的概率性能带来价值的地方使用 LLM。”像“关键零部件(如轮胎)始终保持至少两家供应商”这样的硬约束,“通过确定性代码 100% 地检查,而不是信任 LLM”。模型也不直接优化计划;它“被赋予一个模拟器的访问权限”去探索选项,由代码强制执行限制。这是一个二手的单一案例,没有附带结果:把它当作值得照搬的模式,而不是它有效的证据。
不过,这个道理并不依赖这个案例。模型的输出是一个分布,最好的评测结果也只是一个百分比。客户口中的“绝不能”,是百分比满足不了的,所以它必须放在每次请求都会运行、每次都做同样事情的代码里。实践中,这些代码放在三个位置。
- 模型之前。系统已知的事实直接决定去向,不必问模型。如果理赔系统已经设置了涉诉标记,案件就进涉诉队列,模型的意见要么不请求,要么被忽略。
- 模型之后。输出按固定的 schema 解析,只有允许清单里的值能留下来。规则禁止该理赔类型使用的队列名,会被替换成人工队列。格式不对的答案视同没有答案。
- 动作周围。模型的权限在规则开始的地方结束。在合成案例中,智能体只提建议,由理赔员执行。wiki 的人在回路页面讲了审批放在哪里;当规则多到几十行装不下时,面向智能体的策略即代码讲了规则引擎。
难办的是那种只有模型才能看到触发条件的规则。涉诉标记是一个字段;而未被标记的案件邮件往来里的一封律师函不是。代码读不了这封信,但它可以限制模型读了之后能做什么。只给模型一个方向上的权力:它可以把案件推向谨慎,比如因为某份文档提到了律师,就把理赔送去给人看;但绝不能把案件推离谨慎,既不能清除标记,也不能把被拦下的理赔送进快速通道。一次误报只花理赔员一分钟;一次漏报,正是这条规则要防止的事。在决策记录里,把允许的方向写在规则旁边。
规则要和评测分开测试。评测以百分比报告分派准确率,允许低于 100%。规则测试则是普通的单元测试:每条规则一个用例,加上客户专家点名的边缘情况,任何一个失败,构建就失败。把它们算进评测百分比,会让那一个要紧的失败淹没在几百个无关紧要的失败里。
这也是让安全审查的决定站得住的原因(见安全一章)。写在代码里的规则,审查者可以读、可以测、可以签字。写在提示词里的规则,是要审查者去信任一个分布,而一个谨慎的审查者不会这么做。
构建能通过评测的最不花哨的东西
规则拿出去之后,留给模型的工作通常比预想的小:读一份杂乱的文档,从一个短清单里选一项,给出理由。这种工作很少需要智能体。
Anthropic 的工程指南总结自几十个构建“各行各业的 LLM 智能体”的团队,它也是这么说的:“我们建议找到尽可能简单的方案,只在需要时才增加复杂度”(Anthropic,2024 年 12 月;T4,供应商基于自身客户工作的指南,而不是经过测量的比较)。它建议开发者“从直接使用 LLM API 开始:许多模式只需几行代码就能实现”。它警告说,框架“常常会增加额外的抽象层,遮蔽底层的提示词和响应,使其更难调试”。它也点明了自主性的代价:“智能体的自主特性意味着更高的成本,以及错误不断累积的可能。”
FDE 还多一个理由听从这条建议。你每加一层,客户团队在你离开后就得多弄懂一层,而且是在一个他们装不了你最爱的调试工具的环境里。Nabeel Qureshi 关于 Palantir 的回忆录从另一面说明了这一点。他第一个真正的客户交付是空客,他“搬到图卢兹住了一年,每周四天在工厂里和制造人员一起工作”。软件把“分散的数据来源,包括工单、缺件、质量问题”汇集到一处。他坦率承认这有多普通:“这些都算是基础的软件东西”,然而“仅仅把这些‘最佳实践’界面部署到真实世界,威力就大得惊人”(Qureshi,2024 年 10 月;T4)。他说 A350 的制造节奏提升了“4 倍”,那是一位前员工没有说明方法的回忆,不要把它当作结果转述。有用的是这份坦白:价值来自贴合真实工作流程的基础软件。
用一架梯子,只在评测告诉你需要时才往上爬一级:
- 只用规则。如果代码能根据系统里已有的事实决定一部分案件,就让它决定,只把其余的交给模型。
- 一次固定输出的模型调用。一个提示词、几个示例、一个 schema。大多数分类、提取和分派工作到这里就够了。
- 一条固定的链。按固定顺序进行的几次调用,每一步都能单独检查:先提取,再分类,再检查。当评测的失败类别显示某一环节在出错时,才加一步。
- 一个智能体循环。由模型选择工具和步骤。只有当完成任务的路径确实无法预先知道时才动用它,并且要预料到评测、审计日志和交接都会变得更难。
wiki 的智能体、聊天机器人与工作流页面划出了同样的界线。决定是否往上爬的依据,是评测一章里的失败类别,而不是好奇心。如果分派错误集中在被提取环节弄乱的文档上,就去修提取;规划器帮不上忙。如果客户已经把你需要的系统暴露为工具,MCP 服务器可能是最干净的接口(什么是 MCP),但前提是你所在的那一级里,模型确实在调用工具。
提醒一句。“最不花哨”指的是能通过评测的最不花哨。简单到达不到阈值的设计不叫克制;那是一次代码整洁的失败交付。梯子的存在,是为了让你在数字说该爬时才爬,而不是提前爬。
按他们能自己运行的方式来构建
Qureshi 对这个阶段必须改掉的习惯很坦白:“FDE 往往写那种能快速把事办成的代码,这通常意味着(说得客气点)技术债和取巧的变通办法”(T4)。在客户的环境里,这笔债在你离开那天就成了他们的。五个习惯能让它保持很小。
从第一周起就走他们的流水线上线。如果变更评审会第一次见到这个系统是在上线时,你会把整个上线窗口耗在他们的队列里。尽早把一个无关紧要的东西推过他们的完整路径。在他们网络内部一个镜像生产环境的预发布环境里测试;wiki 的面向智能体的预发布环境页面讲了这个环境需要什么。
锁定每一个版本,并记入日志。模型端点、提示词、示例、规则和代码各有一个版本,每条建议的审计记录都要记下全部版本。当平台团队升级端点时,在变更进入生产之前重跑评测和规则测试。一个你复现不了的分派结果,在模型风险部门面前是辩护不了的。
出错即安全关闭,退回旧流程。任何环节出错(端点超时、输出不符合 schema、规则拒绝了它),案件都去交付之前它去的地方。客户的运营团队本来就知道怎么处理那条路径。退回旧流程,能把一次故障变成慢一点的一天,而不是一起事故。
用他们已经在运行的东西。他们的日志、他们的监控、他们的密钥存储、他们的队列。一个他们还没在运维的组件,就是多一样要交接的东西,也是平台团队多一个说不的理由。
在生产栈上重新测量。试点时的评测数字是在别处测的。请阈值负责人的团队在他们的环境里,把留出集跑过生产部署,确认结果一致之后,才谈上线。文本提取、端点版本或超时上的差异,会在这里暴露,而不是在演示里。
这些对基础设施工程师来说都不新鲜。FDE 的特殊之处在于,要在自己掌控不了的地盘上,为一个将在你之后拥有它的团队做这些事。下一章会把这种所有权变成一项验收测试。
模板:架构决策记录
每个重要决定一份记录,在构建真正采用它之前写好,并由将来要和它一起过日子的人签字。客户的平台负责人签字确认它适合他们的环境;模型风险部门签字确认规则放在了他们批准的位置;FDE 负责人签字确认它能通过评测。把它放在客户的代码仓库里,而不是供应商的。
ARCHITECTURE DECISION RECORD ADR-__ date: ________ Status: proposed | accepted | superseded by ADR-__ 1. CONTEXT (their constraints, in writing from their platform team) Hosting: _______________________________________________ Model endpoint: ____________ region: ________ version: ______ Identity: _______________________________________________ Network/egress: _______________________________________________ Allowed stores: _______________________________________________ Change process: _______________________________________________ On-call owner: _______________________________________________ 2. DECISION (one paragraph) ______________________________________________________________ 3. RULES THAT MUST HOLD (never decided by the model) Rule Enforced where Test - ______________________ before | after ____________ - ______________________ before | after ____________ Rule tests must pass: 100%, on every change Model may move a case toward caution only: Y / N (which rules) 4. WHAT THE MODEL DECIDES Input: ______________ Output schema: ______________________ Allowed values: _______________________________________________ Authority: propose only | act with approval | act 5. OPTIONS CONSIDERED Option Rejected because - ______________________ ___________________________________ - ______________________ ___________________________________ 6. FAILURE BEHAVIOUR Endpoint down / bad output / rule rejects -> ________________ 7. VERSIONS PINNED AND LOGGED PER DECISION model | prompt | examples | rules | code 8. EVAL GATE Held-out set re-run on this stack: ______ matches pilot: Y / N Climb to a more complex design only if: _______________________ 9. REVERSIBILITY How to turn it off: ___________________ Who can: ____________ 10. SIGN-OFF Customer platform owner (fits our environment): ______ date: __ Model risk (rules where approved): ______ date: __ Vendor FDE lead (can clear the eval): ______ date: __
下面是按合成案例填好的版本。按合成案例的规则,每个数字都是区间;真实的记录会写上确切的版本和名字。
ARCHITECTURE DECISION RECORD ADR-03 date: month 2
Status: accepted
1. CONTEXT (their constraints, in writing from their platform team)
Hosting: insurer's container platform, inside their VPC
Model endpoint: approved by model risk region: in-region
version: pinned; change notice from platform
Identity: insurer's identity provider; read-only service
identity issued by IT security
Network/egress: no outbound internet; internal package mirror
Allowed stores: side table owned by claims-platform IT; existing logs
Change process: weekly change board, via insurer's pipeline
On-call owner: insurer platform ops (runtime, after handoff);
claims-platform IT (connector, side table)
2. DECISION (one paragraph)
Route auto FNOL packets with one model call returning a queue
and a reason in a fixed schema. Deterministic rules run before
and after the call. Suggestions go to the side table only; no
agent loop, no retrieval index, no new datastore.
3. RULES THAT MUST HOLD (never decided by the model)
Rule Enforced where Test
- litigation flag set => before + after unit tests,
never the fast queue adjuster edge cases
- listed claim types => before unit tests
always a human queue
- queue not in allowed after schema tests
list => human queue
- counsel named in packet after unit tests,
(model hint) => human attorney-letter case
Rule tests must pass: 100%, on every change
Model may move a case toward caution only: Y (litigation: may
raise a hint; can never clear a flag or pick the fast queue)
4. WHAT THE MODEL DECIDES
Input: extracted packet text Output schema: queue + reason
Allowed values: the auto triage queues the claims director named
Authority: propose only (adjuster acts)
5. OPTIONS CONSIDERED
Option Rejected because
- vendor-hosted service data must stay in insurer VPC
- agent loop + framework eval failures were extraction and
examples, not planning; harder to run
- managed vector store not on platform list; not needed
6. FAILURE BEHAVIOUR
Endpoint down / bad output / rule rejects -> default human
queue (old path)
7. VERSIONS PINNED AND LOGGED PER DECISION
model | prompt | examples | rules | code (in every audit entry)
8. EVAL GATE
Held-out set re-run on this stack: month 2 matches pilot: Y
Climb to a more complex design only if: one failure category
persists that a single call cannot fix
9. REVERSIBILITY
How to turn it off: config flag hides suggestions Who can:
claims ops lead or platform on-call
10. SIGN-OFF
Customer platform owner (fits our environment): yes date: m2
Model risk (rules where approved): yes date: m2
Vendor FDE lead (can clear the eval): yes date: m2
填好的版本里,有两处承担了大部分作用。第 3 节把每一条“绝不能”都放进代码,配上各自的测试,这样评测百分比永远不必承担它;它还用一行话说明,对于只有在文档里才能看到的情况,模型最多能把案件推多远。第 5 节记下了更花哨的选项为什么被否决,这样下一位工程师(可能是客户的人)不会在某个清闲的下午又把它们加回来。
失败信号
这些信号都出现在构建期间,通常在团队之外还没人注意到之前,并且每一个都指向一个解法。
进入下一阶段
当每一项都打上勾,就进入上线与交接:
- 系统运行在客户的环境里,经由他们的流水线部署,使用他们 IT 安全部门签发的身份。
- 每一条必须守住的规则都在模型之外的代码中强制执行,并有每次变更都通过的测试;对于只有模型能看到触发条件的规则,模型只能把案件推向谨慎,绝不能推离。
- 架构决策记录已由客户的平台负责人、模型风险部门和 FDE 负责人签字。
- 每个版本都已锁定,并随每个决定记入日志;退回旧流程的兜底路径已经测试过。
- 留出集在生产栈上重跑的结果与试点结果一致,并由阈值决定是否上线。
如果打破一条规则的结局是投诉、罚款或法庭,它就不该待在提示词里。把它写成审查者读得懂的代码,每次变更都测试它,只让模型在规则留出的空间里工作。模型可以有时出错;规则不可以。