A startup that tried to let a large language model drive all of its API automation discovered that probabilistic outputs clash with the deterministic needs of production. By moving the rule‑heavy parts to code and reserving the LLM for interpretation, they achieved reliable mock data generation and robust validation, illustrating a pragmatic “code‑first, LLM‑second” architecture for AI‑powered services.
The Problem: Expecting Determinism from a Probabilistic Model
A small engineering team built an internal platform to automate API workflows. Their initial design was LLM‑first: feed an OpenAPI/Swagger spec to a large language model, ask it to generate request payloads, validate inputs, and even simulate end‑to‑end flows. Early demos looked impressive – the model produced clean‑looking JSON, the UI rendered mock responses, and stakeholders were thrilled.
When the same pipeline was pressed into real development cycles, the cracks appeared. Some calls succeeded, others failed for no obvious reason. Logs showed no errors; the only pattern was inconsistency. A concrete example involved a dispute API:
- Enum values were sometimes misspelled (e.g., "close" instead of the required "CLOSED").
- Required fields vanished at random.
- IDs that were supposed to stay consistent across calls changed without warning.
The team tried the usual fixes – richer prompts, more examples, stricter formatting instructions – and saw marginal improvement, but the core issue remained: a probabilistic generator cannot guarantee the deterministic behavior that production systems demand.
{{IMAGE:2}}
The Shift: Code‑First Architecture with LLM as a Helper
Realising that the problem was not the model but the architectural assumption, the team rewrote the pipeline around a simple principle:
If a piece of logic must be correct every time, implement it in code. If it needs interpretation or creativity, let the LLM handle it.
Step‑by‑step flow for mock data generation
- Parse the OpenAPI spec with a deterministic parser (e.g.,
swagger-parserin Node oropenapi‑toolsin Python). This extracts:- Required fields
- Data types
- Enum sets
- Constraints such as
minimum,maximum,format
- Map each field to a deterministic generator:
- Names →
faker.name.findName() - Emails →
faker.internet.email() - Enums → random pick from the exact enum list (no LLM guessing)
- Numbers → random within defined bounds
- Names →
- Detect custom or ambiguous fields that lack clear schema guidance. For those, the system prompts the LLM with a focused request like "Generate a realistic value for a field named
customCodethat follows the pattern XYZ-####". - Validate the assembled payload against the JSON schema using a fast validator (
ajvfor JavaScript,jsonschemafor Python). Any mismatch triggers an immediate reject, preventing silent failures downstream. - Log deterministic outcomes (e.g., which enum was chosen, which faker function ran) to aid debugging.
The result? Mock payloads that always conform to the spec, with failures now predictable and traceable. The LLM is no longer the source of truth; it is a fallback for edge cases where the schema is ambiguous.
Why Code‑First Wins in Production
| Aspect | LLM‑First (Demo‑Centric) | Code‑First (Production‑Centric) |
|---|---|---|
| Reliability | Inconsistent; occasional silent errors | Deterministic; every rule enforced by code |
| Debugging | Hard – need to infer why the model chose a value | Simple – logs point to the exact validator failure |
| Performance | Extra latency for each generation request | Minimal overhead; only occasional LLM calls |
| Maintenance | Prompt engineering becomes a moving target | Schema changes trigger code updates, a familiar workflow |
| Cost | Continuous token usage for every payload | Token usage limited to rare edge‑case calls |
The most striking change was cultural: developers stopped treating the LLM as a system and started treating it as a component. This mirrors the broader software engineering practice of separating concerns – keep the deterministic core in code, and delegate the fuzzy, language‑understanding tasks to the model.
Practical Takeaways for Teams Building AI‑Powered APIs
- Start with the schema – let a parser extract every rule you can. Anything not captured should be flagged for manual review.
- Use the LLM sparingly – only when the schema leaves room for interpretation (e.g., free‑form text, custom business logic).
- Enforce validation early – reject malformed payloads before they travel downstream.
- Instrument thoroughly – log both the deterministic decisions and the occasional LLM response for auditability.
- Iterate on the fallback prompts – keep them short, focused, and anchored to the schema context.
By following these steps, teams can enjoy the creativity of large language models without sacrificing the predictability that production environments require.
Looking Ahead
The story underscores a broader lesson for the AI startup ecosystem: hype around “LLM‑first” solutions often masks a hidden cost – the need to constantly manage probabilistic failure modes. A code‑first foundation provides a stable runway for scaling AI features, turning experimental demos into reliable products.
For anyone interested in trying this pattern, the open‑source starter kit used by the team is available on GitHub: github.com/Swapneswar/ai‑code‑first‑pipeline. It includes:
- An OpenAPI parser wrapper
- A deterministic faker mapping library
- A thin LLM fallback layer using OpenAI’s
gpt‑4o - CI scripts that run schema validation on every pull request
Adopting a code‑first mindset doesn’t eliminate the excitement of AI; it simply channels that excitement into a predictable, maintainable product stack.
Author: Swapneswar Sundar Ray, AI‑driven enterprise engineer

Comments
Please log in or register to join the discussion