본문으로 건너뛰기
Refund ops
90 min

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_data and refund_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_orders by combining three sources — raw_orders (ERP), raw_customers (CRM), and refund_history (finance DB) — with multi-key joins.
  • Use the risk_assessment pipeline to assign a 0–100 risk_score and a three-label risk_level (LOW / MEDIUM / HIGH).
  • Run one session of the refund-approval agent that searches the refund_policy knowledge 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:

  1. Two collections — raw_data (alias: Refund Raw Data), refund_ops (alias: Refund Operations)
  2. Five datasets — raw_orders (raw), raw_customers (raw), refund_history (raw), enriched_orders (ops), risk_assessed_orders (ops)
  3. Three codes (Python) — join_order_customer, risk_scorer, build_refund_ontology
  4. Three pipelines — order_enrichment, risk_assessment, ontology_materialization
  5. Ontology — three entities (customer, sales_order, refund_request), two relations (placed_by, requested_for)
  6. One knowledge — refund_policy (refund policy guide)
  7. One dashboard — refund_operations
  8. 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.

ArtifactKindMeaning
customerEntityKey: customer_id. Attributes: name, tier, lifetime_value
sales_orderEntityKey: order_id. Attributes: order_date, total_amount, risk_level
refund_requestEntityKey: refund_id. Attributes: refund_date, refund_amount, reason, status
placed_byRelationsales_ordercustomer
requested_forRelationrefund_requestsales_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.

  1. get_enriched_order tool — The user types the order ID under review; the agent fetches one row from enriched_orders.
  2. search_refund_policy tool (RAG) — Embeds the refund reason and queries the refund_policy knowledge base for the most relevant policy paragraph.
  3. LLM analysis — Combines the order context, policy paragraph, and risk_level to produce a recommendation (APPROVE / PARTIAL / REJECT) with three short justification lines.
  4. Human review (capture_review_decision actor) — 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.
  5. Automated execution — If the decision is APPROVE, the issue_refund actor calls the refund backend; if REJECT, the send_rejection_email actor 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) per customer_id, descending
  • Recent Refund Requests (data table) — 100 most recent rows by requested_at desc

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_assessment for 15-minute CDC runs.
  • Map the recommend + decide shape to your own domain (loan adjudication, contract renewal, ticket triage).

Verification checklist

  • Both raw_data and refund_ops collections appear in the tree with five datasets loaded.
  • After order_enrichment, the past_refund_count column on enriched_orders is populated.
  • After risk_assessment, the risk_level column on risk_assessed_orders is 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.