feat: Implement tool calls and error handling in pipeline execution

This commit is contained in:
uxname committed 2025-05-24 15:09:24 +03:00
1 parent 4194d4239f
commit 6047368080
1 file changed
+59 -12
+59 -12
View File
@@ -1,4 +1,8 @@
import { HumanMessage, SystemMessage } from '@langchain/core/messages'; import {
HumanMessage,
SystemMessage,
ToolMessage,
} from '@langchain/core/messages';
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';
@@ -23,6 +27,7 @@ class MockMcpToolsService {
description: 'Возвращает введенную строку.', description: 'Возвращает введенную строку.',
schema: z.object({ input: z.string().describe('Строка для эхо.') }), schema: z.object({ input: z.string().describe('Строка для эхо.') }),
func: async (input: { input: string }) => { func: async (input: { input: string }) => {
console.log(`Вызов инструмента 'echo' с входом: ${input.input}`);
return input.input; return input.input;
}, },
}); });
@@ -32,6 +37,7 @@ class MockMcpToolsService {
description: 'Возвращает текущую дату в формате ISO.', description: 'Возвращает текущую дату в формате ISO.',
schema: z.object({}), schema: z.object({}),
func: async () => { func: async () => {
console.log('Вызов инструмента "get_current_date"');
return new Date().toISOString(); return new Date().toISOString();
}, },
}); });
@@ -82,15 +88,14 @@ class PipelineExecutor {
async executeChain(params: { async executeChain(params: {
pipeline: Pipeline; pipeline: Pipeline;
variables: Record<string, string>; variables?: Record<string, string>;
systemPrompts: string[]; systemPrompts?: string[];
openAIApiKey: string; openAIApiKey: string;
}): Promise<string[]> { }): Promise<string[]> {
const variables = params.variables === undefined ? {} : params.variables; const variables = params.variables ?? {};
const systemPrompts = const systemPrompts = params.systemPrompts ?? [];
params.systemPrompts === undefined ? [] : params.systemPrompts;
const chain = await this.initChain(params.openAIApiKey); const chain = await this.initChain(params.openAIApiKey);
const messages = this.buildMessages( const initialMessages = this.buildMessages(
[params.pipeline.systemPrompt, ...systemPrompts], [params.pipeline.systemPrompt, ...systemPrompts],
variables, variables,
); );
@@ -98,10 +103,48 @@ class PipelineExecutor {
for (const { prompt } of params.pipeline.steps) { for (const { prompt } of params.pipeline.steps) {
const renderedPrompt = this.renderPrompt(prompt, variables); const renderedPrompt = this.renderPrompt(prompt, variables);
console.log({ renderedPrompt }); const currentMessages = [
const stepMessages = [...messages, new HumanMessage(renderedPrompt)]; ...initialMessages,
const response = await chain.invoke(stepMessages); new HumanMessage(renderedPrompt),
results.push(response?.content ?? ''); ];
let response = await chain.invoke(currentMessages);
while (response.tool_calls && response.tool_calls.length > 0) {
const toolCalls = response.tool_calls;
currentMessages.push(response);
for (const toolCall of toolCalls) {
try {
const tools = await this.mcpToolsService.getTools();
const tool = tools.find((t) => t.name === toolCall.name);
if (!tool) {
throw new Error(`Tool ${toolCall.name} not found`);
}
const toolResult = await tool.func(toolCall.args);
currentMessages.push(
new ToolMessage({
tool_call_id: toolCall.id,
content: JSON.stringify(toolResult),
}),
);
} catch (error) {
console.error(
`Ошибка выполнения инструмента ${toolCall.name}:`,
error,
);
currentMessages.push(
new ToolMessage({
tool_call_id: toolCall.id,
content: `Error: ${error.message}`,
}),
);
}
}
response = await chain.invoke(currentMessages);
}
results.push(response?.content ?? '<empty>');
} }
return results; return results;
} }
@@ -138,7 +181,7 @@ async function main() {
name: 'Получение даты', name: 'Получение даты',
prompt: 'Какая сейчас дата? Используй инструмент `get_current_date`.', prompt: 'Какая сейчас дата? Используй инструмент `get_current_date`.',
}, },
{ name: 'Завершение', prompt: 'Подтверди, что все шаги выполнены.' }, { name: 'Завершение', prompt: 'Напиши резюме, что ты сделал' },
], ],
}; };
@@ -148,6 +191,7 @@ async function main() {
const systemPrompts = ['Отвечай кратко и по существу.']; const systemPrompts = ['Отвечай кратко и по существу.'];
try {
const results = await pipelineExecutor.executeChain({ const results = await pipelineExecutor.executeChain({
pipeline: testPipeline, pipeline: testPipeline,
variables: variables, variables: variables,
@@ -155,6 +199,9 @@ async function main() {
openAIApiKey: openAIApiKey, openAIApiKey: openAIApiKey,
}); });
console.log('Результаты выполнения пайплайна:', results); console.log('Результаты выполнения пайплайна:', results);
} catch (error) {
console.error('Ошибка при выполнении пайплайна:', error);
}
} }
main().catch(console.error); main().catch(console.error);