Ohhnews

分类导航

$ cd ..
foojay原文

构建智能体仓储管理系统(三):工具、决策与行动

#ai智能体#仓储管理#spring ai#决策自动化#补货管理

构建 Agentic 仓库管理系统——第 3 部分:工具、决策和行动

如果你还没有阅读过前两部分,我建议你先从 第 1 部分:AI 智能体在哪些环节创造价值第 2 部分:设计与规划智能体 开始。在这两部分中,我们介绍了 WMS 场景,探讨了 AI 智能体在哪些地方能够创造价值,并使用 Java 和 Spring AI 构建了实现的最初阶段。

在第三部分,也就是最后一部分,我们将基于第 2 部分中创建的执行计划,重点完成智能体工作流中剩余的阶段。我们会看到每个任务如何借助受控工具执行、运营与业务上下文如何收集、补货决策如何作出,以及在必要时智能体如何根据决策采取行动。

Agentic WMS 的在线演示版本可在这里访问,完整源代码可在这里获取。

从计划到执行

让我们重新审视完整的智能体流程。前几个阶段——定义智能体、触发智能体和规划——已经在上一篇文章中介绍过。现在我们将重点关注任务的执行、可用工具的使用、上下文的收集,以及补货决策的作出。

[LOADING...]

使用受控工具执行任务

借助第 2 部分中创建的执行计划,AgentRunner 开始逐个处理任务。对于每个任务,运行器会读取其描述和能力(capability),执行任务,存储结果,然后继续处理下一个任务:

for (int index = 0; index < tasks.size(); index++) {
    String description = tasks.get(index).description();

    String capability = tasks.get(index).capability();

    LocalDateTime startedAt = LocalDateTime.now();

    String result = executeTask(definition, goal, description, capability, tasks);

    tasks.set(index, new AgentRun.AgentTask(

            description,

            AgentRun.TaskStatus.COMPLETED,

            capability,

            result,

            startedAt,

            LocalDateTime.now()

    ));

    agentRunService.save(withTasks(agentRun, tasks));
}

在执行任务之前,运行器只会选择与该任务能力关联的工具:

private Object[] toolsOf(

        AgentDefinition definition,

        String capability

) {

    return definition.capabilities().stream()

            .filter(candidate ->

                    candidate.name().equalsIgnoreCase(capability))

            .map(AgentCapability::tools)

            .filter(Objects::nonNull)

            .flatMap(List::stream)

            .toArray();

}

当任务执行时,执行器会收到当前目标、先前任务产生的结果、当前任务,以及仅与该能力相关的可用工具:

return definition.executor()

        .prompt()

        .tools(tools)

        .user("""

            %s

            Results of the previous tasks:

            %s

            Execute only this task:

            %s

            Use the available tools autonomously.

            """.formatted(

                goal,

                previousResults(tasks),

                description

        ))

        .call()

        .content();

每个已完成任务的结果都会成为后续任务可用上下文的一部分。这使得智能体能够在作出补货决策之前,逐步收集所需的信息。

同时,分配给每个任务的能力决定了它在执行期间可以使用哪些工具。这保持了我们先前提到的边界:例如,ANALYSIS(分析)任务可以查看 WMS 中的信息,但无法访问创建补货请求的工具。

[LOADING...]

访问运营数据

在执行 ANALYSIS 任务期间,智能体可以使用受控工具从 WMS 获取运营数据,例如库存、发票流水、库存移动和待处理的补货请求。

例如,其中一个可用工具会检索由出库发票生成的库存移动记录:

@Tool(description = """
    Get the stock movements generated by a specific invoice.
    Use this tool to discover which products and quantities were affected
    by a completed outbound invoice.
""")
public List<StockMovement> getStockMovementByInvoiceNumber(
        @ToolParam(description = "Outbound invoice number")
        String invoiceNumber
) {
    return stockMovementService.findByInvoiceNumber(invoiceNumber);
}

借助 Spring AI,可以通过 @Tool 和 @ToolParam 等注解将类似方法暴露给模型。当当前任务需要该信息时,执行器即可调用这些方法。

完整应用还暴露了更多工具,用于获取库存、发票流水、待处理补货及其他运营数据。此处不再逐一介绍,但它们的设计思路相同。

检索货主策略

货主策略(depositor policies)也可以通过 POLICY(策略)能力所暴露的专用工具来访问。在我们的应用中,每个货主都可以通过货主策略页面注册业务规则。例如,某条策略可能规定七天提前期(lead time),或要求每份补货请求至少 500 件商品:

[LOADING...]

这些策略以自然语言文档的形式存储,因此我们可以使用语义搜索来检索它们,而不是仅仅依赖精确的关键词。例如:

new DepositorKnowledgeEntry(

 "amz",

  "replenishment-minimum",

  KnowledgeType.REPLENISHMENT,

 "Replenishment orders for Amazon must contain at least 500 units per product."

);

存储策略时,其文本会通过配置的 Voyage AI embedding 模型转换为向量,并添加到向量存储中。在执行 POLICY(策略)任务时,智能体可以根据到目前为止收集到的上下文提出问题:

What minimum quantities, packaging rules and lead times

apply to replenishing product BR01?

这就构成了一个简单的检索增强生成(RAG)流程:用该问题检索最相关的策略,并将它们添加到执行过程中:

[LOADING...]

检索部分使用语义搜索

return vectorStore.similaritySearch(

        SearchRequest.builder()

                .query(question)

                .topK(3)

                .filterExpression(filter)

                .build()

);

并且会按货主和知识类型进行过滤:

String filter =

        "depositorId == '" + depositorId + "'"

        + " && type in ['REPLENISHMENT', 'INBOUND', 'GENERAL']";

这些策略与 ANALYSIS 任务的结果一起,为智能体提供了判断是否需要补货所需的运营和业务上下文。

作出决策

在 ANALYSIS 和 POLICY 任务完成之后,DECISION(决策)任务会利用已收集的上下文来判断是否需要补货。其结果会以以下两个 token 之一结尾:

REPLENISHMENT_REQUIRED 

REPLENISHMENT_NOT_REQUIRED

这让 AgentRunner 能够用简单的方式判断是否应继续执行剩余任务:

private boolean decidedToStop(String capability, String result) {

    return DECISION_CAPABILITY.equals(capability)

            && result != null

            && result.contains("REPLENISHMENT_NOT_REQUIRED");

}

如果不需要补货,剩下的 REPLENISHMENT(补货)和 NOTIFICATION(通知)任务会被标记为 SKIPPED(已跳过),执行过程随之完成:

[LOADING...]

运行器会将那些任务标记为 SKIPPED 并完成执行:

if (decidedToStop(capability, result)) {

    skipRemaining(tasks, index + 1);

    return agentRunService.save(finish(

            agentRun,

            tasks,

            AgentRun.Status.COMPLETED,

            summarize(definition, goal, tasks)

    ));

}

如果需要补货,执行将继续进行计划中的后续任务。

采取行动

一旦确定需要补货,智能体就可以使用应用暴露的操作工具

REPLENISHMENT(补货)任务可以创建补货请求:

@Tool(description = """

    Create a replenishment request when one or more products

    need to be replenished.

""")
public String createReplenishment(

        String depositorCode,

        List<Replenishment.ReplenishmentItem> items,

        String message

) {

    // Validate the request ..

    replenishmentService.save(....)

}

再说一次:该工具并不会取代现有的 WMS 逻辑。它只是为智能体提供了一种受控的方式来请求该操作,而校验与持久化仍然由应用服务内部完成。

创建完成后,NOTIFICATION(通知)任务可以使用该补货 ID 来准备发给货主的邮件草稿:

@Tool(description = """
    Draft and store the notification email for a replenishment request.
    The email is not sent by this tool.
""")
public String draftDepositorEmail(
        @ToolParam(description = ReplenishmentIds.ID_PARAM)
        String id
) {
....  
}

至此,智能体已经作出决策,并执行了决策所需的行为。

完成

当没有更多任务需要执行时,Agent run(智能体运行)即告完成,并生成一份摘要:

[LOADING...]

如果创建了补货请求,现在可以在补货(Replenishments)页面查看:

[LOADING...]

至此完整流程结束:智能体通过受控工具收集上下文,判断是否需要补货,并且只在需要时采取行动。

后续步骤

在单次执行过程中,智能体会将先前任务的结果作为后续任务的上下文。一个自然而然的下一步,是让智能体在不同执行之间也拥有记忆。

例如,在创建新的补货请求之前,智能体可以查看之前的 AgentRun 记录,并参考类似情况下的相关结果:

最近三次针对该产品 500 件的补货请求都遭到了拒绝,而获批的请求通常在 200 至 300 件之间。基于当前的消耗情况,我将申请 250 件。

这将使智能体不仅能够利用当前执行的上下文,还能参考先前执行中的相关信息。一个可能的发展方向是:在作出新决策之前,检索相似的历史执行记录,并将其添加到智能体上下文中。

这个智能体还有很多其他可以演进的方向,但这个例子很好地说明了同一套设计如何能够逐步变得更加具有上下文感知能力。

结论

本系列的主要目标是展示:在业务决策依赖于多种上下文来源和日益复杂规则的情况下,AI 智能体可以如何创造价值。我们的补货示例只是这种方法在真实仓库管理系统中能够支持内容的一个小小缩影。

在第 1 部分中,我们探讨了 AI 智能体在 WMS 中可以创造价值的环节。在第 2 部分中,我们通过定义智能体、其能力以及执行计划,将该设计落地到了 Java 和 Spring AI 中。

在第三部分,也是最后一部分中,我们完成了整个流程:任务通过受控工具执行,运营数据和货主策略被加入上下文,智能体利用这些信息来判断是否需要补货,并在必要时采取行动。

核心思想始终不变:应用系统定义了智能体可以做什么,而智能体在这些边界内决定要做什么。

欢迎浏览我们的 MongoDB JVM Showcase 仓库,了解更多 Java 示例和用例。如果你觉得它有用,不妨给它点个 ⭐。

该文章构建 Agentic 仓库管理系统——第 3 部分:工具、决策和行动最早发布在 foojay 上。