创建控制台项目
创建 AiHttpClientHandler.cs
public class AiHttpClientHandler : HttpClientHandler
{
private readonly string _uri;
public AiHttpClientHandler(string uri) => _uri = uri.TrimEnd('/');
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
UriBuilder uriBuilder;
if (request.RequestUri?.LocalPath == "/v1/chat/completions")
{
uriBuilder = new UriBuilder(_uri + "/v1/chat/completions");
request.RequestUri = uriBuilder.Uri;
}
else if (request.RequestUri?.LocalPath == "/v1/embeddings")
{
uriBuilder = new UriBuilder(_uri + "/v1/embeddings");
request.RequestUri = uriBuilder.Uri;
}
return await base.SendAsync(request, cancellationToken);
}
}
搜索方法
public class HttpClientFunction(IHttpClientFactory httpClientFactory, IChatCompletionService completionService)
{
private const string BingTemplate = "https://cn.bing.com/search?q={0}";
private const string SystemTemplate =
@"
## 角色:
你是一款专业的搜索引擎助手。你的主要任务是从 Html 根据标签生成 md 的内容,并专注于准确地总结段落的大意,而不包含任何其他多余的信息或解释。
## 能力:
- 解析 html 中标签生成对应的 md。
- 将提取的信息准确地总结为一段简洁的文本。
- 不属于用户提问的数据则不用整理。
## 指南:
- 这是一个完整的 html 标签,您需要根据标签生成对应的 md 格式。
- 只包含关键信息,尽量减少非主要信息的出现。
- 完成总结后,立即向用户提供,不需要询问用户是否满意或是否需要进一步的修改和优化。
";
/// <summary>
/// 搜索用户提出的问题
/// </summary>
[KernelFunction, Description("搜索用户提出的问题")]
public async Task<string> GetAsync(string value)
{
var http = httpClientFactory.CreateClient(nameof(HttpClientFunction));
var html = await http.GetStringAsync(string.Format(BingTemplate, value)).ConfigureAwait(false);
var scriptRegex = new Regex(@"<script[^>]*>[\s\S]*?</script>");
var styleRegex = new Regex(@"<style[^>]*>[\s\S]*?</style>");
var commentRegex = new Regex(@"<!--[\s\S]*?-->");
var headRegex = new Regex(@"<head[^>]*>[\s\S]*?</head>");
var tagAttributesRegex = new Regex(@"<(\w+)(?:\s+[^>]*)?>");
var emptyTagsRegex = new Regex(@"<(\w+)(?:\s+[^>]*)?>\s*</\1>");
html = scriptRegex.Replace(html, "");
html = styleRegex.Replace(html, "");
html = commentRegex.Replace(html, "");
html = headRegex.Replace(html, "");
html = tagAttributesRegex.Replace(html, "<$1>");
html = emptyTagsRegex.Replace(html, "");
var result = await completionService.GetChatMessageContentsAsync(new ChatHistory(SystemTemplate){
new(AuthorRole.User, html),
new(AuthorRole.User, value)
}, new OpenAIPromptExecutionSettings()
{
ModelId = "gpt-3.5-turbo-0125"
});
Console.WriteLine("搜索结果:" + result.FirstOrDefault()?.Content);
return result.FirstOrDefault()?.Content ?? "抱歉,未找到相关信息。";
}
}
该方法根据用户提出的问题搜索相关信息。 利用了 https://cn.bing.com/search?q={0}接口去获取我们需要的信息,然后返回 Html,使用正则表达式将 html 中大部分不需要的内容去掉。
然后我们在将获取的 Html 使用以下提示词进行内容精简。
## 角色:
你是一款专业的搜索引擎助手。你的主要任务是从 Html 根据标签生成 md 的内容,并专注于准确地总结段落的大意,而不包含任何其他多余的信息或解释。
## 能力:
– 解析 html 中标签生成对应的 md。
– 将提取的信息准确地总结为一段简洁的文本。
– 不属于用户提问的数据则不用整理。
## 指南:
– 这是一个完整的 html 标签,您需要根据标签生成对应的 md 格式。
– 只包含关键信息,尽量减少非主要信息的出现。
– 完成总结后,立即向用户提供,不需要询问用户是否满意或是否需要进一步的修改和优化。
添加 Program.cs 查询方法
创建了一个循环,然后我们在循环中获取用户输入的问题,然后我们创建了一个 ChatHistory 对象,这个对象是用来存储我们的对话历史的,然后我们调用 chat.GetStreamingChatMessageContentsAsync 方法。 对话的执行流程是:
1、用户输入问题
2、调用 chat.GetStreamingChatMessageContentsAsync 方法,然后传递 kernel,让它自动调用插件,然后根据用户提问去判断调用哪个插件。
3、返回需要调用的插件。
4、调用插件 HttpClientFunction.GetAsync 方法,然后得到有用的信息。
5、整理信息,返回给用户。
var apiKey = "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
var apiHost = "https://www.openai.com/";
var kernelBuilder = Kernel.CreateBuilder().AddOpenAIChatCompletion(modelId: "gpt-4o", apiKey: apiKey, httpClient: new HttpClient(new AiHttpClientHandler(apiHost)));
kernelBuilder.Services.AddHttpClient();
var kernel = kernelBuilder.Build();
kernel.Plugins.AddFromType<HttpClientFunction>(serviceProvider: kernel.Services);
var chat = kernel.GetRequiredService<IChatCompletionService>();
var openAIPromptExecutionSettings = new OpenAIPromptExecutionSettings()
{
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
};
while (true)
{
Console.WriteLine("请输入您的问题:");
var str = Console.ReadLine();
if (str == "exit")
{
break;
}
if (string.IsNullOrWhiteSpace(str))
{
continue;
}
Console.WriteLine("正在思考中……");
var chatHistory = new ChatHistory();
chatHistory.AddUserMessage(str);
var msg = "";
await foreach (var item in chat.GetStreamingChatMessageContentsAsync(chatHistory, openAIPromptExecutionSettings, kernel))
{
Console.Write(item?.Content);
msg += item?.Content;
}
Console.WriteLine("\r\n");
Console.WriteLine("最终结果:");
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(msg);
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine("\r\n");
Console.WriteLine("回答结束");
Console.WriteLine("\r\n");
}
接下来把程序运行起来查看: