从意图识别到人工授权:一次 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 工作流。
它做了三件关键事情:
- 通过意图识别,把用户问题路由到客服、库存、履约、采购等不同能力。
- 通过 ReAct 工具调用,让 AI 能查询库存、判断预警、触发采购需求。
- 通过
approval.requested人工授权事件,把一审、二审、生成采购单这类高风险动作交给用户确认。
最终形成的模式是:
自然语言输入
→ 意图识别
→ 工具调用
→ 业务数据返回
→ 高风险动作请求授权
→ 用户确认
→ ERP 权限校验
→ 完成业务闭环
这也是企业系统里落地 Agent 的一个关键原则:
Agent 可以自动化流程,但不能模糊责任边界。 真正可靠的企业 Agent,必须知道什么时候该执行,什么时候该停下来问人。