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."
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?
Then:
What might those things mean together?
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
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
}
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
and the generated interpretation starts talking about:
your Scorpio Moon
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"
}
]
}
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
}
]
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
I want the LLM to handle:
explanation
synthesis
comparison
follow-up reasoning
language
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
or:
compiler / AST
↓
structured findings
↓
AI explanation
or:
deterministic pricing engine
↓
quote
↓
AI explains the quote
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:
Top comments (0)