领域特定语言(DSLs)使大型语言模型(LLMs)的可靠使用成为可能
现代的大型语言模型(LLMs)具有令人难以置信的能力。它们可以仅凭高层次的自然语言描述生成大量代码,有时甚至是整个系统。在这里一个重要的假设是,需要构建的 '意图' 被很好地表达,使用 LLMs 能够映射到编程构建块的精确词语。然而,有两个重要的观点值得注意:预先规范的限制,以及设计是如何通过实施而发现的。 预先规范的限制 构建大型系统涉及许多小的设计决策,而这些决策并不能全部提前了解或完全由高层规格驱动。规格充其量是一个初步假设:真实的约束、权衡和边缘案例是通过实施的迭代过程中发现的。我们在早期的文章中对此进行了详细讨论,并称之为预先规范的不可能性。关键不在于规格是毫无价值的,而在于第一个规格是需要修订的假设,而不是一个完成的蓝图。自然的反应是进行迭代:完善规格,生成代码,审查返回的内容,将我们学到的知识反馈到下一轮。当每一轮产生一个小的、可审核的更改时,这一循环效果很好。 设计是通过实施而发现的 审查代码,特别是在我们仍在发现设计的时候,并不等同于编写代码。在审查生成的代码时,我们通过代码块进行审查,验证它是否与我们的意图相匹配,并寻找可能的陷阱。但审查很少迫使我们处理设计决策。相比之下,编写代码迫使我们认真思考具体决策——例如,责任应该归属哪里,或者哪些边界应该被暴露,以便设计可以进一步扩展。正是在做出这些决策的过程中,设计最充分地显现出来。我们所使用的编程语言和范式塑造了我们获得的设计洞察。功能设计方法或面向对象设计方法揭示了设计的不同方面,以及与之相关的自然的惯用法和模式。那么,LLMs 在其中适合什么呢?我认为 LLMs 扮演了两个角色。它们在我们塑造设计及其词汇时提供了很大的帮助,作为头脑风暴的伙伴,帮助我们探索设计空间并发现合适的抽象。一旦词汇建立,LLMs 就作为一个优秀的自然语言接口。 领域抽象和领域特定语言(DSLs) 一个有用的框架是通过领域驱动设计(DDD)。它的核心见解是在代码中构建一个共享的领域概念模型,然后使用这个模型——DDD 称之为无处不在的语言——不仅来发展代码库,还为团队提供一个思考和沟通的词汇。通常,在这个模型上构建一个领域特定语言非常有效:一种表达领域概念和操作的受限语法。从这个角度来看,大多数开发都是构建一个领域模型并利用它来发展系统的过程。LLM 扮演着两个不同的角色,具体取决于领域模型是否已经存在。在本文中,我将专注于领域特定语言(DSLs)如何与 LLMs 一起工作。 为什么 DSLs 与 LLMs 间非常契合 DSLs 与 LLMs 之间契合的经验证明是普遍存在的。PlantUML、Mermaid 和 Graphviz 是用于视觉建模的领域特定语言;SQL 是用于查询数据库的 DSL;Kubernetes YAML 是描述云基础设施的 DSL。这些都不是通用编程语言——它们是经过精心限制的,旨在表达单一领域中的一小部分概念。因此,LLMs 在从简单的英语描述中生成 Mermaid 图、SQL 查询或 Kubernetes 清单方面表现出色,并不足为奇。我的观察是,DSLs 使 LLMs 更加可靠,因为它们对少量的上下文示例反应良好。像 Java 这样的通用语言提供了许多有效的表达同一意图的方式。而一个 DSL 将变体剥离开来。给模型几个示例就足以可靠地生成正确的语法。值得注意的是,前线模型在训练过程中已经大量接触到了 PlantUML 或 Java 流式接口,因此它们并不是从零开始。很有趣的是,看看较小、更受限的模型在处理全新 DSL 任务时的表现。 对于一个代理——一个在自主生成和检查循环中运行的 LLM,而不是单一生成——还有一个额外的好处。DSL 几乎总是带有一个确定性的验证器:解析器、JSON 模式、类型检查器或编译器。代理可以生成一个候选项,经过验证器进行检查,并根据错误进行修复,所有这些都不需要人类参与。至关重要的是,错误是在领域层面表达的——“您不能在选择客户端之前选择一个操作”——而不是深埋在生成代码中的堆栈跟踪中。DSL 的工具集本身就充当了一个优秀的支持。
本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。
☕请我喝杯咖啡