historyMessages, $trace->originalMessage, $trace->plan, $trace->contextText); $result = self::callAssistantModel($messages); $trace->responseResult = $result; $trace->finalAnswer = !empty($result['success']) ? trim((string) ($result['content'] ?? '')) : 'AI助手暂时没有生成成功,请稍后再试。'; if ($trace->finalAnswer === '') { $trace->finalAnswer = '我暂时没有找到足够的站内依据,请换个关键词再问一次。'; } return $trace; } private static function buildModelMessages(array $history, string $message, array $plan, string $contextText): array { $messages = [ [ 'role' => 'system', 'content' => AiConfig::getVal('assistant_system_prompt', self::defaultSystemPrompt()), ], ]; foreach ($history as $row) { $role = $row['role'] === 'assistant' ? 'assistant' : 'user'; $content = trim((string) ($row['content'] ?? '')); if ($content !== '') { $messages[] = ['role' => $role, 'content' => mb_substr($content, 0, 1000)]; } } $planSummary = json_encode([ 'intent' => $plan['intent'] ?? '', 'rewritten_query' => $plan['rewritten_query'] ?? '', 'alternate_queries' => $plan['alternate_queries'] ?? [], 'domains' => $plan['domains'] ?? [], 'preferred_domain' => $plan['preferred_domain'] ?? '', 'entities' => $plan['entities'] ?? [], 'date_range' => $plan['date_range'] ?? [], 'needs_realtime' => $plan['needs_realtime'] ?? false, 'confidence' => $plan['confidence'] ?? 0, ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); $messages[] = [ 'role' => 'user', 'content' => "用户问题:\n{$message}\n\n查询理解结果:\n" . $planSummary . "\n\n站内资料、联网资讯与实时上下文:\n" . ($contextText ?: '{}') . "\n\n请按照“直接结论、依据摘要、相关内容、风险提示”的结构回答。" . "如果站内资料不足,请明确说明,不要编造。彩票、赛事预测、加密行情必须提示不构成投资或购彩建议。", ]; return $messages; } private static function callAssistantModel(array $messages): array { $client = new DeepSeekClient(); $optionsList = [self::defaultModelOptions()]; $failedErrors = []; $lastResult = ['success' => false, 'error' => 'AI助手模型服务暂时不可用', 'tokens' => 0]; foreach ($optionsList as $options) { $result = $client->chatMessages($messages, $options); if (!empty($result['success'])) { return $result; } $lastResult = $result; $provider = (string) ($result['provider_label'] ?? ($options['provider_label'] ?? 'AI模型')); $failedErrors[] = $provider . ': ' . (string) ($result['error'] ?? '调用失败'); } if (!empty($failedErrors)) { $lastResult['error'] = implode(' | ', $failedErrors); } return $lastResult; } private static function defaultModelOptions(): array { return DeepSeekClient::defaultModelOptions([ 'max_tokens' => 1600, 'temperature' => 0.45, 'retry_times' => 3, 'retry_sleep_ms' => 1200, ]); } private static function defaultSystemPrompt(): string { return '你是世博头条 AI 助手,面向普通用户回答站内体育资讯、赛事、社区、彩票和加密行情相关问题。' . '必须优先依据提供的站内资料和实时上下文回答;资料不足时要直接说明不足并建议用户换关键词。' . '不要声称可以访问后台、源码、服务器或未提供的内部数据。' . '回答使用中文,结构清晰,语气专业克制。涉及赛事预测、彩票或加密行情时,必须说明仅供参考,不构成投资或购彩建议。'; } }