Skip to content

星球开源共建项目 《OpenAI SDK》 统一大模型标准化对接的技术组件项目,此项目以解决实际市面上的场景为诉求,将 OpenAI、Claude、PalM、文心一言、通义千问、讯飞星火、智谱 ChatGLM、腾讯混元等这些大模型做一个统一的 SDK 对接组件。

fuzhengwei/openai-sdk-java

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

openai-sdk-java —— 统一大模型对接 SDK 设计实现

星球开源共建项目 《OpenAI SDK》 统一大模型标准化对接的技术组件项目,此项目以解决实际市面上的场景为诉求,将 OpenAI、Claude、PalM、文心一言、通义千问、讯飞星火、智谱 ChatGLM、腾讯混元等这些大模型做一个统一的 SDK 对接组件。

参与开发和使用的伙伴可以扫码加群。

目录 ⛳️

  • 一、发布记录
  • 二、对接计划
  • 三、需求开发 - 承接需求
      1. 需求说明
      1. 需求提报 - 开发前提报需求📢
  • 四、安装使用
      1. 单元测试
      1. 应用接入
      1. 程序接入
  • 五、开发规范
  • 六、其他资料

一、发布记录

  • 2.2 @kkc_s 对接Gemini Pro:文本对话 & 图片理解Master @LATASA 百度文心一言图像
  • 2.1 @ouyu 开发对接讯飞图片识别功能 在发呆的_fy 对接 GeminiPro 文生文
  • 2.0 @fy 初始部分 Claude 模型执行器基础类
  • 1.9 @Mooneal 讯飞bug修复
  • 1.8 @二十五六岁 对接 Google PaLM2 聊天模型
  • 1.7 @一乡风 对接 360 智脑
  • 1.6 @二十五六岁 对接 Google PaLM2
  • 1.5 @爱摸鱼的阿恒 对接腾讯混元、@南星泽月 对接百度文心一言
  • 1.4 讯飞开发用户自定义apihost、apikey @H_X
  • 1.3 阿里通义千问 @Vanffer
  • 1.2 支持 ChatGPT、ChatGLM、讯飞星火

二、对接计划

三、需求开发

1. 需求说明

  1. 【简单】工程中有标记 TODO 标签待开发点,此类的功能比如在A模型中实现了,B、C 模型未实现,可以参考代码开发。
  2. 【中等】阅读模型API文档,补全功能。这部分会从会话的调用,一直到执行器包下对应的实现,开发具体实现。
  3. 【复杂】对未实现对接的模型,阅读API文档,添加对接。

以上开发内容,小傅哥会陆续的提交代码,你可以赶在我的前面实现,这样可以很好和我的开发进行对比,学习设计思想和落地实现。

2. 需求提报

📢注意

  1. 开发需求前,先在这里提报。格式为 - [ ] @xxx 开发xxxx功能,预计xxx时间完成。 操作为 fork代码,更新此文档这部分,并提交pr。需求开发完成后[ ] 修改为 [x]
  2. 开发新的模型或者功能对接后,确保单元测试覆盖全面并全部通过在提交代码。另外如果修改了 .env.local 中的配置,一并把配置格式放到 .env 中提交。
  3. 单测目录下有一个 dev-book.md 开发后补充必要的信息,方便后续伙伴验证和使用。此内容后续会收录到对接说明中。
  • @Vanffer 对接阿里-通义千问
  • @H_X @alonewink 对接讯飞星火
  • @爱摸鱼的阿恒 对接腾讯混元
  • @南星泽月 对接百度文心一言
  • @二十五六岁 对接 Google PaLM2
  • @一乡风 对接360智脑
  • @finezhaooo 对接ChatGPT文字转语音,语音转文字,语音翻译git功能,预计4天完成
  • @AZ 对接Gemini Pro
  • @u013446312 对接百度文心一言图像
  • @在发呆的_fy 等待 官网 api 开放,后对接
  • @Geralt001 对接ChatGLM超拟人大模型
  • 开发需求前,先在这里提报。格式为 - [ ] @xxx 开发xxxx功能,预计xxx时间完成。 操作为 fork代码,更新此文档这部分,并提交pr。需求开发完成后[ ] 修改为 [x]

四、安装使用

<dependency>
    <groupId>cn.bugstack</groupId>
    <artifactId>openai-sdk-java</artifactId>
    <version>2.1</version>
</dependency>

1. 单元测试

1.1 阿里通义千问

@Slf4j
public class AliYunTest {

    private OpenAiSession openAiSession;

    @Before
    public void test_OpenAiSessionFactory() throws IOException {
        // 0. 注意;将 resources 包下的 .env修改为 .env.local 并添加各项配置
        Properties prop = new Properties();
        prop.load(ApiTest.class.getClassLoader().getResourceAsStream(".env.local"));

        AliModelConfig aliModelConfig = new AliModelConfig();
        aliModelConfig.setApiHost(prop.getProperty("ali.config.alihost"));
        aliModelConfig.setApiKey(prop.getProperty("ali.config.apikey"));

        // 2. 配置文件
        Configuration configuration = new Configuration();
        configuration.setLevel(HttpLoggingInterceptor.Level.HEADERS);
        configuration.setAliModelConfig(aliModelConfig);

        // 3. 会话工厂
        OpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);
        // 4. 开启会话
        this.openAiSession = factory.openSession();
    }

    /**
     * 文本 & 流式对话;选择不同的模型测试 GPT_3_5_TURBO、GPT_3_5_TURBO_1106、GPT_3_5_TURBO_16K、GPT_4、CHATGLM_TURBO
     */
    @Test
    public void test_completions() throws Exception {
        // 1. 创建参数
        CompletionRequest request = CompletionRequest.builder()
                .stream(true)
                .messages(Collections.singletonList(Message.builder().role(CompletionRequest.Role.USER).content("1+1").build()))
                .model(CompletionRequest.Model.QWEN_TURBO.getCode())
                .build();

        // 2. 请求等待
        CountDownLatch countDownLatch = new CountDownLatch(1);

        // 3. 应答请求
        EventSource eventSource = openAiSession.completions(request, new EventSourceListener() {
            @Override
            public void onEvent(EventSource eventSource, @Nullable String id, @Nullable String type, String data) {
                if ("[DONE]".equalsIgnoreCase(data)) {
                    log.info("OpenAI 应答完成");
                    return;
                }

                CompletionResponse chatCompletionResponse = JSON.parseObject(data, CompletionResponse.class);
                List<ChatChoice> choices = chatCompletionResponse.getChoices();
                for (ChatChoice chatChoice : choices) {
                    Message delta = chatChoice.getDelta();
                    if (CompletionRequest.Role.ASSISTANT.getCode().equals(delta.getRole())) continue;

                    // 应答完成
                    String finishReason = chatChoice.getFinishReason();
                    if (StringUtils.isNoneBlank(finishReason) && "stop".equalsIgnoreCase(finishReason)) {
                        return;
                    }

                    log.info("测试结果:{}", delta.getContent());
                }
            }

            @Override
            public void onClosed(EventSource eventSource) {
                log.info("对话完成");
                countDownLatch.countDown();
            }

            @Override
            public void onFailure(EventSource eventSource, @Nullable Throwable t, @Nullable Response response) {
                log.info("对话异常");
                countDownLatch.countDown();
            }
        });

        countDownLatch.await();
    }

}
👉显示更多

1.2 ChatGLM

@Slf4j
public class ChatGLMTest {

    private OpenAiSession openAiSession;

    @Before
    public void test_OpenAiSessionFactory() throws IOException {
        // 0. 注意;将 resources 包下的 .env修改为 .env.local 并添加各项配置
        Properties prop = new Properties();
        prop.load(ApiTest.class.getClassLoader().getResourceAsStream(".env.local"));

        ChatGLMConfig chatGLMConfig = new ChatGLMConfig();
        chatGLMConfig.setApiHost(prop.getProperty("chatglm.config.apihost"));
        chatGLMConfig.setApiSecretKey(prop.getProperty("chatglm.config.apisecretkey"));

        // 2. 配置文件
        Configuration configuration = new Configuration();
        configuration.setLevel(HttpLoggingInterceptor.Level.HEADERS);
        configuration.setChatGLMConfig(chatGLMConfig);

        // 3. 会话工厂
        OpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);
        // 4. 开启会话
        this.openAiSession = factory.openSession();
    }

    /**
     * 文本 & 流式对话;选择不同的模型测试 GPT_3_5_TURBO、GPT_3_5_TURBO_1106、GPT_3_5_TURBO_16K、GPT_4、CHATGLM_TURBO
     */
    @Test
    public void test_completions() throws Exception {
        // 1. 创建参数
        CompletionRequest request = CompletionRequest.builder()
                .stream(true)
                .messages(Collections.singletonList(Message.builder().role(CompletionRequest.Role.USER).content("1+1").build()))
                .model(CompletionRequest.Model.CHATGLM_TURBO.getCode())
                .build();

        // 2. 请求等待
        CountDownLatch countDownLatch = new CountDownLatch(1);

        // 3. 应答请求
        EventSource eventSource = openAiSession.completions(request, new EventSourceListener() {
            @Override
            public void onEvent(EventSource eventSource, @Nullable String id, @Nullable String type, String data) {
                if ("[DONE]".equalsIgnoreCase(data)) {
                    log.info("OpenAI 应答完成");
                    return;
                }

                CompletionResponse chatCompletionResponse = JSON.parseObject(data, CompletionResponse.class);
                List<ChatChoice> choices = chatCompletionResponse.getChoices();
                for (ChatChoice chatChoice : choices) {
                    Message delta = chatChoice.getDelta();
                    if (CompletionRequest.Role.ASSISTANT.getCode().equals(delta.getRole())) continue;

                    // 应答完成
                    String finishReason = chatChoice.getFinishReason();
                    if (StringUtils.isNoneBlank(finishReason) && "stop".equalsIgnoreCase(finishReason)) {
                        return;
                    }

                    log.info("测试结果:{}", delta.getContent());
                }
            }

            @Override
            public void onClosed(EventSource eventSource) {
                log.info("对话完成");
                countDownLatch.countDown();
            }

            @Override
            public void onFailure(EventSource eventSource, @Nullable Throwable t, @Nullable Response response) {
                log.info("对话异常");
                countDownLatch.countDown();
            }
        });

        countDownLatch.await();
    }
    
}

1.3 ChatGPT

@Slf4j
public class ChatGPTTest {

    private OpenAiSession openAiSession;

    @Before
    public void test_OpenAiSessionFactory() throws IOException {
        // 0. 注意;将 resources 包下的 .env修改为 .env.local 并添加各项配置
        Properties prop = new Properties();
        prop.load(ApiTest.class.getClassLoader().getResourceAsStream(".env.local"));

        ChatGPTConfig chatGPTConfig = new ChatGPTConfig();
        chatGPTConfig.setApiHost(prop.getProperty("chatgpt.config.apihost"));
        chatGPTConfig.setApiKey(prop.getProperty("chatgpt.config.apikey"));

        // 2. 配置文件
        Configuration configuration = new Configuration();
        configuration.setLevel(HttpLoggingInterceptor.Level.HEADERS);
        configuration.setChatGPTConfig(chatGPTConfig);

        // 3. 会话工厂
        OpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);
        // 4. 开启会话
        this.openAiSession = factory.openSession();
    }

    /**
     * 文本 & 流式对话;选择不同的模型测试 GPT_3_5_TURBO、GPT_3_5_TURBO_1106、GPT_3_5_TURBO_16K、GPT_4、CHATGLM_TURBO
     */
    @Test
    public void test_completions() throws Exception {
        // 1. 创建参数
        CompletionRequest request = CompletionRequest.builder()
                .stream(true)
                .messages(Collections.singletonList(Message.builder().role(CompletionRequest.Role.USER).content("1+1").build()))
                .model(CompletionRequest.Model.GPT_3_5_TURBO_1106.getCode())
                .build();

        // 2. 请求等待
        CountDownLatch countDownLatch = new CountDownLatch(1);

        // 3. 应答请求
        EventSource eventSource = openAiSession.completions(request, new EventSourceListener() {
            @Override
            public void onEvent(EventSource eventSource, @Nullable String id, @Nullable String type, String data) {
                if ("[DONE]".equalsIgnoreCase(data)) {
                    log.info("OpenAI 应答完成");
                    return;
                }

                CompletionResponse chatCompletionResponse = JSON.parseObject(data, CompletionResponse.class);
                List<ChatChoice> choices = chatCompletionResponse.getChoices();
                for (ChatChoice chatChoice : choices) {
                    Message delta = chatChoice.getDelta();
                    if (CompletionRequest.Role.ASSISTANT.getCode().equals(delta.getRole())) continue;

                    // 应答完成
                    String finishReason = chatChoice.getFinishReason();
                    if (StringUtils.isNoneBlank(finishReason) && "stop".equalsIgnoreCase(finishReason)) {
                        return;
                    }

                    log.info("测试结果:{}", delta.getContent());
                }
            }

            @Override
            public void onClosed(EventSource eventSource) {
                log.info("对话完成");
                countDownLatch.countDown();
            }

            @Override
            public void onFailure(EventSource eventSource, @Nullable Throwable t, @Nullable Response response) {
                log.info("对话异常");
                countDownLatch.countDown();
            }
        });

        countDownLatch.await();
    }
    
}

1.4 讯飞星火

@Slf4j
public class XunFeiTest {

    private OpenAiSession openAiSession;

    @Before
    public void test_OpenAiSessionFactory() throws IOException {
        // 0. 注意;将 resources 包下的 .env修改为 .env.local 并添加各项配置
        Properties prop = new Properties();
        prop.load(ApiTest.class.getClassLoader().getResourceAsStream(".env.local"));

        XunFeiConfig xunFeiConfig = new XunFeiConfig();
        xunFeiConfig.setApiHost(prop.getProperty("xunfei.config.apihost"));
        xunFeiConfig.setAppid(prop.getProperty("xunfei.config.apiappid"));
        xunFeiConfig.setApiKey(prop.getProperty("xunfei.config.apiapikey"));
        xunFeiConfig.setApiSecret(prop.getProperty("xunfei.config.apiapisecret"));

        // 2. 配置文件
        Configuration configuration = new Configuration();
        configuration.setLevel(HttpLoggingInterceptor.Level.HEADERS);
        configuration.setXunFeiConfig(xunFeiConfig);

        // 3. 会话工厂
        OpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);
        // 4. 开启会话
        this.openAiSession = factory.openSession();
    }

    /**
     * 文本 & 流式对话;选择不同的模型测试 GPT_3_5_TURBO、GPT_3_5_TURBO_1106、GPT_3_5_TURBO_16K、GPT_4、CHATGLM_TURBO
     */
    @Test
    public void test_completions() throws Exception {
        // 1. 创建参数
        CompletionRequest request = CompletionRequest.builder()
                .stream(true)
                .messages(Collections.singletonList(Message.builder().role(CompletionRequest.Role.USER).content("1+1").build()))
                .model(CompletionRequest.Model.XUNFEI.getCode())
                .build();

        // 2. 请求等待
        CountDownLatch countDownLatch = new CountDownLatch(1);

        // 3. 应答请求
        EventSource eventSource = openAiSession.completions(request, new EventSourceListener() {
            @Override
            public void onEvent(EventSource eventSource, @Nullable String id, @Nullable String type, String data) {
                if ("[DONE]".equalsIgnoreCase(data)) {
                    log.info("OpenAI 应答完成");
                    return;
                }

                CompletionResponse chatCompletionResponse = JSON.parseObject(data, CompletionResponse.class);
                List<ChatChoice> choices = chatCompletionResponse.getChoices();
                for (ChatChoice chatChoice : choices) {
                    Message delta = chatChoice.getDelta();
                    if (CompletionRequest.Role.ASSISTANT.getCode().equals(delta.getRole())) continue;

                    // 应答完成
                    String finishReason = chatChoice.getFinishReason();
                    if (StringUtils.isNoneBlank(finishReason) && "stop".equalsIgnoreCase(finishReason)) {
                        return;
                    }

                    log.info("测试结果:{}", delta.getContent());
                }
            }

            @Override
            public void onClosed(EventSource eventSource) {
                log.info("对话完成");
                countDownLatch.countDown();
            }

            @Override
            public void onFailure(EventSource eventSource, @Nullable Throwable t, @Nullable Response response) {
                log.info("对话异常");
                countDownLatch.countDown();
            }
        });

        countDownLatch.await();
    }
    
}

2. 应用接入

3. 程序接入

yml 配置

# OpenAi 配置;ChatGPT、ChatGLM...
openai:
  sdk:
    config:
      chatglm:
         # 状态;true = 开启、false 关闭
         enabled: false
         # 官网地址 
         api-host: https://open.bigmodel.cn/
         # 官网申请 https://open.bigmodel.cn/usercenter/apikeys
         api-secret-key: 4e087e4135306ef4a676f0cce3cee560.sgP2DUs*****

SpringBoot 配置类

@Configuration
@EnableConfigurationProperties(OpenAISDKConfigProperties.class)
public class OpenAISDKConfig {

    @Bean
    @ConditionalOnProperty(value = "openai.sdk.config.enabled", havingValue = "true", matchIfMissing = false)
    public OpenAiSession openAiSession(OpenAISDKConfigProperties properties) {
        // 1. 配置文件
        Configuration configuration = new Configuration();
        // 添加配置

        // 2. 会话工厂
        OpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);

        // 3. 开启会话
        return factory.openSession();
    }

}

@Data
@ConfigurationProperties(prefix = "openai.sdk.config", ignoreInvalidFields = true)
public class ChatGLMSDKConfigProperties {

    /** 添加 ChatGPT、ChatGLM 等 */
    private ChatGPTConfig chatGPTConfig;
    
    private ChatGLMConfig chatGLMConfig;
    
}
@Autowired(required = false)
private OpenAiSession openAiSession;

五、开发规范

  1. 打开地址 openai-sdk-java Fork 代码到自己的仓库
  2. 熟悉工程模型和代码,并调试运行理解整个框架的设计实现。之后开始承接需求并提交代码到自己的仓库。对于自己已经完成运行的调试的代码,可以提交 PR 代码。小傅哥在评审后,会合并你的提交。这样你就成为一个贡献者了,并记录在文档。
  3. 修改 .env 为 .env.local 并配置相关的信息,就可以在 ApiTest 中调试了。
# 主要type
feat:     增加新功能
fix:      修复bug

# 特殊type
docs:     只改动了文档相关的内容
style:    不影响代码含义的改动,例如去掉空格、改变缩进、增删分号
build:    构造工具的或者外部依赖的改动,例如webpacknpm
refactor: 代码重构时使用
revert:   执行git revert打印的message

# 暂不使用type
test:     添加测试或者修改现有测试
perf:     提高性能的改动
ci:       与CI(持续集成服务)有关的改动
chore:    不修改src或者test的其余修改,例如构建过程或辅助工具的变动

六、其他资料

About

星球开源共建项目 《OpenAI SDK》 统一大模型标准化对接的技术组件项目,此项目以解决实际市面上的场景为诉求,将 OpenAI、Claude、PalM、文心一言、通义千问、讯飞星火、智谱 ChatGLM、腾讯混元等这些大模型做一个统一的 SDK 对接组件。

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published