动态提示词支持参数,格式与Tool对齐
This commit is contained in:
parent
6f384920a3
commit
d2b18958c1
@ -98,7 +98,6 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="doc\" />
|
||||
<Folder Include="resource\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@ -1,29 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
using LinkToolAddin.host;
|
||||
using LinkToolAddin.host.prompt;
|
||||
|
||||
namespace LinkToolAddin.client.prompt;
|
||||
|
||||
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();
|
||||
string template = promptTemplate.GetPrompt(name);
|
||||
PromptServerList promptServerList = new PromptServerList();
|
||||
string template = promptServerList.GetPromptServer(name).Content;
|
||||
if (args == null)
|
||||
{
|
||||
return template;
|
||||
}
|
||||
foreach (KeyValuePair<string,object> pair in args)
|
||||
foreach (KeyValuePair<string,string> pair in args)
|
||||
{
|
||||
string replaceKey = "{{"+pair.Key+"}}";
|
||||
template.Replace(replaceKey, pair.Value.ToString());
|
||||
template = template.Replace(replaceKey, pair.Value.ToString());
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
public static Dictionary<string, string> GetAllPrompts()
|
||||
public static List<UserPrompt> GetAllPrompts()
|
||||
{
|
||||
PromptTemplates promptTemplate = new PromptTemplates();
|
||||
Dictionary<string, string> template = promptTemplate.GetPromptsDict();
|
||||
return template;
|
||||
PromptServerList promptServerList = new PromptServerList();
|
||||
List<UserPrompt> prompts = new List<UserPrompt>();
|
||||
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 LinkToolAddin.host.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);
|
||||
string serverName = fullPromptName.Contains(":") ? fullPromptName.Split(':')[0] : 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
|
||||
{
|
||||
Role = "user",
|
||||
@ -271,8 +271,9 @@ public class Gateway
|
||||
});
|
||||
goOn = true;
|
||||
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();
|
||||
PromptServerList promptServerList = new PromptServerList();
|
||||
int loop = 0;
|
||||
string messageContent = ""; //一次请求下完整的response
|
||||
while (goOn)
|
||||
@ -293,7 +294,7 @@ public class Gateway
|
||||
};
|
||||
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
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 (promptMatched, promptRemaining) = ExtractMatchedPart(messageContent, promptPattern);
|
||||
if (toolMatched == "" && promptMatched == "" && messageContent != "")
|
||||
@ -338,7 +339,15 @@ public class Gateway
|
||||
callback?.Invoke(chatMessageListItem);
|
||||
XElement promptUse = XElement.Parse(matchedPrompt);
|
||||
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
|
||||
@ -489,9 +498,9 @@ public class Gateway
|
||||
}
|
||||
}
|
||||
/*统一处理本次请求中的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
|
||||
{
|
||||
Role = "user",
|
||||
@ -503,7 +512,7 @@ public class Gateway
|
||||
toolParams = null,
|
||||
type = MessageType.TOOL_MESSAGE,
|
||||
status = "success",
|
||||
content = "成功调用提示词:"+promptKey,
|
||||
content = "成功调用提示词:"+promptRequest.PromptName,
|
||||
id = (timestamp+1).ToString()
|
||||
};
|
||||
callback?.Invoke(toolMessageItem);
|
||||
@ -588,17 +597,10 @@ public class Gateway
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, string> prompts = DynamicPrompt.GetAllPrompts();
|
||||
foreach (KeyValuePair<string, string> prompt in prompts)
|
||||
List<UserPrompt> prompts = DynamicPrompt.GetAllPrompts();
|
||||
foreach (UserPrompt userPrompt in prompts)
|
||||
{
|
||||
McpPromptDefinition promptDefinition = new McpPromptDefinition
|
||||
{
|
||||
Prompt = new LinkToolAddin.host.mcp.Prompt
|
||||
{
|
||||
Name = prompt.Key
|
||||
}
|
||||
};
|
||||
XNode node = JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(promptDefinition));
|
||||
XNode node = JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(new PromptDefinition(){UserPrompt = userPrompt}));
|
||||
toolInfos.AppendLine(node.ToString());
|
||||
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
|
||||
{
|
||||
|
||||
[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