分类 技术志 下的文章

系统设计的“元素周期表”:40个横跨所有领域的通用设计原则

本文永久链接 – https://tonybai.com/2025/07/31/periodic-table-of-system-design

大家好,我是Tony Bai。

近日,一篇名为《系统设计的元素》(Elements of System Design)的论文引发社区热议。它的目标宏大且吸睛:通过梳理上百篇横跨操作系统、数据库、分布式系统等领域的经典论文,提炼出一套通用的系统设计原则“元素周期表”

这份“周期表”的价值,不在于提供一套死板的规则,而在于为我们提供一套共享的词汇和心智模型。它能帮助我们更清晰地思考、更精确地沟通、更深刻地理解不同系统设计背后的内在联系。

下面便是该论文的中译版,希望能给大家带去启发。


系统设计通常通过特定领域的解决方案来传授,例如数据库、操作系统或计算机体系结构,每个领域都有其自成一派的方法和术语。虽然这种多样性是一种优势,但它也可能掩盖了跨领域反复出现的共通原则。本文提出了一个从计算机系统多个领域中提炼出的系统设计原则的初步分类法。其目标是提供一套共享、简洁的词汇,以帮助学生、研究人员和实践者对系统结构和权衡进行推理,跨领域比较设计,并更清晰地沟通设计选择。

引言

投身于计算机系统领域的一大乐趣在于其纯粹的多样性,它涵盖了操作系统、数据库、计算机体系结构、分布式系统、编程语言、网络等众多分支,每个分支都有着丰富的历史。对于初学者来说,由于传统和词汇的多样性,要发现不同领域之间的联系可能颇具挑战:相同的设计原则可能会以不同的面貌出现在不同的领域中。

例如,思考一下 Jim Gray 等人关于数据库隔离级别的经典论文。它仔细阐述了并发控制机制以及在正确性和性能之间的权衡。然而,如果没有在操作系统或计算机体系结构领域接触过类似问题,这些思想可能看起来仅仅是狭隘地“关于数据库”的。实际上,相同的设计原则,“放宽一致性”,以不同的形式在各种系统中反复出现,从弱顺序内存层次结构到分布式系统中的最终一致性协议。当每个社区都使用自己的术语和范例时,初学者可能很难识别出底层的设计原则。这种碎片化增加了认知开销,因为同一个权衡必须在每个上下文中重新学习。

这是一个更广泛的模式:系统研究富含实践洞见,但在共享的概念性支架上则较为薄弱。在各个领域中,类似的挑战反复出现,如管理并发、确保一致性和适应变化,而其框架和词汇却常常不同。因此,看似毫不相关的领域之间的深层联系可能仍然相对模糊。

本文是朝着弥合这些差距迈出的一小步。借用门捷列夫的比喻,我们提出了一个反复出现的系统设计原则的“元素周期表”。其目标并非一个僵化的分类法,而是一个可用的词汇表:一种用以标注论文、讲座和设计文档中所采用的基本原则的简洁方式。其目的是揭示计算机系统中已经存在的结构,以便学生能形成更连贯的心理地图,研究人员能精确定位其贡献,而实践者能以更高的清晰度跨领域讨论设计选择。

方法论

我们通过回顾操作系统、计算机体系结构、数据库、网络、编程语言、安全以及计算机系统其他领域的 100 多篇有影响力的论文来识别这些原则。这些论文因其历史意义和持续的相关性而被选中,例如关于并发控制 和共识 的经典论文,以及关于在系统内部使用机器学习 和为云设计系统 的近期工作。

对于每篇论文,我们都问:其底层的高层设计原则是什么?在不同领域中,独立的系统常常不是在机制上趋于一致,而是在共享的设计原则上:例如,通过放宽一致性来提高性能,或通过提升抽象来增强可用性。

要被认定为一条系统设计原则,它必须满足两个条件:

  1. 抽象性 – 该原则必须独立于具体的技术或实现。
  2. 通用性 – 该原则必须在不同领域中出现(例如,数据库系统、操作系统、编程语言)。

本分析旨在梳理出许多具有持久、通用价值的原则,而非对所有原则进行编目。

设计原则表

我们整理了一套结构化的、包含 40 多个从系统文献中提炼出的通用设计原则。如下图所示,它们被组织成反映了系统设计中常见维度的不同主题组。

图例: Code = 唯一短符号, Name = 原则名称, Intent = 简短描述。

每个原则都带有一个简短的符号(例如,Co 代表可组合性,Op 代表乐观设计)以便快速参考。我们强调设计意图而非规定具体机制:这些原则阐述的是诸如“在并发下保持正确性”或“优先处理普遍情况”等目标,而不是“使用此锁定协议”或“优化此查询计划”,具体的实现则留给特定领域。

目录

  • Group 1: 结构: 如何用清晰的边界和扩展点来切分和连接组件。
  • Group 2: 效率: 通过将精力集中在有回报的地方,来减少工作或降低成本。
  • Group 3: 语义: 精确地指定行为和接口。
  • Group 4: 分布: 在分布式架构中协调工作和数据。
  • Group 5: 规划: 根据目标、成本和约束自动选择方案。
  • Group 6: 可操作性: 在最小化中断的情况下观察、适应和演进运行中的系统。
  • Group 7: 可靠性: 在故障、并发和部分失效下保持正确性。
  • Group 8: 安全性: 约束权限和强制隔离以保护安全和完整性。

Group 1: 结构

Si – Simplicity (简单性)

选择满足当前需求的最简单的系统设计;抵制复杂性,例如“以防万一”而增加的额外层次、服务或通用性,直到有证据表明其有益。

示例: 避免对系统进行过早的架构优化。

Mo – Modularity (模块化)

将系统划分为具有最小化接口的高内聚单元,以便每个单元都可以被独立地推理、替换或演进。该原则专注于分解:选择边界以促进关注点的清晰分离,使每个职责都位于一个模块内。

示例: OSI 模型将通信分解为具有明确边界的标准化层次,允许独立开发和替换。

Co – Composability (可组合性)

设计可被安全、灵活地重新组合的组件;依赖显式的合约和类型约束的接口,以使每个合法的组合都保持正确,让组件能像可互换的积木一样被组装。与模块化不同,该原则专注于重新组合:确保组件可以安全、灵活地结合。

示例: Unix 程序(如 grep, sort, uniq)从标准输入读取并写入到标准输出,让用户可以组合复杂的文本处理管道。

Ex – Extensibility (可扩展性)

设计系统以允许安全的用户自定义扩展,例如插件,而无需修改系统核心。当扩展来自不受信任方时,通过沙箱进行隔离以保护安全。

示例: Unix 也体现了可扩展性:用户可以添加新程序而无需更改内核。

Pm – Policy/Mechanism Separation (策略与机制分离)

通过暴露一个通用接口,将“应该做什么”(策略)与“如何执行”(机制)分离开来,使得多种策略可以插入到同一个机制中。

示例: Hydra 拥有一个通用机制的内核(调度、分页、保护),并将资源分配策略移至用户级模块。

Gr – Generalized Design (通用化设计)

设计一个具有明确变化点(如类型、可调参数或插件)的单一核心,使其可以在不产生重复的情况下服务于多种用例,但当特化能带来性能、准确性或清晰度的显著提升时,则进行特化。

示例: C++ 标准模板库是一组通过模板参数化的容器、迭代器和算法的集合。Postgres 允许用户向核心数据库系统添加类型和操作符。

Group 2: 效率

Sc – Scalability (可伸缩性)

设计系统以应对数据、流量或节点的增长,同时保持成本或延迟的近线性增长。

示例: MapReduce 通过将工作分解为并行任务并以最小的协调来聚合结果,从而在节点间进行扩展。

Rc – Reuse of Computation (计算复用)

通过缓存、物化中间结果(例如索引),或在重复或稍作修改的输入上增量更新输出来避免冗余工作,从而节省计算。

示例: B+树复用其已排序的键顺序:查找遵循现有的搜索路径,而不是每次重新扫描整个数据集,从而复用了计算。

Wv – Work Avoidance (工作规避)

跳过不会改变外部可观察结果的计算。例子包括惰性求值和谓词短路。

示例: 惰性求值将工作推迟到值被需要时才执行,从而消除了无用的计算。

Cc – Common-Case Specialization (普遍情况特化)

检测主导运行时的执行路径或数据项(“热点”),并专门为它们创建一个精简的快速路径,同时用一个较慢的通用路径来正确处理所有情况。

示例: 在首次调用时缓存接收者类的目标方法,这样后续对该普遍接收者的调用将命中快速路径;不常见的类则回退到完整的方法查找例程。

Bo – Bottleneck-Oriented Optimisation (瓶颈导向优化)

对端到端性能进行剖析,定位最紧张的资源约束,并在此处集中改进,直到另一个阶段成为限制因素。

示例: 罕见的第99百分位延迟的长尾请求是延迟瓶颈,而复制请求有助于削减尾部响应时间。

Ha – Hardware-Aware Design (硬件感知设计)

根据底层硬件的延迟、带宽、并行性和持久性特性(例如缓存层次、NUMA、SSD、GPU)来塑造算法和数据结构。

示例: BLAS 定义了经过缓存和向量优化的内核,使线性代数代码能高效利用硬件。

Op – Optimistic Design (乐观设计)

假设普遍情况会成功并继续执行,跳过协调,仅在假设被证明错误时才依赖一个(可能昂贵的)恢复路径。

示例: 乐观并发控制无锁地运行事务,然后在提交时进行验证,仅在检测到冲突时才回滚。

La – Learned Approximation (学习式近似)

用在数据上训练的模型替换手工制作的算法,以牺牲有界的不精确性来换取效率或灵活性。

示例: 感知器分支预测器在线学习权重以预测分支结果,其性能优于固定的两位计数器,且无需扩大表的大小。

Group 3: 语义

Al – Abstraction Lifting (抽象提升)

将底层操作封装在一个更高层的接口或领域特定语言之后,该接口表达的是意图而非步骤。这使得内部优化成为可能,也允许单一的定义能针对不同的后端。

示例: SQL 查询声明要检索的结果;DBMS 自动选择访问路径、连接顺序和物理操作符。

Lu – Language Homogeneity (语言同质性)

在核心组件和扩展中采用单一、良定义的中间表示(或语言),从而使语义对齐、工具可组合,并以最小的努力实现跨层优化和复用。

示例: LLVM 暴露了一个基于类型和SSA的IR,许多前端以此为目标,许多后端也共享它,从而实现了跨语言优化和相同中间端遍的复用。

Se – Semantically Explicit Interfaces (语义明确的接口)

精确地指定一个接口(涵盖效果可见性、顺序、持久性等),以便用户可以对调用的真实外部可观察状态进行推理,而无需猜测隐藏的缓冲或复制。

示例: SQL 隔离级别指定了精确的异常语义,并明确了可见性保证。

Fs – Formal Specification (形式化规约)

使用数学模型或逻辑来描述系统行为,以支持严格的推理、验证或综合。实现此原则的机制包括时序逻辑、状态机以及其他使系统属性可分析的形式化方法。

示例: TLA+展示了如何使用逻辑和集合论来规约和检查系统,以便在编码前捕获设计错误。

Ig – Invariant-Guided Transformation (不变量驱动转换)

使用形式化声明的不变量来驱动安全的重构、优化或重新配置。

示例: 在编译器中,SSA 将“每个名称只有一个定义”视为 IR 不变量;各个遍在重写代码时保持语义,然后重新建立 SSA。在查询优化器中,关系代数等价(例如,选择/投影下推)保持结果的语义。

Group 4: 分布

Lt – Location Transparency (位置透明)

隐藏资源的物理位置,以便客户端通过统一的名称或句柄进行交互。

示例: 程序可以像调用本地过程一样调用远程过程,从而掩盖了主机的地理位置。

Dc – Decentralised Control (去中心化控制)

将决策权分散到多个节点,以避免单点故障或瓶颈。

示例: Dynamo 通过一致性哈希对数据进行分区,并使用基于 gossip 的成员关系,从而避免了任何中央协调器。

Fp – Function Placement (功能放置)

将功能放置在拥有必要上下文和资源的地方,以实现正确性和效率,避免在别处进行冗余工作。

示例: 端到端论证表明,像可靠性检查这样的功能只有在端点才能实现其正确性。

Lo – Locality of Reference (引用局部性)

将相关的数据和操作在时间和空间上彼此靠近,以保持访问模式并最小化计算与状态之间的分离。

示例: 工作集模型形式化了时间局部性,以将热点页面保留在内存中。

Group 5: 规划

Ep – Equivalence-based Planning (等价规划)

在保持语义等价的通用IR上应用代数/逻辑重写规则;将最终选择推迟到后续的成本/约束阶段。

示例: Starburst 的基于规则的重写系统应用关系等价(例如,谓词下推)来生成逻辑上等价的查询。

Cm – Cost-based Planning (成本规划)

当系统必须在备选的设计、配置或执行策略中做出选择时,使用成本模型来指导搜索,以找到低成本的解决方案(能源、金钱等),而无需枚举整个空间。

示例: Selinger 查询优化器在一个成本模型下选择成本最低的计划。

Cp – Constraint-based Planning (约束规划)

将决策和硬性或软性约束进行编码,并依赖一个求解器(ILP/SMT等)来找到一个可行或最优的分配方案。

示例: Quincy 将集群调度问题建模为带有局部性和公平性约束的最小成本流问题,并求解以获得分配方案。

Gd – Goal-Directed Planning (目标导向规划)

接受对期望最终状态的声明性描述,并自动合成一个具体的操作序列来达到它,从而将用户与实现细节隔离开来。

示例: Cascades 查询优化器通过基于规则的转换和成本引导的搜索,将一个 SQL 查询(目标)转化为一个可执行的计划。

Bb – Black-Box Tuning (黑盒调优)

当分析性的成本模型不可用时,通过在目标系统上测量候选方案来搜索计划/配置空间,迭代地选择更好的方案(例如,启发式或贝叶斯搜索),并缓存胜出者。

示例: ATLAS 在目标 CPU 上凭经验对候选的 BLAS 内核配置进行计时,并固定性能最佳的参数,而无需分析性的成本模型。

Ah – Advisory Hinting (建议性提示)

提供非强制性的提示,系统可以利用这些提示来提高性能,但不会改变正确性或需要强制执行。

示例: Lampson 提倡使用可选的“提示”,这些提示有助于提高性能,但如果被忽略,绝不能影响正确性。

Group 6: 可操作性

Ad – Adaptive Processing (自适应处理)

监控运行时条件,并自动调整参数或策略。

示例: Eddies 根据反馈在运行时持续地对查询操作符进行重新排序,在不停止执行的情况下进行适应。

Ec – Elasticity (弹性)

根据不断变化的需求和成本目标,自动调整资源分配。例子包括预测性自动伸缩和负载整形。

示例: Chase 等人根据负载和效用动态地配置服务器,体现了弹性资源管理。

Wa – Workload-Aware Optimisation (负载感知优化)

持续观察工作负载的形态(倾斜、局部性、访问频率等),并调整数据布局、算法选择或资源分配以匹配当前模式。

示例: 数据库“cracking”技术根据查询谓词增量地重组列数据,从而使数据布局持续地适应观察到的工作负载。

Au – Automation and Autonomy (自动化与自治)

让系统无需人工干预即可执行常规或响应式任务,通常通过从追踪或用户提供的示例中学习来实现。

示例: AutoAdmin 从工作负载追踪中自动推荐索引/物化视图 [7]。通过示例编程的系统通过从少数用户提供的示例中进行泛化来自动化任务。

Ho – Human Observability (人类可观测性)

暴露系统的内部状态,如指标、追踪、计划,以使系统有意地变得透明;这种透明度提高了可观测性、调试、内省和控制能力。

示例: Paxson 的端到端互联网数据包动态分析展示了丰富的测量和追踪如何实现有根据的调试和调优。

Ev – Evolvability (可演进性)

设计系统使其能在最小化停机时间或重写成本的情况下进行变更,且不破坏现有客户端的外部合约或可观察行为。与让外部人员通过定义的钩子点添加新行为而不触及核心的可扩展性不同,可演进性让系统内部随时间变化而不会破坏现有的外部合约。

示例: Parnas 展示了模块化设计如何使系统更容易在不进行颠覆性重写的情况下进行扩展。

Group 7: 可靠性

Ft – Fault Tolerance (容错性)

设计系统使其在组件故障时仍能继续运行,尽管可能以一种降级的形式。

示例: Gray 对计算机为何停止运行的分析表明,复制和自动重启让服务能够在硬件和软件故障中持续运行。

Is – Isolation for Correctness (隔离以保正确)

防止组件间的意外干扰,从而使局部推理保持有效。

示例: 两阶段行级锁定阻止一个事务读取或覆盖另一个事务未提交的数据,从而保持隔离保证。

At – Atomic Execution (原子执行)

将多个操作组合在一起,使其表现为不可分割的,要么全部生效,要么全不生效。

示例: 使用事务性内存,事务内的内存操作会进行推测性执行,然后原子性地提交;如果发生任何冲突或故障,整个块将中止,不留下任何部分状态。

Cr – Consistency Relaxation (一致性松弛)

为提高性能、可用性或并发性,在有文档记录的边界内,刻意放宽强一致性或顺序约束。

示例: Bayou 允许移动客户端在断开连接时更新副本,并保证在副本重新连接时最终会趋于一致,这是用严格的一致性换取离线可用性。

Group 8: 安全性

Sy – Security via Isolation (隔离以保安全)

强制执行严格的边界,使故障或恶意代码无法影响其他组件。

示例: 一个正确的虚拟机监视器为每个客户机呈现一个完整、隔离的机器,并拦截特权操作,防止一个客户机危及其他客户机或宿主机。

Ac – Access Control and Auditing (访问控制与审计)

定义权限,并记录每次访问以备问责。

示例: Lampson 对访问控制列表、能力(capabilities)和审计追踪的分类法是现代安全机制的基础。

Lp – Least Privilege (最小权限)

只授予完成任务所必需的最小权限,以缩小爆炸半径。

示例: 对1988年互联网蠕虫的尸检报告显示,过度的权限让蠕虫得以传播,并促使了最小权限守护进程的广泛采用。

Tq – Trust via Quorum (法定人数信任)

依赖多个独立参与者的一致同意,而非单一权威。

示例: Paxos 算法将状态复制到一个多数法定人数中,这样即使少数节点崩溃或行为恶意,服务也能保持正确。

Cf – Conservative Defaults (保守默认值)

发布时采用限制性的、安全的设置;让专家选择性地进入风险更高、速度更快的模式。

示例: 采用“默认无访问”策略,每个保护机制都应只在明确授予时才允许访问。

Sa – Safety by Construction (构造即安全)

通过代码或数据的结构设计,使整类错误变得不可能发生,而不仅仅是被检测到。

示例: Rust 的所有权和借用检查器在编译时就防止了数据竞争和悬垂指针。

案例研究

为了说明多个设计原则在实践中如何交织在一起,我们以关系数据库系统中从逻辑操作符计划到物理操作符计划的映射为例。

  • 数据库系统将声明性意图转化为可执行步骤(策略与机制分离)。
  • SQL 表达了“做什么”(抽象提升),并具有精确的语义(语义明确的接口)。
  • 优化器首先使用代数等价来重写查询(等价规划)。
  • 然后它使用成本模型来选择具体的物理操作符(成本规划)。
  • 物理操作符通常针对底层硬件特性进行优化(硬件感知设计)。
  • 谓词下推体现了工作规避,而索引则实现了计算复用
  • 建议性提示可以指导优化器,而较新的数据库系统增加了运行时重优化(自适应处理)、学习模型(学习式近似)和采样(Probabilistic Design注:原文表格未列出此原则,但案例中提及)。

因此,数据库系统中从逻辑到物理操作符的映射,体现了多个设计原则如何共同作用,以高效处理声明性的SQL查询。

局限性

任何试图组织像计算机系统这样广泛的领域的尝试都涉及到权衡。此表不是一份检查清单或一个普适的理论;它是一个共享的词汇表,旨在突出反复出现的原则并鼓励进行结构性反思。话虽如此,仍有几个局限性:

  • 正交性:原则之间可能重叠、相互加强或部分冲突;设计就是关于平衡这些张力。
  • 主观性与粒度:推导和映射原则涉及判断;边界是模糊的,不同的读者可能会以不同的方式标记同一个系统,或以不同的方式解释同一个原则。
  • 非形式化分类法:这不是一个完整或最小的设计原则集合。没有尝试从一个最小的核心推导出这些原则。

最终,此表是一种帮助学生更清晰地看到反复出现的设计原则,协助系统设计师更精确地沟通权衡,并帮助研究人员认识到他们的思想在更广阔的系统设计蓝图中所处位置的手段。

结论

系统设计横跨不同的领域和词汇,这可能使共享讨论变得更加困难。我们继承机制,研究权衡,并建立直觉,然而用于描述底层思想的简洁术语并不总是唾手可得。这里提供的设计原则“元素周期表”旨在提供一种适度的通用语言,通过命名反复出现的思想,使其更容易被传授、比较和在其上进行构建。

参考文献

[1] Ron Avnur and Joseph M. Hellerstein. Eddies: Continuously Adaptive Query Processing. In SIGMOD, 2000.
[2] Rudolf Bayer and Edward McCreight. Organization and Maintenance of Large Ordered Indexes. Acta Informatica, 1972.

… (请参考原文中的详细参考文献列表) …

[48] Hubert Zimmermann. OSI Reference Model – The ISO Model of Architecture for Open Systems Interconnection. IEEE Transactions on Communications, 1980.

如何引用

如果您觉得本分析有用,请按如下方式引用:

Joy Arulraj. Elements of System Design arXiv preprint arXiv:TBD, 2025.

论文地址:https://github.com/jarulraj/periodic-table


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

你的 AI Agent 为何总“犯傻”?构建生产级 Agent 所需的6大工程原则

本文永久链接 – https://tonybai.com/2025/07/30/six-principles-production-ai-agents

大家好,我是Tony Bai。

随着 AI Agent 技术的兴起,许多开发者都投入到构建智能体的浪潮中,但很快就会发现,让 Agent 稳定、可靠地工作远非想象中容易。它们时而产生幻觉,时而偏离轨道,时而做出一些令人费解的“愚蠢”行为。最近,来自 app.build 的 Arseni Kravchenko 分享了他们在构建生产级 AI Agent 过程中总结出的六大核心工程原则。这些原则摒弃了虚无缥缈的“提示词黑魔法”,回归到坚实的软件工程基础。对于正在或计划使用 Go 构建 AI Agent 的开发者来说,这是一份宝贵的实践指南。

原则一:投资你的系统提示 (System Prompt)

许多人对“提示词工程”持怀疑态度,认为它充满了“我奶奶快不行了,请帮帮我”之类的奇技淫巧。然而,作者指出,现代 LLM 真正需要的是直接、详细、清晰且无矛盾的上下文,而非情感操控。

对于开发者而言,你要做的就是不要耍小聪明,要把系统提示当作给 Agent 的API 文档来写。

当你为 Agent 提供一个通过 os/exec 调用的工具时,不要只告诉它工具的名字。在系统提示中清晰地说明:

  • 工具的完整命令是什么。
  • 每个参数的含义、类型和格式
  • 预期的输出格式以及如何解析它。
  • 前置条件和错误情况

一个详尽的系统提示是 Agent 可靠行为的基石。

原则二:拆分上下文 (Split the Context)

“上下文工程”是比“提示词工程”更重要的概念。巨大的、单一的上下文不仅成本高、延迟大,还会导致模型出现“注意力衰减”,忽略掉关键信息。

作者建议大家:默认只提供最少必要知识,并通过工具让 Agent 在需要时主动获取更多上下文。

与其在初始提示中塞入整个项目的源代码,不如:

  • 提供文件列表:在提示中只给出项目的文件树结构。
  • 提供 read_file 工具:让 Agent 在需要时,通过调用这个工具来读取特定文件的内容。
  • 上下文压缩:在 Agent 的反馈循环中,主动使用工具(甚至另一个 LLM)来压缩和总结日志、工具输出等动态信息,避免上下文无限膨胀。

如上图所示,将一个庞大的任务分解为多个具有专注上下文的、可编排的子任务,是构建高效 Agent 的关键。

原则三:精心设计你的工具 (Design Tools Carefully)

工具是 AI Agent 的核心。设计给 Agent 用的工具,比设计给人用的 API 更具挑战性,因为 LLM 不会“读心术”,它们会毫不留情地滥用你留下的任何漏洞。

作者建议:把你的 Agent 当成一个聪明但容易分心的初级开发者,为它设计 API:

  • 保持粒度一致:工具(函数)应该有相似的抽象层次。不要混用一个 read_byte 和一个 deploy_to_kubernetes。
  • 限制数量和参数:一个典型的工程 Agent 通常只有不到 10 个核心工具,每个工具只有 1-3 个严格类型的参数。
  • 追求幂等性:尽可能让工具是幂等的,这可以极大地简化 Agent 的状态管理和错误恢复逻辑。
  • 清晰、无歧义、无冗余:确保没有两个工具的功能是重叠的,这会让 LLM 感到困惑。

原则四:设计一个反馈循环 (Design a Feedback Loop)

一个没有验证和反馈的 Agent 是不可靠的。优秀的 Agent 系统总是将 LLM 的创造力与传统软件的严格性结合起来,形成一个“演员-评论家”(Actor-Critic)模型:让 LLM Actor 自由创造,让严格的 Critic 程序来验证。

对于开发者来说,这是一个天然的优势领域!

  • Actor (LLM):负责生成代码、配置文件或执行计划。
  • Critic:负责执行一系列自动化验证:
    • 代码能否编译通过
    • 代码能否通过测试
    • 代码是否符合静态检查规范
    • 领域特定不变量:例如,如果 Agent 修改了订单系统,是否依然满足“订单总价等于所有商品价格之和”这个业务规则?

这个反馈循环不仅能过滤掉错误的输出,更是 Agent 学习和改进的基础。

原则五:用 LLM 驱动错误分析

当 Agent 失败时,手动排查海量的日志是不现实的。我们可以构建一个“meta Agent”来解决这个问题,即让另一个 LLM 来分析失败 Agent 的日志,找出问题的根源。

流程

  1. 建立一个基线版本的 Agent。
  2. 部署多个实例并收集它们的执行轨迹和日志。
  3. 将失败的日志喂给一个具有更大上下文窗口(如 Gemini 1.5 Pro)的 LLM进行分析。
  4. 根据 LLM 的分析洞察,改进基线 Agent 的系统提示、工具或上下文管理。

这个元循环能高效地发现我们自己可能忽略的系统性问题。

原则六:令人沮丧的行为是系统问题的信号

当 Agent 做出一些“愚蠢”的行为,比如忽略你的明确指令,或者用一种奇怪的方式绕过问题时,我们的第一反应通常是“这个模型真笨”。

但作者建议:先调试你自己的系统,再怪罪模型。

作者分享了一个亲身经历:他明确要求 Agent 使用一个集成工具来获取数据,但 Agent 却固执地使用模拟的随机数据。在愤怒地检查日志后,他发现自己忘了给 Agent 配置正确的 API 密钥。Agent 尝试调用工具,连续失败,最后只能选择一个它能走的通的、但却是错误的路径。

因此,当你的 Agent 行为异常时,请检查一下:

  • 工具是否缺失? 它是否需要一个 write_file 的能力而你没有提供?
  • 提示是否模糊? 你是否清晰地解释了工具的用法和边界?
  • 上下文是否充分? 它是否因为缺少必要信息(比如一个 API 密钥或文件权限)而无法执行任务?

小结

构建有效的 AI Agent,关键不在于寻找一个能解决所有问题的“银弹”提示或高级框架。它回归到了系统设计和严谨的软件工程

作为开发者,我们应该聚焦于:

  • 清晰的指令(通过系统提示)
  • 精简的上下文管理(通过工具和压缩)
  • 健壮的工具接口(简单、幂等、无歧义)
  • 自动化的验证循环(编译、测试、静态检查)

当你被 Agent 的行为所困扰时,记住,问题很可能出在缺失的工具、模糊的提示或不足的上下文,而不是模型本身的局限性。将错误分析视为开发过程中的一等公民,我们的目标不是构建一个从不犯错的完美 Agent,而是构建一个可靠的、可恢复的、能够优雅地失败并被我们迭代改进的Agent。

资料链接:https://www.app.build/blog/six-principles-production-ai-agents


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言进阶课 Go语言精进之路1 Go语言精进之路2 Go语言第一课 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats