完整接入MCP工具调用流程
This commit is contained in:
parent
b3e2664acd
commit
d9b98df57f
@ -98,6 +98,7 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="doc\" />
|
||||
<Folder Include="resource\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"profiles": {
|
||||
"LinkToolAddin": {
|
||||
"commandName": "Executable",
|
||||
"executablePath": "C:\\Users\\PeterZhong\\AppData\\Local\\Programs\\ArcGIS\\Pro\\bin\\ArcGISPro.exe",
|
||||
"executablePath": "C:\\Program Files\\ArcGIS\\Pro\\bin\\ArcGISPro.exe",
|
||||
"applicationUrl": "https://localhost:5001",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
|
||||
@ -8,7 +8,9 @@ using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using ArcGIS.Desktop.Framework.Dialogs;
|
||||
using LinkToolAddin.client;
|
||||
using LinkToolAddin.client.prompt;
|
||||
using LinkToolAddin.host.llm;
|
||||
@ -23,6 +25,7 @@ using Microsoft.Extensions.AI;
|
||||
using ModelContextProtocol.Client;
|
||||
using ModelContextProtocol.Protocol.Types;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Schema;
|
||||
using Newtonsoft.Json.Schema.Generation;
|
||||
using Tool = LinkToolAddin.host.mcp.Tool;
|
||||
@ -52,8 +55,8 @@ public class Gateway
|
||||
Content = message
|
||||
});
|
||||
bool goOn = true;
|
||||
string pattern = "<tool_use>[\\s\\S]*?<\\/tool_use>";
|
||||
string promptPattern = "<prompt>[\\s\\S]*?<\\/prompt>";
|
||||
string pattern = "^<tool_use>[\\s\\S]*?<\\/tool_use>$";
|
||||
string promptPattern = "^<prompt>[\\s\\S]*?<\\/prompt>$";
|
||||
McpServerList mcpServerList = new McpServerList();
|
||||
while (goOn)
|
||||
{
|
||||
@ -65,6 +68,7 @@ public class Gateway
|
||||
TopP = 1,
|
||||
MaxTokens = 1000,
|
||||
});
|
||||
log.Info(reponse);
|
||||
messages.Add(new Message
|
||||
{
|
||||
Role = "assistant",
|
||||
@ -213,18 +217,20 @@ public class Gateway
|
||||
|
||||
private static async Task<string> GetToolInfos(McpServerList mcpServerList)
|
||||
{
|
||||
int loop = 0;
|
||||
StringBuilder toolInfos = new StringBuilder();
|
||||
foreach (McpServer mcpServer in mcpServerList.GetAllServers())
|
||||
{
|
||||
loop++;
|
||||
if (loop > 3)
|
||||
{
|
||||
MessageBox.Show("达到最大循环次数", "退出循环");
|
||||
break;
|
||||
}
|
||||
if (mcpServer is InnerMcpServer)
|
||||
{
|
||||
string serverName = mcpServer.Name;
|
||||
if (serverName is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Type type = Type.GetType("LinkToolAddin.client.tool." + serverName);
|
||||
Type type2 = Type.GetType("LinkToolAddin.client.tool.ArcGisPro");
|
||||
InnerMcpServer innerMcpServer = (InnerMcpServer)mcpServer;
|
||||
Type type = Type.GetType("LinkToolAddin.client.tool." + innerMcpServer.Name);
|
||||
MethodInfo[] methods = type.GetMethods();
|
||||
foreach (MethodInfo method in methods)
|
||||
{
|
||||
@ -237,12 +243,14 @@ public class Gateway
|
||||
{
|
||||
Tool = new Tool
|
||||
{
|
||||
Name = methodName,
|
||||
Name = innerMcpServer.Name + ":" + methodName,
|
||||
Description = methodDescription,
|
||||
Arguments = methodParamSchema
|
||||
}
|
||||
};
|
||||
toolInfos.AppendLine(JsonConvert.DeserializeXmlNode(JsonConvert.SerializeObject(toolDefinition)).ToString());
|
||||
XNode node = JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(toolDefinition));
|
||||
toolInfos.AppendLine(node.ToString());
|
||||
toolInfos.AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -252,7 +260,7 @@ public class Gateway
|
||||
IList<McpClientTool> tools = await client.GetToolListAsync();
|
||||
foreach (McpClientTool tool in tools)
|
||||
{
|
||||
string toolName = tool.Name;
|
||||
string toolName = (mcpServer as SseMcpServer).Name + ":" + tool.Name;
|
||||
string toolDescription = tool.Description;
|
||||
string toolParamSchema = tool.JsonSchema.ToString();
|
||||
McpToolDefinition toolDefinition = new McpToolDefinition
|
||||
@ -265,6 +273,7 @@ public class Gateway
|
||||
}
|
||||
};
|
||||
toolInfos.AppendLine(JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(toolDefinition)).ToString());
|
||||
toolInfos.AppendLine();
|
||||
}
|
||||
}else if (mcpServer is StdioMcpServer)
|
||||
{
|
||||
@ -272,7 +281,7 @@ public class Gateway
|
||||
IList<McpClientTool> tools = await client.GetToolListAsync();
|
||||
foreach (McpClientTool tool in tools)
|
||||
{
|
||||
string toolName = tool.Name;
|
||||
string toolName = (mcpServer as StdioMcpServer).Name + ":" + tool.Name;;
|
||||
string toolDescription = tool.Description;
|
||||
string toolParamSchema = tool.JsonSchema.ToString();
|
||||
McpToolDefinition toolDefinition = new McpToolDefinition
|
||||
@ -281,16 +290,25 @@ public class Gateway
|
||||
{
|
||||
Name = toolName,
|
||||
Description = toolDescription,
|
||||
Arguments = toolParamSchema
|
||||
Arguments = CompressJson(toolParamSchema)
|
||||
}
|
||||
};
|
||||
toolInfos.AppendLine(JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(toolDefinition)).ToString());
|
||||
toolInfos.AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
return toolInfos.ToString();
|
||||
}
|
||||
|
||||
public static string CompressJson(string json)
|
||||
{
|
||||
// 解析JSON并自动去除无关空白
|
||||
var token = JToken.Parse(json);
|
||||
// 序列化为无格式紧凑字符串
|
||||
return token.ToString(Newtonsoft.Json.Formatting.None);
|
||||
}
|
||||
|
||||
private static string GenerateMethodParamSchema(MethodInfo method)
|
||||
{
|
||||
var generator = new JSchemaGenerator
|
||||
@ -316,8 +334,11 @@ public class Gateway
|
||||
|
||||
paramSchema.Properties.Add(param.Name, typeSchema);
|
||||
}
|
||||
|
||||
return paramSchema.ToString();
|
||||
var settings = new JsonSerializerSettings {
|
||||
Formatting = Newtonsoft.Json.Formatting.None, // 关键设置:禁用缩进和换行
|
||||
NullValueHandling = NullValueHandling.Ignore // 可选:忽略空值
|
||||
};
|
||||
return JsonConvert.SerializeObject(paramSchema, settings);;
|
||||
}
|
||||
|
||||
public static async void TestChatMessage(string message, string model, string gdbPath,
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
public class SystemPrompt
|
||||
{
|
||||
public static string SysPromptTemplate = "现在你是一个精通ArcGIS Pro的专家,请以此身份回答用户的问题。";
|
||||
public static string SysPromptTemplate = "现在你是一个精通ArcGIS Pro的专家,请以此身份回答用户的问题。你有以下工具可以调用{{toolInfos}},用户的数据库路径是{{gdbPath}}。MCP工具调用的格式要求示例:<tool_use>\n <name>search</name>\n <arguments>{\\\"query\\\": \\\"上海 人口\\\"}</arguments>\n</tool_use>";
|
||||
|
||||
public static string ContinuePromptTemplate = "上一个工具执行的结果如下,请据此继续执行";
|
||||
|
||||
|
||||
@ -18,11 +18,20 @@
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="24"/>
|
||||
<RowDefinition Height="24"/>
|
||||
<RowDefinition Height="240"/>
|
||||
</Grid.RowDefinitions>
|
||||
<DockPanel Grid.Row="0" LastChildFill="true" KeyboardNavigation.TabNavigation="Local" Height="30">
|
||||
<Button Content="Test Workflow" Name="TestWorkflow" Click="TestWorkflow_OnClick"></Button>
|
||||
</DockPanel>
|
||||
<Button Grid.Row="0" Content="Test Workflow" Name="TestServer" Click="TestWorkflow_OnClick"></Button>
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.RowDefinitions><RowDefinition Height="24"/></Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox Grid.Row="0" Grid.Column="0" ToolTip="输入测试提示词" Name="PromptTestTextBox"></TextBox>
|
||||
<Button Grid.Row="0" Grid.Column="1" Content="测试" Name="PromptTestButton" Click="PromptTestButton_OnClick"></Button>
|
||||
</Grid>
|
||||
<TextBox Grid.Row="2" ToolTip="大模型回复" Name="ReplyTextBox" TextWrapping="Wrap"></TextBox>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using LinkToolAddin.client;
|
||||
@ -146,12 +147,27 @@ namespace LinkToolAddin.ui.dockpane
|
||||
|
||||
private void TestWorkflow_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Gateway.SendMessage("你有什么工具","qwen-max","test.gdb",ShowMessage);
|
||||
// Gateway.SendMessage("你有什么工具可以调用的?","qwen-max","test.gdb",ShowMessage);
|
||||
Gateway.TestWorkflow("dafdfdgdagdgui","","",AddReply);
|
||||
}
|
||||
|
||||
public void ShowMessage(MessageListItem msg)
|
||||
{
|
||||
log.Info(msg.content);
|
||||
}
|
||||
|
||||
private void PromptTestButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string userPrompt = PromptTestTextBox.Text;
|
||||
Gateway.SendMessage(userPrompt,"qwen-max","C:/Project/test.gdb",AddReply);
|
||||
}
|
||||
|
||||
public void AddReply(MessageListItem msg)
|
||||
{
|
||||
string content = msg.content;
|
||||
log.Info(content);
|
||||
string originContent = ReplyTextBox.Text;
|
||||
ReplyTextBox.Text = originContent + content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ namespace LinkToolAddin.ui.dockpane
|
||||
/// <summary>
|
||||
/// Text shown near the top of the DockPane.
|
||||
/// </summary>
|
||||
private string _heading = "My DockPane";
|
||||
private string _heading = "Test Dockpane";
|
||||
public string Heading
|
||||
{
|
||||
get => _heading;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user