CASE STUDY: AI Report Writing Built Into a Property Inspection Platform
Summary: Our client was writing two narrative sections of every commercial property inspection report by hand in the ChatGPT web app. We built both directly into their reporting platform, using constrained output and verified web search. If you are weighing up whether an AI feature belongs in your product or in a browser tab, this is what the difference looks like in practice.
Our client produces commercial property inspection reports. Two sections of each report are narrative rather than data: a description of the surrounding area with market rent and vacancy figures, and a general write-up of the subject property.
Their team was producing both by hand. Paste report data and a prompt into the consumer ChatGPT app, read the result, copy it back into the platform, then fix everything the model had added that nobody asked for. It worked. It also did not scale, and it drifted.
We built both features directly into their reporting platform through the OpenAI API. Both are in production.
Why did the manual approach stop working?
Because a general-purpose chat interface has no way to be held to a format. Their team described the pattern: after roughly a hundred reports the model starts adding content nobody asked for and blowing past the character limits the report fields enforce.
That is not a prompt problem, and it is worth being precise about why. A better prompt raises the odds of a good answer. It does not make the answer a guaranteed shape. When the output has to land in a fixed field, in a fixed order, under a fixed character count, “usually right” is a defect.
The other failure was quieter and more serious. We will come back to it.
How do you stop a model adding things nobody asked for?
You stop asking it for the whole answer. You get a strict data structure from the model, then assemble the finished text in code.
Three techniques do the work:
- Structured output. The model returns a strict JSON schema rather than prose. The right fields come back, in the right order, every time, because the shape is enforced by the API rather than requested in a prompt.
- Hardcoded sentences. Any sentence that must be identical on every report is written in code, not generated. The compliance line in the general comments section is a fixed string. The model never sees it as something to write.
- Code-side limits. Character counts are validated and enforced in code after generation. A language model cannot reliably count characters, so asking it to respect a limit is asking for the wrong thing. Low temperature settings sit on top of that.
The pattern generalises. Decide what must be exact, put that in code, and give the model only the part that genuinely needs judgment.
What the two features do
Surrounding area and market data. Takes two inputs, the subject property address and its primary type, and populates the surrounding area fields plus average market rent and average market vacancy. Comparable properties follow fixed selection rules: exclude the subject, same city and state, similar type and market orientation, start within one mile and expand no further than ten, never cross a state line. Land use percentages must total one hundred in five percent increments. Market rent comes back as a single dollar figure and vacancy as a single percentage, with no ranges and no commentary. Output order is fixed.
General comments. Summarises the subject property from the report’s own data, with no web access. The first sentence is a template with values substituted from the report fields, including a small rule that matters more than it looks: when the unit count is one, the word “single” is substituted rather than the numeral. The second sentence is the hardcoded compliance line. The remainder is the generated summary of capital expenditures, deferred maintenance and repair verification, written to MBA 4.03 and to a neutral tone for Fannie Mae and Freddie Mac, and held to roughly nine hundred characters.
The surrounding area feature runs once. General comments can be re-run whenever the underlying report data changes. Neither runs automatically: the team validates photos and fixed fields first, then triggers the AI population deliberately.
How do you know the model actually checked?
You verify that the search ran before you let it say anything, and you refuse to publish the sentence otherwise.
This is the quiet failure worth the most attention. Part of the surrounding area section reports whether there have been fire or violent crime incidents at the exact property address in the past twelve months. If there were none, a specific disclosure sentence is required.
In manual testing, ChatGPT inserted that disclosure without having performed the search. Challenged on it, the model admitted it had not checked. Read that again: the report said a review found nothing, and no review had happened.
Nothing in a browser tab prevents this. The build does:
- The web search tool is forced to execute for that step. The model is not permitted to answer from memory.
- Real search evidence is verified before any statement is composed. The tool call has to have run.
- The disclosure sentence is emitted only when a search actually ran and returned no hits at that exact address. Otherwise the step re-runs or flags rather than fabricating.
That is the clearest argument we know for building AI into a product rather than working alongside a chat window. The manual version was not just inconsistent. It was capable of asserting that a check had been done when it had not, inside a professional report. The engineered version cannot.
Everything the features produce is still treated as a draft for review, and the client’s team validates it as they always did. Web search reduces hallucination on comparables, rents and vacancy. It does not eliminate it.
“The recent integration has noticeably improved productivity, eliminating those redundant manual tasks of summarizing data that was already keyed somewhere else in the report.”
The client
What this project shows
The distinction that matters is not which model you use. It is whether the output is constrained.
The manual process worked until it did not, and the way it failed was invisible from the outside: correct-looking sentences, some of which were not backed by anything. The production version is constrained so that it cannot drift past a character limit, cannot reorder the output, cannot invent a compliance sentence, and cannot claim a check it did not perform.
We build with the OpenAI API. The interesting engineering is rarely the model call. It is the schema, the code that assembles the result, and the checks that decide whether the model is allowed to speak at all.
Talk to Us About Your AI Project
We build AI into the systems a business already runs on, where it has real data to work with and a real job to do. If you have a workflow running through a chat window today and you want it in your product instead, we can tell you what that takes.
See our AI application development and integration work, our custom application development services, or the MediaTrAiner case study for an AI platform we built and support end to end. Or just tell us what you are trying to automate.

