mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-28 05:11:24 +08:00
refactor: update reasoning plugins and enhance performance
- Replaced `smoothReasoningPlugin` with `reasoningTimePlugin` to improve reasoning time tracking. - Commented out the unused `textPlugin` in the plugin list for better clarity. - Adjusted delay settings in both `smoothReasoningPlugin` and `textPlugin` for optimized processing. - Enhanced logging in reasoning plugins for better debugging and performance insights.
This commit is contained in:
parent
cf5ed8e858
commit
182ab6092c
@ -28,8 +28,7 @@ import AiSdkToChunkAdapter from './AiSdkToChunkAdapter'
|
||||
import LegacyAiProvider from './index'
|
||||
import { AiSdkMiddlewareConfig, buildAiSdkMiddlewares } from './middleware/aisdk/AiSdkMiddlewareBuilder'
|
||||
import { CompletionsResult } from './middleware/schemas'
|
||||
import smoothReasoningPlugin from './plugins/smoothReasoningPlugin'
|
||||
import textPlugin from './plugins/textPlugin'
|
||||
import reasoningTimePlugin from './plugins/reasoningTimePlugin'
|
||||
import { getAiSdkProviderId } from './provider/factory'
|
||||
|
||||
/**
|
||||
@ -119,11 +118,11 @@ export default class ModernAiProvider {
|
||||
private buildPlugins(middlewareConfig: AiSdkMiddlewareConfig) {
|
||||
const plugins: AiPlugin[] = []
|
||||
// 1. 总是添加通用插件
|
||||
plugins.push(textPlugin)
|
||||
// plugins.push(textPlugin)
|
||||
|
||||
// 2. 推理模型时添加推理插件
|
||||
if (middlewareConfig.enableReasoning) {
|
||||
plugins.push(smoothReasoningPlugin)
|
||||
plugins.push(reasoningTimePlugin)
|
||||
}
|
||||
|
||||
// 3. 启用Prompt工具调用时添加工具插件
|
||||
@ -151,7 +150,6 @@ export default class ModernAiProvider {
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
console.log(
|
||||
'最终插件列表:',
|
||||
plugins.map((p) => p.name)
|
||||
|
||||
67
src/renderer/src/aiCore/plugins/reasoningTimePlugin.ts
Normal file
67
src/renderer/src/aiCore/plugins/reasoningTimePlugin.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { definePlugin } from '@cherrystudio/ai-core'
|
||||
|
||||
export default definePlugin({
|
||||
name: 'reasoningTimePlugin',
|
||||
|
||||
transformStream: () => () => {
|
||||
// === 时间跟踪状态 ===
|
||||
let thinkingStartTime = 0
|
||||
let hasStartedThinking = false
|
||||
let accumulatedThinkingContent = ''
|
||||
|
||||
return new TransformStream({
|
||||
transform(chunk, controller) {
|
||||
if (chunk.type !== 'reasoning') {
|
||||
// === 处理 reasoning 结束 ===
|
||||
if (hasStartedThinking) {
|
||||
console.log(`[ReasoningPlugin] Ending reasoning.`)
|
||||
|
||||
// 生成 reasoning-signature
|
||||
controller.enqueue({
|
||||
type: 'reasoning-signature',
|
||||
text: accumulatedThinkingContent,
|
||||
thinking_millsec: performance.now() - thinkingStartTime
|
||||
})
|
||||
|
||||
// 重置状态
|
||||
accumulatedThinkingContent = ''
|
||||
hasStartedThinking = false
|
||||
thinkingStartTime = 0
|
||||
}
|
||||
|
||||
controller.enqueue(chunk)
|
||||
return
|
||||
}
|
||||
|
||||
// === 处理 reasoning 类型 ===
|
||||
|
||||
// 1. 时间跟踪逻辑
|
||||
if (!hasStartedThinking) {
|
||||
hasStartedThinking = true
|
||||
thinkingStartTime = performance.now()
|
||||
console.log(`[ReasoningPlugin] Starting reasoning session`)
|
||||
}
|
||||
accumulatedThinkingContent += chunk.textDelta
|
||||
|
||||
// 2. 直接透传 chunk,并附加上时间
|
||||
console.log(`[ReasoningPlugin] Forwarding reasoning chunk: "${chunk.textDelta}"`)
|
||||
controller.enqueue({
|
||||
...chunk,
|
||||
thinking_millsec: performance.now() - thinkingStartTime
|
||||
})
|
||||
},
|
||||
|
||||
// === flush 处理流结束时仍在reasoning状态的场景 ===
|
||||
flush(controller) {
|
||||
if (hasStartedThinking) {
|
||||
console.log(`[ReasoningPlugin] Final flush for reasoning-signature.`)
|
||||
controller.enqueue({
|
||||
type: 'reasoning-signature',
|
||||
text: accumulatedThinkingContent,
|
||||
thinking_millsec: performance.now() - thinkingStartTime
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@ -1,7 +1,9 @@
|
||||
// 可能会废弃,在流上做delay还是有问题
|
||||
|
||||
import { definePlugin } from '@cherrystudio/ai-core'
|
||||
|
||||
const chunkingRegex = /([\u4E00-\u9FFF])|\S+\s+/
|
||||
const delayInMs = 20
|
||||
const delayInMs = 50
|
||||
|
||||
export default definePlugin({
|
||||
name: 'reasoningPlugin',
|
||||
@ -15,12 +17,32 @@ export default definePlugin({
|
||||
let hasStartedThinking = false
|
||||
let accumulatedThinkingContent = ''
|
||||
|
||||
// === 日志计数器 ===
|
||||
let chunkCount = 0
|
||||
let delayCount = 0
|
||||
|
||||
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
|
||||
|
||||
const detectChunk = (buffer: string) => {
|
||||
const match = chunkingRegex.exec(buffer)
|
||||
if (!match) return null
|
||||
return buffer.slice(0, match.index) + match?.[0]
|
||||
// 收集所有当前可匹配的chunks
|
||||
const collectMatches = (inputBuffer: string) => {
|
||||
const matches: string[] = []
|
||||
let tempBuffer = inputBuffer
|
||||
let match
|
||||
|
||||
// 重置regex状态
|
||||
chunkingRegex.lastIndex = 0
|
||||
|
||||
while ((match = chunkingRegex.exec(tempBuffer)) !== null) {
|
||||
matches.push(match[0])
|
||||
tempBuffer = tempBuffer.slice(match.index + match[0].length)
|
||||
// 重置regex以从头开始匹配剩余内容
|
||||
chunkingRegex.lastIndex = 0
|
||||
}
|
||||
|
||||
return {
|
||||
matches,
|
||||
remaining: tempBuffer
|
||||
}
|
||||
}
|
||||
|
||||
return new TransformStream({
|
||||
@ -28,8 +50,13 @@ export default definePlugin({
|
||||
if (chunk.type !== 'reasoning') {
|
||||
// === 处理 reasoning 结束 ===
|
||||
if (hasStartedThinking && accumulatedThinkingContent) {
|
||||
console.log(
|
||||
`[ReasoningPlugin] Ending reasoning. Final stats: chunks=${chunkCount}, delays=${delayCount}, efficiency=${(chunkCount / Math.max(delayCount, 1)).toFixed(2)}x`
|
||||
)
|
||||
|
||||
// 先输出剩余的 buffer
|
||||
if (buffer.length > 0) {
|
||||
console.log(`[ReasoningPlugin] Flushing remaining buffer: "${buffer}"`)
|
||||
controller.enqueue({
|
||||
type: 'reasoning',
|
||||
textDelta: buffer,
|
||||
@ -49,6 +76,8 @@ export default definePlugin({
|
||||
accumulatedThinkingContent = ''
|
||||
hasStartedThinking = false
|
||||
thinkingStartTime = 0
|
||||
chunkCount = 0
|
||||
delayCount = 0
|
||||
}
|
||||
|
||||
controller.enqueue(chunk)
|
||||
@ -61,28 +90,56 @@ export default definePlugin({
|
||||
if (!hasStartedThinking) {
|
||||
hasStartedThinking = true
|
||||
thinkingStartTime = performance.now()
|
||||
console.log(`[ReasoningPlugin] Starting reasoning session`)
|
||||
}
|
||||
accumulatedThinkingContent += chunk.textDelta
|
||||
|
||||
// 2. Smooth 处理逻辑
|
||||
// 2. 动态Smooth处理逻辑
|
||||
const beforeBuffer = buffer
|
||||
buffer += chunk.textDelta
|
||||
let match
|
||||
|
||||
while ((match = detectChunk(buffer)) != null) {
|
||||
controller.enqueue({
|
||||
type: 'reasoning',
|
||||
textDelta: match,
|
||||
thinking_millsec: performance.now() - thinkingStartTime
|
||||
})
|
||||
buffer = buffer.slice(match.length)
|
||||
console.log(`[ReasoningPlugin] Received chunk: "${chunk.textDelta}", buffer: "${beforeBuffer}" → "${buffer}"`)
|
||||
|
||||
// 收集所有当前可以匹配的chunks
|
||||
const { matches, remaining } = collectMatches(buffer)
|
||||
|
||||
if (matches.length > 0) {
|
||||
console.log(
|
||||
`[ReasoningPlugin] Collected ${matches.length} matches: [${matches.map((m) => `"${m}"`).join(', ')}], remaining: "${remaining}"`
|
||||
)
|
||||
|
||||
// 批量输出所有匹配的chunks
|
||||
for (const matchText of matches) {
|
||||
controller.enqueue({
|
||||
type: 'reasoning',
|
||||
textDelta: matchText,
|
||||
thinking_millsec: performance.now() - thinkingStartTime
|
||||
})
|
||||
chunkCount++
|
||||
}
|
||||
|
||||
// 更新buffer为剩余内容
|
||||
buffer = remaining
|
||||
|
||||
// 只等待一次,而不是每个chunk都等待
|
||||
delayCount++
|
||||
console.log(
|
||||
`[ReasoningPlugin] Delaying ${delayInMs}ms (delay #${delayCount}, efficiency: ${(chunkCount / delayCount).toFixed(2)} chunks/delay)`
|
||||
)
|
||||
const delayStart = performance.now()
|
||||
await delay(delayInMs)
|
||||
const actualDelay = performance.now() - delayStart
|
||||
console.log(`[ReasoningPlugin] Delay completed: expected=${delayInMs}ms, actual=${actualDelay.toFixed(1)}ms`)
|
||||
} else {
|
||||
console.log(`[ReasoningPlugin] No matches found, keeping in buffer: "${buffer}"`)
|
||||
}
|
||||
// 如果没有匹配,保留在buffer中等待下次数据
|
||||
},
|
||||
|
||||
// === flush 处理剩余 buffer ===
|
||||
flush(controller) {
|
||||
if (buffer.length > 0) {
|
||||
console.log(`[ReasoningPlugin] Final flush: "${buffer}"`)
|
||||
controller.enqueue({
|
||||
type: 'reasoning',
|
||||
textDelta: buffer,
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
// 可能会废弃,在流上做delay还是有问题
|
||||
|
||||
import { definePlugin, smoothStream } from '@cherrystudio/ai-core'
|
||||
|
||||
export default definePlugin({
|
||||
name: 'textPlugin',
|
||||
transformStream: () =>
|
||||
smoothStream({
|
||||
delayInMs: 20,
|
||||
delayInMs: 50,
|
||||
// 中文3个字符一个chunk,英文一个单词一个chunk
|
||||
chunking: /([\u4E00-\u9FFF]{3})|\S+\s+/
|
||||
})
|
||||
|
||||
@ -148,7 +148,7 @@ const getBlockThrottler = (id: string) => {
|
||||
}
|
||||
|
||||
const rafId = requestAnimationFrame(() => {
|
||||
// store.dispatch(updateOneBlock({ id, changes: blockUpdate }))
|
||||
store.dispatch(updateOneBlock({ id, changes: blockUpdate }))
|
||||
blockUpdateRafs.delete(id)
|
||||
})
|
||||
|
||||
@ -167,7 +167,7 @@ const getBlockThrottler = (id: string) => {
|
||||
*/
|
||||
const throttledBlockUpdate = (id: string, blockUpdate: any) => {
|
||||
const throttler = getBlockThrottler(id)
|
||||
store.dispatch(updateOneBlock({ id, changes: blockUpdate }))
|
||||
// store.dispatch(updateOneBlock({ id, changes: blockUpdate }))
|
||||
throttler(blockUpdate)
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user