从 ERP 系统出发,我是如何设计一套 LLM 多 Agent 系统的(二)

28 阅读8分钟

从意图识别到人工授权:一次 ERP Agent 的落地实践

在 ERP 系统里做 Agent,不能只让大模型“会聊天”。真正有价值的是:它能识别用户意图、调用业务工具、执行流程,并且在关键动作前主动停下来,让人授权。

本文记录一次 AI 助手在 ERP 中的实现思路,重点讲两件事:

  • Agent 如何做意图识别,并路由到正确能力
  • Agent 如何在“下采购单、需求审核、生成采购单”等高风险动作前向用户要授权

一、为什么 ERP Agent 不能只靠聊天

ERP 场景和普通客服问答不一样。

用户可能会问:

WGXB02000201 这个商品需要补货吗?
春假假期有抽奖活动吗?
帮我查一下刘周测试这个商品库存
这个缺货了,直接补货

这些问题看起来都是自然语言,但背后的业务意图完全不同:

用户输入意图
商品库存多少查询库存
缺货了补货库存预警 + 采购补货
春假活动客服知识库问答
订单怎么发货履约流程
生成采购单高风险 ERP 操作,需要授权

所以 Agent 第一层能力不是生成回答,而是识别意图。

二、整体架构

本项目采用的是:

前端 AI 助手
  ↓
ERP WebAPI AgentAssistant 代理
  ↓
AGENT 服务 Orchestrator
  ↓
意图识别 / Skill / Tool / Workflow
  ↓
ERP 业务接口

核心模块如下:

flowchart TD
  A["用户输入"] --> B["AgentAssistant 前端"]
  B --> C["ERP WebAPI SSE 代理"]
  C --> D["AGENT Orchestrator"]
  D --> E["意图识别"]
  E --> F["客服 FAQ Skill"]
  E --> G["库存查询 Tool"]
  E --> H["履约 Workflow"]
  E --> I["采购补货 Tool"]
  I --> J["ERP 创建采购需求单"]
  J --> K["返回 approvalRequest"]
  K --> L["前端授权卡片"]
  L --> M["用户授权"]
  M --> N["一审"]
  N --> O["二审"]
  O --> P["生成采购单"]

三、意图识别怎么做

意图识别采用“规则优先 + LLM 工具路由 + Skill 匹配”的方式。

1. 先识别业务 Skill

如果用户命中已注册的业务 Skill,就优先走 Skill。

例如客服类问题:

交了服务费可以退款吗?
春节假期有活动吗?
采购款怎么充值?
收益怎么提现?

这类问题不应该走库存工具,而应该走客服知识库 RAG。

因此会路由到:

skill:customer_service_faq

客服 Skill 会基于 FAQ 知识库检索,再生成中文客服回复。

2. 库存类问题走库存工具

如果用户输入里包含 SKU、货号、库存、补货等关键词,会优先走库存查询。

例如:

WGXB02000201 这个商品库存多少?
刘周测试这个商品需要补货吗?

Agent 会调用:

query_inventory

查询后返回结构化结果,例如:

{
  "skuCode": "WGXB02000201",
  "availableQty": 1,
  "alertLevel": "high_risk",
  "procurementRequired": true,
  "deficitQty": 2
}

3. 库存触发预警后继续补货

系统提示里明确要求:

当 query_inventory 返回 alertLevel 为 high_risk / ordinary,
或者 procurementRequired 为 true 时,
必须继续调用 trigger_purchase 自动触发补货。

也就是说,Agent 不是查完库存就结束,而是继续执行采购动作。

流程变成:

用户问库存
  ↓
query_inventory
  ↓
发现高危预警
  ↓
trigger_purchase
  ↓
创建采购需求单

四、ReAct 工具调用机制

Agent 使用的是 ReAct 思路:

思考 → 选择工具 → 执行工具 → 观察结果 → 再决定下一步

简化后的流程是:

sequenceDiagram
  participant User as 用户
  participant LLM as 大模型
  participant Tool as 工具
  participant ERP as ERP接口

  User->>LLM: WGXB02000201 需要补货吗?
  LLM->>Tool: query_inventory
  Tool->>ERP: 查询库存
  ERP-->>Tool: 库存高危预警
  Tool-->>LLM: alertLevel=high_risk
  LLM->>Tool: trigger_purchase
  Tool->>ERP: 创建采购需求单
  ERP-->>Tool: 返回需求单详情
  Tool-->>LLM: applyId + approvalRequest
  LLM-->>User: 已创建需求单,需要授权继续审核和生成采购单

工具本身不是写死在 Prompt 里的文字,而是注册到 Orchestrator 的工具列表中。

每个工具都有:

{
  name: 'trigger_purchase',
  description: '对库存不足的 SKU 生成采购补货动作,并选择推荐供应商。',
  parameters: { ... },
  execute: async (args) => { ... }
}

大模型只负责决定“该调用哪个工具、传什么参数”。

真正执行的是后端工具函数。

五、为什么采购不能让 AI 直接做完

采购需求审核、二审、生成采购单属于高风险操作。

原因很简单:

  • 会产生真实 ERP 单据
  • 会影响采购、供应商、库存和财务
  • 需要当前登录账号具备权限
  • 需要人工确认数量、供应商、预计到货时间等信息

所以不能让大模型直接调用:

FirstAuditApply
SecondAuditApply
GenPurchaseOrderFromApply

正确做法是:

AI 可以建议
AI 可以准备数据
AI 可以创建待审核需求
但 AI 不能绕过人直接完成审核和生成采购单

这就是 Human-in-the-loop。

六、Agent 是怎么“要授权”的

这里的关键不是让大模型说一句“请授权”,而是让工具结果里返回一个结构化授权请求。

trigger_purchase 创建采购需求单成功后,会生成:

{
  "approvalId": "purchase-apply-123-456",
  "kind": "purchase_apply_full_approval",
  "applyId": 123,
  "applyNumber": "CGXQ202604170007",
  "applySkuId": 456,
  "skuCode": "WGXB02000201",
  "qty": 2,
  "supplierId": 11,
  "supplierName": "ces11",
  "estimatedArrivalDate": "2026-04-21",
  "actions": [
    "first_audit",
    "second_audit",
    "gen_purchase_order"
  ]
}

这个对象叫:

approvalRequest

它表达的意思是:

我已经准备好了后续动作,但需要用户授权才能继续。

七、这是怎么“打断” ReAct 的

严格来说,这不是在 ReAct 循环内部强行中断大模型。

它是一个软打断机制。

也就是:

ReAct 工具调用正常完成
  ↓
工具结果中包含 approvalRequest
  ↓
AGENT 服务把 approvalRequest 转成 SSE 事件
  ↓
前端收到 approval.requested
  ↓
前端插入授权卡片

事件如下:

event: approval.requested
data: { ...approvalRequest }

所以“打断”发生在输出层,而不是大模型内部。

这种设计更稳定:

  • 不需要让大模型保持等待状态
  • 不依赖模型继续记住某个审批上下文
  • 授权动作由前端和 ERP 接口确定性执行
  • 审核权限仍由当前登录账号控制

八、前端如何弹出授权卡片

前端 SSE 接收到:

approval.requested

之后,把它转成一条消息:

{
  type: 'approval',
  request: approvalRequest,
  status: 'pending'
}

然后在 AI 对话里渲染授权卡片:

采购授权

AI 已创建采购需求单,需要你授权当前账号继续执行一审、二审和生成采购单。

需求单:CGXQ202604170007
SKU:WGXB02000201
数量:2 件
供应商:ces11

[授权执行]

这就实现了用户在对话里完成授权。

九、授权后怎么继续执行

用户点击“授权执行”后,不再让大模型继续猜下一步,而是前端按固定顺序调用 ERP 接口:

await firstAuditApply(...)
await secondAuditApply(...)
await genPurchaseOrderFromApply(...)

对应业务动作是:

一审通过
  ↓
二审通过
  ↓
根据需求单生成采购单

这三个接口仍然走 ERP 自己的权限体系。

如果当前账号没有权限,后端会返回无权限。

如果当前账号是管理员,具备对应权限,就可以完成操作。

十、为什么授权动作放在前端执行

这里有一个重要设计取舍。

授权后的动作没有继续交给 AGENT 服务执行,而是由前端用当前登录用户的 token 调用 ERP。

这样做有几个好处:

1. 权限清晰

谁点授权,谁执行。

ERP 后端能拿到当前登录账号。

2. 审计清晰

操作日志里可以记录真实操作人,而不是统一记录成 Agent 服务账号。

3. 风险可控

AI 不能绕过前端确认,也不能直接批量生成真实采购单。

4. 失败可解释

如果一审失败、二审失败、生成采购单失败,前端能直接展示 ERP 返回的错误。

十一、安全边界

这个实现里,AI 的权限边界很明确:

能力AI 是否能直接做
查询库存可以
推荐供应商可以
创建采购需求单可以,属于待审核动作
一审不直接做,需要授权
二审不直接做,需要授权
生成采购单不直接做,需要授权
绕过 ERP 权限不允许

核心原则是:

AI 负责建议和准备,人负责授权和确认,ERP 负责权限和落库。

十二、这个方案的优点

1. 意图识别和业务动作解耦

用户可以自然语言提问,Agent 自动决定走 FAQ、库存、履约还是采购。

2. 工具调用可审计

每次工具调用都有:

{
  "toolName": "query_inventory",
  "inputSummary": "...",
  "outputSummary": "..."
}

前端可以展示“工具调用”,方便排查 AI 为什么这么回答。

3. 高风险动作有人工确认

不是让 AI 全自动跑到底,而是在关键节点弹出授权框。

4. 和现有 ERP 权限体系兼容

不重新发明权限系统,不绕过原有接口。

5. 用户体验自然

用户不需要离开 AI 对话,也不需要自己去多个页面找按钮。

十三、可以继续优化的点

后续可以继续升级为真正的可恢复工作流:

Agent 创建 approval task
  ↓
状态变成 waiting_for_approval
  ↓
用户授权
  ↓
Agent 恢复执行后续 workflow

这样可以支持更复杂的场景:

  • 多人审批
  • 审批超时
  • 审批撤销
  • 审批前修改数量
  • 审批后继续让 Agent 总结结果
  • 审批任务落库,刷新页面也不丢

但第一版用前端授权卡片已经能覆盖核心业务闭环。

十四、总结

这次 Agent 改造的核心不是“让 AI 更会说话”,而是让 AI 真正进入 ERP 工作流。

它做了三件关键事情:

  1. 通过意图识别,把用户问题路由到客服、库存、履约、采购等不同能力。
  2. 通过 ReAct 工具调用,让 AI 能查询库存、判断预警、触发采购需求。
  3. 通过 approval.requested 人工授权事件,把一审、二审、生成采购单这类高风险动作交给用户确认。

最终形成的模式是:

自然语言输入
  → 意图识别
  → 工具调用
  → 业务数据返回
  → 高风险动作请求授权
  → 用户确认
  → ERP 权限校验
  → 完成业务闭环

这也是企业系统里落地 Agent 的一个关键原则:

Agent 可以自动化流程,但不能模糊责任边界。 真正可靠的企业 Agent,必须知道什么时候该执行,什么时候该停下来问人。