使用存储过程构建安全的电子商务聊天代理

发布: (2026年1月6日 GMT+8 22:58)
6 min read
原文: Dev.to

I’m happy to translate the article for you, but I’ll need the full text of the post (the content you’d like translated). Could you please paste the article’s body here? Once I have the text, I’ll provide a complete Simplified Chinese translation while preserving the source line, formatting, markdown, and any code blocks.

背景

最近,我尝试为一个特定的电商平台构建一个 GPT‑类聊天代理——不是通用聊天机器人,也不是演示,而是面向真实产品的助理,能够回答诸如:

  • “我的订单在哪里?”
  • “我可以退款吗?”
  • “显示我的最近一次购买。”

为实现这一点,代理必须 访问真实的生产数据——订单、发货、付款。就在这时,我遇到了一个重要的问题。

我遇到的问题

一旦代理需要数据库访问,就会出现一个诱人的想法:

“为什么不直接让 LLM 根据用户的问题生成 SQL 呢?”

听起来很简单,在演示中也能工作,但在真实的电子商务系统中,这很快就会变得危险。

场景

您正在为特定的电子商务平台构建聊天应用程序。聊天代理支持:

  • 订单状态查询
  • 发货与送达跟踪
  • 退款资格检查
  • 购买历史摘要
  • 与账户相关的问题

这不是通用 GPT。它是一个平台绑定的助理,能够访问敏感的用户数据。

核心问题

聊天代理经常需要访问数据库。一个常见但不安全的方法是:

  1. 与 LLM 共享数据库模式。
  2. 要求 LLM 根据用户输入生成 SQL。
  3. 直接执行该 SQL。

在生产环境中,这种做法会失败。

为什么 LLM‑生成的 SQL 是个坏主意

安全风险

  • 提示注入可能操纵查询。
  • 过于宽泛的 SELECT * 查询会泄露敏感数据。
  • 可能导致特权提升。

幻想查询

  • 不存在的表或列。
  • 错误的连接。
  • 错误的业务逻辑。

缺乏治理

  • 没有明确的允许查询的合同。
  • 难以审计数据访问。
  • 模式更改会破坏提示。

核心原则

LLMs 应该决定 要实现的意图,而不是 如何查询数据
这与传统的后端设计相呼应。

正确的架构:将存储过程作为代理工具

高层流程

Architecture diagram

关键设计规则

  • 数据库逻辑位于 存储过程 中。
  • LLM 永不直接看到表名或列。
  • 代理仅选择 调用哪个过程

第一步:定义存储过程(数据库层)

获取最新订单

CREATE PROCEDURE get_latest_order (
  IN p_user_id BIGINT
)
BEGIN
  SELECT
    order_id,
    order_status,
    total_amount,
    created_at
  FROM orders
  WHERE user_id = p_user_id
  ORDER BY created_at DESC
  LIMIT 1;
END;
  • ✔ 强制执行用户级数据隔离。
  • ✔ 不向代理暴露模式。

获取订单的运输状态

CREATE PROCEDURE get_order_shipping_status (
  IN p_order_id BIGINT,
  IN p_user_id BIGINT
)
BEGIN
  SELECT
    shipping_provider,
    tracking_number,
    shipping_status,
    estimated_delivery
  FROM shipments
  WHERE order_id = p_order_id
    AND user_id = p_user_id;
END;
  • ✔ 在数据库层进行所有权验证。
  • ✔ 防止跨用户访问。

第2步:将过程公开为代理工具

LLM 从不直接看到 SQL;它看到的是 工具

[
  {
    "name": "get_latest_order",
    "description": "Get the most recent order for the authenticated user",
    "parameters": {}
  },
  {
    "name": "get_order_shipping_status",
    "description": "Get shipping details for a specific order",
    "parameters": {
      "order_id": "number"
    }
  }
]

用户身份由系统注入——而不是由 LLM 注入。

第3步:Agent Reasoning Flow

User Message

Where is my last order?

Agent Behavior

  1. Identify intent: order inquiry
  2. No order ID provided → call get_latest_order
  3. Use the returned order_id to call get_order_shipping_status

步骤 4:用户响应

Your latest order was placed on March 2.

Status: Shipped
Carrier: Yamato
Tracking Number: 1234‑5678
Estimated Delivery: March 6

高级示例:退款资格

存储过程

CREATE PROCEDURE check_refund_eligibility (
  IN p_order_id BIGINT,
  IN p_user_id BIGINT
)
BEGIN
  SELECT
    CASE
      WHEN order_status = 'DELIVERED'
           AND DATEDIFF(NOW(), delivered_at) <= 7
      THEN 'ELIGIBLE'
      ELSE 'NOT_ELIGIBLE'
    END AS refund_status
  FROM orders
  WHERE order_id = p_order_id
    AND user_id = p_user_id;
END;

业务规则保持 不在提示中

为什么这种设计有效

默认安全

  • 没有任意的 SQL 执行。
  • 严格的访问边界。
  • 最小的影响范围。

无幻觉

  • 大语言模型无法凭空创建表或连接。
  • 只能调用允许的操作。

强大的可观测性

每次调用都可以记录,例如:

user_id=123
tool=check_refund_eligibility
order_id=88921
timestamp=2026-01-06T12:34:56Z

存储过程 vs. LLM 生成的 SQL

方面LLM 生成的 SQL存储过程
安全性❌ 有风险✅ 安全
幻觉❌ 常见✅ 不会出现
审计❌ 困难✅ 容易
模式更改❌ 会导致提示失效✅ 隔离处理
企业级准备❌ 否✅ 是

最后思考

聊天代理看起来很新颖,但后端基础仍然适用。

把你的数据库当作私有 API 来对待。

存储过程为你提供:

  • 安全性
  • 稳定性
  • 可观测性
  • 企业级控制

这就是构建 真实、可投入生产的电子商务聊天代理 的方式——而不是演示。

Back to Blog

相关文章

阅读更多 »