Chapter 19 · Capstone 1: Production-Grade Smart Customer Service Agent
Chapter goals: Synthesize everything learned in Chapters 1–18 to build an e-commerce after-sales customer service Agent from scratch — intent routing, order query, return-policy RAG Q&A, human transfer, and session memory; land the three production red lines (cost tiered routing, credential safety, eval closed-loop) during construction, not as事后补课.
19.1 Requirements and Architecture
Define the business边界 first. This customer service Agent only handles four after-sales scenarios:
| Requirement | Capability | Chapter |
|---|---|---|
| Chat / simple Q&A fast reply | Cheap small-model triage | ch08 branch |
| Query order status | queryOrder tool | ch05 createTool |
| Return-policy RAG Q&A | RAG retrieval of policy docs | ch12 |
| Agitated user / over-权限 request | Workflow suspend → human handoff | ch09 |
Overall architecture — intent routing is the总闸门 for cost and quality:
User message
│
▼
┌──────────────────┐ Simple/chat (~70% traffic)
│ Intent triage │──────────────▶ gpt-5-mini direct reply
│ (gpt-5-mini) │
└───────┬──────────┘
│ Business question (order / return-policy)
▼
┌─────────────────────────────────┐
│ expertAgent (claude-sonnet) │
│ ├─ queryOrder tool ──▶ order DB │
│ ├─ RAG policy retrieval ──▶ vector store │
│ └─ Memory (user-isolated sessions) │
└───────┬─────────────────────────┘
│ Agitated / beyond refund权限
▼
workflow.suspend() ──▶ human agent takes overThe one design主线: let the cheap model handle what it can应付, save the expensive model for where itcounts.
19.2 Project Scaffold and Model Tiered Routing
Reuse the Chapter 1 scaffold; add directory structure:
npm install @mastra/core @mastra/libsql @mastra/memory zod
mkdir -p src/mastra/{agents,tools,workflows}Write two tier agents. Follow the Chapter 4 three-principles (define role, draw boundaries, give format):
// src/mastra/agents/triage-agent.ts —— Front-line triage: cheap modelhandles most traffic
import { Agent } from '@mastra/core/agent';
export const triageAgent = new Agent({
id: 'triage',
name: 'Triage',
instructions: `
You are the first reception for e-commerce after-sales. Responsibilities:
- Judge user intent: casual chat / order query / return-policy inquiry / complaint
- For casual chat and simple common questions, answer in one sentence directly
- For requests involving a specific order or policy, output "transfer" with a summary of the original request
Always use Chinese; replies under 80 characters.`,
// Cheap tier: intent recognition does not need a flagship model
model: 'openai/gpt-5-mini',
});// src/mastra/agents/expert-agent.ts —— Expert seat: only消耗 the high-capability model when needed
import { Agent } from '@mastra/core/agent';
export const expertAgent = new Agent({
id: 'expert',
name: 'Support Expert',
instructions: `
You are a senior after-sales specialist handling order queries and return-policy inquiries.
Rules:
- When answering policy questions, you must rely on the provided policy materials; never fabricate clauses
- Before querying an order, you must have a valid order ID
- If the user is agitated or requests exceed standard policy, reply "I will transfer you to a human agent"
Always use Chinese.`,
// High-capability tier: tool calls + policy reasoning
model: 'anthropic/claude-sonnet-4-5',
});Wire them into a分流主干 with the workflow branch() syntax (Chapter 8):
// src/mastra/workflows/support-router.ts —— Intent分流主干
import { createStep, createWorkflow } from '@mastra/core/workflows';
import { z } from 'zod';
const classifyStep = createStep({
id: 'classify',
inputSchema: z.object({ message: z.string(), userId: z.string() }),
outputSchema: z.object({ simple: z.boolean(), message: z.string(), userId: z.string() }),
execute: async ({ inputData, mastra }) => {
// Let the cheap小模型 judge whether this is a simple question
const res = await mastra.getAgent('triage').generate(inputData.message);
const simple = !res.text.includes('transfer');
return { simple, message: inputData.message, userId: inputData.userId };
},
});
export const supportFlow = createWorkflow({
id: 'support-router',
inputSchema: z.object({ message: z.string(), userId: z.string() }),
outputSchema: z.object({ answer: z.string() }),
})
.then(classifyStep)
.branch([
// Simple question: use the triage answer (already cached in classify)
[async ({ inputData }) => inputData.simple, answerSimpleStep],
// Business question: hand off to the expert seat for the full tool + RAG pipeline
[async () => true, expertAnswerStep],
])
.commit();Cost benefit
In typical e-commerce customer service traffic, ~70% is casual chat and common questions. The全量 flagship-model bill通常 drops to under one-third after分流.
19.3 Order Query Tool and Policy RAG
The expert seat needs two weapons: an order查询 tool and policy RAG retrieval.
// src/mastra/tools/query-order.ts —— Order query tool:连模拟 database
import { createTool } from '@mastra/core/tools';
import { z } from 'zod';
// Demo mock data; replace with a real order service API in production
const mockOrderDb: Record<string, { status: string; amount: number; item: string }> = {
'SO-2026-0001': { status: 'Shipped', amount: 299, item: 'Wireless Earbuds' },
'SO-2026-0002': { status: 'Pending Payment', amount: 1299, item: 'Mechanical Keyboard' },
};
export const queryOrderTool = createTool({
id: 'query-order',
description: 'Query order status, amount, and item by order ID. Call only when the user provides an order ID.',
inputSchema: z.object({
orderId: z.string().regex(/^SO-\d{4}-\d{4}$/, 'Order ID format: SO-2026-0001'),
}),
outputSchema: z.object({
found: z.boolean(),
status: z.string().optional(),
amount: z.number().optional(),
item: z.string().optional(),
}),
execute: async ({ inputData }) => {
// Least-privilege: read-only here; never expose write credentials
const order = mockOrderDb[inputData.orderId];
if (!order) return { found: false };
return { found: true, ...order };
},
});The policy RAG pipeline follows Chapter 12: chunk the return-policy Markdown docs, embed, store in LibSQL, retrieve on query, inject into the expert agent's context.
19.4 Production Red Lines Landed During Construction
Red Line 1: Cost Tiered Routing
The triage→expert branch结构 ensures ~70% of traffic never touches the expensive model. Verified by comparing crew.usage_metrics-equivalent stats before and after分流.
Red Line 2: Credential Safety
API keys flow exclusively through .env + process.env; no硬编码. The queryOrderTool is read-only — no write credentials are ever exposed to the agent.
Red Line 3: Evals Closed-Loop
Chapter 15's Scorers are mounted on the expert agent: answerRelevancy (权重 0.7) + toxicity (权重 0.3). A CI job runs a regression batch on each PR; scores below threshold fail the build.
19.5 Human Transfer via Suspend
When the expert agent detects an agitated user or an over-权限 request, the workflow suspends:
const handoffStep = createStep({
id: 'handoff',
inputSchema: z.object({ userId: z.string(), issue: z.string() }),
outputSchema: z.object({ transferred: z.boolean() }),
execute: async ({ inputData, suspend }) => {
await suspend({
message: `User ${inputData.userId} requires human handoff: ${inputData.issue}`,
});
return { transferred: false }; // Only reached if not suspended
},
});The suspended run persists to Storage; a human agent resumes with run.resume({ resumeData: { resolved: true } }).
19.6 Chapter Summary
- Architecture: triage (cheap) → branch → expert (expensive) with tools + RAG + memory;
- Cost tiered routing lands the #1 production red line during design, not after;
- Order query tool follows least-privilege (read-only, validated input);
- Policy RAG injects authoritative knowledge without hallucination;
- Human transfer via workflow suspend + Storage persistence;
- Evals mounted on the expert agent with CI regression gates.
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. What percentage of typical e-commerce customer service traffic should the cheap triage model handle?
2. Why is the order query tool designed as read-only?
3. What triggers a workflow suspend in this capstone?
4. How is the evals closed-loop landed in this capstone?
🛠️ Hands-On Exercises
- Build the full capstone: triage agent → branch → expert agent with queryOrder tool + RAG policy retrieval + Memory. Verify the分流 saves ~70% token cost.
- Add a suspension point for over-权限 requests; verify the workflow persists and can be resumed by a human.
- Mount eval scorers on the expert agent; run a CI regression batch and verify the build fails when scores drop.
Capstone 1 complete. Next: Capstone 2: Full-Stack AI App.