芥末
发布于 2026-01-15 / 0 阅读
0
0

Assistant Agent:基于 Spring AI Alibaba 的 Code-as-Action 智能助手框架

Assistant Agent 是一个基于 Spring AI Alibaba 构建的企业级智能助手框架,代码仓库地址是:

https://github.com/spring-ai-alibaba/AssistantAgent

它面向的不是单轮聊天,而是能够接入企业知识库、调用外部系统、执行诊断动作、主动触发任务的智能助手。例如:

场景典型能力
智能客服查询企业知识库,回答产品、订单、售后、配置等问题
运维助手对接监控、日志、工单、发布系统,辅助排查告警
业务助理连接 CRM、ERP、订单系统,帮助员工查询和处理业务
AIOps(智能运维)结合告警、指标、日志和工具调用,完成自动化诊断与处置

Assistant Agent 的核心设计是 Code-as-Action,也就是“代码即行动”。智能体不是只从一组固定函数里挑一个调用,而是让大语言模型(Large Language Model,LLM)生成一段可执行代码,再由框架在受控环境中运行这段代码,通过代码编排多个工具完成任务。

Code-as-Action:让智能体用代码编排工具

传统工具调用通常是“模型判断意图 → 选择工具 → 填参数 → 执行工具”。这种方式适合简单动作,比如查天气、查订单状态、创建工单。但当任务需要多步判断、循环查询、条件分支、多个工具协作时,单次工具调用就会变得很笨重。

Code-as-Action 把任务表达成代码逻辑。模型可以生成类似这样的执行计划:

// 示例为概念性伪代码,用来说明 Code-as-Action 的思路

const order = tools.order.query({ orderId: userInput.orderId });

if (!order) {
  tools.reply.send("没有查询到对应订单,请确认订单号是否正确。");
  return;
}

const logistics = tools.logistics.query({ trackingNo: order.trackingNo });

if (logistics.status === "delayed") {
  const ticket = tools.ticket.create({
    title: "订单物流延迟",
    orderId: order.id,
    reason: logistics.reason
  });

  tools.reply.send(`订单存在物流延迟,已创建工单:${ticket.id}`);
} else {
  tools.reply.send(`订单当前状态:${logistics.status}`);
}

这段逻辑里面包含了查询、判断、创建工单、回复用户等多个动作。如果用普通函数调用方式,需要多轮模型推理才能完成;使用 Code-as-Action 时,模型可以一次生成更完整的流程,由运行时负责安全执行。

两种模式的差异可以这样理解:

对比项传统工具调用Code-as-Action
执行单元单个工具调用一段可执行代码
多步骤流程通常需要多轮模型交互可以在代码里组织分支、循环和组合调用
工具组合依赖模型多次选择工具由代码明确编排多个工具
可控性工具参数较容易控制需要沙箱、权限、超时和资源隔离
适合任务简单问答、简单动作诊断、运维、业务流程自动化、多系统协作

Assistant Agent 使用 GraalVM 多语言沙箱运行 AI 生成的代码。沙箱的作用是把模型生成的代码限制在受控边界内,避免代码直接访问宿主机的文件、网络、线程或敏感资源。代码真正能调用什么,取决于框架注册给它的工具。

一个请求从进入到回复的完整链路

Assistant Agent 处理请求时,不是直接把用户输入丢给模型,而是先做评估、检索、经验匹配,再动态组装 Prompt,模型生成行动代码后进入沙箱执行,执行结果再通过指定渠道返回。

flowchart TD
    A[用户输入] --> B[评估模块识别意图与上下文]
    B --> C[检索经验、知识和可用工具]
    C --> D[Prompt Builder 动态组装 Prompt]
    D --> E[LLM 生成行动代码]
    E --> F[GraalVM 沙箱执行代码]
    F --> G[调用已注册工具]
    G --> H{是否完成任务}
    H -- 否 --> D
    H -- 是 --> I[回复渠道返回结果]
    I --> J[学习模块提取经验]
    J --> K[经验库沉淀可复用模式]

这个流程里有几个关键点:

  • 评估模块负责判断用户输入是否清晰、是否需要改写、是否能匹配已有经验、是否需要搜索知识库。
  • Prompt Builder 根据评估结果决定给模型注入哪些上下文。
  • 模型生成的是“要执行的代码”,不是普通文本。
  • 沙箱只允许代码调用框架暴露出来的工具。
  • 学习模块会从成功或失败的执行过程中提取经验,供后续请求复用。

项目模块结构

Assistant Agent 按 Spring Boot 工程组织,核心能力被拆成多个模块:

assistant-agent/
├── assistant-agent-common
│   └── 通用工具、枚举、常量
├── assistant-agent-core
│   └── 核心引擎:GraalVM 执行器、工具注册表
├── assistant-agent-extensions
│   ├── dynamic
│   │   └── 动态工具:MCP、HTTP API 等
│   ├── experience
│   │   └── 经验管理与快速意图配置
│   ├── learning
│   │   └── 学习提取与经验存储
│   ├── search
│   │   └── 统一搜索能力
│   ├── reply
│   │   └── 多渠道回复
│   ├── trigger
│   │   └── 触发器机制
│   └── evaluation
│       └── 评估能力集成
├── assistant-agent-prompt-builder
│   └── Prompt 动态组装
├── assistant-agent-evaluation
│   └── 评估引擎
├── assistant-agent-autoconfigure
│   └── Spring Boot 自动配置
└── assistant-agent-start
    └── 启动模块

从工程结构可以看出,assistant-agent-core 负责运行时底座,扩展能力主要放在 assistant-agent-extensions 中,业务方接入时通常会围绕搜索、工具、回复渠道、触发器和经验模块做定制。

评估模块:把用户输入拆成可决策的信息

评估模块的任务是识别“当前请求到底应该怎么处理”。它不是只做一个意图分类,而是通过评估图把多个判断组合起来。

例如用户输入:

查询今日订单

系统可以同时做这些判断:

  • 输入是否模糊?
  • 是否需要改写成更明确的查询?
  • 是否有历史经验可以复用?
  • 是否存在合适工具?
  • 是否需要检索知识库?

评估过程可以组织成有依赖关系的图:

flowchart TD
    A[用户输入:查询今日订单] --> B1[判断输入是否模糊]
    A --> B2[输入改写]

    B1 --> C1[检索相似经验]
    B2 --> C1
    B2 --> C2[匹配可用工具]
    B2 --> C3[搜索知识库]

    C1 --> D[整合评估结果]
    C2 --> D
    C3 --> D

    D --> E[传递给 Prompt Builder]

评估模块支持两类评估方式:

评估方式适合场景特点
LLM 评估复杂语义判断、模糊意图识别、自然语言改写可以自定义评估 Prompt,也可以使用默认模板
Rule-based 规则评估阈值判断、格式校验、精确匹配、元数据判断通过 Java 函数实现,可预测性更强

规则评估适合明确判断,例如订单号格式是否合法、用户角色是否有权限、消息是否命中特定前缀。LLM 评估适合语义类判断,例如“这个问题是不是在问配置错误”“这个请求是否需要追问用户”。

评估结果可以是多种类型:

类型用途
BOOLEAN是/否判断
ENUM意图类别、状态类别
SCORE置信分、相似度
JSON结构化评估结果
TEXT改写文本、解释文本

这些结果会进入 Prompt Builder,决定模型调用时应该携带哪些上下文。

Prompt Builder:按场景动态拼装模型输入

在企业智能助手里,把所有说明、知识、工具文档、历史经验一次性塞进 Prompt 会带来两个问题:上下文过长,模型容易被无关信息干扰。

Prompt Builder 的做法是按条件注入内容。评估模块给出结果后,不同 Builder 根据结果决定是否贡献 Prompt 片段。

flowchart TD
    A[评估结果] --> B{输入是否模糊}
    A --> C{是否有历史经验}
    A --> D{是否匹配工具}
    A --> E{是否检索到知识}

    B -- 是 --> B1[注入澄清引导]
    B -- 否 --> B2[注入直接执行说明]

    C -- 是 --> C1[注入历史经验]
    D -- 是 --> D1[注入工具使用说明]
    E -- 是 --> E1[注入相关知识片段]

    B1 --> F[组合动态 Prompt]
    B2 --> F
    C1 --> F
    D1 --> F
    E1 --> F

    F --> G[发送给模型]

一个最终 Prompt 可能由这些部分组成:

[系统角色与安全边界]
[任务处理原则]
[澄清或直接执行策略]
[可用工具说明]
[检索到的知识片段]
[历史经验]
[用户输入]

这种方式的好处是:需要追问时注入追问策略,需要执行时注入工具说明,有知识命中时注入知识片段,有经验命中时注入历史做法。模型看到的是当前任务真正需要的信息,而不是一大段固定模板。

知识检索模块:用 SPI 接入企业知识源

Assistant Agent 的知识检索模块提供统一搜索接口,可以把知识库、项目资料、Web、内部 API 等数据源接到同一个检索流程里。

flowchart TD
    A[用户问题] --> B[统一检索接口 SearchProvider]
    B --> C1[知识库 Provider]
    B --> C2[项目资料 Provider]
    B --> C3[Web Provider]
    B --> C4[自定义 Provider]

    C1 --> D[FAQ、文档、历史问答]
    C2 --> E[代码、配置、日志]
    C3 --> F[网页、技术论坛]
    C4 --> G[数据库、向量库、内部 API]

    D --> H[聚合排序]
    E --> H
    F --> H
    G --> H

    H --> I[注入 Prompt 或供工具调用]

框架默认提供 Mock Provider,适合演示和本地测试。生产环境需要实现 SearchProvider SPI(Service Provider Interface,服务提供者接口),把真实知识源接进来,例如向量数据库、Elasticsearch、企业知识库 API 或数据库。

一个知识库 Provider 的基本结构如下:

package com.example.knowledge;

import com.alibaba.assistant.agent.extension.search.spi.SearchProvider;
import com.alibaba.assistant.agent.extension.search.model.SearchRequest;
import com.alibaba.assistant.agent.extension.search.model.SearchResultItem;
import com.alibaba.assistant.agent.extension.search.model.SearchSourceType;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class MyKnowledgeSearchProvider implements SearchProvider {

    @Override
    public boolean supports(SearchSourceType type) {
        return SearchSourceType.KNOWLEDGE == type;
    }

    @Override
    public List<SearchResultItem> search(SearchRequest request) {
        List<SearchResultItem> results = new ArrayList<>();

        // 1. 使用 request.getQuery() 查询真实知识源
        // 例如:向量数据库、Elasticsearch、企业知识库 API、数据库等
        //
        // List<Doc> docs = vectorStore.similaritySearch(request.getQuery());

        // 2. 转换成框架统一的 SearchResultItem
        //
        // for (Doc doc : docs) {
        //     SearchResultItem item = new SearchResultItem();
        //     item.setId(doc.getId());
        //     item.setSourceType(SearchSourceType.KNOWLEDGE);
        //     item.setTitle(doc.getTitle());
        //     item.setSnippet(doc.getSummary());
        //     item.setContent(doc.getContent());
        //     item.setScore(doc.getScore());
        //     results.add(item);
        // }

        return results;
    }

    @Override
    public String getName() {
        return "MyKnowledgeSearchProvider";
    }
}

常见知识源可以按下面方式映射:

知识源接入方式返回内容
向量数据库相似度检索文档片段、标题、分数
Elasticsearch关键词检索或混合检索FAQ、文档、历史问答
企业知识库 APIHTTP 调用业务文档、标准操作流程
数据库SQL 查询产品配置、规则、业务数据
代码仓库文件检索代码片段、配置文件、 README
日志系统查询 API错误日志、调用链、异常堆栈

对应配置示例:

spring:
  ai:
    alibaba:
      codeact:
        extension:
          search:
            enabled: true
            knowledge-search-enabled: true
            project-search-enabled: false
            web-search-enabled: false
            default-top-k: 5
            search-timeout-ms: 5000

工具扩展模块:让 Agent 能调用外部系统

智能助手真正产生业务价值,通常不是靠回答文字,而是靠连接外部系统。Assistant Agent 的动态工具模块负责把外部能力注册成智能体可调用的工具。

flowchart TD
    A[Agent 需要执行动作] --> B[CodeactTool 工具体系]

    B --> C1[MCP Tools]
    B --> C2[HTTP API Tools]
    B --> C3[Search Tools]
    B --> C4[Trigger Tools]
    B --> C5[Reply Tools]
    B --> C6[自定义 Tools]

    C1 --> D1[MCP Server]
    C2 --> D2[REST API / OpenAPI]
    C3 --> D3[知识库、项目、Web 检索]
    C4 --> D4[定时任务、回调事件]
    C5 --> D5[文本、卡片、IM、Webhook]
    C6 --> D6[业务系统能力]

MCP(Model Context Protocol,模型上下文协议)适合复用已有工具生态。HTTP API 接入适合把企业内部 REST 接口暴露给智能体,例如订单查询、工单创建、库存查询、发布系统操作等。

工具扩展通常需要重点设计三件事:

设计点说明
工具描述模型要能理解工具能做什么、参数是什么、什么时候调用
权限边界不同用户或场景可以调用的工具不应完全相同
执行保护高风险操作需要二次确认、审计、限流或只读模式

学习模块和经验模块:把成功路径沉淀下来

Assistant Agent 不只依赖当前请求推理,也会从执行历史中提取经验。学习模块负责“提取”,经验模块负责“保存和复用”。

flowchart TD
    A[Agent 执行过程] --> B[捕获学习上下文]
    B --> C[用户输入]
    B --> D[中间推理步骤]
    B --> E[生成代码]
    B --> F[工具调用结果]
    B --> G[最终输出]

    C --> H[学习提取器]
    D --> H
    E --> H
    F --> H
    G --> H

    H --> I1[成功经验]
    H --> I2[通用模式]
    H --> I3[失败教训]

    I1 --> J[经验库]
    I2 --> J
    I3 --> J

    J --> K[后续任务复用]

学习可以发生在不同阶段:

学习阶段说明
After-AgentAgent 完整运行结束后,从整体执行过程提取经验
After-Model每次模型调用后,分析模型输出和上下文
Tool Interceptor从工具调用过程里提取成功模式或失败原因
离线学习批量分析历史执行记录,提取更稳定的模式

经验模块支持多种经验类型:

经验类型用途
Code 经验复用类似任务的代码生成方式
ReAct 决策经验复用“观察、思考、行动”的决策路径
常识经验沉淀业务常识、限制条件、常见处理规则

经验的复用有两种方式。

一种是把匹配到的经验注入 Prompt,让模型参考历史成功路径。

另一种是快速意图响应。某些高频、稳定、低风险的请求可以显式配置 fastIntentConfig,命中条件后跳过完整 LLM 推理,直接执行预记录的代码或工具调用。

flowchart TD
    A[用户请求:查看今日销量] --> B{是否命中快速意图}
    B -- 否 --> C[走完整 LLM 推理与代码生成]
    B -- 是 --> D[跳过 LLM]
    D --> E[执行预配置工具调用或代码]
    E --> F[返回结果]
    C --> F

快速意图适合“条件稳定、动作确定”的场景,例如固定报表查询、固定状态查询、固定知识卡片返回。不适合高风险变更操作,也不适合需要复杂判断的诊断任务。

触发器模块:让助手主动执行任务

普通聊天助手只能被动响应用户输入。触发器模块让 Assistant Agent 能处理定时任务、延迟任务和外部事件。

flowchart TD
    A[用户提出主动任务] --> B{触发类型}

    B --> C1[TIME_CRON 定时触发]
    B --> C2[TIME_ONCE 一次性延迟触发]
    B --> C3[CALLBACK 回调触发]

    C1 --> D1[每天 9 点生成销售日报]
    C2 --> D2[30 分钟后提醒开会]
    C3 --> D3[Webhook 收到事件后执行处理]

    D1 --> E[触发 Agent 执行]
    D2 --> E
    D3 --> E

    E --> F[调用工具]
    F --> G[发送结果]

触发器能力可以用在这些任务里:

触发类型适合场景
TIME_CRON日报、周报、定时巡检、周期性同步
TIME_ONCE延迟提醒、稍后重试、一次性回调
CALLBACK告警事件、审批事件、外部系统通知

需要注意的是,主动任务通常涉及幂等性和重复执行问题。比如“每天生成日报”可以重复执行,但“自动退款”“自动发布”这类操作必须设计确认机制、幂等键和审计记录。

回复渠道模块:把结果发到正确的地方

Assistant Agent 的回复不局限于控制台文本。回复渠道模块提供统一接口,把消息路由到不同输出端。

flowchart TD
    A[Agent 需要回复] --> B[回复渠道路由]

    B --> C1[DEFAULT 文本]
    B --> C2[IDE_CARD 卡片]
    B --> C3[IM_NOTIFICATION 消息通知]
    B --> C4[WEBHOOK_JSON JSON 推送]

    C1 --> D1[控制台或默认通道]
    C2 --> D2[IDE 富文本卡片]
    C3 --> D3[钉钉、飞书、企微等]
    C4 --> D4[第三方系统]

内置示例渠道包括 IDE_TEXT,更多渠道可以通过实现 ReplyChannelDefinition SPI 扩展。例如:

渠道输出形式
IDE_TEXTIDE 或控制台文本
IDE_CARDIDE 卡片
IM_NOTIFICATIONIM 消息通知
WEBHOOK_JSONJSON 推送到第三方系统

回复渠道需要和任务类型匹配。诊断报告适合卡片或 Markdown,异步任务结果适合 IM 通知,系统间联动适合 Webhook。

快速启动

运行 Assistant Agent 需要准备:

  • Java 17+
  • Maven 3.8+
  • DashScope API Key

克隆并构建:

git clone https://github.com/spring-ai-alibaba/AssistantAgent
cd AssistantAgent
mvn clean install -DskipTests

配置 DashScope API Key:

export DASHSCOPE_API_KEY=your-api-key-here

最小配置可以写在 assistant-agent-start/src/main/resources/application.yml

spring:
  ai:
    dashscope:
      api-key: ${DASHSCOPE_API_KEY}
      chat:
        options:
          model: qwen-max

启动应用:

cd assistant-agent-start
mvn spring-boot:run

默认扩展模块已经开启,并提供演示用 Mock 实现。只做本地体验时,可以直接运行;进入生产环境后,需要替换真实知识库、真实工具、真实回复渠道和必要的权限控制。

哪些场景适合使用 Assistant Agent

Assistant Agent 更适合“需要知识 + 工具 + 多步执行”的智能助手,不适合把所有问题都简单包装成聊天机器人。

场景是否适合原因
企业知识库问答适合SearchProvider 可以接入真实知识源,并支持答案溯源
运维告警诊断适合可以组合日志、指标、工单、发布系统等多个工具
固定报表查询适合高频稳定任务可配置快速意图
主动提醒和定时巡检适合触发器模块支持定时、延迟和回调
简单闲聊不太适合框架能力偏工程化,接入成本高于普通聊天接口
高风险自动变更谨慎使用需要审批、权限、审计、幂等和回滚机制
无真实知识源的客服不适合直接上线Mock 数据只能演示,无法支撑真实业务问答

接入时容易踩的坑

Mock Provider 不能当生产知识库

默认知识库、项目搜索、Web 搜索的 Mock 实现只适合演示。真实场景里必须接入企业知识源,并处理检索质量、召回数量、排序策略和答案溯源问题。

沙箱不是权限系统的全部

GraalVM 沙箱可以限制代码运行环境,但业务权限仍然要在工具层实现。比如同样是“查询订单”,客服、运营、财务能看到的数据范围可能不同,工具接口需要根据用户身份做鉴权。

快速意图只能用于稳定低风险任务

快速意图会跳过完整 LLM 推理,速度更快,但也少了一层语义判断。适合固定查询,不适合模糊需求、复杂诊断、高风险写操作。

工具描述会直接影响模型行为

工具名称、参数说明、返回结构如果写得模糊,模型生成的代码就容易误用工具。企业内部工具接入时,要把可调用条件、参数含义、错误返回和示例写清楚。

主动触发任务要考虑幂等

定时任务、回调任务、延迟任务都有重复触发的可能。凡是会改变业务状态的操作,都应该设计幂等键、执行日志和失败重试策略。

小结

Assistant Agent 的核心价值在于把大语言模型、工具调用、知识检索、沙箱执行、经验学习和主动触发整合成一个工程化框架。它不是简单的问答壳子,而是用 Code-as-Action 让智能体生成并执行代码,通过代码组织复杂流程,再用 GraalVM 沙箱和工具注册表控制执行边界。

如果要构建企业级智能客服、运维诊断助手、业务助理或 AIOps 系统,可以把 Assistant Agent 理解成一个智能体运行时底座:知识从 SearchProvider 接入,外部能力从工具体系接入,输出从回复渠道接出,经验由学习模块沉淀,稳定高频任务再用快速意图和触发器优化执行路径。


评论