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、文档、历史问答 |
| 企业知识库 API | HTTP 调用 | 业务文档、标准操作流程 |
| 数据库 | 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-Agent | Agent 完整运行结束后,从整体执行过程提取经验 |
| 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_TEXT | IDE 或控制台文本 |
IDE_CARD | IDE 卡片 |
IM_NOTIFICATION | IM 消息通知 |
WEBHOOK_JSON | JSON 推送到第三方系统 |
回复渠道需要和任务类型匹配。诊断报告适合卡片或 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 接入,外部能力从工具体系接入,输出从回复渠道接出,经验由学习模块沉淀,稳定高频任务再用快速意图和触发器优化执行路径。