feat(admin): LLM config, knowledge base, and WeCom AI binding
CI / verify (pull_request) Has been cancelled
CI / verify (pull_request) Has been cancelled
Add owner-scoped model API settings, uploadable knowledge bases, and WeCom bot AI/KB wiring with OpenAI-compatible URL normalization. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { PrismaService } from '../../common/prisma/prisma.module';
|
||||
import { LlmChatClient } from '../llm/llm-chat.client';
|
||||
import { KnowledgeRetrievalService } from '../llm/knowledge-retrieval.service';
|
||||
import type { WecomBotRuntimeConfig } from './wecom-bot.types';
|
||||
|
||||
const DEFAULT_SYSTEM = [
|
||||
'你是杜康好客企业内部助手。',
|
||||
'优先依据提供的知识库内容回答;知识库未覆盖时如实说明不确定。',
|
||||
'不要编造订单号、金额、权限;涉及写操作请引导用户使用指令(如「帮助」)。',
|
||||
'回答简洁,使用中文。',
|
||||
].join('');
|
||||
|
||||
@Injectable()
|
||||
export class WecomBotAiService {
|
||||
private readonly logger = new Logger(WecomBotAiService.name);
|
||||
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly llm: LlmChatClient,
|
||||
private readonly kb: KnowledgeRetrievalService,
|
||||
) {}
|
||||
|
||||
async replyIfConfigured(bot: WecomBotRuntimeConfig, userText: string): Promise<string | null> {
|
||||
if (!bot.aiEnabled || !bot.llmConfigId) return null;
|
||||
|
||||
const cfg = await this.prisma.llmApiConfig.findUnique({
|
||||
where: { id: BigInt(bot.llmConfigId) },
|
||||
});
|
||||
if (!cfg?.enabled) {
|
||||
return '已开启 AI,但绑定的语言模型未启用或已删除。请在 HQ「企微机器人」检查配置。';
|
||||
}
|
||||
|
||||
let kbBlock = '';
|
||||
if (bot.knowledgeBaseId) {
|
||||
try {
|
||||
kbBlock = await this.kb.buildContext(BigInt(bot.knowledgeBaseId), userText);
|
||||
} catch (e) {
|
||||
this.logger.warn(`kb retrieve failed: ${String(e)}`);
|
||||
}
|
||||
}
|
||||
|
||||
const systemParts = [
|
||||
cfg.systemPrompt?.trim() || DEFAULT_SYSTEM,
|
||||
kbBlock ? `\n\n以下为知识库检索片段:\n${kbBlock}` : '',
|
||||
];
|
||||
|
||||
try {
|
||||
return await this.llm.chat({
|
||||
baseUrl: cfg.baseUrl,
|
||||
apiKey: cfg.apiKey,
|
||||
model: cfg.modelName,
|
||||
temperature: cfg.temperature != null ? Number(cfg.temperature) : 0.3,
|
||||
maxTokens: cfg.maxTokens ?? 1024,
|
||||
messages: [
|
||||
{ role: 'system', content: systemParts.join('') },
|
||||
{ role: 'user', content: userText },
|
||||
],
|
||||
});
|
||||
} catch (e) {
|
||||
const msg = e instanceof Error ? e.message : String(e);
|
||||
this.logger.error(`wecom ai reply failed: ${msg}`);
|
||||
return `AI 回复失败:${msg}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user