Our Blog: How I Built an AI Expert That Costs About Two Cents

Most people assume the AI was the hard part. It wasn't.

How I Built an AI Expert That Costs About Two Cents

There is a lot of money being spent right now on AI products that are impressive in a demonstration and difficult to justify in production. A prototype can absorb a surprisingly expensive prompt, wait thirty seconds for an answer, and occasionally produce something strange without causing much trouble. Once real users arrive, those same details become the product. Cost matters. Response time matters. Consistency matters. Most importantly, the system has to know the difference between information it can generate and facts it must get right.

I ran into all of those problems while building an AI-powered astrology application. The system generates personalized readings for people, relationships, companies, product launches, and other events. It does more than paste a birth date into a generic prompt and ask a model to improvise a horoscope. It calculates a complete chart, selects the details relevant to a particular type of reading, and gives those facts to an AI agent with a defined personality and a narrow job.

That agent is called Sage. The goal was to make Sage feel like a consistent expert rather than a different chatbot every time someone requested a reading. The writing needed to be personal without becoming vague, confident without inventing facts, and detailed without producing ten pages of repetitive filler. After optimizing the system, a typical reading costs roughly two cents to generate.

The cost is a useful headline, but it was not achieved through one clever prompt or a hidden model setting. It came from treating the AI as one component of an ordinary software system. Most of the work involved deciding what the model should not be allowed to do.

Astrology Is a Better AI Test Than It Sounds

Astrology may seem like an odd domain for this experiment, especially if you are skeptical of it. I am not interested in convincing anyone that astrology is true, but from an engineering perspective it creates a useful combination of rigid calculations and subjective interpretation.

A birth chart begins with objective inputs: a date, a time, a timezone, a latitude, and a longitude. Those inputs are used to calculate the locations of planets, the ascendant, the midheaven, house cusps, retrogrades, and angular relationships between different bodies. Relationship readings introduce another chart and require comparisons between them. Composite readings generate a chart representing the relationship itself. Vedic compatibility uses an additional set of calculations and scoring rules.

Whatever someone believes those results mean, the underlying chart cannot simply be improvised. Mars is either in a particular position or it is not. A planet either forms an aspect within the configured orb or it does not. A timezone error can shift the houses and change the reading. These are deterministic problems, and a language model is not the right tool for solving them.

Interpretation is different. Two astrologers can look at the same chart, emphasize different patterns, and explain those patterns in different language. That is where generative AI becomes useful. It can take a large collection of structured facts and turn them into prose that feels coherent, personal, and readable.

This gave me a fairly clean architectural boundary: traditional software would establish the facts, and the AI would interpret them.

The Model Is Not Allowed to Calculate the Chart

The most important decision in the entire system was refusing to ask the language model to perform astrology calculations. The application uses Swiss Ephemeris through a PHP integration to calculate the chart. Separate domain services handle natal charts, relationship comparisons, composite charts, and Vedic compatibility. Those services return structured data that the rest of the application can test, cache, inspect, and reuse.

By the time Sage receives a request, the expensive and error-prone domain work has already happened. The application knows the relevant planet positions, houses, retrogrades, angles, and major aspects. It converts that data into a compact reading context rather than handing the model the full internal chart structure. Sage is then asked to explain the supplied chart, not recreate it.

That distinction sounds obvious after the fact, but it is easy to ignore when building with language models. The model appears capable of doing nearly anything, so there is a temptation to keep expanding its responsibility. A prompt starts with a few instructions, then grows into a combination of business rules, reference material, formatting requirements, calculations, examples, exceptions, and personality notes. Eventually the prompt becomes an application written in English, except it is more expensive to run and much harder to test.

I wanted the opposite. If PHP could calculate something reliably, PHP calculated it. If a rule could be expressed as code, it stayed in code. The AI only received information that required interpretation or communication.

This did more than reduce errors. It also reduced the amount of context required for each reading. Instead of sending every field the chart engine produces, the generation job selects the pieces Sage actually needs. For a natal reading that may include the birth information, primary angles, formatted planet placements, houses, retrograde markers, and the most significant aspects ordered by orb. The model does not need every intermediate value or the entire object graph behind the calculation.

The smaller context made the system cheaper, but it also made the output better. Giving a model more information does not automatically make it more intelligent. Irrelevant detail competes with important detail. The tighter the boundary became, the easier it was for Sage to identify the dominant patterns and write a focused reading.

Building a Consistent Expert

Once the calculations were removed from the AI, the next problem was consistency. A generic chatbot can answer in whatever style seems appropriate at the moment. An expert inside a product needs a recognizable voice and a stable set of boundaries.

Sage has a reusable system prompt that defines how the agent should behave. The voice is warm and plainspoken rather than theatrical. The instructions discourage generic horoscope language and require claims to be grounded in the chart data provided for the current reading. The agent is told to acknowledge strengths and tensions without turning every difficult placement into a crisis or every pleasant placement into a promise. It can use Markdown for readability, but the result should still feel like a person explaining a chart rather than a template filling in headings.

The actual task prompts are deliberately small. A natal reading asks for an honest interpretation of the person's chart, including its dominant tone, strengths, tensions, and unusual features. A relationship reading asks Sage to focus on communication, attraction, conflict, what works, and what may break down. A composite reading treats the relationship as its own chart. Entity readings use the same agent to interpret companies, products, funding rounds, domain registrations, and significant events.

The personality and grounding rules remain stable, while the immediate task changes. The chart data is injected into the reusable instructions as the current reading context, and the user-level prompt simply tells Sage what kind of interpretation to produce. The system also uses the provider's prompt-caching support for that reusable block.

This is where the phrase "AI expert" needs some clarification. Sage is not sentient, and I am not claiming that it possesses human expertise. What I built is a constrained expert interface. It receives facts from a domain engine, applies a consistent interpretive voice, and produces a useful explanation. The expertise of the product comes from the combination of deterministic domain logic, curated instructions, carefully bounded context, and the language model's ability to synthesize it.

The personality is useful, but the boundaries matter more. A convincing tone is dangerous when a model is free to invent the substance underneath it. Sage can sound confident because the application has already supplied the chart it must discuss.

How the Cost Reached Two Cents

There was no single moment when the cost suddenly dropped from dollars to pennies. The two-cent result came from a collection of ordinary engineering decisions that reduced unnecessary work.

The first was model selection. Sage uses a smaller, lower-cost Anthropic model rather than assuming every reading requires the largest model available. A larger model may perform better on certain benchmarks, but that does not make it the right choice for every bounded writing task. Once the application provides reliable facts and a strong structure, the model has a much simpler job.

The second was prompt reuse and caching. The agent's personality and general behavior do not need to be treated as completely new information on every request. The system takes advantage of prompt caching on the reusable instruction block so repeated generation can avoid paying the full price for the same stable context each time.

The third was context reduction. The chart engine produces a rich data structure, but Sage receives a smaller representation prepared specifically for interpretation. Only major aspects are included in the natal and entity reading contexts, and they are sorted so the strongest relationships appear first. Static domain calculations stay in PHP, where they can also be cached independently of the AI call.

The fourth was preventing duplicate or obsolete generation. AI calls run in queued jobs rather than during the incoming web request. Those jobs check whether a reading has already been generated before calling the model. They use cache markers and locks to debounce rapid changes, and stale jobs can exit rather than producing a reading for birth data that has already been updated. Chart calculations themselves are cached, so regenerating related views does not require repeating the same astronomical work.

These details are not exciting enough to sell as a new category of prompt engineering, but they are where much of the savings came from. The system uses a less expensive model, sends less information, reuses stable instructions, caches deterministic work, and avoids requests that should never happen. The repository also records the provider, model, invocation identifier, and token usage with every generated message, including prompt-cache reads and writes. That makes the cost observable instead of relying on a vague estimate from a monthly bill.

The two-cent figure is not a constant hard-coded into the application. It is the approximate cost produced by the current model, prompt sizes, response lengths, caching behavior, and provider pricing. Those variables can change, which is why recording usage per generated artifact matters. I can see what a reading consumed and evaluate the economics as the application evolves.

Production AI Still Looks Like Normal Software

AI demos tend to focus on the request and the response because those are the visibly impressive parts. A production feature has much more surrounding it.

Readings are generated asynchronously in Laravel queue jobs. The application retries failed jobs at the queue level, stores the generated response as a message within a scoped thread, broadcasts a completion event over a private channel, and also polls while the reading is still pending. The WebSocket path makes completion feel immediate when everything works normally, while polling gives the interface a fallback if a realtime event is missed.

The same thread abstraction supports different kinds of readings without requiring a separate persistence model for each one. A user can have a natal thread, a relationship can have separate synastry, composite, and Vedic threads, and a company or product can have an entity reading. Generated messages retain internal metadata about which agent and model created them, while the public API only exposes the content needed by the client.

Testing also required a deliberate decision: the test suite fakes Sage globally so automated tests cannot accidentally make real model calls and spend money. The code can test the application's behavior around generation without depending on a live provider or paying for every run.

None of this is uniquely "AI architecture." It is application architecture. Jobs, locks, caching, events, database models, retries, authorization, test doubles, and observability remain necessary. The model does not remove the need for those systems. It introduces another external dependency that must be controlled by them.

There are also areas that still need improvement. Narrative Markdown is easy to display but difficult to validate formally. A reading can be checked for presence and rendered safely, but there is no JSON schema proving that the model discussed every required topic or used only the supplied facts. Some reading paths have a more complete pending, ready, and failed lifecycle than others. The relationship-reading context also needs continued work to ensure every prompt receives all of the comparison data it claims to use.

That is another part of building real AI products that tends to disappear from the demos: the boundary is never finished. You keep finding places where the model has too much freedom, too little context, or inconsistent error handling. The answer is usually not to add another paragraph to the prompt. It is to improve the surrounding software.

Why I Did Not Use a Giant Knowledge Base

One useful side effect of this architecture is that it grounds Sage without requiring a large retrieval-augmented generation system.

RAG is valuable when an application needs to search a changing body of unstructured knowledge. This application has a different problem. The important facts for a reading are produced directly by typed domain services at the moment the request is made. There is no need to search a vector database to find someone's ascendant or determine whether two planets form an aspect. The chart engine already knows.

The application converts those facts into a bounded reading context and places it directly in the model's instructions. Sage is told to base the interpretation on what is present. This does not guarantee perfect compliance, because language-model output remains probabilistic, but it gives the model a small and authoritative source of truth.

For this product, structured context is simpler, cheaper, and easier to reason about than adding a retrieval layer merely because RAG has become a common part of the AI stack. The best architecture is not the one with the most fashionable components. It is the one that matches the shape of the data and the job being performed.

The Broader Business Lesson

The architecture behind Sage applies to far more than astrology. Most businesses already have deterministic systems full of useful information. A manufacturer has production schedules, inventory counts, job statuses, quality records, and delivery dates. A healthcare application has measurements, appointments, claims, and care plans. An internal sales system has customer history, quote activity, and order data.

The AI should not be asked to recreate those facts from a vague prompt. It should receive the facts from the systems that own them and help a person understand what they mean.

A manufacturing assistant might explain why a group of orders is at risk based on data calculated by the scheduling system. A customer-service agent might summarize an account history assembled by the application. A compliance tool might explain which documented conditions triggered a rule without allowing the model to invent the rule itself. In each case, the valuable pattern is the same: deterministic software establishes reality, and the language model turns that reality into useful language.

This is also why cost optimization cannot be separated from product design. If a model has to inspect the entire history of a company and rediscover the business rules on every request, the application will be expensive because its architecture is expensive. If the application prepares the relevant facts first, the language model's responsibility becomes smaller and the economics improve naturally.

The cheapest token is the one the application never needed to send.

What I Would Do Differently

The next version of this system will continue moving responsibilities away from unstructured generation wherever the product benefits from stronger guarantees. I would make the generation lifecycle consistent across every type of reading, add explicit output limits instead of relying only on prose instructions, and improve validation around the claims a reading makes.

I also want better evaluation tooling. The system can already inspect usage and dry-run the context sent to Sage, which is useful for understanding cost. Quality is more difficult. A response can sound excellent while quietly ignoring an important aspect, repeating a theme, or introducing a statement that is not clearly supported by the chart. Production AI needs repeatable quality checks just as much as it needs token accounting.

I would not, however, move the domain calculations into the model. That boundary has held up well. The more reliable logic stays in the application, the easier the AI layer is to replace, test, and improve. Model providers will change, pricing will change, and the quality of smaller models will continue to improve. The deterministic chart engine should remain useful regardless of which model writes the final interpretation.

That separation protects the product from becoming a wrapper around one provider. Sage is an important part of the experience, but Sage is not the entire application.

Two Cents Is a Result, Not the Strategy

It would be easy to treat the price as the main accomplishment. Two cents is memorable, and it makes a good headline. The more important result is that the system became cheaper as it became better structured.

That is not always what happens in early AI development. It is common to improve apparent quality by increasing the model size, sending more context, and allowing longer responses. Those changes may help in the short term, but they can disguise an application that has never decided what the model is actually responsible for.

In this case, reducing the model's responsibility improved the output. Sage no longer needed to sort through raw calculation data or infer facts the application could provide directly. The persona became more consistent because the instructions had a stable home. The readings became easier to reproduce because the domain data was deterministic. Costs fell because the prompt was smaller and repeated work was cached or eliminated.

The model did not become more capable. The system became more disciplined.

That is the main lesson I am taking from this project. Building a useful AI expert is less about persuading a model to know everything and more about surrounding it with software that knows exactly what it should do.

Today that produces an astrology reading for roughly two cents. Tomorrow the same pattern could explain manufacturing delays, summarize operational data, guide an employee through a complicated workflow, or turn a dense report into something a customer can understand.

The domain will change. The principle probably will not: calculate what can be calculated, validate what can be validated, and only ask the AI to do the part that genuinely requires language.

Want to check it out? click here.