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