动态提示词支持参数,格式与Tool对齐
This commit is contained in:
parent
6f384920a3
commit
d2b18958c1
@ -98,7 +98,6 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="doc\" />
|
|
||||||
<Folder Include="resource\" />
|
<Folder Include="resource\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -1,29 +1,41 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using LinkToolAddin.host;
|
||||||
|
using LinkToolAddin.host.prompt;
|
||||||
|
|
||||||
namespace LinkToolAddin.client.prompt;
|
namespace LinkToolAddin.client.prompt;
|
||||||
|
|
||||||
public class DynamicPrompt
|
public class DynamicPrompt
|
||||||
{
|
{
|
||||||
public static string GetPrompt(string name,Dictionary<string,object> args = null)
|
public static string GetPrompt(string name,Dictionary<string,string> args = null)
|
||||||
{
|
{
|
||||||
PromptTemplates promptTemplate = new PromptTemplates();
|
PromptServerList promptServerList = new PromptServerList();
|
||||||
string template = promptTemplate.GetPrompt(name);
|
string template = promptServerList.GetPromptServer(name).Content;
|
||||||
if (args == null)
|
if (args == null)
|
||||||
{
|
{
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
foreach (KeyValuePair<string,object> pair in args)
|
foreach (KeyValuePair<string,string> pair in args)
|
||||||
{
|
{
|
||||||
string replaceKey = "{{"+pair.Key+"}}";
|
string replaceKey = "{{"+pair.Key+"}}";
|
||||||
template.Replace(replaceKey, pair.Value.ToString());
|
template = template.Replace(replaceKey, pair.Value.ToString());
|
||||||
}
|
}
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Dictionary<string, string> GetAllPrompts()
|
public static List<UserPrompt> GetAllPrompts()
|
||||||
{
|
{
|
||||||
PromptTemplates promptTemplate = new PromptTemplates();
|
PromptServerList promptServerList = new PromptServerList();
|
||||||
Dictionary<string, string> template = promptTemplate.GetPromptsDict();
|
List<UserPrompt> prompts = new List<UserPrompt>();
|
||||||
return template;
|
Dictionary<string, PromptServer> promptDefinitions = promptServerList.GetPromptsDict();
|
||||||
|
foreach (KeyValuePair<string, PromptServer> pair in promptDefinitions)
|
||||||
|
{
|
||||||
|
prompts.Add(new UserPrompt()
|
||||||
|
{
|
||||||
|
Name = pair.Value.Name,
|
||||||
|
Description = pair.Value.Description,
|
||||||
|
Arguments = pair.Value.Arguments
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return prompts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using LinkToolAddin.host.prompt;
|
||||||
|
|
||||||
namespace LinkToolAddin.client.prompt;
|
namespace LinkToolAddin.client.prompt;
|
||||||
|
|
||||||
|
|||||||
15
doc/TodoList.md
Normal file
15
doc/TodoList.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# 待办事项
|
||||||
|
|
||||||
|
本文档用于记录和跟踪当前阶段待办事项及完成进度
|
||||||
|
|
||||||
|
## 核心程序
|
||||||
|
|
||||||
|
- [ ] 提示词调用完整实现:以面向对象形式取代字典形式,加入参数和描述
|
||||||
|
- [ ] 接入本地文件系统等基础性MCP服务
|
||||||
|
- [ ] Python代码执行的实现
|
||||||
|
- [ ] 适配qwen3、deepseek等推理模型并迁移
|
||||||
|
- [ ] 工具执行错误消息合并为一条
|
||||||
|
|
||||||
|
## 提示词工程
|
||||||
|
|
||||||
|
## 前端交互
|
||||||
@ -204,7 +204,7 @@ public class Gateway
|
|||||||
Dictionary<string, object> promptParams = JsonConvert.DeserializeObject<Dictionary<string, object>>(promptArgs);
|
Dictionary<string, object> promptParams = JsonConvert.DeserializeObject<Dictionary<string, object>>(promptArgs);
|
||||||
string serverName = fullPromptName.Contains(":") ? fullPromptName.Split(':')[0] : fullPromptName;
|
string serverName = fullPromptName.Contains(":") ? fullPromptName.Split(':')[0] : fullPromptName;
|
||||||
string promptName = fullPromptName.Contains(":") ? fullPromptName.Split(':')[1] : fullPromptName;
|
string promptName = fullPromptName.Contains(":") ? fullPromptName.Split(':')[1] : fullPromptName;
|
||||||
string promptRes = DynamicPrompt.GetPrompt(promptName, promptParams);
|
string promptRes = DynamicPrompt.GetPrompt(promptName, null);
|
||||||
messages.Add(new Message
|
messages.Add(new Message
|
||||||
{
|
{
|
||||||
Role = "user",
|
Role = "user",
|
||||||
@ -271,8 +271,9 @@ public class Gateway
|
|||||||
});
|
});
|
||||||
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]*?)<\\/prompt>";
|
string promptPattern = "<prompt>([\\s\\S]*?)<name>([\\s\\S]*?)<\\/name>([\\s\\S]*?)<arguments>([\\s\\S]*?)<\\/arguments>([\\s\\S]*?)<\\/prompt>";
|
||||||
McpServerList mcpServerList = new McpServerList();
|
McpServerList mcpServerList = new McpServerList();
|
||||||
|
PromptServerList promptServerList = new PromptServerList();
|
||||||
int loop = 0;
|
int loop = 0;
|
||||||
string messageContent = ""; //一次请求下完整的response
|
string messageContent = ""; //一次请求下完整的response
|
||||||
while (goOn)
|
while (goOn)
|
||||||
@ -293,7 +294,7 @@ public class Gateway
|
|||||||
};
|
};
|
||||||
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||||
List<McpToolRequest> mcpToolRequests = new List<McpToolRequest>();
|
List<McpToolRequest> mcpToolRequests = new List<McpToolRequest>();
|
||||||
List<string> promptKeys = new List<string>();
|
List<PromptRequest> promptRequests = new List<PromptRequest>();
|
||||||
var (toolMatched, toolRemaining) = ExtractMatchedPart(messageContent, toolPattern);
|
var (toolMatched, toolRemaining) = ExtractMatchedPart(messageContent, toolPattern);
|
||||||
var (promptMatched, promptRemaining) = ExtractMatchedPart(messageContent, promptPattern);
|
var (promptMatched, promptRemaining) = ExtractMatchedPart(messageContent, promptPattern);
|
||||||
if (toolMatched == "" && promptMatched == "" && messageContent != "")
|
if (toolMatched == "" && promptMatched == "" && messageContent != "")
|
||||||
@ -338,7 +339,15 @@ public class Gateway
|
|||||||
callback?.Invoke(chatMessageListItem);
|
callback?.Invoke(chatMessageListItem);
|
||||||
XElement promptUse = XElement.Parse(matchedPrompt);
|
XElement promptUse = XElement.Parse(matchedPrompt);
|
||||||
string promptKey = promptUse.Element("name")?.Value;
|
string promptKey = promptUse.Element("name")?.Value;
|
||||||
promptKeys.Add(promptKey);
|
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
|
else
|
||||||
@ -489,9 +498,9 @@ public class Gateway
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*统一处理本次请求中的Prompt调用需求*/
|
/*统一处理本次请求中的Prompt调用需求*/
|
||||||
foreach (string promptKey in promptKeys)
|
foreach (PromptRequest promptRequest in promptRequests)
|
||||||
{
|
{
|
||||||
string promptContent = DynamicPrompt.GetPrompt(promptKey);
|
string promptContent = DynamicPrompt.GetPrompt(promptRequest.PromptName, promptRequest.PromptArgs);
|
||||||
messages.Add(new Message
|
messages.Add(new Message
|
||||||
{
|
{
|
||||||
Role = "user",
|
Role = "user",
|
||||||
@ -503,7 +512,7 @@ public class Gateway
|
|||||||
toolParams = null,
|
toolParams = null,
|
||||||
type = MessageType.TOOL_MESSAGE,
|
type = MessageType.TOOL_MESSAGE,
|
||||||
status = "success",
|
status = "success",
|
||||||
content = "成功调用提示词:"+promptKey,
|
content = "成功调用提示词:"+promptRequest.PromptName,
|
||||||
id = (timestamp+1).ToString()
|
id = (timestamp+1).ToString()
|
||||||
};
|
};
|
||||||
callback?.Invoke(toolMessageItem);
|
callback?.Invoke(toolMessageItem);
|
||||||
@ -588,17 +597,10 @@ public class Gateway
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<string, string> prompts = DynamicPrompt.GetAllPrompts();
|
List<UserPrompt> prompts = DynamicPrompt.GetAllPrompts();
|
||||||
foreach (KeyValuePair<string, string> prompt in prompts)
|
foreach (UserPrompt userPrompt in prompts)
|
||||||
{
|
{
|
||||||
McpPromptDefinition promptDefinition = new McpPromptDefinition
|
XNode node = JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(new PromptDefinition(){UserPrompt = userPrompt}));
|
||||||
{
|
|
||||||
Prompt = new LinkToolAddin.host.mcp.Prompt
|
|
||||||
{
|
|
||||||
Name = prompt.Key
|
|
||||||
}
|
|
||||||
};
|
|
||||||
XNode node = JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(promptDefinition));
|
|
||||||
toolInfos.AppendLine(node.ToString());
|
toolInfos.AppendLine(node.ToString());
|
||||||
toolInfos.AppendLine();
|
toolInfos.AppendLine();
|
||||||
}
|
}
|
||||||
|
|||||||
40
host/PromptServerList.cs
Normal file
40
host/PromptServerList.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using LinkToolAddin.host.prompt;
|
||||||
|
|
||||||
|
namespace LinkToolAddin.host;
|
||||||
|
|
||||||
|
public class PromptServerList
|
||||||
|
{
|
||||||
|
Dictionary<string, PromptServer> promptServers = new Dictionary<string, PromptServer>();
|
||||||
|
|
||||||
|
public PromptServerList()
|
||||||
|
{
|
||||||
|
promptServers.Add("plan", new PromptServer("plan",
|
||||||
|
"根据用户描述的问题推断出需要使用的ArcGIS Pro工具调用名称列表",
|
||||||
|
"请根据用户所提问题进行工具规划,输出格式为'1.工具2.工具’,如果是ArcGIS Pro的工具,根据用户的具体需求和提供的数据类型," +
|
||||||
|
"判断并列出所有必要的分析步骤和工具,同时严格遵守知识库中“ArcGIS Pro工具调用大全”里“工具调用名称”一列的工具命名规则(例如:analysis.Erase)," +
|
||||||
|
"确保工具名的准确无误,工具与所属工具箱的对应关系正确无误,严格遵循文档规定的格式和大小写。工具的组合顺序优先参考知识库中“ArcGIS Pro的帮助文档”。" +
|
||||||
|
"有一些与分析无关的数据能够进行排除,在选择工具时不受其干扰。"));
|
||||||
|
promptServers.Add("param", new PromptServer("param",
|
||||||
|
"填写ArcGIS Pro工具调用参数,生成规范的可执行的工具调用请求",
|
||||||
|
"根据帮助文档填写工具参数,请你根据“所需调用工具”,参照知识库“ArcGIS Pro工具调用大全”里工具所需的参数顺序进行陈列。" +
|
||||||
|
"列出所需调用工具的名称及其按照“ArcGIS Pro工具调用大全”里“的该工具所需的参数顺序陈列对应的参数。如果跳过了可选参数需要用空字符表示。" +
|
||||||
|
"不能更改所需调用工具的名称。例如:arcpy.analysis.Buffer,不能只写成Buffer。确保格式、参数的完整性和准确性,避免任何遗漏或错误。" +
|
||||||
|
"特别注意,所有参数均应视为字符串类型,即使它们可能代表数字或文件路径。例如问题为:使用地理处理中的\"擦除分析\"工具(Erase),将圆形要素(circle.shp)与方形要素(square.shp)进行空间叠加运算。" +
|
||||||
|
"输出: \"in_features\":\"circle.shp\",\r\n \"erase_features\":\"sqaure.shp\",\r\n \"out_feature_class\":\"res.shp\",\r\n \"cluster_tolerance\":\"1\""));
|
||||||
|
promptServers.Add("code", new PromptServer("code",
|
||||||
|
"生成可运行的arcpy代码",
|
||||||
|
"根据你在多种编程语言、框架、设计模式和最佳实践方面拥有的广泛知识。现在需要根据用户需求生成高质量的代码,并确保语法正确。" +
|
||||||
|
"编写Arcpy代码时必须符合ArcGIS官方文档要求。参考官方文档的方法参数,确保编写正确。"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<string, PromptServer> GetPromptsDict()
|
||||||
|
{
|
||||||
|
return promptServers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PromptServer GetPromptServer(string key)
|
||||||
|
{
|
||||||
|
return promptServers[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
9
host/prompt/PromptDefinition.cs
Normal file
9
host/prompt/PromptDefinition.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace LinkToolAddin.host.prompt;
|
||||||
|
|
||||||
|
public class PromptDefinition
|
||||||
|
{
|
||||||
|
[JsonProperty("prompt")]
|
||||||
|
public UserPrompt UserPrompt { get; set; }
|
||||||
|
}
|
||||||
10
host/prompt/PromptRequest.cs
Normal file
10
host/prompt/PromptRequest.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace LinkToolAddin.host.prompt;
|
||||||
|
|
||||||
|
public class PromptRequest
|
||||||
|
{
|
||||||
|
public PromptServer PromptServer { get; set; }
|
||||||
|
public string PromptName { get; set; }
|
||||||
|
public Dictionary<string, string> PromptArgs { get; set; }
|
||||||
|
}
|
||||||
32
host/prompt/PromptServer.cs
Normal file
32
host/prompt/PromptServer.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace LinkToolAddin.host.prompt;
|
||||||
|
|
||||||
|
public class PromptServer
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public string Arguments { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
|
||||||
|
public PromptServer(string name, string description, string content)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Description = description;
|
||||||
|
Content = content;
|
||||||
|
string pattern = "{{([\\s\\S]*?)}}";
|
||||||
|
var matches = Regex.Matches(content, pattern);
|
||||||
|
StringBuilder args = new StringBuilder();
|
||||||
|
foreach (var match in matches)
|
||||||
|
{
|
||||||
|
string variableName = match.ToString().Replace("{{","").Replace("}}","");
|
||||||
|
string arg = "{ \"" + variableName + "\" : \"type\" : \" string \" }";
|
||||||
|
args.Append(arg);
|
||||||
|
}
|
||||||
|
if (args.ToString() != string.Empty)
|
||||||
|
{
|
||||||
|
Arguments = "{\"type\":\"object\",\"properties\":" + args.ToString() + "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,13 @@
|
|||||||
namespace LinkToolAddin.host.prompt;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace LinkToolAddin.host.prompt;
|
||||||
|
|
||||||
public class UserPrompt
|
public class UserPrompt
|
||||||
{
|
{
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
[JsonProperty("description")]
|
||||||
|
public string Description { get; set; }
|
||||||
|
[JsonProperty("arguments")]
|
||||||
|
public string Arguments { get; set; }
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user