Refactor: Remove redundant comments and simplify code

This commit is contained in:
uxname committed 2025-05-24 16:07:39 +03:00
1 parent c348b4902e
commit da064fcb66
1 file changed
+20 -41
+20 -41
View File
@@ -7,16 +7,15 @@ import {
import { Runnable } from '@langchain/core/runnables';
import { DynamicStructuredTool } from '@langchain/core/tools';
import { ChatOpenAI } from '@langchain/openai';
import dotenv from 'dotenv'; // Импортируем dotenv для загрузки переменных окружения
import dotenv from 'dotenv';
import Handlebars from 'handlebars';
import { z } from 'zod';
// MCP SDK imports
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
import { Tool as McpTool, TextContent } from '@modelcontextprotocol/sdk/types';
dotenv.config(); // Загружаем переменные окружения из .env файла
dotenv.config();
interface PipelineStep {
name: string;
@@ -29,9 +28,6 @@ interface Pipeline {
steps: PipelineStep[];
}
/**
* Сервис для взаимодействия с MCP сервером и предоставления инструментов LangChain.
*/
class McpToolsService {
private mcpClient: Client | null = null;
private transport: SSEClientTransport | null = null;
@@ -41,12 +37,9 @@ class McpToolsService {
this.serverUrl = serverUrl;
}
/**
* Устанавливает соединение с MCP сервером.
*/
async connect(): Promise<void> {
if (this.mcpClient && this.transport) {
return; // Уже подключено
return;
}
try {
this.transport = new SSEClientTransport(new URL(this.serverUrl));
@@ -65,9 +58,6 @@ class McpToolsService {
}
}
/**
* Закрывает соединение с MCP сервером.
*/
async disconnect(): Promise<void> {
if (this.mcpClient) {
await this.mcpClient.close();
@@ -77,10 +67,6 @@ class McpToolsService {
}
}
/**
* Получает список инструментов с MCP сервера и преобразует их в формат LangChain.
* @returns Массив инструментов LangChain.
*/
async getLangchainTools(): Promise<DynamicStructuredTool[]> {
if (!this.mcpClient) {
throw new Error('MCP клиент не подключен. Сначала вызовите .connect()');
@@ -90,8 +76,6 @@ class McpToolsService {
const langchainTools: DynamicStructuredTool[] = [];
for (const mcpTool of mcpTools) {
// Простая конвертация JSON Schema в Zod schema.
// Для сложных схем рекомендуется использовать специализированную библиотеку (например, json-schema-to-zod).
const properties: Record<string, z.ZodTypeAny> = {};
for (const key in mcpTool.inputSchema.properties) {
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
@@ -108,11 +92,9 @@ class McpToolsService {
schemaType = z.boolean();
break;
case 'array':
// Для массивов без явного типа элементов, используем z.array(z.any())
schemaType = z.array(z.any());
break;
case 'object':
// Для объектов без явной вложенной схемы, используем z.object({})
schemaType = z.object({});
break;
default:
@@ -149,7 +131,6 @@ class McpToolsService {
);
}
// Предпочтительно возвращаем структурированный контент, если он есть
if (result.structuredContent) {
return result.structuredContent;
}
@@ -160,7 +141,7 @@ class McpToolsService {
if (c.type === 'image') return `[Изображение: ${c.mimeType}]`;
if (c.type === 'audio') return `[Аудио: ${c.mimeType}]`;
if (c.type === 'resource') return `[Ресурс: ${c.uri}]`;
return JSON.stringify(c); // Запасной вариант для других типов
return JSON.stringify(c);
})
.join('\n');
},
@@ -181,8 +162,8 @@ class PipelineExecutor {
private async _getOrLoadTools(): Promise<DynamicStructuredTool[]> {
if (!this.cachedTools) {
await this.mcpToolsService.connect(); // Устанавливаем соединение с MCP сервером
this.cachedTools = await this.mcpToolsService.getLangchainTools(); // Получаем инструменты LangChain
await this.mcpToolsService.connect();
this.cachedTools = await this.mcpToolsService.getLangchainTools();
}
return this.cachedTools;
}
@@ -225,25 +206,25 @@ class PipelineExecutor {
const variables = options.variables ?? {};
const systemPrompts = options.systemPrompts ?? [];
const chain = await this.initChain(options.openAIApiKey);
const initialMessages = this.buildMessages(
[options.pipeline.systemPrompt, ...systemPrompts],
variables,
);
// Инициализируем массив сообщений, который будет накапливаться
const messages: (HumanMessage | SystemMessage | AIMessage | ToolMessage)[] =
this.buildMessages(
[options.pipeline.systemPrompt, ...systemPrompts],
variables,
);
const results: string[] = [];
for (const { prompt } of options.pipeline.steps) {
const renderedPrompt = this.renderPrompt(prompt, variables);
const currentMessages: (
| HumanMessage
| SystemMessage
| AIMessage
| ToolMessage
)[] = [...initialMessages, new HumanMessage(renderedPrompt)];
// Добавляем текущий промпт пользователя в общий массив сообщений
messages.push(new HumanMessage(renderedPrompt));
const finalResponse = await this._resolveToolCalls(
chain,
currentMessages,
messages, // Передаем накопительный массив сообщений
);
// Добавляем ответ ИИ в общий массив сообщений для сохранения контекста
messages.push(finalResponse);
results.push(finalResponse?.content.toString() ?? '<empty>');
}
return results;
@@ -260,7 +241,7 @@ class PipelineExecutor {
for (const toolCall of response.tool_calls) {
try {
const tools = await this._getOrLoadTools(); // Получаем LangChain-совместимые инструменты
const tools = await this._getOrLoadTools();
const tool = tools.find((t) => t.name === toolCall.name);
if (!tool) {
@@ -276,12 +257,11 @@ class PipelineExecutor {
continue;
}
// Выполняем функцию LangChain инструмента, которая внутри вызывает MCP сервер
const toolResult = await tool.func(toolCall.args);
messages.push(
new ToolMessage({
tool_call_id: toolCall.id!,
content: JSON.stringify(toolResult), // LangChain ожидает строковый контент здесь
content: JSON.stringify(toolResult),
}),
);
} catch (error) {
@@ -305,7 +285,6 @@ class PipelineExecutor {
async function main() {
const openAIApiKey = process.env.OPENAI_API_KEY;
// Используйте переменную окружения для URL сервера MCP, с запасным вариантом по умолчанию
const mcpServerUrl =
process.env.MCP_SERVER_URL || 'https://santiment-mcp.dev.mind-dev.com/sse';
@@ -316,7 +295,7 @@ async function main() {
process.exit(1);
}
const pipelineExecutor = new PipelineExecutor(mcpServerUrl); // Передаем URL сервера
const pipelineExecutor = new PipelineExecutor(mcpServerUrl);
const testPipeline: Pipeline = {
description: 'Тестовый пайплайн',