实战效果

刚开始用ppt录制的视频,导进来有声音,又通过视频转gif网站转成了图片
支持markdown格式显示,流式调用
前期准备
阿里云百炼控制台申请apikey和创建智能体应用得到appid,并配置到系统环境变量。


同时要注意使用的模型用量,记得开启免费额度用完即停

一个模型免费额度用完了可以到应用配置里切换成其他模型,同时在智能体应用配置里可以做两个配置,最大回复token可以改小一点,这样测试的次数会多一点。同时关闭自主思考enbale thinking,这样流式调用返回的结果会快一点

后端代码
jdk使用17版本,电脑是win7系统,IDEA版本是2021.3
控制器
java
package com.xmliu.alidemo;
import com.alibaba.cloud.ai.dashscope.agent.DashScopeAgent;
import com.alibaba.cloud.ai.dashscope.agent.DashScopeAgentOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/ai")
public class BailianStreamController {
private static final Logger logger = LoggerFactory.getLogger(BailianStreamController.class);
private DashScopeAgent agent;
@Value("${spring.ai.dashscope.agent.app-id}")
private String appId;
@CrossOrigin(origins = "http://localhost:3000")
@GetMapping(value = "/bailian/agent/stream", produces = "text/event-stream;charset=UTF-8")
public Flux<String> stream(@RequestParam(value = "message",
defaultValue = "知识库文档主要内容是什么?") String message) {
logger.info("----开始流式聊天----");
return agent.stream(new Prompt(message, DashScopeAgentOptions.builder().withAppId(appId).build()))
.map(response -> {
if (response == null || response.getResult() == null) {
logger.error("chat response is null");
// 空响应返回空串,最后统一处理
return "";
}
AssistantMessage app_output = response.getResult().getOutput();
String content = app_output.getText();
logger.info("content:\n{}\n\n", content);
return content != null ? content : "";
})
// 过滤空字符串
.filter(content -> !content.isBlank())
// 流结束追加标识
.concatWith(Mono.just("data:__STREAM_END__"));
}
}
配置文件
application.properties,其中appid和key配置在系统环境变量中,故代码里看不到具体的值
xml
spring.application.name=alidemo
# appID
spring.ai.dashscope.agent.app-id=${APP_ID}
spring.ai.dashscope.agent.connect-timeout=30000
spring.ai.dashscope.agent.read-timeout=30000
# API Key
spring.ai.dashscope.api-key=${DASHSCOPE_API_KEY}
spring.ai.dashscope.logging.request-response=true
server.tomcat.connection-timeout=30000
server.servlet.session.timeout=30m
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enable=true
server.servlet.encoding.force=true
##server:
## port: 9000
POM文件
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.10</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xmliu</groupId>
<artifactId>alidemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>alidemo</name>
<description/>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
<version>1.0.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>default-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
</execution>
<execution>
<id>default-testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
前端代码
前端使用HbuilderX 5.07开发,nodejs版本是13.14.0,vue3开发
核心代码App.vue
javascript
<template>
<h1 class="box">阿里百炼大模型智能体应用测试</h1>
<div class="chat-container">
<div class="reply-content">
<span v-html="parsedReply"></span>
<span v-if="errorMsg" class="error-tip">{{errorMsg}}</span>
</div>
<div class="input-area">
<input @keyup.enter="send" v-model="question" class="chat-input" placeholder="输入问题" />
<button @click="send" class="send-button" :class="{disabled:isLoading}" :disabled="isLoading">发送</button>
</div>
</div>
</template>
<script setup>
import {
ref,
computed,
nextTick
} from 'vue'
import {
marked
} from 'marked'
const question = ref('')
const reply = ref('')
const isLoading = ref(false)
const errorMsg = ref('')
const parsedReply = computed(() => {
return marked.parse(reply.value)
})
// 调用后端接口
const send = async () => {
console.log("点击了按钮")
if (!question.value.trim()) return;
isLoading.value = true
reply.value = ''
errorMsg.value = ''
try {
const url =
`http://127.0.0.1:8080/ai/bailian/agent/stream?message=${encodeURIComponent(question.value)}`
const eventSoure = new EventSource(url)
eventSoure.onmessage = (e) => {
console.log('e.data==', e.data)
if ('data:__STREAM_END__' === e.data) {
console.log('--------------结束-----------------------------', e.data)
eventSoure.close()
isLoading.value = false;
return;
}
errorMsg.value = '';
reply.value += e.data;
}
eventSoure.onerror = (err) => {
if (eventSoure.readyState === 2) {
console.log("正常结束")
} else {
eventSoure.close()
errorMsg.value = '接口请求失败,请稍后再试'
console.error('接口错误1', err)
}
isLoading.value = false
}
} catch (error) {
isLoading.value = false
errorMsg.value = '接口异常,请稍后再试'
console.error('接口异常', error)
}
}
</script>
<style>
.error-tip {
color: #ff4d4f;
font-size: 14px;
}
.loading-tip {
color: #666;
font-size: 14px;
}
.chat-container {
max-width: 800px;
margin: 20px auto;
padding: 0 20px;
}
.input-area {
display: flex;
gap: 10px;
margin-top: 20px;
}
.chat-input {
flex: 1;
padding: 12px 16px;
border: 1px solid #e0e0e0;
border-radius: 8px;
font-size: 14px;
outline: none;
transition: border-color 0.2s;
}
.chat-input :focus {
border-color: #1677ff;
}
.send-button {
padding: 0 24px;
background-color: #1677ff;
color: white;
border: none;
border-radius: 8px;
font-size: 14px;
cursor: pointer;
}
.send-button.disabled {
background-color: #cccccc;
cursor: not-allowed;
}
.send-button :hover {
background-color: #0f5fd7;
}
.blink {
animation: blink 1.2s infinite;
}
@keyframes blink {
0%,
100% {
opacity: 0;
}
50% {
opacity: 1;
}
}
.reply-content {
text-align: left;
min-height: 40px;
margin: 20px 0;
}
.reply-content h1 {
font-size: 20px;
font-weight: bold;
}
.reply-content code {
background: #f5f5f5;
padding: 2px 4px;
}
.box {
text-align: center;
}
</style>