Give visual and reasoning models their own first-chunk timeouts

Vision and reasoning requests reused the chat model's 10s first-chunk
timeout, but both legitimately need longer before the first chunk:
vision must download the image server-side first, and reasoning has a
thinking warmup. Logs showed frequent TimeoutCancellationException at
10s/15s for imageRecognition and reasoning.

Add separate visualFirstChunkTimeout (120s) and reasoningFirstChunkTimeout
(90s) config, and raise each service's socket timeout to at least its
first-chunk budget so the socket layer doesn't sever the connection
before the first-chunk timeout can apply. Chat endpoints are unchanged.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
2026-06-26 14:06:00 +08:00
co-authored by Claude Opus 4.8
parent 826dc460df
commit bc61e99013
2 changed files with 16 additions and 4 deletions
+10 -4
View File
@@ -146,22 +146,28 @@ object LargeLanguageModels {
// 初始化推理模型
if (PluginConfig.reasoningModelApi.isNotBlank() && PluginConfig.reasoningModelToken.isNotBlank()) {
// 推理模型出首块前常有思考预热,比对话慢,使用单独放宽的首块超时;
// socket 超时(两次读间隔,等首块时也归它管)不能小于首块预算,否则首块超时形同虚设
val reasoningFirstChunk = PluginConfig.reasoningFirstChunkTimeout.milliseconds
reasoning = ModelService(
baseUrl = PluginConfig.reasoningModelApi,
token = PluginConfig.reasoningModelToken,
timeout = timeout,
firstChunkTimeout = firstChunkTimeout,
timeout = maxOf(timeout, reasoningFirstChunk),
firstChunkTimeout = reasoningFirstChunk,
extraBody = parseExtraBody(PluginConfig.reasoningModelExtraBody)
)
}
// 初始化视觉模型
if (PluginConfig.visualModelApi.isNotBlank() && PluginConfig.visualModelToken.isNotBlank()) {
// 视觉模型需服务端先下载图片再出首块,比对话天然慢,使用单独放宽的首块超时;
// socket 超时(两次读间隔,等首块时也归它管)不能小于首块预算,否则首块超时形同虚设
val visualFirstChunk = PluginConfig.visualFirstChunkTimeout.milliseconds
visual = ModelService(
baseUrl = PluginConfig.visualModelApi,
token = PluginConfig.visualModelToken,
timeout = timeout,
firstChunkTimeout = firstChunkTimeout,
timeout = maxOf(timeout, visualFirstChunk),
firstChunkTimeout = visualFirstChunk,
extraBody = parseExtraBody(PluginConfig.visualModelExtraBody)
)
}
+6
View File
@@ -105,6 +105,12 @@ object PluginConfig : AutoSavePluginConfig("Config") {
@ValueDescription("首块响应超时时间,单位毫秒,默认10秒。若连接建立后在此时间内没收到首块data:则中断走重试")
val firstChunkTimeout: Long by value(10000L)
@ValueDescription("视觉模型首块响应超时时间,单位毫秒,默认120秒。视觉模型需先下载图片再出首块,比对话天然慢,故单独放宽")
val visualFirstChunkTimeout: Long by value(120000L)
@ValueDescription("推理模型首块响应超时时间,单位毫秒,默认90秒。推理模型出首块前常有思考预热,比对话慢,故单独放宽")
val reasoningFirstChunkTimeout: Long by value(90000L)
@Deprecated("使用外部文件而不是在配置文件内保存提示词")
@ValueDescription("系统提示词,该字段已弃用,使用提示词文件而不是在这里修改")
var prompt: String by value("你是一个乐于助人的助手")