Merge branch 'feature/parallel-tool-test' of https://github.com/LSTM-Kirigaya/openmcp-client into feature/parallel-tool-test
This commit is contained in:
commit
a45f65816e
@ -161,6 +161,125 @@ export function topoSortParallel(state: DiagramState): string[][] {
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function makeParallelTest(
|
||||
dataViews: Reactive<NodeDataView>[],
|
||||
enableXmlWrapper: boolean,
|
||||
prompt: string | null = null,
|
||||
context: DiagramContext
|
||||
) {
|
||||
if (dataViews.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置所有节点状态为运行中
|
||||
const createAt = Date.now();
|
||||
dataViews.forEach(dataView => {
|
||||
dataView.status = 'running';
|
||||
dataView.createAt = createAt;
|
||||
});
|
||||
context.render();
|
||||
|
||||
try {
|
||||
const loop = new TaskLoop({ maxEpochs: 1 });
|
||||
|
||||
// 构建所有工具的信息
|
||||
const allTools = dataViews.map(dataView => ({
|
||||
name: dataView.tool.name,
|
||||
description: dataView.tool.description,
|
||||
inputSchema: dataView.tool.inputSchema,
|
||||
enabled: true
|
||||
}));
|
||||
|
||||
// 构建测试提示词,包含所有工具
|
||||
const toolNames = dataViews.map(dv => dv.tool.name).join(', ');
|
||||
const usePrompt = (prompt || 'please call the tools {tool} to make some test').replace('{tool}', toolNames);
|
||||
|
||||
const chatStorage = {
|
||||
messages: [],
|
||||
settings: {
|
||||
temperature: 0.6,
|
||||
systemPrompt: '',
|
||||
enableTools: allTools,
|
||||
enableWebSearch: false,
|
||||
contextLength: 5,
|
||||
enableXmlWrapper,
|
||||
parallelToolCalls: true // 开启并行工具调用
|
||||
}
|
||||
} as ChatStorage;
|
||||
|
||||
loop.setMaxEpochs(1);
|
||||
|
||||
// 记录工具调用信息,用于匹配工具调用结果
|
||||
const toolCallMap: Map<string, Reactive<NodeDataView>> = new Map(); // toolCallId -> dataView
|
||||
let completedToolsCount = 0;
|
||||
|
||||
loop.registerOnToolCall(toolCall => {
|
||||
// 找到对应的dataView
|
||||
const dataView = dataViews.find(dv => dv.tool.name === toolCall.function?.name);
|
||||
if (dataView) {
|
||||
dataView.function = toolCall.function;
|
||||
dataView.llmTimecost = Date.now() - createAt;
|
||||
context.render();
|
||||
|
||||
// 记录工具调用ID与dataView的映射
|
||||
if (toolCall.id) {
|
||||
toolCallMap.set(toolCall.id, dataView);
|
||||
}
|
||||
}
|
||||
return toolCall;
|
||||
});
|
||||
|
||||
loop.registerOnToolCalled(toolCalled => {
|
||||
// 这里我们需要改变策略,因为没有工具调用ID信息
|
||||
// 对于并行调用,我们可以根据工具调用的顺序来匹配结果
|
||||
// 简单的策略:找到第一个仍在运行状态的工具
|
||||
const runningView = dataViews.find(dv => dv.status === 'running');
|
||||
if (runningView) {
|
||||
runningView.toolcallTimecost = Date.now() - createAt - (runningView.llmTimecost || 0);
|
||||
|
||||
if (toolCalled.state === MessageState.Success) {
|
||||
runningView.status = 'success';
|
||||
runningView.result = toolCalled.content;
|
||||
} else {
|
||||
runningView.status = 'error';
|
||||
runningView.result = toolCalled.content;
|
||||
}
|
||||
|
||||
completedToolsCount++;
|
||||
context.render();
|
||||
|
||||
// 如果所有工具都完成了,终止循环
|
||||
if (completedToolsCount >= dataViews.length) {
|
||||
loop.abort();
|
||||
}
|
||||
}
|
||||
return toolCalled;
|
||||
});
|
||||
|
||||
loop.registerOnError(error => {
|
||||
dataViews.forEach(dataView => {
|
||||
if (dataView.status === 'running') {
|
||||
dataView.status = 'error';
|
||||
dataView.result = error;
|
||||
}
|
||||
});
|
||||
context.render();
|
||||
});
|
||||
|
||||
await loop.start(chatStorage, usePrompt);
|
||||
|
||||
} finally {
|
||||
const finishAt = Date.now();
|
||||
dataViews.forEach(dataView => {
|
||||
dataView.finishAt = finishAt;
|
||||
if (dataView.status === 'running') {
|
||||
dataView.status = 'success';
|
||||
}
|
||||
});
|
||||
context.render();
|
||||
}
|
||||
}
|
||||
|
||||
export async function makeNodeTest(
|
||||
dataView: Reactive<NodeDataView>,
|
||||
enableXmlWrapper: boolean,
|
||||
|
@ -37,6 +37,13 @@
|
||||
color: enableXmlWrapper ? 'var(--main-color)' : undefined
|
||||
}">XML</span>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center; margin-bottom: 8px;">
|
||||
<el-switch v-model="enableParallelTest" style="margin-right: 8px;" />
|
||||
<span :style="{
|
||||
opacity: enableParallelTest ? 1 : 0.7,
|
||||
color: enableParallelTest ? 'var(--main-color)' : undefined
|
||||
}">{{ t('parallel-test') }}</span>
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<el-button size="small" @click="testFormVisible = false">{{ t("cancel") }}</el-button>
|
||||
<el-button size="small" type="primary" @click="onTestConfirm">
|
||||
@ -70,7 +77,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, provide, ref } from 'vue';
|
||||
import Diagram from './diagram.vue';
|
||||
import { makeNodeTest, topoSortParallel, type DiagramContext, type DiagramState } from './diagram';
|
||||
import { makeNodeTest, makeParallelTest, topoSortParallel, type DiagramContext, type DiagramState } from './diagram';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
import { useI18n } from 'vue-i18n';
|
||||
@ -137,43 +144,60 @@ if (autoDetectDiagram) {
|
||||
// 新增:自检参数表单相关
|
||||
const testFormVisible = ref(false);
|
||||
const enableXmlWrapper = ref(false);
|
||||
const enableParallelTest = ref(false);
|
||||
const testPrompt = ref('please call the tool {tool} to make some test');
|
||||
|
||||
async function onTestConfirm() {
|
||||
testFormVisible.value = false;
|
||||
// 这里可以将 enableXmlWrapper.value 和 testPrompt.value 传递给自检逻辑
|
||||
const state = context.state;
|
||||
|
||||
|
||||
tabStorage.autoDetectDiagram!.views = [];
|
||||
|
||||
if (state) {
|
||||
const dispatches = topoSortParallel(state);
|
||||
for (const nodeIds of dispatches) {
|
||||
for (const id of nodeIds) {
|
||||
const view = state.dataView.get(id);
|
||||
if (view) {
|
||||
await makeNodeTest(view, enableXmlWrapper.value, testPrompt.value, context)
|
||||
tabStorage.autoDetectDiagram!.views!.push({
|
||||
tool: view.tool,
|
||||
status: view.status,
|
||||
function: view.function,
|
||||
result: view.result,
|
||||
createAt: view.createAt,
|
||||
finishAt: view.finishAt,
|
||||
llmTimecost: view.llmTimecost,
|
||||
toolcallTimecost: view.toolcallTimecost,
|
||||
});
|
||||
if (enableParallelTest.value) {
|
||||
// 并行测试模式:一次性测试所有工具
|
||||
const allViews = Array.from(state.dataView.values());
|
||||
await makeParallelTest(allViews, enableXmlWrapper.value, testPrompt.value, context);
|
||||
|
||||
context.render();
|
||||
// 保存结果
|
||||
allViews.forEach(view => {
|
||||
tabStorage.autoDetectDiagram!.views!.push({
|
||||
tool: view.tool,
|
||||
status: view.status,
|
||||
function: view.function,
|
||||
result: view.result,
|
||||
createAt: view.createAt,
|
||||
finishAt: view.finishAt,
|
||||
llmTimecost: view.llmTimecost,
|
||||
toolcallTimecost: view.toolcallTimecost,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// 串行测试模式:按拓扑顺序逐个测试
|
||||
const dispatches = topoSortParallel(state);
|
||||
for (const nodeIds of dispatches) {
|
||||
for (const id of nodeIds) {
|
||||
const view = state.dataView.get(id);
|
||||
if (view) {
|
||||
await makeNodeTest(view, enableXmlWrapper.value, testPrompt.value, context);
|
||||
tabStorage.autoDetectDiagram!.views!.push({
|
||||
tool: view.tool,
|
||||
status: view.status,
|
||||
function: view.function,
|
||||
result: view.result,
|
||||
createAt: view.createAt,
|
||||
finishAt: view.finishAt,
|
||||
llmTimecost: view.llmTimecost,
|
||||
toolcallTimecost: view.toolcallTimecost,
|
||||
});
|
||||
context.render();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ElMessage.error('error');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
const resetPopoverVisible = ref(false);
|
||||
|
@ -157,6 +157,7 @@
|
||||
"feedback": "Feedback",
|
||||
"waiting-mcp-server": "Waiting for MCP server response",
|
||||
"parallel-tool-calls": "Allow model to call multiple tools in single response",
|
||||
"parallel-test": "Parallel Test",
|
||||
"proxy-server": "Proxy Server",
|
||||
"update-model-list": "Update Model List",
|
||||
"preset-env-sync.success": "Preset environment variables synced",
|
||||
|
@ -157,6 +157,7 @@
|
||||
"feedback": "反馈",
|
||||
"waiting-mcp-server": "等待 MCP 服务器响应",
|
||||
"parallel-tool-calls": "允许模型在单轮回复中调用多个工具",
|
||||
"parallel-test": "并行测试",
|
||||
"proxy-server": "代理服务器",
|
||||
"update-model-list": "更新模型列表",
|
||||
"preset-env-sync.success": "预设环境变量同步完成",
|
||||
|
Loading…
x
Reference in New Issue
Block a user