At CGI I work on an internal audit application for a major Canadian bank, used by more than 1,000 auditors. I own its sync features and report generation, including the UI and the APIs behind them.
Auditors were preparing workpapers and reports across scattered systems, and the report process was slow, manual and tied to a third-party application we couldn’t easily improve. Report preparation took hours.
It now takes minutes, and the pipeline and sync handle hundreds of reports and workpapers a month. Three decisions got it there.
Don’t make people wait for the model
Report generation is slow, especially the AI-written sections. If it ran inside a request, auditors would sit and watch a spinner, so it runs on background workers tracked in a task table instead. An auditor starts a report and carries on with other work.
Moving work into the background creates its own question: what happens when it fails? Try it here.
- Job added to the task tabledone
- Worker picks up the jobdone
- Upstream data rendered into the Word templatedone
- OpenAI API drafts the report and summarydone
- Auditor reviews before approvalready
A failed job retries up to 20 times, then fails for good rather than retrying forever. A separate heartbeat check catches a dead worker, so a job can’t sit stuck with nobody noticing.
The AI draft is never final
The pipeline uses the OpenAI API to draft the report and its summary sections, with the prompt built from audit context. But the output never goes straight through. An auditor reviews every generated report before it goes for approval.
That review is part of the design, not a formality. In audit, someone has to stand behind the document. The model proposes, and a person decides.
Data handling mattered just as much. The prompt carries structured context and summaries rather than raw workpapers, and client and personal fields are redacted before anything is sent.
The hardest part wasn’t the AI
The hardest bug on this work was getting the Word documents right. The pipeline renders upstream data through XML into a Word template, and the first versions were wrong in three ways:
- Repeating sections such as tables and lists rendered incorrectly. I restructured the XML so repeated rows and blocks matched the template’s repeat markers.
- Empty fields left raw placeholders in the document or broke generation. I added defaults and validation, so a missing value now leaves a clean gap.
- Formatting from the source, such as line breaks and styles, was lost. I mapped those onto the matching Word XML elements.
Auditors now receive a correctly formatted Word document. Nobody praises a table for rendering properly, but one broken table is enough to make people stop trusting the whole report.
Approvals in tiers
Reports and workpapers don’t get a single approve or reject. I modelled approvals as tier-based chains and built them across the frontend and backend.
Auditors responded well. Preparation moved into one central system, and they no longer have to wait for a report to finish before moving on.