Refund Approval — from data enrichment to risk scoring and a HITL agent
Walk one cycle of the QuickReturn Electronics scenario — joining orders/customers/refund history, risk scoring, policy RAG, and a Human-in-the-Loop refund-approval agent.
Workshop goal
By the time you finish this Workshop, you will have walked through one full cycle of the following flow inside D.Hub.
- Load a single scenario into portal so that two sub-collections (
raw_dataandrefund_ops), 5 datasets, 3 code nodes, 3 pipelines, an ontology with 3 entities and 2 relations, a dashboard, one knowledge, and one agent are all registered together. - Build
enriched_ordersby combining three sources —raw_orders(ERP),raw_customers(CRM), andrefund_history(finance DB) — with multi-key joins. - Use the
risk_assessmentpipeline to assign a 0–100risk_scoreand a three-labelrisk_level(LOW / MEDIUM / HIGH). - Run one session of the
refund-approvalagent that searches therefund_policyknowledge via RAG and walks one refund through AI analysis → human review → automated execution. - Expand a customer-order-refund graph to surface a single customer's refund history cluster.
It's an integrated exercise that combines the Analyst Path's data joining / visualization and the Engineer Path's pipelines / agents. The HITL (Human-in-the-Loop) workflow is the core idea. Recommended duration: 90 minutes.
Prerequisites
- An analyst or engineer account with access to D.Hub portal (Editor or higher)
- ~55 KB of download room for one scenario zip
No terminal, Python, or dhub2-examples clone needed. Finishing the entry-level tutorial Import a scenario zip in one shot first makes step 1 flow smoothly.
1. Load the scenario (10 min)
refund_approval.zip Download(54 KB)Go to Collections in the left sidebar → more (⋯) menu → Import (가져오기) and upload the zip. Two collections appear automatically.
Following manifest.json, the import creates the following in order:
- Two collections —
raw_data(alias: Refund Raw Data),refund_ops(alias: Refund Operations) - Five datasets —
raw_orders(raw),raw_customers(raw),refund_history(raw),enriched_orders(ops),risk_assessed_orders(ops) - Three codes (Python) —
join_order_customer,risk_scorer,build_refund_ontology - Three pipelines —
order_enrichment,risk_assessment,ontology_materialization - Ontology — three entities (
customer,sales_order,refund_request), two relations (placed_by,requested_for) - One knowledge —
refund_policy(refund policy guide) - One dashboard —
refund_operations - One agent —
refund-approval(HITL workflow)
Step 1 is complete once raw_data and refund_ops show in the left tree.
2. Browse the raw data (15 min)
This scenario's core is combining three sources. In the raw_data collection, work through the three datasets.
raw_orders (12 rows) — Order transactions. Columns: order_id, customer_id, product_category (phones / laptops / headphones / tablets), order_date, total_amount, payment_method.
raw_customers (10 rows) — Customer profile. Columns: customer_id, name, email, signup_date, tier (standard / silver / gold / platinum), lifetime_value.
refund_history (10 rows) — Past refund records. Columns: refund_id, customer_id, order_id, refund_date, refund_amount, reason (defective / wrong_item / not_as_described / change_of_mind), status (approved / rejected / pending).
In each dataset's Schema tab, confirm that customer_id and order_id are the same type (string) across sources. The enrichment in §3 runs a 3-way join on these two keys.
3. Data enrichment pipeline (15 min)
In the refund_ops collection's Pipelines section, open order_enrichment. One node — join_order_customer combines the three sources into enriched_orders.
The script body: left-join raw_orders with raw_customers on customer_id, then left-join that result with refund_history on customer_id to attach each customer's past refund counts. Output columns include the original order plus tier, lifetime_value, past_refund_count, past_approval_rate.
Press Run. When it finishes, open the Preview tab on enriched_orders and confirm one row carries the merged shape across all three sources. past_refund_count should fall between 0 and 3.
4. Risk scoring (15 min)
In the refund_ops collection, open risk_assessment. One node — risk_scorer reads enriched_orders and produces risk_assessed_orders. The new columns: risk_score (0–100) and risk_level (LOW / MEDIUM / HIGH).
The weighted scoring formula in the risk_scorer script reads in one line.
risk_score = clip(
past_refund_count × 12
+ (1 − past_approval_rate) × 30
+ (lifetime_value < 1000 ? 20 : 0)
+ (order_amount > 1500 ? 15 : 0),
0, 100
)
- +12 per past refund (e.g. 3 refunds → +36)
- +30 if past rejection rate is 100%
- +20 if LTV is below 1000
- +15 if order amount exceeds 1500 (high-ticket)
Label cutoffs: ≤30 = LOW, 31–60 = MEDIUM, ≥61 = HIGH.
Press Run. When it finishes, open risk_assessed_orders and check the risk_level distribution across 12 rows. On the seed data, LOW : MEDIUM : HIGH ≈ 5 : 4 : 3.
5. Ontology + graph exploration (10 min)
Run ontology_materialization once. build_refund_ontology reads three raw + two enriched datasets in batch mode and lands the following five artifacts in upsert mode.
| Artifact | Kind | Meaning |
|---|---|---|
customer | Entity | Key: customer_id. Attributes: name, tier, lifetime_value |
sales_order | Entity | Key: order_id. Attributes: order_date, total_amount, risk_level |
refund_request | Entity | Key: refund_id. Attributes: refund_date, refund_amount, reason, status |
placed_by | Relation | sales_order → customer |
requested_for | Relation | refund_request → sales_order |
In the Graph explorer, surface a single platinum customer's order ↔ refund cluster with one Cypher line.
MATCH (c:customer {tier: 'platinum'})<-[:placed_by]-(o:sales_order)<-[:requested_for]-(r:refund_request)
RETURN c, o, r
LIMIT 25
A single platinum customer's orders alongside their refund requests appears in one graph. The high-tier yet high-refund-frequency pattern materializes visually.
6. HITL agent — one refund through the loop (20 min)
In the refund_ops collection's Agents section, open refund-approval and start a new session. This step is the Workshop's punchline.
The agent workflow has five steps.
get_enriched_ordertool — The user types the order ID under review; the agent fetches one row fromenriched_orders.search_refund_policytool (RAG) — Embeds the refund reason and queries therefund_policyknowledge base for the most relevant policy paragraph.- LLM analysis — Combines the order context, policy paragraph, and
risk_levelto produce a recommendation (APPROVE / PARTIAL / REJECT) with three short justification lines. - Human review (
capture_review_decisionactor) — The reviewer accepts the recommendation or overrides it. This is the H of HITL. A single Approve / Partial / Reject button flows into the next actor. - Automated execution — If the decision is APPROVE, the
issue_refundactor calls the refund backend; if REJECT, thesend_rejection_emailactor sends a notification.
After starting the session, enter order_id = ORD-007 (one of the seed HIGH-risk orders) and wait for the recommendation. The recommendation body should cite risk_level: HIGH alongside a refund policy §3.2 reference — a clean signal that RAG grounded the answer.
Click Reject to complete the cycle. The email-send actor logs an entry and the session closes.
7. Dashboard + next steps (5 min)
Take a quick tour through the refund_operations (alias: Refund operations dashboard). Six widgets all read from one dataset — refund_history.
- Total Refund Requests (statistic) —
COUNT(*) - Total Refund Amount (statistic) —
SUM(refund_amount) - Decision Distribution (donut) — Counts per
status(approved/rejected/pending) - Refund by Reason (bar) — Counts per
reason(defective/wrong_item/not_as_described/change_of_mind) - Refund Amount by Customer (bar, Top 10) —
SUM(refund_amount)percustomer_id, descending - Recent Refund Requests (data table) — 100 most recent rows by
requested_atdesc
This dashboard summarizes the operational view of historical refund data. Meta-metrics like AI-recommendation vs human-decision agreement rate aren't built into the seed — once the §6 HITL agent goes live and the recommendation/decision pairs accumulate, adding such a widget is a natural next-round topic.
Pick the most appealing direction:
- The Agents Path (Phase 2) covers RAG + HITL patterns in more depth.
- The Engineer Path Pipeline scheduling lesson — register
risk_assessmentfor 15-minute CDC runs. - Map the recommend + decide shape to your own domain (loan adjudication, contract renewal, ticket triage).
Verification checklist
- Both
raw_dataandrefund_opscollections appear in the tree with five datasets loaded. - After
order_enrichment, thepast_refund_countcolumn onenriched_ordersis populated. - After
risk_assessment, therisk_levelcolumn onrisk_assessed_ordersis distributed across LOW / MEDIUM / HIGH. - In the Graph explorer, a single platinum customer's order ↔ refund cluster fits in one view.
- One agent session surfaces a RAG-grounded recommendation citing a policy paragraph, and clicking Reject triggers the email actor.