AI Agent 工程 · 02
02.2 实战:让 AI 查询模拟订单
用不含密钥和真实客户信息的本地 JavaScript 模拟订单工具,走完成功、不存在、工具失败和无权访问四条路径。
知识定位
这是第一个可运行的工程练习。它不调用真实模型,也不连接 Shopify、ERP、支付或物流 API;目标是先看懂“模型建议 → 服务端验证 → 工具结果”的安全边界。
一句话定义
在这个练习里,queryOrder 是订单工具的本地替身。未来可把它换成真实订单服务,但权限、校验和错误分支仍必须保留。
系统位置
客户消息 → AI(只决定是否建议查询) → queryOrder(模拟服务端工具)
↓
模拟订单数据 / 业务错误
所有订单、客户和状态均为模拟数据。不要把真实订单号、邮箱、API key 粘贴到练习中。
实践代码
新建 order-tool-demo.mjs,复制以下代码后运行 node order-tool-demo.mjs。若电脑未安装 Node.js,本节可先阅读并手工推演四个结果;不要为了本练习配置任何真实密钥。
const orders = {
"XB-1024": { customerId: "customer-amy", status: "in_transit", tracking: "SIM-CA-889" },
"XB-2048": { customerId: "customer-ben", status: "refund_processing", tracking: null },
};
function queryOrder({ orderId, requesterId }) {
if (orderId === "XB-5000") throw new Error("模拟物流服务暂时不可用");
const order = orders[orderId];
if (!order) return { ok: false, code: "NOT_FOUND", message: "未找到该订单" };
if (order.customerId !== requesterId) return { ok: false, code: "FORBIDDEN", message: "无权访问该订单" };
return { ok: true, order: { orderId, status: order.status, tracking: order.tracking } };
}
const cases = [
{ label: "查询成功", input: { orderId: "XB-1024", requesterId: "customer-amy" } },
{ label: "订单不存在", input: { orderId: "XB-9999", requesterId: "customer-amy" } },
{ label: "工具执行失败", input: { orderId: "XB-5000", requesterId: "customer-amy" } },
{ label: "无权访问", input: { orderId: "XB-2048", requesterId: "customer-amy" } },
];
for (const test of cases) {
try { console.log(test.label, queryOrder(test.input)); }
catch (error) { console.log(test.label, { ok: false, code: "TOOL_ERROR", message: error.message }); }
}
预期输出与验收
| 场景 | 预期结果 | 客服应如何表达 |
|---|---|---|
| 查询成功 | ok: true 与模拟物流号 | 说明状态,并提醒物流号为查询结果 |
| 订单不存在 | NOT_FOUND | 请客户核对订单号,不编造状态 |
| 工具执行失败 | TOOL_ERROR | 说明暂时无法查询,建议稍后重试或转人工 |
| 无权访问 | FORBIDDEN | 不泄露订单是否存在;请客户登录正确账户 |
验收标准:脚本输出四个标签;无权访问时不打印 XB-2048 的订单详情;工具异常被捕获而不是让程序静默失败。
知识连接
未来由 LLM 提取订单号或选择调用工具时,queryOrder 前的身份验证仍然不能省略。结构化输出解决“参数长什么样”,Tool Calling 解决“谁执行”,而业务权限决定“是否允许执行”。
主动回忆
为什么 FORBIDDEN 的客服回复不应该说“订单 XB-2048 属于另一位客户”?
纸质笔记
- 必须记:成功、正常业务失败、系统失败、权限失败是四种不同结果。
- 建议记:错误信息对用户要友好,对日志要可诊断;两者可不同。
- 不用记:示例中的订单号和物流号。