The Prompt Library gives you patterns for driving analysis with AI. This is where you practice them. Below is a small customer table. Pick an analysis goal, watch the matching prompt pattern fill in, edit it to make it your own, and run it against this data. When you are ready to hand an AI a whole assignment rather than one question, go to Plan the whole task.
A synthetic accounts-receivable extract. Revenue is right-skewed, two accounts are far larger than the rest, and there are two segments. This is the table every prompt below runs against.
| customer_id | segment | revenue ($) | days_to_pay | region |
|---|
Each goal is one of the five moves from the Prompt Library. Click one and its prompt pattern fills the box below, already adapted to this table's columns.
Run prompt sends your prompt straight to the model, which gets the 20 rows along with it, and shows the answer below. If you would rather use your own AI in another tab, Copy prompt gives you the text plus the data to paste in. Either way, compare what you get back to the model answer.
Pick a goal first. This reveal shows the kind of answer a strong version of that prompt should pull back, so you can compare it to what you got. It is a yardstick, not a substitute for running your own.
The first five cards are the five categories from the Prompt Library page, each pre-filled with a worked version pointed at this table. The sixth, Chart it, asks the model to draw a chart of the same data so you can compare it to the reference chart the page already knows is right.
Everything above works on one question at a time. A homework assignment is different, because it is a set of instructions, a template to fill, and a group of numbers that all have to tie to each other.
If you paste the whole assignment into an AI and ask for the answer, you will usually get a confident answer that nobody has checked. It can look finished and still be wrong in a way that is hard to find, such as a duplicate row counted twice or a void that was never excluded.
If you instead ask the AI to plan first, build in steps, and prove each step against an independent check, you get work you can walk someone through and defend. The independent check is the part that matters most. It works like a control in an audit, where a number is accepted because a separate test that recomputes it from the source agrees, not because it looks reasonable.
These prompts do not run on this page. Fill in the [brackets], copy the prompt, and paste it into the AI tool you already use, where you can keep the whole assignment in one conversation.
Open a pattern to see the prompt. The first one is the anchor, and the rest are the pieces it is built from, in roughly the order you would use them on a real assignment.
This homework, the company and its data are illustrative, made up for this example. The numbers are internally consistent, so every check below ties to every other one.
This is the anchor pattern filled in for an assignment shaped like Lab 3 and Homework 3, where you fill an aging workbook in Excel and then tie it out in SQL.
invoices.csv (invoice_id, customer_id, invoice_date, amount, status) and customers.csv (customer_id, segment, terms_days). Age everything as of March 31, 2026.ar_aging_template.xlsx: total open AR (B4), open invoice count (B5), open AR and invoice count for Not due, 1-30, 31-60, 61-90 and 90+ days past due (B8:C12), and the share of open AR more than 60 days past due (B14).I have been assigned this homework. Here are the full instructions, copied exactly: Homework: AR aging tie-out for Juniper Ridge Supply Co. 1. Use invoices.csv (invoice_id, customer_id, invoice_date, amount, status) and customers.csv (customer_id, segment, terms_days). Age everything as of March 31, 2026. 2. Age every open invoice by days past due against the customer's net terms. The due date is the invoice date plus terms_days. An open invoice still within its terms is Not due. 3. Exclude void and paid invoices. 4. Fill the Summary sheet of ar_aging_template.xlsx: total open AR (B4), open invoice count (B5), open AR and invoice count for Not due, 1-30, 31-60, 61-90 and 90+ days past due (B8:C12), and the share of open AR more than 60 days past due (B14). 5. Tie your workbook out in SQL. Reproduce total open AR and every bucket total to the cent. 6. Write two sentences for the controller on where the collection risk sits. I need to populate the Summary sheet of ar_aging_template.xlsx. The data is in invoices.csv and customers.csv. Please generate a script that can complete the homework as assigned. I am using Excel formulas for the workbook and SQLite for the tie-out, and I do not know Python yet. Before you write anything, give me a numbered plan with the input, the output and a checkpoint for each step, and list anything in the instructions that is ambiguous. Then set up a separate model where I can independently verify the results. Reload the raw CSVs and my filled Summary sheet into a SQLite database, and write queries that test each assumption the plan makes: row counts, duplicate invoice IDs, invoices whose customer is missing from customers.csv, status values, bucket edges, and totals that should tie. For each check, tell me what result means the work is right and what result means it is wrong. The verification has to recompute every number from the raw data. Do not check the workbook by rereading it.
A strong response plans before it builds, names what it is unsure of, and hands you checks that recompute the numbers from the raw files. Compare the shape of what your AI gives you to this, not the exact wording.
| Step | Input | Output | Checkpoint |
|---|---|---|---|
| 1. Load and profile | invoices.csv, customers.csv | Two SQLite tables | 241 invoice rows and 30 customers, status is only Open, Paid or Void |
| 2. Clean | invoices | One row per open invoice | 114 open invoices, down from 115 open rows once one exact duplicate is removed |
| 3. Attach terms and age | Open invoices, customers | days_past_due for each invoice | No blank due dates, and the one invoice without a customer is flagged |
| 4. Bucket and summarize | Aged invoices | Five bucket totals and counts | The buckets add back to total open AR |
| 5. Fill the workbook | A cleaned invoice sheet | Summary sheet B4:C12 and B14, as SUMIFS and COUNTIFS formulas | Every cell filled with a formula, not a typed value |
| 6. Verify independently | Raw CSVs plus the saved Summary sheet | A difference table | The difference query returns zero rows |
| 7. Write the note | Verified numbers | Two sentences | Every number in the note is one the difference query checked |
| Assumption | How it is tested | What it found, and what changes |
|---|---|---|
| invoice_id is unique | Check B | It is not. INV-10002 appears twice as an exact copy, so one copy is dropped before anything is summed. |
| Every invoice has a customer record | Check C | INV-10058 ($880.61, customer K031) has none. On 30-day terms it is 28 days past due, and on 45-day terms it would be 13, so it lands in 1-30 either way and the bucket does not depend on the guess. |
| Status is spelled exactly Open, Paid or Void | Check A | Holds. If it did not, a variant such as "open " would silently drop out of the open total. |
| Amounts are positive, with no credit memos | Check D | Holds. A negative amount would need a rule for netting it against the customer's balance. |
| Every invoice_date is a real date | Check D | Holds, with dates from 2025-11-01 to 2026-03-31. A date stored as text in another format would age wrong without an error. |
| Bucket edges are read correctly | Check F | Five invoices sit on an edge, two at 31 days and one each at 60, 90 and 91, and each is spot-checked by hand. |
Import the two CSVs as tables named invoices and customers, for example with File, Import, Table from CSV in DB Browser for SQLite. None of these queries read the workbook until check G, which is what makes them an independent check.
SELECT status, COUNT(*) AS n, ROUND(SUM(amount), 2) AS total FROM invoices GROUP BY status ORDER BY status;
Open 115 rows, $289,477.74. Paid 106 rows, $356,351.36. Void 20 rows, $46,843.89. The three add to 241, which matches the number of data rows in invoices.csv, and no other status appears.
SELECT invoice_id, COUNT(*) AS copies FROM invoices GROUP BY invoice_id HAVING COUNT(*) > 1;
One row back: INV-10002, 2 copies. Zero rows would mean the IDs are unique. This one is an exact duplicate of an open $1,918.32 invoice.
SELECT i.invoice_id, i.customer_id, i.amount, i.status FROM invoices i LEFT JOIN customers c ON c.customer_id = i.customer_id WHERE c.customer_id IS NULL;
One row back: INV-10058, K031, $880.61, Open. This is a customer in one table and not the other, and an inner join would have dropped it from the total without any warning.
SELECT SUM(CASE WHEN amount IS NULL OR amount <= 0 THEN 1 ELSE 0 END) AS bad_amounts, SUM(CASE WHEN julianday(invoice_date) IS NULL THEN 1 ELSE 0 END) AS bad_dates, MIN(invoice_date) AS first_date, MAX(invoice_date) AS last_date FROM invoices;
0 bad amounts, 0 bad dates, first 2025-11-01, last 2026-03-31. Nothing is dated after the as-of date.
CREATE VIEW open_aged AS
SELECT *,
CASE
WHEN days_past_due <= 0 THEN 'Not due'
WHEN days_past_due <= 30 THEN '1-30'
WHEN days_past_due <= 60 THEN '31-60'
WHEN days_past_due <= 90 THEN '61-90'
ELSE '90+'
END AS bucket
FROM (
SELECT DISTINCT i.invoice_id, i.customer_id, i.invoice_date, i.amount,
CAST(julianday('2026-03-31')
- julianday(i.invoice_date, '+' || COALESCE(c.terms_days, 30) || ' days')
AS INTEGER) AS days_past_due
FROM invoices i
LEFT JOIN customers c ON c.customer_id = i.customer_id
WHERE i.status = 'Open'
);
SELECT bucket, COUNT(*) AS n, ROUND(SUM(amount), 2) AS total
FROM open_aged
GROUP BY bucket;
Not due 27, $83,174.21. 1-30 23, $46,353.83. 31-60 31, $74,364.19. 61-90 18, $46,539.40. 90+ 15, $37,127.79. Together that is 114 invoices and $287,559.42, which is the open total from check A less the $1,918.32 duplicate. The LEFT JOIN keeps INV-10058, and DISTINCT drops the second copy of INV-10002.
SELECT invoice_id, days_past_due, bucket FROM open_aged WHERE days_past_due IN (0, 1, 30, 31, 60, 61, 90, 91) ORDER BY days_past_due;
Five rows: two at 31 days in 31-60, one at 60 in 31-60, one at 90 in 61-90, and one at 91 in 90+. These are the rows an off-by-one mistake would move, so compare each to the workbook by hand.
Save the Summary sheet as summary.csv with two columns, label and value, and import it as a table named template_out. Then recompute the same labels in SQL and list every one that disagrees.
CREATE TABLE sql_out AS SELECT 'Total open AR' AS label, ROUND(SUM(amount), 2) AS value FROM open_aged UNION ALL SELECT 'Open invoice count', COUNT(*) FROM open_aged UNION ALL SELECT 'AR ' || bucket, ROUND(SUM(amount), 2) FROM open_aged GROUP BY bucket UNION ALL SELECT 'Count ' || bucket, COUNT(*) FROM open_aged GROUP BY bucket UNION ALL SELECT 'Share over 60 days (%)', ROUND(100.0 * SUM(CASE WHEN days_past_due > 60 THEN amount ELSE 0 END) / SUM(amount), 1) FROM open_aged; SELECT s.label, t.value AS workbook, s.value AS recomputed, ROUND(t.value - s.value, 2) AS difference FROM sql_out s LEFT JOIN template_out t ON t.label = s.label WHERE t.value IS NULL OR ABS(t.value - s.value) > 0.005;
On the first pass this returned five rows, which is the check doing its job.
| label | workbook | recomputed | difference |
|---|---|---|---|
| Total open AR | 289,477.74 | 287,559.42 | 1,918.32 |
| Open invoice count | 115 | 114 | 1 |
| AR 31-60 | 76,282.51 | 74,364.19 | 1,918.32 |
| Count 31-60 | 32 | 31 | 1 |
| Share over 60 days (%) | 28.9 | 29.1 | -0.2 |
Every dollar difference is $1,918.32, which is INV-10002 from check B. The workbook's SUMIFS counted the duplicate twice, and it sits in 31-60 because it is 39 days past due. The share moved too, even though the duplicate is not over 60 days, because it inflated the total underneath the ratio. Removing the duplicate row in the workbook and saving the Summary sheet again brings the difference query to zero rows.
Second pass: zero rows. SQL and the workbook are two separate methods, and they now agree on every label, so the numbers can go in the note.
Open AR is $287,559.42 across 114 invoices as of March 31, 2026, and 29.1 percent of it, $83,667.19, is more than 60 days past due. One open invoice for $880.61 (customer K031) has no customer record and was aged on 30-day terms, so the billing team should confirm that customer before the next aging runs.
Notice what the response did not do. It did not report a total until the duplicate and the missing customer had been found, and it did not trust the workbook because the workbook looked right. The workbook was accepted when a separate method, built from the raw files, agreed with it.