From 3d1a559825ca7dd339cca808399bb15ddbf4e313 Mon Sep 17 00:00:00 2001 From: T4nzQ <2890888215@qq.com> Date: Wed, 1 Jul 2026 14:17:07 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:deepseek=20v4=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/agentlab/src/catalog.ts | 2 ++ packages/agentlab/src/extract.ts | 10 +++++----- packages/agentlab/src/http.ts | 19 ++++++++++++++----- packages/agentlab/src/index.ts | 2 +- packages/service/src/account/assistant.ts | 8 ++++---- 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/packages/agentlab/src/catalog.ts b/packages/agentlab/src/catalog.ts index 9369845..a0e25da 100644 --- a/packages/agentlab/src/catalog.ts +++ b/packages/agentlab/src/catalog.ts @@ -26,6 +26,8 @@ export const AGENTLAB_PROVIDER_CATALOG: AgentLabProviderCatalogEntry[] = [ models: [ { id: 'deepseek-chat', label: 'deepseek-chat', capabilities: ['chat'] }, { id: 'deepseek-reasoner', label: 'deepseek-reasoner', capabilities: ['chat'] }, + { id: 'deepseek-v4-flash', label: 'deepseek-v4-flash', capabilities: ['chat'] }, + { id: 'deepseek-v4-pro', label: 'deepseek-v4-pro', capabilities: ['chat'] }, ], }, { diff --git a/packages/agentlab/src/extract.ts b/packages/agentlab/src/extract.ts index b629cb4..77a25be 100644 --- a/packages/agentlab/src/extract.ts +++ b/packages/agentlab/src/extract.ts @@ -12,7 +12,7 @@ import type { AgentLabExpression, AgentLabFewShotPair, } from './types'; -import { reportUsage } from './http'; +import { reportUsage, pickMessageText } from './http'; function coerceString(value: unknown): string { if (typeof value === 'string') return value.trim(); @@ -63,9 +63,9 @@ async function chatCompletion( if (!res.ok) { throw new Error(`AgentLab 提炼接口调用失败: HTTP ${res.status}`); } - const data = (await res.json()) as { choices?: Array<{ message?: { content?: string } }> }; + const data = (await res.json()) as { choices?: Array<{ message?: { content?: string; reasoning_content?: string } }> }; reportUsage(endpoint, data); - return data.choices?.[0]?.message?.content ?? ''; + return pickMessageText(data.choices?.[0]?.message); } /** @@ -103,9 +103,9 @@ async function visionCompletion( if (!res.ok) { throw new Error(`AgentLab 视觉接口调用失败: HTTP ${res.status}`); } - const data = (await res.json()) as { choices?: Array<{ message?: { content?: string } }> }; + const data = (await res.json()) as { choices?: Array<{ message?: { content?: string; reasoning_content?: string } }> }; reportUsage(endpoint, data); - return data.choices?.[0]?.message?.content ?? ''; + return pickMessageText(data.choices?.[0]?.message); } /** generateText + 宽松解析 + 失败重试一次。 */ diff --git a/packages/agentlab/src/http.ts b/packages/agentlab/src/http.ts index 442b6fb..5cf93fc 100644 --- a/packages/agentlab/src/http.ts +++ b/packages/agentlab/src/http.ts @@ -345,20 +345,29 @@ async function postJson( return (await res.json()) as T; } +/** OpenAI 兼容消息里同时可能存在 content 和 reasoning_content(推理模型专用),取首个非空。 */ +export function pickMessageText(msg: { content?: string; reasoning_content?: string } | undefined): string { + if (!msg) return ''; + return (msg.content || msg.reasoning_content || '').trim(); +} + /** * 设置页「测试连通性」:用最小的 chat 请求探活,返回 ok + 详细错误(含 HTTP 状态码与响应体)。 * 不抛错——把失败包装成 { ok:false, error },让前端直接展示「模型不对 / key 不对」。 + * 推理模型(如 deepseek-v4 系列)会把思考过程放在 reasoning_content 中, + * 当 max_tokens 较小时 content 可能为空——因此同时检查两个字段。 */ export async function testChatEndpoint( endpoint: AgentLabEndpoint, ): Promise<{ ok: boolean; error?: string; reply?: string }> { try { - const data = await postJson<{ choices?: Array<{ message?: { content?: string } }> }>( + const data = await postJson<{ choices?: Array<{ message?: { content?: string; reasoning_content?: string } }> }>( endpoint, '/chat/completions', - { model: endpoint.model, messages: [{ role: 'user', content: '你好' }], max_tokens: 16 }, + // 推理模型需要更多 token 预算才能产出 content;64 足够短路"你好"又不浪费。 + { model: endpoint.model, messages: [{ role: 'user', content: '你好' }], max_tokens: 64 }, ); - const reply = data.choices?.[0]?.message?.content?.trim(); + const reply = pickMessageText(data.choices?.[0]?.message); if (!reply) return { ok: false, error: '接口可达,但返回内容为空(模型可能不支持 chat/completions)。' }; return { ok: true, reply }; } catch (e) { @@ -564,7 +573,7 @@ export async function runPersonaChat( ]; const data = await postJson<{ - choices?: Array<{ message?: { content?: string } }>; + choices?: Array<{ message?: { content?: string; reasoning_content?: string } }>; usage?: OpenAiUsage; }>(chat, '/chat/completions', { model: chat.model, @@ -573,7 +582,7 @@ export async function runPersonaChat( messages, }); reportUsage(chat, data); - const raw = data.choices?.[0]?.message?.content?.trim(); + const raw = pickMessageText(data.choices?.[0]?.message); if (!raw) { throw new Error('AgentLab chat 返回为空'); } diff --git a/packages/agentlab/src/index.ts b/packages/agentlab/src/index.ts index 2b6176b..4c61ea2 100644 --- a/packages/agentlab/src/index.ts +++ b/packages/agentlab/src/index.ts @@ -5,7 +5,7 @@ export { modelsWithCapability, resolveEndpoint, } from './provider'; -export { embedTexts, runPersonaChat, reportUsage, keywordsOf, testChatEndpoint } from './http'; +export { embedTexts, runPersonaChat, reportUsage, keywordsOf, testChatEndpoint, pickMessageText } from './http'; export { selectStickerByEmotion } from './sticker'; export { humanizeText, DEFAULT_TYPO_INTENSITY } from './typo'; export { scoreReplyWillingness } from './willing'; diff --git a/packages/service/src/account/assistant.ts b/packages/service/src/account/assistant.ts index 86723b2..4289ef4 100644 --- a/packages/service/src/account/assistant.ts +++ b/packages/service/src/account/assistant.ts @@ -13,7 +13,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; import { randomUUID } from 'node:crypto'; import { basename, dirname, extname, join, resolve, sep } from 'node:path'; -import { reportUsage, type AgentLabEndpoint, type AgentLabModelRef, type AgentLabUsage } from '@weq/agentlab'; +import { reportUsage, pickMessageText, type AgentLabEndpoint, type AgentLabModelRef, type AgentLabUsage } from '@weq/agentlab'; import type { TokenUsageStore } from './agentlab_usage'; import type { ConversationStore, ConversationTurn } from './agentlab_conversation'; @@ -384,8 +384,8 @@ export class AssistantService { ], [], ); - const raw = data.choices?.[0]?.message?.content; - return cleanTitle(typeof raw === 'string' ? raw : ''); + const raw = pickMessageText(data.choices?.[0]?.message); + return cleanTitle(raw); } /** 核心多轮循环:返回最终文本。中途只 emit 过程 step,不 emit final。 */ @@ -424,7 +424,7 @@ export class AssistantService { const msg = data.choices?.[0]?.message; if (!msg) throw new Error('助手返回为空'); - const content = typeof msg.content === 'string' ? msg.content.trim() : ''; + const content = pickMessageText(msg); if (allowTools && msg.tool_calls?.length) { // 模型在调用工具前给出的思路 → 作为"思考"展示。 From 6fe81c31176fae8a904cdf4125f25c735a7a529c Mon Sep 17 00:00:00 2001 From: T4nzQ <2890888215@qq.com> Date: Wed, 1 Jul 2026 14:24:09 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E5=92=95=E5=92=95=E5=98=8E=E5=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/agentlab/src/http.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/agentlab/src/http.ts b/packages/agentlab/src/http.ts index 5cf93fc..5c86391 100644 --- a/packages/agentlab/src/http.ts +++ b/packages/agentlab/src/http.ts @@ -346,9 +346,11 @@ async function postJson( } /** OpenAI 兼容消息里同时可能存在 content 和 reasoning_content(推理模型专用),取首个非空。 */ -export function pickMessageText(msg: { content?: string; reasoning_content?: string } | undefined): string { +export function pickMessageText(msg: { content?: unknown; reasoning_content?: unknown } | undefined): string { if (!msg) return ''; - return (msg.content || msg.reasoning_content || '').trim(); + const c = typeof msg.content === 'string' ? msg.content : ''; + const r = typeof msg.reasoning_content === 'string' ? msg.reasoning_content : ''; + return (c || r).trim(); } /**