메뉴
HN
Hacker News 14일 전

DSL이 LLM의 신뢰성을 보장하는 방법

IMP
8/10
핵심 요약

대형 언어 모델(LLM)은 코드를 매우 빠르게 생성하지만, 의도한 대로 정확한 결과를 얻으려면 명확한 경계가 필요합니다. 도메인 주도 설계(DDD)의 유비쿼터스 언어를 바탕으로 추상화와 도메인 특화 언어(DSL)를 구축하면 LLM의 환각과 오류를 제어할 수 있습니다. 결국 DSL은 LLM 시대에 소프트웨어 시스템의 신뢰할 수 있는 단일 진실 공급원(Source of Truth) 역할을 하게 됩니다.

번역된 본문

DSL이 LLM의 신뢰성을 보장하는 방법

LLM은 놀라울 정도로 빠르게 코드를 생성하지만, 우리가 의도한 것을 정확하게 생성하도록 보장하려면 명확한 경계가 필요합니다. 추상화(Abstractions)와 도메인 특화 언어(DSLs)는 처음부터 LLM을 올바른 방향으로 안내하는 강력한 틀을 제공합니다. 분산 시스템의 동작을 설명하기 위한 도메인 모델이자 DSL인 'Tickloom'의 예시는 LLM을 반복적으로 DSL을 구축하는 파트너로, 그리고 그것을 사용하는 자연어 인터페이스로 어떻게 활용할 수 있는지 보여줍니다. 이러한 DSL은 LLM 세계의 소프트웨어 시스템을 위한 핵심 '단일 진실 공급원(Source of truth)' 역할을 할 수 있습니다.

2026년 7월 14일 언메시 조시 (Unmesh Joshi) 언메시 조시는 인도 푸네에 위치한 Thoughtworks의 디스팅귀시드 엔지니어(Distinguished Engineer)입니다. 그는 『Patterns of Distributed Systems』의 저자입니다.

목차

  • 사전 명세(Specification)의 한계
  • 구현을 통해 발견되는 설계
  • 도메인 추상화와 DSL
  • DSL이 LLM과 잘 작동하는 이유
  • 예시: LLM을 사용하여 다이어그램이 풍부한 파워포인트 프레젠테이션 생성하기
  • 의미론적 모델(Semantic Model) 구축
  • 예시: Tickloom — 분산 시스템을 위한 의미론적 모델
  • DSL 없이도 훌륭한 추상화는 도움이 됩니다
  • 예시: 분산 시스템 시나리오 테스트를 위한 DSL 구축
  • LLM과 작업하는 두 가지 단계
  • 단일 진실 공급원으로서의 DSL

현대 LLM은 놀라운 능력을 갖추고 있습니다. 높은 수준의 자연어 설명만으로 대량의 코드를 생성할 수 있으며, 때로는 전체 시스템을 만들어내기도 합니다. 여기서 중요한 전제 조건은 구축해야 할 대상의 '의도(Intent)'가 명확하게 표현되어, LLM이 이를 코딩 빌딩 블록(구성 요소)으로 매핑할 수 있는 정확한 단어를 사용해야 한다는 것입니다. 하지만 주목해야 할 두 가지 중요한 사항이 있습니다. 바로 사전 명세의 한계와 설계가 구현을 통해 발견된다는 점입니다.

사전 명세의 한계 대규모 시스템을 구축하려면 수많은 세부적인 설계 결정이 필요하며, 이 모든 것을 미리 알거나 높은 수준의 명세서만으로 도출하는 것은 불가능합니다. 명세는 기껏해야 시작을 위한 가설일 뿐입니다. 실제 제약 조건, 트레이드오프, 예외 사항들은 구현을 진행하면서 반복적으로 발견됩니다. 우리는 이전 글에서 이에 대해 깊이 논의하며 '사전 명세 불가능성(Upfront Specification Impossibility)'이라고 불렀습니다. 요점은 명세가 쓸모없다는 것이 아니라, 최초의 명세는 수정되어야 할 가설이지 결코 완성된 청사진이 아니라는 것입니다. 자연스러운 대응은 반복(Iteration)입니다. 명세를 다듬고, 코드를 생성하고, 결과를 검토하며, 배운 점을 다음 단계에 반영하는 것입니다. 이러한 루프는 각 주기가 작고 검토 가능한 변경 사항을 생성할 때 잘 작동합니다.

구현을 통해 발견되는 설계 특히 우리가 아직 설계를 모색하는 단계에서 코드를 리뷰하는 것은 코드를 직접 작성하는 것과 다릅니다. 생성된 코드를 리뷰할 때 우리는 코드 덩어리가 우리의 의도와 부합하는지 검증하고 가능한 함정을 찾습니다. 하지만 리뷰만으로는 설계 결정을 두고 씨름하도록 강요하는 경우는 거의 없습니다. 반면 코드를 직접 작성하는 것은 책임이 어디에 속하는지, 설계를 더 확장하기 위해 어떤 경계를 노출해야 하는지와 같은 구체적인 결정을 내리도록 강제합니다. 설계는 바로 그러한 결정을 내리는 과정에서 가장 완전하게 드러납니다. 우리가 코딩하는 프로그래밍 언어와 패러다임은 우리가 얻는 설계 통찰력의 형태를 결정짓습니다. 함수형 설계 접근법이나 객체 지향 설계 접근법은 해당 패러다임에 자연스러운 관용구와 패턴과 함께 설계의 다른 측면을 드러냅니다.

그렇다면 LLM은 어디에 들어맞을까요? 저는 LLM이 두 가지 역할을 한다고 봅니다. 먼저, 설계와 그 어휘를 형성하는 동안 설계 공간을 탐색하고 올바른 추상화를 발견하도록 돕는 브레인스토밍 파트너로서 훌륭한 역할을 합니다. 어휘가 확립되고 나면, LLM은 이를 활용하는 훌륭한 자연어 인터페이스로 작동합니다.

도메인 추상화와 DSL 이를 구성하는 유용한 방법은 도메인 주도 설계(DDD, Domain Driven Design)를 통하는 것입니다. DDD의 핵심 통찰은 코드로 도메인에 대한 공유 개념 모델을 구축하고, DDD에서 '유비쿼터스 언어(Ubiquitous Language)'라고 부르는 이 모델을 사용하여 코드베이스를 발전시키고 팀이 사고하고 협업할 수 있는 어휘를 제공하는 것입니다.

원문 보기
원문 보기 (영어)
DSLs Enable Reliable Use of LLMs LLMs generate code incredibly fast, but to ensure they generate exactly what is intended, they need clear boundaries. Abstractions and Domain-Specific Languages (DSLs) provide a strong harness that guides LLMs right from the start. The example of Tickloom - a domain model and DSL for illustrating distributed system behavior - shows how we can use an LLM as a partner to iteratively build a DSL and as a natural language interface to use it. Such a DSL can act as the key source of truth for software systems in the world of LLMs. 14 July 2026 Unmesh Joshi Unmesh is a Distinguished Engineer at Thoughtworks, based in Pune, India. He is the author of Patterns of Distributed Systems . Contents The Limits of Upfront Specification Design Is Discovered Through Implementation Domain Abstractions and DSLs Why DSLs work so well with LLMs Example: Using LLMs to generate diagram rich powerpoint presentations Building the Semantic Model Example: Tickloom — a semantic model for distributed systems Even good abstractions help — without a DSL Example: Building a DSL for testing distributed system scenarios Two phases working with LLMs The DSL as the Source of Truth Modern LLMs possess an incredible capability. They can generate large amounts of code, and sometimes entire systems, from just a high-level natural language description. An important assumption here is that the 'intent' of what needs to be built is well articulated, using precise words that LLMs can map to coding building blocks. However, there are two important points worth noting: the limits of upfront specification, and how design is discovered through implementation. The Limits of Upfront Specification Building large systems involves a great many small design decisions, and these cannot all be known in advance or driven entirely from a high-level spec. A specification is at best a starting hypothesis: the real constraints, trade-offs, and edge cases are discovered iteratively, as we proceed with the implementation. We discussed this at length in an earlier article, where we called it Upfront Specification Impossibility . The point is not that specs are worthless, but that the first one is a hypothesis to be revised, never a finished blueprint. The natural response is to iterate: refine the spec, generate code, review what comes back, and feed what we learn into the next round. That loop works well when each round produces a small, reviewable change. Design Is Discovered Through Implementation Reviewing code, particularly while we are still discovering the design, is not the same as writing it. While reviewing the generated code, we review through the chunks validating if it maps to our intent and looking for possible pitfalls. But reviewing rarely forces us to wrestle with the design decisions. Writing code, by contrast, forces us to think through concrete decisions—such as where a responsibility belongs or what boundaries should be exposed so the design can be extended further. It is in making those decisions that a design most fully reveals itself. The programming language and paradigm we code in shapes the design insight we get . A functional design approach or an object-oriented design approach reveals different aspects of the design, along with idioms and patterns that are natural to the paradigm. So where do LLMs fit in? I see LLMs playing two roles. They are a great help while we shape the design and its vocabulary, acting as brainstorming partners to help us explore the design space and discover the right abstractions. Once the vocabulary is established, LLMs work as an excellent natural language interface to it. Domain Abstractions and DSLs A useful way to frame this is through Domain Driven Design . Its core insight is building a shared conceptual model of the domain in code, and then using that model - which DDD calls a Ubiquitous Language - both to evolve the codebase and to give the team a vocabulary to think and communicate in. Often, it is highly effective to build a domain specific language on top of that model: a constrained syntax for expressing the domain's concepts and operations. Seen this way, most development is the process of building a domain model and using it to evolve the system. The LLM plays two distinct roles depending on whether the domain model already exists. In this article, I will focus on how Domain-Specific Languages (DSLs) work with LLMs. Why DSLs work so well with LLMs It is a common experience that DSLs work well with LLMs. PlantUML, Mermaid, and Graphviz are domain specific languages for visual modeling; SQL is a DSL for querying databases; Kubernetes YAML is a DSL for describing cloud infrastructure. These are not general-purpose programming languages — they are deliberately constrained, designed to express a narrow set of concepts in one domain. And it is no surprise that LLMs are remarkably good at generating Mermaid diagrams, SQL queries, or Kubernetes manifests from a plain English description. My observation is that DSLs make LLMs more reliable because they respond so well to a few in-context examples. A general-purpose language like Java offers lots of valid ways to express the same intent. A DSL strips the variation away. Giving the model a few examples is enough to reliably generate the correct syntax. It's worth noting that frontline models are already heavily exposed to PlantUML or Java fluent interfaces during training, so they aren't starting from scratch. It will be curious to see how smaller, more constrained models perform when tasked with a truly novel DSL. For an agent — an LLM running in an autonomous generate-and-check loop rather than a single shot generation — there is one more benefit. A DSL almost always ships with a deterministic validator: a parser, a JSON schema, a type checker, or a compiler. The agent can generate a candidate, run it past the validator, and repair it from the error, all without a human in the loop. Crucially, the errors are phrased at the level of the domain — “you cannot select an action before choosing a client” — rather than as a stack trace buried deep in generated code. DSL's toolset itself acts as an excellent harness. We will see it concretely in the Tickloom examples below, where the DSL's grammar is enforced by the host language's compiler and the resulting runs are checked automatically. It is important to note that this is not a one-size-fits-all solution. The advantage holds while the DSL stays small and constrained enough that a few in-context examples can convey its usage. There is also a real upfront cost in designing and maintaining the language and its semantic model. The payoff is therefore concentrated in well-factored, genuinely constrained DSLs backed by a validator. Example: Using LLMs to generate diagram rich powerpoint presentations LLMs make it really easy to build custom tools . While teaching distributed systems, I frequently need to create presentations which mostly have diagrams explaining distributed operations in a cluster. UML Sequence diagrams have been great for that but showing a full sequence diagram while explaining the flow of messages through the cluster is not very useful. I needed a tool to show a sequence diagram step by step in a powerpoint presentation. With the help of LLMs I was able to build a tool which processes a YAML describing the presentation structure with references to the PlantUML diagrams and generates a powerpoint presentation. The PlantUML diagrams are marked with steps, and the tool generates a separate slide for each step. This made it really easy to create diagram-rich presentations. Generate a PlantUML sequence diagram showing a cluster of three nodes athens, byzantium and cyrene. Put a box to mark the cluster. Actor Alice sends a message “title”, “After Dawn” to athens, Athens sends message to itself. Put a note to show state 'title: After Dawn'. Athens sends message