【開源】給ChatGLM寫個,Java對接的SDK

作者:小傅哥 - 百度搜 小傅哥bugstack

博客:bugstack.cn

沉澱、分享、成長,讓自己和他人都能有所收穫!😄

大家好,我是技術UP主小傅哥。

清華大學計算機系的超大規模訓練模型 ChatGLM-130B 使用效果非常牛,所以我也想把這樣的Ai能力接入到自己的應用中或者做一些 IntelliJ IDEA Plugin 使用。但經過了一晚上的折騰,我決定給它寫個對接的SDK開源出來!—— 🤔 智譜Ai不是已經有了一個SDK嗎?爲啥還要寫呢?那你寫多少了?

在很早之前就關注了智譜Ai(ChatGLM),也看到官網有一個Java對接的SDK方式。但從前幾天開始正式對接發現,這SDK是8月份提交的,10個commit,而且已經2個月沒有更新了。所以真的是不少Bug呀,呀,呀!如果不去修改它的SDK代碼,就沒法對接。如;ConfigV3類中,拆分ApiKey的操作;String[] arrStr = apiSecretKey.split("."); 但這裏的.是正則的關鍵字,所以根本沒法拆分。一起動就報錯 invalid apiSecretKey 這對於初次對接並且沒有看源碼的夥伴來說,是不小的炸雷。

不過,雖然 SDK 有點趕工,不好用。但不影響智譜Ai(ChatGLM)是個好東西。他的官網中有API HTTP 接口對接描述。所以,小傅哥決定跟着按照它的文檔寫一個能簡單對接,代碼有乾淨整潔的 SDK 讓大家使用。

那麼,接下來小傅哥就介紹下,如何基於智譜Ai(ChatGLM)的開發者文檔,開發一個通用的SDK組件。也讓後續有想法PR貢獻源碼的夥伴,一起參與進來。—— 別看東西不大,寫到簡歷上,也是非常精彩的一筆!

本文不止有智譜Ai-SDK開發,還有如何在項目中運用SDK開發一個自己的OpenAi服務。文末有SDK鏈接和OpenAi應用工程。

一、對接鑑權

智譜Ai的Api文檔,與ChatGPT對接有一些差

如果大家對接過ChatGPT開發,直接獲取一個ApiKey就可以使用了。但在對接智譜Ai的Api時,需要把獲取的ApiKey按照.號分割,並需要進行JWT-Token的創建。而這個Token纔是實際傳給接口的內容。

  • 因爲生成Token會比較耗時,所以這裏會使用Guava框架進行本地緩存29分鐘,有效期30分鐘的Token,確保可以有效的刷新。
  • 在工程中提供了 BearerTokenUtils Token 生成工具類,測試的時候可以使用。

二、接口處理

文檔https://open.bigmodel.cn/dev/api#chatglm_lite - 以Api文檔的chatglm_lite模型舉例對接

傳輸方式 https
請求地址 https://open.bigmodel.cn/api/paas/v3/model-api/chatglm_lite/sse-invoke
調用方式 SSE
字符編碼 UTF-8
接口請求頭 accept: text/event-stream
接口請求格式 JSON
響應格式 標準 Event Stream
接口請求類型 POST
開發語言 任意可發起 HTTP 請求的開發語言

在正式開發代碼,要把接口的使用先簡單測試運行出來。之後再去編寫代碼。爲此這裏小傅哥先根據官網的文檔和鑑權使用方式,編寫了 curl http 請求;

curl -X POST \
        -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsInNpZ25fdHlwZSI6IlNJR04ifQ.eyJhcGlfa2V5IjoiNGUwODdlNDEzNTMwNmVmNGE2NzZmMGNjZTNjZWU1NjAiLCJleHAiOjE2OTY5OTM5ODIzMTQsInRpbWVzdGFtcCI6MTY5Njk5MjE4MjMxNH0.9nxhRXTJcP4Q_YTQ8w5y0CZOBOu0epP1J56oDaYewQ8" \
        -H "Content-Type: application/json" \
        -H "User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)" \
        -H "Accept: text/event-stream" \
        -d '{
        "top_p": 0.7,
        "sseFormat": "data",
        "temperature": 0.9,
        "incremental": true,
        "request_id": "xfg-1696992276607",
        "prompt": [
        {
        "role": "user",
        "content": "寫個java冒泡排序"
        }
        ]
        }' \
  http://open.bigmodel.cn/api/paas/v3/model-api/chatglm_lite/sse-invoke
  • 注意:Authorization: Bearer 後面傳的是 JWT Token 不是一個直接從官網複製的 ApiKey - 你可以使用工程中 BearerTokenUtils 創建
  • 之後可以直接運行這段腳本(也可以導入到ApiPost工具中),執行後就能獲得到運行效果了。—— 速度非常快!

三、組件開發

在🤔考慮到抽象和設計原則下,小傅哥這裏採用了會話模型結構進行工程框架設計。把程序的調用抽象爲一次會話,而會話的創建則交給工廠🏭。通過工廠屏蔽使用細節,在使用上簡化調用,儘可能讓外部最少知道原則。這樣的設計實現方式,既可以滿足調用方開心的使用,也可以讓SDK貢獻者見代碼如見文檔,容易理解和上手。

1. 工程結構

  • 工程非常注重會話的設計和使用,因爲框架的根基搭建好以後,擴展各項功能就會有跡可循。大部分代碼就是因爲早期沒有考慮好框架,最後功能來了被填充的很亂。

2. 會話流程

  • 會話流程以工廠創建 Session 爲入口點進行使用,其他的操作都在組件內自己處理好。

3. 代碼舉例

@Override
public OpenAiSession openSession() {
    // 1. 日誌配置
    HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
    httpLoggingInterceptor.setLevel(configuration.getLevel());
    
    // 2. 開啓 Http 客戶端
    OkHttpClient okHttpClient = new OkHttpClient
            .Builder()
            .addInterceptor(httpLoggingInterceptor)
            .addInterceptor(new OpenAiHTTPInterceptor(configuration))
            .connectTimeout(configuration.getConnectTimeout(), TimeUnit.SECONDS)
            .writeTimeout(configuration.getWriteTimeout(), TimeUnit.SECONDS)
            .readTimeout(configuration.getReadTimeout(), TimeUnit.SECONDS)
            .build();
    configuration.setOkHttpClient(okHttpClient);
    
    // 3. 創建 API 服務
    IOpenAiApi openAiApi = new Retrofit.Builder()
            .baseUrl(configuration.getApiHost())
            .client(okHttpClient)
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(JacksonConverterFactory.create())
            .build().create(IOpenAiApi.class);
    configuration.setOpenAiApi(openAiApi);
    return new DefaultOpenAiSession(configuration);
}
  • 這是一段 DefaultOpenAiSessionFactory 創建工廠開啓會話的服務對象。使用方只需要在自己的工程中,創建出一個工廠對象就可以對接使用了。下文有代碼示例
  • 其他更多的代碼,直接看小傅哥開發好的 chatglm-sdk-java

四、組件使用

1. 組件配置

  • 申請ApiKey:https://open.bigmodel.cn/usercenter/apikeys - 註冊申請開通,即可獲得 ApiKey
  • 運行環境:JDK 1.8+
  • maven pom - 暫時測試階段,未推送到Maven中央倉庫,需要下載代碼本地 install 後使用
<dependency>
    <groupId>cn.bugstack</groupId>
    <artifactId>chatglm-sdk-java</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

2. 單元測試

@Slf4j
public class ApiTest {

    private OpenAiSession openAiSession;

    @Before
    public void test_OpenAiSessionFactory() {
        // 1. 配置文件
        Configuration configuration = new Configuration();
        configuration.setApiHost("https://open.bigmodel.cn/");
        configuration.setApiSecretKey("4e087e4135306ef4a676f0cce3cee560.sgP2*****");
        // 2. 會話工廠
        OpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);
        // 3. 開啓會話
        this.openAiSession = factory.openSession();
    }

    /**
     * 流式對話
     */
    @Test
    public void test_completions() throws JsonProcessingException, InterruptedException {
        // 入參;模型、請求信息
        ChatCompletionRequest request = new ChatCompletionRequest();
        request.setModel(Model.CHATGLM_LITE); // chatGLM_6b_SSE、chatglm_lite、chatglm_lite_32k、chatglm_std、chatglm_pro
        request.setPrompt(new ArrayList<ChatCompletionRequest.Prompt>() {
            private static final long serialVersionUID = -7988151926241837899L;

            {
                add(ChatCompletionRequest.Prompt.builder()
                        .role(Role.user.getCode())
                        .content("寫個java冒泡排序")
                        .build());
            }
        });

        // 請求
        openAiSession.completions(request, new EventSourceListener() {
            @Override
            public void onEvent(EventSource eventSource, @Nullable String id, @Nullable String type, String data) {
                ChatCompletionResponse response = JSON.parseObject(data, ChatCompletionResponse.class);
                log.info("測試結果 onEvent:{}", response.getData());
                // type 消息類型,add 增量,finish 結束,error 錯誤,interrupted 中斷
                if (EventType.finish.getCode().equals(type)) {
                    ChatCompletionResponse.Meta meta = JSON.parseObject(response.getMeta(), ChatCompletionResponse.Meta.class);
                    log.info("[輸出結束] Tokens {}", JSON.toJSONString(meta));
                }
            }

            @Override
            public void onClosed(EventSource eventSource) {
                log.info("對話完成");
            }
        });

        // 等待
        new CountDownLatch(1).await();
    }

}
  • 這是一個單元測試類,也是最常使用的流式對話模式。

五、應用接入

1. SpringBoot 配置類

@Configuration
@EnableConfigurationProperties(ChatGLMSDKConfigProperties.class)
public class ChatGLMSDKConfig {

    @Bean
    @ConditionalOnProperty(value = "wxpay.config.enabled", havingValue = "true", matchIfMissing = false)
    public OpenAiSession openAiSession(ChatGLMSDKConfigProperties properties) {
        // 1. 配置文件
        cn.bugstack.chatglm.session.Configuration configuration = new cn.bugstack.chatglm.session.Configuration();
        configuration.setApiHost(properties.getApiHost());
        configuration.setApiSecretKey(properties.getApiSecretKey());

        // 2. 會話工廠
        OpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);

        // 3. 開啓會話
        return factory.openSession();
    }

}

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

    /** 狀態;open = 開啓、close 關閉 */
    private boolean enable;
    /** 轉發地址 */
    private String apiHost;
    /** 可以申請 sk-*** */
    private String apiSecretKey;

}
@Autowired(required = false)
private OpenAiSession openAiSession;
  • 注意:如果你在服務中配置了關閉啓動 ChatGLM SDK 那麼注入 openAiSession 爲 null

2. yml 配置

# ChatGLM SDK Config
chatglm:
  sdk:
    config:
      # 狀態;true = 開啓、false 關閉
      enabled: false
      # 官網地址 
      api-host: https://open.bigmodel.cn/
      # 官網申請 https://open.bigmodel.cn/usercenter/apikeys
      api-key: 4e087e4135306ef4a676f0cce3cee560.sgP2DUs*****
  • 你可以在配置文件中,通過 enabled 參數,啓動和關閉 ChatGLM SDK

六、應用開發

基於本文開發的 ChatGLM SDK 就可以對接到 OpenAi 開發一個自己的應用了。https://bugstack.cn/md/project/chatgpt/chatgpt.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章