v0.1.4版本 #2

Merged
PeterZhong merged 70 commits from host into master 2025-06-15 14:42:58 +00:00
2 changed files with 249 additions and 220 deletions
Showing only changes of commit 660ba2ad53 - Show all commits

View File

@ -239,17 +239,25 @@ public class Gateway
api_key = "sk-db177155677e438f832860e7f4da6afc" api_key = "sk-db177155677e438f832860e7f4da6afc"
}; };
List<Message> messages = new List<Message>(); List<Message> messages = new List<Message>();
string toolInfos = await GetToolInfos(new McpServerList()); string toolInfos = "";
messages.Add(new Message try
{ {
Role = "system", toolInfos = await GetToolInfos(new McpServerList());
Content = SystemPrompt.SysPrompt(gdbPath, toolInfos) messages.Add(new Message
}); {
messages.Add(new Message Role = "system",
Content = SystemPrompt.SysPrompt(gdbPath, toolInfos)
});
messages.Add(new Message
{
Role = "user",
Content = message
});
}catch (Exception ex)
{ {
Role = "user", log.Error(ex);
Content = message MessageBox.Show(ex.Message,"获取MCP列表失败");
}); }
goOn = true; goOn = true;
string toolPattern = "<tool_use>([\\s\\S]*?)<name>([\\s\\S]*?)<\\/name>([\\s\\S]*?)<arguments>([\\s\\S]*?)<\\/arguments>([\\s\\S]*?)<\\/tool_use>"; string toolPattern = "<tool_use>([\\s\\S]*?)<name>([\\s\\S]*?)<\\/name>([\\s\\S]*?)<arguments>([\\s\\S]*?)<\\/arguments>([\\s\\S]*?)<\\/tool_use>";
string promptPattern = "<prompt>([\\s\\S]*?)<name>([\\s\\S]*?)<\\/name>([\\s\\S]*?)<arguments>([\\s\\S]*?)<\\/arguments>([\\s\\S]*?)<\\/prompt>"; string promptPattern = "<prompt>([\\s\\S]*?)<name>([\\s\\S]*?)<\\/name>([\\s\\S]*?)<arguments>([\\s\\S]*?)<\\/arguments>([\\s\\S]*?)<\\/prompt>";
@ -282,56 +290,106 @@ public class Gateway
{ {
//如果本次回复不包含任何工具的调用或提示词的调用,则不再请求 //如果本次回复不包含任何工具的调用或提示词的调用,则不再请求
goOn = false; goOn = false;
MessageListItem endMessageListItem1 = new ChatMessageItem MessageListItem endMessageListItem1 = new ChatMessageItem
{ {
type = MessageType.END_TAG, type = MessageType.END_TAG,
content = "", content = "",
id = (timestamp+3).ToString(), id = (timestamp + 3).ToString(),
role = "assistant" role = "assistant"
}; };
callback?.Invoke(endMessageListItem1); callback?.Invoke(endMessageListItem1);
break; break;
} }
await foreach(LlmStreamChat llmStreamChat in bailian.SendChatStreamAsync(jsonContent))
{
if (!goOn)
{
MessageListItem endMessageListItem2 = new ChatMessageItem
{
type = MessageType.END_TAG,
content = "",
id = (timestamp+3).ToString(),
role = "assistant"
};
callback?.Invoke(endMessageListItem2);
break;
}
try try
{
await foreach(LlmStreamChat llmStreamChat in bailian.SendChatStreamAsync(jsonContent))
{ {
string chunk = llmStreamChat.Choices[0].Delta.Content; if (!goOn)
MessageListItem reasonMessageListItem = new ChatMessageItem()
{ {
content = llmStreamChat.Choices[0].Delta.ResoningContent, MessageListItem endMessageListItem2 = new ChatMessageItem
role = "assistant",
type = MessageType.REASON_MESSAGE,
id = (timestamp+2).ToString()
};
Application.Current.Dispatcher.Invoke(() =>
{
callback?.Invoke(reasonMessageListItem);
});
messageContent = chunk;
var (matched, remaining) = ExtractMatchedPart(chunk, toolPattern);
if (matched == "")
{
var (matchedPrompt, remainingPrompt) = ExtractMatchedPart(chunk, promptPattern);
if (matchedPrompt == "")
{ {
//普通消息文本 type = MessageType.END_TAG,
content = "",
id = (timestamp+3).ToString(),
role = "assistant"
};
callback?.Invoke(endMessageListItem2);
break;
}
try
{
string chunk = llmStreamChat.Choices[0].Delta.Content;
MessageListItem reasonMessageListItem = new ChatMessageItem()
{
content = llmStreamChat.Choices[0].Delta.ResoningContent,
role = "assistant",
type = MessageType.REASON_MESSAGE,
id = (timestamp+2).ToString()
};
Application.Current.Dispatcher.Invoke(() =>
{
callback?.Invoke(reasonMessageListItem);
});
messageContent = chunk;
var (matched, remaining) = ExtractMatchedPart(chunk, toolPattern);
if (matched == "")
{
var (matchedPrompt, remainingPrompt) = ExtractMatchedPart(chunk, promptPattern);
if (matchedPrompt == "")
{
//普通消息文本
MessageListItem chatMessageListItem = new ChatMessageItem()
{
content = remainingPrompt,
role = "assistant",
type = MessageType.CHAT_MESSAGE,
id = timestamp.ToString()
};
Application.Current.Dispatcher.Invoke(() =>
{
callback?.Invoke(chatMessageListItem);
});
}
else
{
//包含Prompt调用请求的消息
MessageListItem chatMessageListItem = new ChatMessageItem()
{
content = remainingPrompt,
role = "assistant",
type = MessageType.CHAT_MESSAGE,
id = timestamp.ToString()
};
callback?.Invoke(chatMessageListItem);
XElement promptUse = XElement.Parse(matchedPrompt);
string promptKey = promptUse.Element("name")?.Value;
string promptArgs = promptUse.Element("arguments")?.Value;
Dictionary<string, string> promptParams = JsonConvert.DeserializeObject<Dictionary<string, string>>(promptArgs);
promptRequests = new List<PromptRequest>();
promptRequests.Add(new PromptRequest()
{
PromptName = promptKey,
PromptArgs = promptParams,
PromptServer = promptServerList.GetPromptServer(promptKey)
});
}
}
else
{
//包含工具调用请求的消息
XElement toolUse = XElement.Parse(matched);
string fullToolName = toolUse.Element("name")?.Value;
string toolArgs = toolUse.Element("arguments")?.Value;
Dictionary<string, object> toolParams = JsonConvert.DeserializeObject<Dictionary<string, object>>(toolArgs);
string serverName = fullToolName.Contains(":") ? fullToolName.Split(':')[0] : fullToolName;
string toolName = fullToolName.Contains(":") ? fullToolName.Split(':')[1] : fullToolName;
McpServer mcpServer = mcpServerList.GetServer(serverName);
//将工具调用请求添加至列表中待一次回答完整后再统一进行调用
MessageListItem chatMessageListItem = new ChatMessageItem() MessageListItem chatMessageListItem = new ChatMessageItem()
{ {
content = remainingPrompt, content = remaining,
role = "assistant", role = "assistant",
type = MessageType.CHAT_MESSAGE, type = MessageType.CHAT_MESSAGE,
id = timestamp.ToString() id = timestamp.ToString()
@ -340,84 +398,43 @@ public class Gateway
{ {
callback?.Invoke(chatMessageListItem); callback?.Invoke(chatMessageListItem);
}); });
} MessageListItem toolMessageListItem = new ToolMessageItem()
else
{
//包含Prompt调用请求的消息
MessageListItem chatMessageListItem = new ChatMessageItem()
{ {
content = remainingPrompt, content = "",
role = "assistant", result = "",
type = MessageType.CHAT_MESSAGE, toolName = toolName,
id = timestamp.ToString() toolParams = toolParams,
role = "user",
type = MessageType.TOOL_MESSAGE,
id = (timestamp+1).ToString(),
status = "loading"
}; };
callback?.Invoke(chatMessageListItem); Application.Current.Dispatcher.Invoke(() =>
XElement promptUse = XElement.Parse(matchedPrompt);
string promptKey = promptUse.Element("name")?.Value;
string promptArgs = promptUse.Element("arguments")?.Value;
Dictionary<string, string> promptParams = JsonConvert.DeserializeObject<Dictionary<string, string>>(promptArgs);
promptRequests = new List<PromptRequest>();
promptRequests.Add(new PromptRequest()
{ {
PromptName = promptKey, callback?.Invoke(toolMessageListItem);
PromptArgs = promptParams,
PromptServer = promptServerList.GetPromptServer(promptKey)
}); });
mcpToolRequests = new List<McpToolRequest>();
McpToolRequest mcpToolRequest = new McpToolRequest()
{
McpServer = mcpServer,
ToolName = toolName,
ToolArgs = toolParams,
};
mcpToolRequests.Add(mcpToolRequest);
} }
} }
else catch (Exception e)
{ {
//包含工具调用请求的消息 Console.WriteLine(e);
XElement toolUse = XElement.Parse(matched); log.Error(e.Message);
string fullToolName = toolUse.Element("name")?.Value;
string toolArgs = toolUse.Element("arguments")?.Value;
Dictionary<string, object> toolParams = JsonConvert.DeserializeObject<Dictionary<string, object>>(toolArgs);
string serverName = fullToolName.Contains(":") ? fullToolName.Split(':')[0] : fullToolName;
string toolName = fullToolName.Contains(":") ? fullToolName.Split(':')[1] : fullToolName;
McpServer mcpServer = mcpServerList.GetServer(serverName);
//将工具调用请求添加至列表中待一次回答完整后再统一进行调用
MessageListItem chatMessageListItem = new ChatMessageItem()
{
content = remaining,
role = "assistant",
type = MessageType.CHAT_MESSAGE,
id = timestamp.ToString()
};
Application.Current.Dispatcher.Invoke(() =>
{
callback?.Invoke(chatMessageListItem);
});
MessageListItem toolMessageListItem = new ToolMessageItem()
{
content = "",
result = "",
toolName = toolName,
toolParams = toolParams,
role = "user",
type = MessageType.TOOL_MESSAGE,
id = (timestamp+1).ToString(),
status = "loading"
};
Application.Current.Dispatcher.Invoke(() =>
{
callback?.Invoke(toolMessageListItem);
});
mcpToolRequests = new List<McpToolRequest>();
McpToolRequest mcpToolRequest = new McpToolRequest()
{
McpServer = mcpServer,
ToolName = toolName,
ToolArgs = toolParams,
};
mcpToolRequests.Add(mcpToolRequest);
} }
} }
catch (Exception e) }catch (Exception e)
{ {
Console.WriteLine(e); log.Error(e.Message);
log.Error(e.Message); MessageBox.Show(e.Message, "请求大模型出错");
}
} }
if (messageContent != "") if (messageContent != "")
{ {
messages.Add(new Message messages.Add(new Message
@ -616,85 +633,97 @@ public class Gateway
StringBuilder toolInfos = new StringBuilder(); StringBuilder toolInfos = new StringBuilder();
foreach (McpServer mcpServer in mcpServerList.GetAllServers()) foreach (McpServer mcpServer in mcpServerList.GetAllServers())
{ {
log.Info($"正在列出{mcpServer.Name}中的工具"); try
if (mcpServer is InnerMcpServer)
{ {
InnerMcpServer innerMcpServer = (InnerMcpServer)mcpServer; if (mcpServer is InnerMcpServer)
Type type = Type.GetType("LinkToolAddin.client.tool." + innerMcpServer.Name);
MethodInfo[] methods = type.GetMethods();
foreach (MethodInfo method in methods)
{ {
if (method.IsPublic && method.IsStatic) InnerMcpServer innerMcpServer = (InnerMcpServer)mcpServer;
Type type = Type.GetType("LinkToolAddin.client.tool." + innerMcpServer.Name);
MethodInfo[] methods = type.GetMethods();
foreach (MethodInfo method in methods)
{ {
string methodName = method.Name; if (method.IsPublic && method.IsStatic)
string methodDescription = method.GetCustomAttribute<DescriptionAttribute>()?.Description; {
string methodParamSchema = LinkToolAddin.common.JsonSchemaGenerator.GenerateJsonSchema(method); string methodName = method.Name;
string methodDescription = method.GetCustomAttribute<DescriptionAttribute>()?.Description;
string methodParamSchema = LinkToolAddin.common.JsonSchemaGenerator.GenerateJsonSchema(method);
McpToolDefinition toolDefinition = new McpToolDefinition
{
Tool = new Tool
{
Name = innerMcpServer.Name + ":" + methodName,
Description = methodDescription,
Arguments = methodParamSchema
}
};
XNode node = JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(toolDefinition));
toolInfos.AppendLine(node.ToString());
toolInfos.AppendLine();
}
}
}
else if(mcpServer is SseMcpServer)
{
SseMcpClient client = new SseMcpClient((mcpServer as SseMcpServer).BaseUrl);
IList<McpClientTool> tools = await client.GetToolListAsync();
foreach (McpClientTool tool in tools)
{
string toolName = (mcpServer as SseMcpServer).Name + ":" + tool.Name;
string toolDescription = tool.Description;
string toolParamSchema = tool.JsonSchema.ToString();
McpToolDefinition toolDefinition = new McpToolDefinition McpToolDefinition toolDefinition = new McpToolDefinition
{ {
Tool = new Tool Tool = new Tool
{ {
Name = innerMcpServer.Name + ":" + methodName, Name = toolName,
Description = methodDescription, Description = toolDescription,
Arguments = methodParamSchema Arguments = toolParamSchema
} }
}; };
XNode node = JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(toolDefinition)); toolInfos.AppendLine(JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(toolDefinition)).ToString());
toolInfos.AppendLine(node.ToString()); toolInfos.AppendLine();
}
}else if (mcpServer is StdioMcpServer)
{
StdioMcpClient client = new StdioMcpClient((mcpServer as StdioMcpServer).Command, (mcpServer as StdioMcpServer).Args);
IList<McpClientTool> tools = await client.GetToolListAsync();
foreach (McpClientTool tool in tools)
{
string toolName = (mcpServer as StdioMcpServer).Name + ":" + tool.Name;;
string toolDescription = tool.Description;
string toolParamSchema = tool.JsonSchema.ToString();
McpToolDefinition toolDefinition = new McpToolDefinition
{
Tool = new Tool
{
Name = toolName,
Description = toolDescription,
Arguments = CompressJson(toolParamSchema)
}
};
toolInfos.AppendLine(JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(toolDefinition)).ToString());
toolInfos.AppendLine(); toolInfos.AppendLine();
} }
} }
} }catch (Exception e)
else if(mcpServer is SseMcpServer)
{ {
SseMcpClient client = new SseMcpClient((mcpServer as SseMcpServer).BaseUrl); log.Error(e.Message);
IList<McpClientTool> tools = await client.GetToolListAsync();
foreach (McpClientTool tool in tools)
{
string toolName = (mcpServer as SseMcpServer).Name + ":" + tool.Name;
string toolDescription = tool.Description;
string toolParamSchema = tool.JsonSchema.ToString();
McpToolDefinition toolDefinition = new McpToolDefinition
{
Tool = new Tool
{
Name = toolName,
Description = toolDescription,
Arguments = toolParamSchema
}
};
toolInfos.AppendLine(JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(toolDefinition)).ToString());
toolInfos.AppendLine();
}
}else if (mcpServer is StdioMcpServer)
{
StdioMcpClient client = new StdioMcpClient((mcpServer as StdioMcpServer).Command, (mcpServer as StdioMcpServer).Args);
IList<McpClientTool> tools = await client.GetToolListAsync();
foreach (McpClientTool tool in tools)
{
string toolName = (mcpServer as StdioMcpServer).Name + ":" + tool.Name;;
string toolDescription = tool.Description;
string toolParamSchema = tool.JsonSchema.ToString();
McpToolDefinition toolDefinition = new McpToolDefinition
{
Tool = new Tool
{
Name = toolName,
Description = toolDescription,
Arguments = CompressJson(toolParamSchema)
}
};
toolInfos.AppendLine(JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(toolDefinition)).ToString());
toolInfos.AppendLine();
}
} }
} }
List<UserPrompt> prompts = DynamicPrompt.GetAllPrompts(); List<UserPrompt> prompts = DynamicPrompt.GetAllPrompts();
foreach (UserPrompt userPrompt in prompts) foreach (UserPrompt userPrompt in prompts)
{ {
XNode node = JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(new PromptDefinition(){UserPrompt = userPrompt})); try
toolInfos.AppendLine(node.ToString()); {
toolInfos.AppendLine(); XNode node = JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(new PromptDefinition(){UserPrompt = userPrompt}));
toolInfos.AppendLine(node.ToString());
toolInfos.AppendLine();
}
catch (Exception e)
{
log.Error(e.Message);
}
} }
return toolInfos.ToString(); return toolInfos.ToString();
} }

View File

@ -35,53 +35,53 @@ public class McpServerList
Description = "可以调用进行查询知识库,获取相关参考信息。", Description = "可以调用进行查询知识库,获取相关参考信息。",
IsActive = true IsActive = true
}); });
//servers.Add("filesystem", new StdioMcpServer() servers.Add("filesystem", new StdioMcpServer()
//{ {
// Name = "filesystem", Name = "filesystem",
// Type = "stdio", Type = "stdio",
// Command = "npx", Command = "npxh",
// Args = new List<string>() Args = new List<string>()
// { {
// "-y", "-y",
// "@modelcontextprotocol/server-filesystem", "@modelcontextprotocol/server-filesystem",
// "D:\\01_Project\\20250305_LinkTool\\20250420_AiDemoProject\\TestData" "D:\\01_Project\\20250305_LinkTool\\20250420_AiDemoProject\\TestData"
// } }
//}); });
//servers.Add("fetch", new StdioMcpServer() servers.Add("fetch", new StdioMcpServer()
//{ {
// Name = "fetch", Name = "fetch",
// Type = "stdio", Type = "stdio",
// Command = "uvx", Command = "uvx",
// Args = new List<string>() Args = new List<string>()
// { {
// "mcp-server-fetch" "mcp-server-fetch"
// } }
//}); });
//servers.Add("bing-search", new StdioMcpServer() servers.Add("bing-search", new StdioMcpServer()
//{ {
// Name = "bing-search", Name = "bing-search",
// Type = "stdio", Type = "stdio",
// Command = "npx", Command = "npx",
// Args = new List<string>() Args = new List<string>()
// { {
// "bing-cn-mcp" "bing-cn-mcp"
// } }
//}); });
//servers.Add("mcp-python-interpreter", new StdioMcpServer() servers.Add("mcp-python-interpreter", new StdioMcpServer()
//{ {
// Name = "mcp-python-interpreter", Name = "mcp-python-interpreter",
// Type = "stdio", Type = "stdio",
// Command = "uvx", Command = "uvx",
// Args = new List<string>() Args = new List<string>()
// { {
// "--native-tls", "--native-tls",
// "mcp-python-interpreter", "mcp-python-interpreter",
// "--dir", "--dir",
// "D:\\01_Project\\20250305_LinkTool\\20250420_AiDemoProject\\TestData", "D:\\01_Project\\20250305_LinkTool\\20250420_AiDemoProject\\TestData",
// "--python-path", "--python-path",
// "C:\\Program Files\\ArcGIS\\Pro\\bin\\Python\\envs\\custom\\python.exe" "C:\\Program Files\\ArcGIS\\Pro\\bin\\Python\\envs\\custom\\python.exe"
// } }
//}); });
} }
public McpServer GetServer(string name) public McpServer GetServer(string name)