Spring AI 2.0:阿里云百炼平台(智能体应用)

一、内网穿透

二、JSONPlaceholder

POST/PUT 只是模拟成功,不会真实保存数据 ,非常适合 Agent 工具调用调试。

返回模拟 JSON 数据,无 token 无鉴权。

c 复制代码
GET https://jsonplaceholder.typicode.com/posts/1

{
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
  "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}

GET https://jsonplaceholder.typicode.com/users 用户列表
GET https://jsonplaceholder.typicode.com/todos 待办列表

三、创建应用

创建智能体应用

https://bailian.console.aliyun.com/cn-beijing?tab=app#/app-market/suggest

设置模型

设置提示词

md 复制代码
角色
你作为在线教育平台资深客服代表兼讲师。你的任务根据学员的需求,调用知识库中的课程信息,为学员推荐合适的课程,同时解答学员对课程内容和知识点的疑问。

技能 1: 课程推荐
1. 当学员提出课程推荐需求时,需判断是否提供必要信息。必要信息包含年龄、学历、是否有编程基础。
2. 若缺少必要信息,需礼貌追问。
3. 若学员未提供感兴趣的方向,需追问。若没有明确方向,优先推荐学习人数多的课程。
4. 若信息充足,根据必要信息和感兴趣的课程方向,去知识库匹配合适的课程,获取课程id,调用queryCourseById,根据课程id查询课程详细信息,为学员推荐课程,可推荐单门/多门课程。
5. 若知识库未包含学员感兴趣方向,需明确告知学员未提供该方向课程,并推荐其他课程。
6. 若必要信息未匹配合适课程,需提示学员您的情况与现有课程要求并不完全匹配,说明详细原因后,再推荐其他课程。
7. 推荐课程,必须要通过queryCourseById查询后,才能返回数据。

技能 2: 课程购买
1. 当学员提出购买课程时,需判断此次会话中,学员是否明确提出购买xx课/系统已为学员推荐课程。
2. 若已推荐/明确课程名称,需调用prePlaceOrder,根据此次上文已推荐/学员明确的课程,直接进入预下单流程。
3. 若未推荐课程,需引导学员进入到课程推荐流程。
4. 若学员未明确提出购买某门课程时,需询问用户购买哪门课程。
5. 支持购买一门/多门课程。

技能 3: 课程咨询
1. 当学员咨询课程内容时,需去知识库匹配合适的课程,获取课程id,根据课程id查询课程详细信息。回复的内容要全面,要引导学员报名购买。
2. 若未查询到,需礼貌告知学员未检索到相关的内容,请联系人工客服010-12345678。
3. 若咨询课程有效期,需将当前时间{now} 与 课程有效期相加,回复学员准确日期。课程有效期999天,代表永久有效。

技能 4: 知识讲解
1. 当学员咨询与IT相关的知识点内容时,需详细讲解知识点并提供示例。

限制:
- 推荐的课程只能从知识库中选择,坚决不能凭空编造
- 回答的内容要逻辑清晰、内容全面、不要有遗漏。
- 只能回答与课程和IT知识点相关的内容,若学员咨询与课程无关的内容,你需告知学员不能回答与课程和IT知识点无关的问题,并引导学员咨询与课程/IT知识点相关的问题。
- 若学员询问课程ID,则告知学员无法提供课程ID,引导学员咨询其他的问题。

数据连接

导入数据

知识库

这里也可以直接上传文件。

添加知识库。

添加插件

添加工具,需要发布。

工具转为MCP。也可以直接创建MCP。

添加MCP

调试完即可发布。

四、程序调用

xml 复制代码
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dashscope-sdk-java</artifactId>
    <version>2.19.0</version>
    <exclusions>
        <exclusion>
            <groupId>com.github.victools</groupId>
            <artifactId>jsonschema-generator</artifactId>
        </exclusion>
        <exclusion>
            <artifactId>slf4j-api</artifactId>
            <groupId>org.slf4j</groupId>
        </exclusion>
        <exclusion>
            <artifactId>slf4j-simple</artifactId>
            <groupId>org.slf4j</groupId>
        </exclusion>
    </exclusions>
</dependency>
c 复制代码
public class AppTest {

    @Test
    public void testAppCall() throws Exception {
        // 构造业务参数(工具调用需要)
        String token = "xxxxxxxxxxx";
        Map<String, Object> bizParams = MapUtil.<String, Object>builder()
                .put("user_defined_tokens", MapUtil.of("tool_xxxxx", // 工具id
                        MapUtil.of("user_token", token)))
                .build();

        // bizParams.add("user_defined_tokens", JsonObject);
        ApplicationParam param = ApplicationParam.builder()
                // 若没有配置环境变量,可用百炼API Key将下行替换为:.apiKey("sk-xxx")。但不建议在生产环境中直接将API Key硬编码到代码中,以减少API Key泄露风险。
                .apiKey(System.getenv("ALIYUN_API_KEY")
                .appId("xxxxxxxxxx") // 智能体id
                .prompt("课程推荐,20岁,本科,没有编程基础,对java感兴趣")
                .incrementalOutput(true) // 开启增量输出
                .bizParams(JsonUtils.toJsonObject(bizParams))
                .build();

        Application application = new Application();
        Flowable<ApplicationResult> result = application.streamCall(param);

        // 阻塞式的打印内容
        result.blockingForEach(data -> {
            System.out.printf("%s\n",data.getOutput().getText());
        });
    }
}

五、Spring集成

yaml 复制代码
tj:
  ai:
    dashscope:
      key: sk-xxxxxxxxxxx
      app-agent:
        id: xxxxxxxxx
        tools: 
          - "tool_xxxxx"
          - "tool_xxxxx"
java 复制代码
@Data
@Configuration
@ConfigurationProperties(prefix = "tj.ai.dashscope")
public class DashScopeProperties {

    private String key;
    private AppAgent appAgent;

    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public static class AppAgent {
        private String id;
        private List<String> tools;
    }
}

提供App版本(阿里云百炼)的ChatService实现。

java 复制代码
@Service
@RequiredArgsConstructor
@ConditionalOnProperty(prefix = "tj.ai", name = "chat-type", havingValue = "APP")
public class AppAgentChatService implements ChatService {

    private final DashScopeProperties dashScopeProperties;

    // 存储大模型的生成状态,这里采用ConcurrentHashMap是确保线程安全
    // 目前的版本暂时用Map实现,如果考虑分布式环境的话,可以考虑用redis来实现
    private static final Map<String, Boolean> GENERATE_STATUS = new ConcurrentHashMap<>();
    // 输出结束的标记
    private static final ChatEventVO STOP_EVENT = ChatEventVO.builder().eventType(ChatEventTypeEnum.STOP.getValue()).build();

    @Override
    public Flux<ChatEventVO> chat(String question, String sessionId) {
        // 获取对话id
        var conversationId = ChatService.getConversationId(sessionId);
        var token = TokenContext.getToken();
        var toolsMap = new HashMap<String, Object>();
        for (var tool : dashScopeProperties.getAppAgent().getTools()) {
            toolsMap.put(tool, Map.of("user_token", token));
        }
        var bizParams = Map.of("user_defined_tokens", toolsMap);

        var param = ApplicationParam.builder()
                .apiKey(dashScopeProperties.getKey())
                .appId(dashScopeProperties.getAppAgent().getId()) // 智能体id
                .prompt(question)
                .incrementalOutput(true) // 开启增量输出
                .bizParams(JsonUtils.toJsonObject(bizParams))
                .sessionId(conversationId) // 设置会话ID
                .build();

        var application = new Application();
        try {
            var result = application.streamCall(param);

            // 将Flowable 转化为 Flux 进行处理输出
            return Flux.from(result)
                    .doFirst(() -> { //输出开始,标记正在输出
                        GENERATE_STATUS.put(sessionId, true);
                    })
                    .doOnComplete(() -> { //输出结束,清除标记
                        GENERATE_STATUS.remove(sessionId);
                    })
                    .doOnError(throwable -> GENERATE_STATUS.remove(sessionId)) // 错误时清除标记
                    // 输出过程中,判断是否正在输出,如果正在输出,则继续输出,否则结束输出
                    .takeWhile(s -> GENERATE_STATUS.getOrDefault(sessionId, false))
                    .map(applicationResult -> {
                        // 获取大模型的输出的内容
                        var text = applicationResult.getOutput().getText();
                        // 封装响应对象
                        return ChatEventVO.builder()
                                .eventData(text)
                                .eventType(ChatEventTypeEnum.DATA.getValue())
                                .build();
                    })
                    .concatWith(Flux.just(STOP_EVENT));

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void stop(String sessionId) {
        // 移除标记
        GENERATE_STATUS.remove(sessionId);
    }
}

在线平台适合通用的功能,没法自定义功能(返回值没法自定义结合客户端展示,没有历史记录等),常适用于一次性的功能(各种工具),常用于个人,企业中还需要自己开发。

相关推荐
肠畔码农1 小时前
深度解密 Redis 分布式锁:从单机原子语义到集群架构博弈
redis·分布式·架构
宠友信息3 小时前
IM系统开发技术路线分析,即时通讯源码助力快速搭建聊天应用
java·spring boot·redis·websocket·mysql·uni-app·vue
肠畔码农3 小时前
Redis 主从复制内核深潜:从物理模型到全量增量同步的本质
网络·redis·php
风流 少年4 小时前
Spring AI 2.0:阿里云百炼平台(工作流应用)
java·后端·spring
手握风云-5 小时前
Spring Cloud:分布式系统的“粘合剂”(五)
后端·spring·spring cloud
SQL-First布道者6 小时前
全面解构传统持久层框架,拥抱真正的 SQL-First
java·数据库·spring boot·sql·spring·mybatis·spring jdbc
翼龙云_cloud6 小时前
阿里云国际版代理商:OSS自定义域名绑定与HTTPS配置排障教程
数据库·阿里云·https·云计算
小的~~6 小时前
面试被问分布式锁,我差点语塞…直到搞懂了Redis、ZooKeeper和etcd的“三国杀”
redis·分布式·面试
2602_959960927 小时前
Java大厂面试实录:Spring Boot、Redis、Kafka、Elasticsearch、分布式事务与云原生高并发系统
java·jvm·spring boot·redis·面试题