From 5886270e298e119d14a34ff582c1ea02cc934459 Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 13 Jun 2025 22:31:32 +0300 Subject: [PATCH] add history tool --- .../support-ai-agent/support-agent.ts | 44 +++++++-------- .../support-ai-agent/support-context-tool.ts | 56 +++++++++++++++++++ 2 files changed, 77 insertions(+), 23 deletions(-) create mode 100644 server/routers/kfu-m-24-1/sber_mobile/support-ai-agent/support-context-tool.ts diff --git a/server/routers/kfu-m-24-1/sber_mobile/support-ai-agent/support-agent.ts b/server/routers/kfu-m-24-1/sber_mobile/support-ai-agent/support-agent.ts index 3ea39b7..0850b95 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/support-ai-agent/support-agent.ts +++ b/server/routers/kfu-m-24-1/sber_mobile/support-ai-agent/support-agent.ts @@ -3,6 +3,7 @@ import { ChatPromptTemplate, MessagesPlaceholder } from '@langchain/core/prompts import { createReactAgent } from '@langchain/langgraph/prebuilt'; import { MemorySaver } from '@langchain/langgraph'; import gigachat from './gigachat'; +import { SupportContextTool } from './support-context-tool'; export interface SupportAgentConfig { temperature?: number; @@ -22,30 +23,31 @@ export class SupportAgent { private systemPrompt: string; private threadId: string; private isFirstMessage: boolean; + private userId: string; constructor(config: SupportAgentConfig = {}) { this.systemPrompt = this.getDefaultSystemPrompt(); this.threadId = config.threadId || 'default'; + this.userId = this.threadId; this.memorySaver = new MemorySaver(); this.isFirstMessage = true; - // Настраиваем модель с заданной температурой this.llm = gigachat; if (config.temperature !== undefined) { this.llm.temperature = config.temperature; } - // Создаем агента без инструментов для простого чата + const tools = [ + new SupportContextTool(this.userId) + ]; + this.agent = createReactAgent({ llm: this.llm, - tools: [], + tools: tools, checkpointSaver: this.memorySaver }); } - /** - * Получить системный промпт по умолчанию для агента поддержки - */ private getDefaultSystemPrompt(): string { return `Ты - профессиональный агент службы поддержки. @@ -56,29 +58,26 @@ export class SupportAgent { - Проявлять эмпатию к проблемам пользователей - Если не знаешь ответ, честно сообщить об этом и предложить альтернативные способы получения помощи +ВАЖНО: У тебя есть доступ к инструменту get_support_context, который позволяет получить историю предыдущих сообщений пользователя. +ВСЕГДА используй этот инструмент ПЕРВЫМ ДЕЛОМ при получении каждого нового сообщения, чтобы понять контекст и предыдущие обращения пользователя. +Только после получения контекста отвечай на вопрос пользователя. + +Если в истории есть предыдущие обращения, обязательно ссылайся на них в своем ответе, показывая что помнишь предыдущее общение. + Всегда отвечай на русском языке и старайся быть максимально полезным.`; } - - - /** - * Обработать сообщение пользователя и получить ответ - */ public async processMessage(userMessage: string): Promise { try { - // Создаем массив сообщений const messages: BaseMessage[] = []; - // Добавляем системный промпт только в первом сообщении if (this.isFirstMessage) { messages.push(new SystemMessage(this.systemPrompt)); this.isFirstMessage = false; } - // Добавляем сообщение пользователя messages.push(new HumanMessage(userMessage)); - // Получаем ответ от агента const response = await this.agent.invoke({ messages: messages }, { @@ -87,7 +86,6 @@ export class SupportAgent { } }); - // Извлекаем последнее сообщение от ассистента const lastMessage = response.messages[response.messages.length - 1]; return { @@ -105,19 +103,19 @@ export class SupportAgent { } } - /** - * Очистить историю диалога - */ public async clearHistory(): Promise { this.memorySaver = new MemorySaver(); + + const tools = [ + new SupportContextTool(this.userId) + ]; + this.agent = createReactAgent({ llm: this.llm, - tools: [], + tools: tools, checkpointSaver: this.memorySaver }); - // Сбрасываем флаг первого сообщения + this.isFirstMessage = true; } - - } \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/support-ai-agent/support-context-tool.ts b/server/routers/kfu-m-24-1/sber_mobile/support-ai-agent/support-context-tool.ts new file mode 100644 index 0000000..94a573c --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/support-ai-agent/support-context-tool.ts @@ -0,0 +1,56 @@ +import { StructuredTool, ToolRunnableConfig } from '@langchain/core/tools'; +import { z } from 'zod'; +import { CallbackManagerForToolRun } from '@langchain/core/callbacks/manager'; +import { getSupabaseClient } from '../supabaseClient'; + +export class SupportContextTool extends StructuredTool { + name = 'get_support_context'; + description = 'Получает последние 10 сообщений из истории поддержки для понимания контекста разговора. Используй этот инструмент в начале разговора.'; + + schema = z.object({}); + + private userId: string; + + constructor(userId: string) { + super(); + this.userId = userId; + } + + protected async _call( + arg: z.infer, + runManager?: CallbackManagerForToolRun, + parentConfig?: ToolRunnableConfig> + ): Promise { + try { + const supabase = getSupabaseClient(); + + const { data: messages, error } = await supabase + .from('support') + .select('message, is_from_user, created_at') + .eq('user_id', this.userId) + .order('created_at', { ascending: false }) + .limit(10); + + if (error) { + return 'Не удалось получить историю сообщений.'; + } + + if (!messages || messages.length === 0) { + return 'История сообщений поддержки пуста. Это первое обращение пользователя.'; + } + + const chronologicalMessages = messages.reverse(); + + const contextMessages = chronologicalMessages.map((msg, index) => { + const role = msg.is_from_user ? 'Пользователь' : 'Агент поддержки'; + const time = new Date(msg.created_at).toLocaleString('ru-RU'); + return `${index + 1}. [${time}] ${role}: ${msg.message}`; + }).join('\n'); + + return `Последние сообщения из истории поддержки (${messages.length} сообщений):\n\n${contextMessages}\n\nИспользуй этот контекст для понимания предыдущих обращений пользователя и предоставления более точных ответов.`; + + } catch (error) { + return 'Произошла ошибка при получении истории сообщений.'; + } + } +} \ No newline at end of file