适合人群:希望统一多厂商(OpenAI、阿里、科大讯飞等)调用体验的后端开发者或技术爱好者。
建议先看:实践三(RESTful API 设计原则)、实践六(阿里大模型对接)。
你将收获:一套可扩展的适配层模型与返回体规范,最小变更对接新厂商。

设计目标与边界

  • 统一接口:隐藏厂商差异,暴露稳定域模型(模型、聊天、流式聊天、图片)。
  • 易于扩展:新增厂商仅需实现适配器,不影响上层调用与返回结构。
  • 一致的错误语义:统一 success/code/message,流式以 [process]/[done] 信号闭环。
  • 安全与合规:不在代码中硬编码密钥,敏感信息通过环境变量或配置中心注入。

对输入参数进行统一

几乎不改

返回值统一

模型

@Data
public class BigModel {
    private String id;

    public BigModel(String id) {
        this.id = id;
    }
    public BigModel() {}
}

文字聊天

@Data
public class ChatMessage {
    private String id;
    private String content;
    private String status; // success fail
    private String error;
}

文字聊天流

@Data
public class ChatMessageStream {
    private String id;
    private String content;
    private String status; // done process
}

图片

@Data
public class ChatImage {
    private String id;
    private String imageUrl;
    private String status; // success fail
    private String error;
}

流程合并

使用统一接口

OpenAI

@Service
public class OpenAiAdopter {
    @Autowired
    private OpenAiService openAiService;

    public List<BigModel> getModels() {
        Map model = openAiService.getModel();
        List<Map> models = (List<Map>) model.get("data");
        return models.stream().map(m -> new BigModel(m.get("id").toString())).collect(Collectors.toList());
    }

    public ChatMessage chat(String model, String message) {
        Map chat = openAiService.chat(model, message);
        String id = chat.get("id").toString();
        List<Map> output = (List<Map>) chat.get("output");

        ChatMessage chatMessage = new ChatMessage();
        chatMessage.setId(id);
        String contentStr = "";
        chatMessage.setStatus("completed");
        for (Map map : output) {

            if (!map.get("type").toString().equals("message")) {
                continue;
            }
            if (!map.get("status").toString().equals("completed")) {
                continue;
            }

            List<Map> contents = (List<Map>) map.get("content");

            for (Map content : contents) {
                contentStr += content.get("text").toString();
            }
        }
        chatMessage.setContent(contentStr);
        return chatMessage;
    }

    public void chatStream(String model, String message, Consumer<ChatMessageStream> onDelta){
        openAiService.chatStream(model, message, (delta)->{
            ChatMessageStream chatMessageStream = new ChatMessageStream();
            chatMessageStream.setId(UUID.randomUUID().toString());
            chatMessageStream.setStatus("process");
            chatMessageStream.setContent(delta);
            onDelta.accept(chatMessageStream);
        });
    }

    public ChatImage generateImage(String model, String prompt, String size) {
        try {
            Map image = openAiService.generateImageUrl(model, prompt, size);
            ChatImage chatImage = new ChatImage();
            chatImage.setId(UUID.randomUUID().toString());
            List<Map> images =  (List<Map>)image.get("data");
            chatImage.setImageUrl(images.get(0).get("url").toString());
            chatImage.setStatus("success");
            return chatImage;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

阿里

@RestController
@RequestMapping("/ai")
public class AiController {
    @Autowired
    private AliAiAdopter aliAiAdopter;
    @Autowired
    private OpenAiAdopter openAiAdopter;

    @GetMapping("/get/models")
    public List<BigModel> getModels(@RequestParam("platform") String platform) {
        if ("ali".equals(platform)) {
            return aliAiAdopter.getModels();
        }
        return openAiAdopter.getModels();
    }

    @PostMapping("/chat")
    public ChatMessage chat(@RequestBody Map<String, String> param) throws JsonProcessingException {
        String platform = "";
        if (param.get("platform") != null) {
            platform = param.get("platform");
        }
        String model = "";
        if (param.get("model") != null) {
            model = param.get("model");
        }
        String message = "";
        if (param.get("message") != null) {
            message = param.get("message");
        }
        if ("ali".equals(platform)) {
            return aliAiAdopter.chat(model, message);
        }
        return openAiAdopter.chat(model, message);
    }

    @PostMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter chatStream(@RequestBody Map<String, String> param, HttpServletResponse response) {
        String platform = "";
        if (param.get("platform") != null) {
            platform = param.get("platform");
        }
        String model;
        if (param.get("model") != null) {
            model = param.get("model");
        } else {
            model = "";
        }
        String message;
        if (param.get("message") != null) {
            message = param.get("message");
        } else {
            message = "";
        }
        SseEmitter emitter = new SseEmitter(0L); // 0 表示不超时;可按需设置毫秒
        if ("ali".equals(platform)) {
            CompletableFuture.runAsync(() -> {
                try {
                    aliAiAdopter.chatStream(model, message, delta -> {
                        try {
                            emitter.send(SseEmitter.event().name("delta").data(delta));
                        } catch (IOException e) {
                            emitter.completeWithError(e);
                        }
                    });
                    // 上游完成
                    emitter.send(SseEmitter.event().name("done").data("[DONE]"));
                    emitter.complete();
                } catch (Exception ex) {
                    emitter.completeWithError(ex);
                }
            });
        } else {
            CompletableFuture.runAsync(() -> {
                try {
                    openAiAdopter.chatStream(model, message, delta -> {
                        try {
                            emitter.send(SseEmitter.event().name("delta").data(delta));
                        } catch (IOException e) {
                            emitter.completeWithError(e);
                        }
                    });
                    // 上游完成
                    ChatMessageStream chatMessageStream = new ChatMessageStream();
                    chatMessageStream.setId(UUID.randomUUID().toString());
                    chatMessageStream.setStatus("[done]");
                    chatMessageStream.setContent("");
                    emitter.send(SseEmitter.event().name("done").data(chatMessageStream));
                    emitter.complete();
                } catch (Exception ex) {
                    emitter.completeWithError(ex);
                }
            });
        }
        return emitter;
    }

    @PostMapping("/generate/image")
    public ChatImage generateImage(@RequestBody Map<String, String> param) {
        String model = param.getOrDefault("model", "dall-e-3");
        String platform = param.getOrDefault("platform", "ali");
        String prompt = param.getOrDefault("prompt", "");
        String size = param.getOrDefault("size", "1024x1024");

        if ("ali".equals(platform)) {
            return aliAiAdopter.generateImage(model, prompt, size);
        }
        return openAiAdopter.generateImage(model, prompt, size);
    }
}

接口统一

@RestController
@RequestMapping("/ai")
public class AiController {
    @Autowired
    private AliAiAdopter aliAiAdopter;
    @Autowired
    private OpenAiAdopter openAiAdopter;

    @GetMapping("/get/models")
    public List<BigModel> getModels(@RequestParam("platform") String platform) {
        if ("ali".equals(platform)) {
            return aliAiAdopter.getModels();
        }
        return openAiAdopter.getModels();
    }

    @PostMapping("/chat")
    public ChatMessage chat(@RequestBody Map<String, String> param) throws JsonProcessingException {
        String platform = "";
        if (param.get("platform") != null) {
            platform = param.get("platform");
        }
        String model = "";
        if (param.get("model") != null) {
            model = param.get("model");
        }
        String message = "";
        if (param.get("message") != null) {
            message = param.get("message");
        }
        if ("ali".equals(platform)) {
            return aliAiAdopter.chat(model, message);
        }
        return openAiAdopter.chat(model, message);
    }

    @PostMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter chatStream(@RequestBody Map<String, String> param, HttpServletResponse response) {
        String platform = "";
        if (param.get("platform") != null) {
            platform = param.get("platform");
        }
        String model;
        if (param.get("model") != null) {
            model = param.get("model");
        } else {
            model = "";
        }
        String message;
        if (param.get("message") != null) {
            message = param.get("message");
        } else {
            message = "";
        }
        SseEmitter emitter = new SseEmitter(0L); // 0 表示不超时;可按需设置毫秒
        if ("ali".equals(platform)) {
            CompletableFuture.runAsync(() -> {
                try {
                    aliAiAdopter.chatStream(model, message, delta -> {
                        try {
                            emitter.send(SseEmitter.event().name("delta").data(delta));
                        } catch (IOException e) {
                            emitter.completeWithError(e);
                        }
                    });
                    // 上游完成
                    emitter.send(SseEmitter.event().name("done").data("[DONE]"));
                    emitter.complete();
                } catch (Exception ex) {
                    emitter.completeWithError(ex);
                }
            });
        } else {
            CompletableFuture.runAsync(() -> {
                try {
                    openAiAdopter.chatStream(model, message, delta -> {
                        try {
                            emitter.send(SseEmitter.event().name("delta").data(delta));
                        } catch (IOException e) {
                            emitter.completeWithError(e);
                        }
                    });
                    // 上游完成
                    ChatMessageStream chatMessageStream = new ChatMessageStream();
                    chatMessageStream.setId(UUID.randomUUID().toString());
                    chatMessageStream.setStatus("[done]");
                    chatMessageStream.setContent("");
                    emitter.send(SseEmitter.event().name("done").data(chatMessageStream));
                    emitter.complete();
                } catch (Exception ex) {
                    emitter.completeWithError(ex);
                }
            });
        }
        return emitter;
    }

    @PostMapping("/generate/image")
    public ChatImage generateImage(@RequestBody Map<String, String> param) {
        String model = param.getOrDefault("model", "dall-e-3");
        String platform = param.getOrDefault("platform", "ali");
        String prompt = param.getOrDefault("prompt", "");
        String size = param.getOrDefault("size", "1024x1024");

        if ("ali".equals(platform)) {
            return aliAiAdopter.generateImage(model, prompt, size);
        }
        return openAiAdopter.generateImage(model, prompt, size);
    }
}
Last modification:September 19, 2025
如果觉得我的文章对你有用,请随意赞赏
END
本文作者:
文章标题:软件工程实践七:AI 大模型 API 合并与适配层设计
本文地址:https://blog.ybyq.wang/archives/1119.html
版权说明:若无注明,本文皆Xuan's blog原创,转载请保留文章出处。