DEV Community

Separating Deterministic Calculations from AI Interpretation

 One rule in GetBirthChart has become more important as I’ve added more AI features:

The AI does not get to invent the chart.

It can explain the chart.

It can compare things in the chart.

It can synthesize several placements into a larger pattern.

But the underlying facts come from code.

The easiest architecture is also the one I didn't want

You could build an astrology AI product like this:

User:
"I was born on Nov 3, 1992 at 2:35 PM in Hanoi."

        ↓

LLM:
"Calculate the birth chart and explain it."
Enter fullscreen mode Exit fullscreen mode

Very little infrastructure.

Very impressive demo.

The problem is that one model is now responsible for two completely different jobs.

First:

Where was Saturn?
What was the Ascendant?
Which house contained Venus?
Is Mars retrograde?
Enter fullscreen mode Exit fullscreen mode

Then:

What might those things mean together?
Enter fullscreen mode Exit fullscreen mode

The first group has deterministic answers under a given calculation methodology.

The second group is interpretation.

I don't want them mixed.

The architecture is deliberately less magical

GetBirthChart works more like this:

birth input
    ↓
Python calculation engine
    ↓
canonical chart facts
    ↓
evidence/context selection
    ↓
LLM
    ↓
interpretation
Enter fullscreen mode Exit fullscreen mode

The Python engine uses Swiss Ephemeris and produces structured chart data.

The model receives that data.

So instead of asking the LLM:

Which sign is the Moon in?

I can give it something like:

{
  "body": "moon",
  "sign": "aquarius",
  "degreeInSign": 21.29,
  "house": 12
}
Enter fullscreen mode Exit fullscreen mode

The language model has a much more appropriate job now:

Explain this placement in the context of the other available chart evidence.

This gives the system a source of truth

Imagine the engine returns:

Moon: Aquarius
Enter fullscreen mode Exit fullscreen mode

and the generated interpretation starts talking about:

your Scorpio Moon
Enter fullscreen mode Exit fullscreen mode

That’s a contradiction I can detect.

Without a deterministic chart model, there isn’t a clean authority to compare the output against.

The LLM becomes the calculator, database and writer at the same time.

That makes QA much harder.

Missing data is even more important

Unknown birth time is a good example.

If birth time is unknown, the engine intentionally omits time-dependent fields.

The model might receive:

{
  "birthTimeKnown": false,
  "angles": {},
  "houses": [],
  "warnings": [
    {
      "code": "UNKNOWN_BIRTH_TIME"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

There is no Rising sign in the evidence.

There is no house placement.

That’s much stronger than putting this sentence in the prompt:

Do not make up an Ascendant.

Prompt instructions are useful.

Structural absence is better.

I like evidence-based prompts more than giant context dumps

Another pattern I’ve been using is selecting chart facts as evidence instead of dumping every available field into every generation.

Conceptually:

[
  {
    "id": "moon.sign",
    "value": "Aquarius"
  },
  {
    "id": "moon.house",
    "value": 12
  },
  {
    "id": "moon.square.saturn",
    "orb": 3.2
  }
]
Enter fullscreen mode Exit fullscreen mode

Now a piece of interpretation can be tied back to actual chart facts.

This is useful for the UI too.

A user can eventually ask:

Why are you saying this?

and the product has something better to show than:

The AI thought so.

It can show the relevant calculated evidence.

AI gets better when I give it less authority

This was a little counterintuitive.

The instinct with LLMs is to give them more.

More context.

More freedom.

More responsibility.

But I’ve found the product gets more reliable when the model owns fewer deterministic decisions.

I want code to handle:

timezone conversion
planet positions
houses
aspect geometry
retrograde
schema validation
Enter fullscreen mode Exit fullscreen mode

I want the LLM to handle:

explanation
synthesis
comparison
follow-up reasoning
language
Enter fullscreen mode Exit fullscreen mode

That division is much easier to test.

This isn't specific to astrology

The same architecture makes sense in other domains.

SQL query
   ↓
actual metrics
   ↓
AI explanation
Enter fullscreen mode Exit fullscreen mode

or:

compiler / AST
   ↓
structured findings
   ↓
AI explanation
Enter fullscreen mode Exit fullscreen mode

or:

deterministic pricing engine
   ↓
quote
   ↓
AI explains the quote
Enter fullscreen mode Exit fullscreen mode

If something important can be calculated or retrieved deterministically, I increasingly prefer doing that before the model sees it.

Then the AI can work with evidence instead of pretending to be the evidence source.

The rule I use now

The rule is simple:

Code determines what is in the chart.
AI helps explain what the chart may mean.

That doesn’t eliminate hallucinations.

It doesn’t solve every quality problem.

But it gives the system a stable foundation.

And once you have that, everything from testing to UI explanations gets easier.

The calculation engine behind this architecture is open source here:

https://github.com/getbirthchart-com/gbc-astro-engine

The hosted product using it is:

https://getbirthchart.com/

Top comments (0)