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

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

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

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

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

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

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

用户可能会问:

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

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

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

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

二、整体架构

本项目采用的是:

text 复制代码
前端 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。

例如客服类问题:

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

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

因此会路由到:

text 复制代码
skill:customer_service_faq

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

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

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

例如:

text 复制代码
WGXB02000201 这个商品库存多少?
刘周测试这个商品需要补货吗?

Agent 会调用:

text 复制代码
query_inventory

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

json 复制代码
{
  "skuCode": "WGXB02000201",
  "availableQty": 1,
  "alertLevel": "high_risk",
  "procurementRequired": true,
  "deficitQty": 2
}

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

系统提示里明确要求:

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

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

流程变成:

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

四、ReAct 工具调用机制

Agent 使用的是 ReAct 思路:

text 复制代码
思考 → 选择工具 → 执行工具 → 观察结果 → 再决定下一步

简化后的流程是:

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 的工具列表中。

每个工具都有:

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

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

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

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

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

原因很简单:

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

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

text 复制代码
FirstAuditApply
SecondAuditApply
GenPurchaseOrderFromApply

正确做法是:

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

这就是 Human-in-the-loop。

六、Agent 是怎么"要授权"的

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

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

json 复制代码
{
  "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"
  ]
}

这个对象叫:

text 复制代码
approvalRequest

它表达的意思是:

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

七、这是怎么"打断" ReAct 的

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

它是一个软打断机制。

也就是:

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

事件如下:

text 复制代码
event: approval.requested
data: { ...approvalRequest }

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

这种设计更稳定:

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

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

前端 SSE 接收到:

text 复制代码
approval.requested

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

ts 复制代码
{
  type: 'approval',
  request: approvalRequest,
  status: 'pending'
}

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

text 复制代码
采购授权

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

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

[授权执行]

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

九、授权后怎么继续执行

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

ts 复制代码
await firstAuditApply(...)
await secondAuditApply(...)
await genPurchaseOrderFromApply(...)

对应业务动作是:

text 复制代码
一审通过
  ↓
二审通过
  ↓
根据需求单生成采购单

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

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

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

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

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

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

这样做有几个好处:

1. 权限清晰

谁点授权,谁执行。

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

2. 审计清晰

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

3. 风险可控

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

4. 失败可解释

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

十一、安全边界

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

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

核心原则是:

text 复制代码
AI 负责建议和准备,人负责授权和确认,ERP 负责权限和落库。

十二、这个方案的优点

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

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

2. 工具调用可审计

每次工具调用都有:

json 复制代码
{
  "toolName": "query_inventory",
  "inputSummary": "...",
  "outputSummary": "..."
}

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

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

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

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

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

5. 用户体验自然

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

十三、可以继续优化的点

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

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

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

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

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

十四、总结

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

它做了三件关键事情:

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

最终形成的模式是:

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

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

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

相关推荐
keyipatience2 小时前
3.Linux基本指令2
前端·html
Java后端的Ai之路2 小时前
还在手写 Agent 代码?封装一个 SDK 让你从“码农“升级“包工头“
人工智能·langchain·ai编程·vibe coding·agent sdk
redreamSo2 小时前
Claude Code 最佳实践:从「能用」到「用得好」的 15 个关键技巧
人工智能·claude
源码老李2 小时前
Day 07 · 游戏也要管理状态:场景切换·资源加载·对象池实战
前端·javascript·游戏
Merkyor2 小时前
我花一下午修了 7 个 bug:一个 Electron AI Agent 发版前夜的 debug 长征
人工智能
石榴树下的七彩鱼2 小时前
智能抠图 API 接入实战:3 行代码实现图片自动去背景(Python / Java / PHP / JS)
java·图像处理·人工智能·python·php·api·抠图
星哥说事2 小时前
开源项目OpenClaw:多AI模型统一调用的技术学习与实践
人工智能·学习
aidenxian2 小时前
iOS App 真实包大小:你以为的大小为什么是错的
前端
天才熊猫君2 小时前
📄 第三篇:Vue 3 命令式弹窗 Provide 污染与关闭动画修复
前端·javascript·vue.js