AIGC大模型从入门到放弃之路
第一章 使用Android完成KIMI API简单使用
第二章 使用Android完成KIMI API流式输出
第三章 Android使用KIMI API模拟小说网络作家写大纲
第四章 Android上使用阿里的通义万相大模型完成小说的封面图片制作
前言
前面第一章主要介绍了怎么申请Kimi的API Key和怎么通过API调用。
这一章主要介绍怎么使用Kimi的流式输出。流式相对与非流式来说,用户体验会更好一点。当用户输入一个问题或者一个对话时,机器人一个一个字生成回答,有一种拟人化。同时如果机器人需要回到的内容比较大时,一次性输出需要等待的时间非比较长,用户体验就比较差了。
一、流式是什么?
在计算机编程和API(应用程序编程接口)的上下文中,“流式”(Streaming)通常指的是一种数据传输方式,其中数据被分成小块连续地发送和接收,而不是一次性发送或接收整个数据集。这种技术在处理大量数据或实时数据传输时非常有用。
对于KIMI API或任何其他API来说,如果提供"流式输出"的选项,这意味着API可以:
- 实时数据传输:API可以立即开始发送数据,而不是等待所有数据都准备好后再发送。
- 节省内存:对于客户端,不必一次性加载全部数据,从而节省内存资源。
- 处理大数据:允许客户端逐步处理数据,而不是一次性处理大量数据,这在处理大数据集时尤其有用。
- 连续更新:适用于需要连续更新数据的应用场景,如实时监控、社交媒体动态流等。
选择流式返回可以提高应用性能和用户体验,特别是在网络延迟较高或数据集较大的情况下。然而,流式处理也要求客户端能够处理这种连续的数据流,并且可能需要额外的逻辑来正确地解析和使用数据。
二、使用步骤
1.引入okhttp库
相对于使用Java的HttpURLConnection,okhttp使用起来更加方便,所以我这里把HttpURLConnection换成了okhttp。
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
2.新建对应的请求数据类和响应数据类
详见官方的demo:https://github.com/MoonshotAI/MoonshotAI-Cookbook/tree/master
因为我这里使用的是kotlin,代码可能跟官方有点区别,但大体上是一致的。
ChatCompletionChoice
package com.ckt.kimi.demo.bean
import com.google.gson.annotations.SerializedName
data class ChatCompletionChoice(val index: Int,
val message:ChatCompletionMessage,
@SerializedName("finish_reason")
val finishReason: String)
ChatCompletionMessage
package com.ckt.kimi.demo.bean
data class ChatCompletionMessage(
val role: String,
val content: String,
var name: String? = null,
var partial: Boolean = false
)
ChatCompletionRequest
package com.ckt.kimi.demo.bean
import com.google.gson.annotations.SerializedName
data class ChatCompletionRequest(val model: String,
/**
* 包含迄今为止对话的消息列表
*/
val messages: MutableList<ChatCompletionMessage>,
/**
* 这个值建议按需给个合理的值,如果不给的话,我们会给一个不错的整数比如 1024。
* 特别要注意的是,这个 max_tokens 是指您期待我们返回的 token 长度,
* 而不是输入 + 输出的总长度。比如对一个 moonshot-v1-8k 模型,它的最大输入 + 输出总长度是 8192,
* 当输入 messages 总长度为 4096 的时候,您最多只能设置为 4096,
* 否则我们服务会返回不合法的输入参数( invalid_request_error ),并拒绝回答。
* 如果您希望获得“输入的精确 token 数”,可以使用下面的“计算 Token” API 使用我们的计算器获得计数
*/
@SerializedName("max_tokens")
val maxTokens: Int,
/**
* 使用什么采样温度,介于 0 和 1 之间。较高的值(如 0.7)将使输出更加随机,
* 而较低的值(如 0.2)将使其更加集中和确定性
*/
@SerializedName("temperature")
val temperature: Float,
/**
* 另一种采样方法,即模型考虑概率质量为 top_p 的标记的结果。因此,
* 0.1 意味着只考虑概率质量最高的 10% 的标记。
* 一般情况下,我们建议改变这一点或温度,但不建议 同时改变
*/
val topP: Float,
/**
* 为每条输入消息生成多少个结果,默认为 1,不得大于 5。
* 特别的,当 temperature 非常小靠近 0 的时候,我们只能返回 1 个结果,
* 如果这个时候 n 已经设置并且 > 1,我们的服务会返回不合法的输入参数(invalid_request_error)
*/
val n: Int = 1,
/**
* 是否流式返回.
* 默认 false, 可选 true
*/
var stream: Boolean = false,
var top: MutableList<String>? = null,
/**
* 存在惩罚,介于-2.0到2.0之间的数字。
* 正值会根据新生成的词汇是否出现在文本中来进行惩罚,增加模型讨论新话题的可能性
* 默认为 0
*/
@SerializedName("presence_penalty")
var presencePenalty: Float = 0F,
/**
* 频率惩罚,介于-2.0到2.0之间的数字。
* 正值会根据新生成的词汇在文本中现有的频率来进行惩罚,减少模型一字不差重复同样话语的可能性
* 默认为 0
*/
@SerializedName("frequency_penalty")
var frequencyPenalty: Float = 0F,
var user: String?= null)
ChatCompletionResponse
package com.ckt.kimi.demo.bean
import com.google.gson.annotations.SerializedName
data class ChatCompletionResponse(val id: String,
@SerializedName("object")
val obj: String,
val created: Long,
val model: String,
val choices: MutableList<ChatCompletionChoice>,
val usage: Usage)
ChatCompletionStreamChoice
package com.ckt.kimi.demo.bean
import com.google.gson.annotations.SerializedName
data class ChatCompletionStreamChoice(val index: Int,
val delta:ChatCompletionStreamChoiceDelta,
@SerializedName("finish_reason")
val finishReason: String,
val usage: Usage)
ChatCompletionStreamChoiceDelta
package com.ckt.kimi.demo.bean
data class ChatCompletionStreamChoiceDelta(val content:String,
val role: String)
ChatCompletionStreamResponse
package com.ckt.kimi.demo.bean
import com.google.gson.annotations.SerializedName
data class ChatCompletionStreamResponse(val id: String,
@SerializedName("object")
val obj: String,
val created: Long,
val model: String,
val choices:MutableList<ChatCompletionStreamChoice>)
ChatMessageRole
package com.ckt.kimi.demo.bean
enum class ChatMessageRole(val value: String) {
SYSTEM("system"),
USER("user"),
ASSISTANT("assistant");
}
Model
package com.ckt.kimi.demo.bean
import com.google.gson.annotations.SerializedName
/**
* 目前是 moonshot-v1-8k,moonshot-v1-32k,moonshot-v1-128k 其一
*/
data class Model(val id: String,
@SerializedName("object")
val obj: String,
@SerializedName("owner_by")
val ownedBy: String,
val root: String,
val parent: String)
ModelsList
package com.ckt.kimi.demo.bean
data class ModelsList(val data: MutableList<Model>)
Usage
package com.ckt.kimi.demo.bean
data class Usage(val promptTokens: Int,
val completionTokens: Int,
val totalTokens: Int)
3.完成流式请求
将参数stream设置为true即可,默认值为false
@JvmStatic
@Throws(IOException::class)
fun doChatCompletionStream(request: ChatCompletionRequest, streamCallback: OnStreamCallback) {
request.stream = true
val client = OkHttpClient()
val mediaType: MediaType? = "application/json".toMediaTypeOrNull()
val body = RequestBody.create(mediaType, Gson().toJson(request))
val httpRequest: Request = Request.Builder()
.url(getChatCompletionUrl())
.addHeader("Authorization", "Bearer " + getApiKey())
.addHeader("Content-Type", "application/json")
.post(body)
.build()
val response = client.newCall(httpRequest).execute()
if (response.code != 200) {
throw RuntimeException ("Failed to start stream: " + response.body?.string())
}
val responseBody = response.body ?: throw RuntimeException("Response body is null")
var line: String
streamCallback.onStart()
while (responseBody.source().readUtf8Line().also { line = it!! } != null) {
Log.d(MainActivity.TAG, "read Line : ${line}")
if (line.startsWith("data:")) {
line = line.substring(5)
line = line.trim { it <= ' ' }
}
if (Objects.equals(line, "[DONE]")) {
streamCallback.onComplete()
return
}
line = line.trim { it <= ' ' }
if (line.isEmpty()) {
continue
}
val gson = Gson()
val streamResponse = gson.fromJson(
line,
ChatCompletionStreamResponse::class.java
)
streamCallback.onNext(streamResponse)
}
}
4. 效果展示
功能展示详见下图:
总结
功能还是挺简单,主要就是通过Kimi的api接口根据回调依次显示即可。
代码如果有需要参考的,我也上传了,仅供参考:https://download.csdn.net/download/alishaoxiong/89517864