8 - AI 服务化 - AI 超级智能体项目教程

8 - AI 服务化 - AI 超级智能体项目教程AI 服务化是指将原本只能本地运行的 AI 能力转化为可远程调用的接口服务 使更多人能够便捷地访问 AI 能力 通过本节学习 你将掌握如何将 AI 智能体转变为可供他人调用的服务 具体内容包括 在开始之前 先给大家提个醒 Spring AI 版本更新飞快 有些代码的写法随时可能失效 尽量以 官方文档 为准 我们平时开发的大多数接口都是同步接口 也就是等后端处理完再返回 但是对于 AI

大家好,我是讯享网,很高兴认识大家。这里提供最前沿的Ai技术和互联网信息。



AI 服务化是指将原本只能本地运行的 AI 能力转化为可远程调用的接口服务,使更多人能够便捷地访问 AI 能力。通过本节学习,⁠你将掌握如何将 AI 智能体转变为可供他人调用的服务

具体内容包括:

在开始之前,先给大家提个醒,Spring AI 版本更新飞快,有些代码的写法随时可能失效,尽量以 官方文档 为准。

我们平时开发的大多数接口都是同步接口,也就是等后端处理完再返回。但是对于 AI 应用,特别是响应时间较长的对话类应用,可能会让⁠用户失去耐心等待,因此推荐使用 SSE(Server-Sent Events)技术实现实时流式输出,类似打字机效果,大幅提升用户体验。

接下来我们会同时提供同步接口(一次性完整返回)⁠和基于 SSE 的流式输出接口。

开发

1、支持流式调用

首先,我们需要为 InterviewAPP 添加流式调用方法⁠,通过 stream 方法就可以返回 Flux 响应式对象了:

public Flux 
    
      
      
        doChatByStream(String message, String chatId) { 
      

GPT plus 代充 只需 145return chatClient .prompt() .user(message) .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId) .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10)) .stream() .content(); 

}

💡 建议不要直接使用 ChatResponse 作为返回类型,因为这会导致返回内容膨⁠胀,影响传输效率。所以上述代码中我们使用 content 方法,只返回 AI 输出的文本信息。

2、开发同步接口

在 controller 包下新建 AiController,将所有的接口都写在这个文件内。

先编写一个同步接口:

@RestController@RequestMapping("/ai")public class AiController {

GPT plus 代充 只需 145@Resourceprivate InterviewAPP interviewAPP; @Resourceprivate ToolCallback[] allTools; @Resourceprivate ChatModel dashscopeChatModel; @GetMapping("/interview_app/chat/sync")public String doChatWithInterviewAPPSync(String message, String chatId) { return interviewAPP.doChat(message, chatId); } 

}

3、开发 SSE 流式接口

然后编写基于 SSE 的流式输出接口,有几种常⁠见的实现方式:

1) 返回 Flux 响应式对象,并且添加 S⁠SE 对应的 MediaType:

@GetMapping(value = "/interview_app/chat/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux 
    
      
      
        doChatWithInterviewAPPSSE(String message, String chatId) { 
      

GPT plus 代充 只需 145return interviewAPP.doChatByStream(message, chatId); 

}

2)返回 Flux 对象,并且设置泛型为 Serv⁠erSentEvent。使用这种方式可以省略 MediaType:

@GetMapping(value = "/interview_app/chat/sse")public Flux 
    
      
      
        > doChatWithInterviewAPPSSE(String message, String chatId) { 
      

GPT plus 代充 只需 145return interviewAPP.doChatByStream(message, chatId) .map(chunk -> ServerSentEvent. 
  
    
    
      builder() .data(chunk) .build()); 
    

}

3)使用 SSEEmiter,通过 send 方法⁠持续向 SseEmitter 发送消息(有点像 IO 操作):

@GetMapping("/interview_app/chat/sse/emitter")public SseEmitter doChatWithInterviewAPPSseEmitter(String message, String chatId) {

GPT plus 代充 只需 145// 创建一个超时时间较长的 SseEmitterSseEmitter emitter = new SseEmitter(L); // 3分钟超时// 获取 Flux 数据流并直接订阅 interviewAPP.doChatByStream(message, chatId) .subscribe( // 处理每条消息 chunk -> { try { emitter.send(chunk); } catch (IOException e) { emitter.completeWithError(e); } }, // 处理错误 emitter::completeWithError, // 处理完成 emitter::complete ); // 返回emitterreturn emitter; 

}

测试接口

开发完成后,我们可以通过 Swagger 接口文档来测试接口功能、验证会话上下文是否正常⁠工作。但是,浏览器控制台可能无法实时查看 SSE 返回的内容,这时我们不妨使用 CURL 工具进行测试。

一般 Linux 和 Mac 系统自带了 CU⁠RL 工具,打开终端,输入下列命令:

控制台会持续不断地输出文本片段

💡 在浏览器 F12 控制台中,可以直接选中⁠网络请求来复制 CURL 命令,非常便于测试

当然,如果你无法使用 CURL,也可以使用 IDEA 自带的 HT⁠TP Client 工具进行测试。点击接口旁边的绿豆就能自动生成测试代码:

由于智能体执行过程通常包含多个步骤,执行时间较长,使用同步方法会导⁠致用户体验不佳。因此,我们采用 SSE 技术将智能体的推理过程实时分步输出给用户。

开发

1)首先在 BaseAgent 类中添加流式输出方法:

  • 运行代理(流式输出) *
  • @param userPrompt 用户提示词
  • @return SseEmitter实例 */public SseEmitter runStream(String userPrompt)
     if (StringUtil.isBlank(userPrompt)) { emitter.send("错误:不能使用空提示词运行代理"); emitter.complete(); return; } // 更改状态 state = AgentState.RUNNING; // 记录消息上下文 messageList.add(new UserMessage(userPrompt)); try { for (int i = 0; i < maxSteps && state != AgentState.FINISHED; i++) { int stepNumber = i + 1; currentStep = stepNumber; log.info("Executing step " + stepNumber + "/" + maxSteps); // 单步执行String stepResult = step(); String result = "Step " + stepNumber + ": " + stepResult; // 发送每一步的结果 emitter.send(result); } // 检查是否超出步骤限制if (currentStep >= maxSteps) { state = AgentState.FINISHED; emitter.send("执行结束: 达到最大步骤 (" + maxSteps + ")"); } // 正常完成 emitter.complete(); } catch (Exception e) catch (Exception ex) { emitter.completeWithError(ex); } } finally { // 清理资源this.cleanup(); } } catch (Exception e) { emitter.completeWithError(e); } 

    });

    // 设置超时和完成回调 emitter.onTimeout(() -> {

    GPT plus 代充 只需 145this.state = AgentState.ERROR; this.cleanup(); log.warn("SSE connection timed out"); 

    });

    emitter.onCompletion(() ->

    this.cleanup(); log.info("SSE connection completed"); 

    });

    return emitter; }

    上述代码虽然看着很复杂,但是大部分都是在原有 run 方⁠法的基础上进行改造,补充给 SseEmitter 推送消息的代码。

    注意,上述代码中使用 CompletableFuture.runAsync() 实现非阻塞式异步执行,否则会长时间占用 Web 服务器线程池资源。

    2)在 AiController 中编写新的接口,注意每次对话都要创建一个新的实例:

    GPT plus 代充 只需 145@Resourceprivate ToolCallback[] allTools;

@Resourceprivate ChatModel dashscopeChatModel;

/

  • 流式调用 Manus 超级智能体 *
  • @param message
  • @return */@GetMapping("/manus/chat")public SseEmitter doChatWithManus(String message) { YuManus yuManus = new YuManus(allTools, dashscopeChatModel); return yuManus.runStream(message); }

    测试接口

    跟前面一样,使用 CURL 工具进行测试,效果如图:

    后端支持跨域

    为了让前端项目能够顺利调用后端接口,我们需要在后端⁠配置跨域支持。在 config 包下创建跨域配置类,代码如下:

    /

  • 全局跨域配置 */@Configurationpublic class CorsConfig implements WebMvcConfigurer {

    @Overridepublic void addCorsMappings(CorsRegistry registry) {

    GPT plus 代充 只需 145// 覆盖所有请求 registry.addMapping("/") // 允许发送 Cookie .allowCredentials(true) // 放行哪些域名(必须用 patterns,否则 * 会和 allowCredentials 冲突) .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .exposedHeaders("*"); 

    } }

    注意,如果 .allowedOrigins("*").allowCredentials(true) 同时配置会导致冲突,因为出于安全考虑,跨域请求不能同时允许所有域名访问和发送认证信息(比如 Cookie)。

小讯
上一篇 2026-03-18 13:37
下一篇 2026-03-18 13:35

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/243354.html