SK入门第一篇(设置baseurl)

2024-01-15 07:52

本文主要是介绍SK入门第一篇(设置baseurl),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

问题说明

之前在一些公众号就看到了关于SK的开发文章,然后说自己也试试看。然后就遇到一个关于如何设置baseurl的问题。啥意思呢?同样是SK,用python语言的话,OpenAI的baseurl是可以直接设置的,但是在C#下没法直接设置。

然后,开始调试,找野路子…

解决方式1

官方案例初始化OpenAIClient的构造函数,只有一个OpenAIKey的参数

但是,可以看到,这个构造函数,其实是调用了另一个构造函数,参数有Endpoint(即baseurl信息)、OpenAIKey,以及OPenAIClientOptions。

这个时候,脑海里有了一个想法,我通过下面的构造函数搞起来不就行了,为了方便后续统一调整,自己搞一个通用类实现

public class OpenAIClientExtend
{/// <summary>/// 创建一个OpenAIClient对象,通过apikey和baseurl/// </summary>/// <param name="openAIApiKey"></param>/// <param name="openAIApiKeyBaseUrl"></param>/// <returns></returns>public static OpenAIClient CreateOpenAIClient(string openAIApiKey, string openAIApiBaseUrl){OpenAIClient openAIClient = new OpenAIClient(new Uri(openAIApiBaseUrl), CreateDelegatedToken(openAIApiKey), new OpenAIClientOptions());return openAIClient;}/// <summary>/// 直接把OPenAIClient代码的相关逻辑拿来,通过apikey生成token/// </summary>/// <param name="token">实际这里是OPenAIKey</param>/// <returns></returns>private static TokenCredential CreateDelegatedToken(string token){var accessToken = new AccessToken(token, DateTimeOffset.Now.AddDays(180));return DelegatedTokenCredential.Create((_, _) => accessToken);}

试了下,发现还是不行啊。。

然后又回到那个构造函数那里,想起来它在调用了另一个构造函数后,其实还写了一句:

_isConfiguredForAzureOpenAI = false;

看字面意思,是否是针对AzureOpenAI设置,默认值是true,那就知道为啥了,不过看了下这个字段是private,那么只能通过反射修改了。

//通过反射冬天修改私有字段,否则按照原来的逻辑,会初始化AzureOpenAI,导致无法使用报错
OpenAIClientExtend.ModifyObj<OpenAIClient>(openAIClient, "_isConfiguredForAzureOpenAI", false);

 具体修改实例类字段的代码如下:

public static void ModifyObj<T>(object obj,string filedName,object newVal)
{Type type = typeof(T);FieldInfo? field = type.GetField(filedName, BindingFlags.NonPublic | BindingFlags.Instance);if (field != null && field.IsPrivate){object? value = field.GetValue(obj); // 获取私有字段的值Console.WriteLine("原始私有字段的值为:" + value);field.SetValue(obj, newVal); // 修改私有字段的值Console.WriteLine("修改后的私有字段的值为:" + field.GetValue(obj));}
}

这个时候,baseurl的设置终于生效了,可以愉快的开始后面的coding了

完整的OPenAIClient初始化代码

public static Kernel CreateKernel()
{OpenAIClient openAIClient = OpenAIClientExtend.CreateOpenAIClient(OPENAI_API_KEY, OPENAI_BASE_URL);//通过反射冬天修改私有字段,否则按照原来的逻辑,会初始化AzureOpenAI,导致无法使用报错OpenAIClientExtend.ModifyObj<OpenAIClient>(openAIClient, "_isConfiguredForAzureOpenAI", false);// Create a kernelvar builder = Kernel.CreateBuilder();// Add a text or chat completion service using either:// builder.Services.AddAzureOpenAIChatCompletion()// builder.Services.AddAzureOpenAITextGeneration()//IServiceCollection serviceCollection = builder.Services.AddLogging(c => c.SetMinimumLevel(LogLevel.Trace).AddDebug());//这里使用的是OpenAI的聊天模型,不太理想,需要改进,更好的方法是在Add方法中实例化大模型对象builder.Services.AddOpenAIChatCompletion("gpt-3.5-turbo", openAIClient);// builder.Services.AddOpenAITextGeneration()builder.Plugins.AddFromType<AuthorEmailPlanner>();builder.Plugins.AddFromType<EmailPlugin>();var kernel = builder.Build();return kernel;
}

解决方式2

隔了有几天,在公众号看到有大佬也提到了这个问题,不过还是大佬技高一筹,解决方式更好,直接上代码。 

    var kernel = Kernel.CreateBuilder()
.AddOpenAIChatCompletion(modelId: "gpt-3.5-turbo",apiKey: Util.OPENAI_API_KEY,httpClient: new HttpClient(new MyOpenAIHandler())
).Build();

可以看到,最后一个参数httpClient即动态设置baseurl的

/// <summary>
/// 自定义baseurl
/// </summary>
class MyOpenAIHandler : DelegatingHandler
{public MyOpenAIHandler(): base(new HttpClientHandler()){}protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken){var newUriBuilder = new UriBuilder(request.RequestUri);newUriBuilder.Scheme = "https";newUriBuilder.Host = "api.xx.com";//newUriBuilder.Port = 21000;request.RequestUri = newUriBuilder.Uri;return base.SendAsync(request, cancellationToken);}
}

测试可用,大概思路,动态修改了原来OPenAI的base地址。

不过和方式1的差别,方式1 直接修改完整地址,方式2在OPenAI地址基础上,修改了http或https标记,修改域名部分,修改端口,即部分修改。

这篇关于SK入门第一篇(设置baseurl)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/608176

相关文章

linux hostname设置全过程

《linuxhostname设置全过程》:本文主要介绍linuxhostname设置全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录查询hostname设置步骤其它相关点hostid/etc/hostsEDChina编程A工具license破解注意事项总结以RHE

Python设置Cookie永不超时的详细指南

《Python设置Cookie永不超时的详细指南》Cookie是一种存储在用户浏览器中的小型数据片段,用于记录用户的登录状态、偏好设置等信息,下面小编就来和大家详细讲讲Python如何设置Cookie... 目录一、Cookie的作用与重要性二、Cookie过期的原因三、实现Cookie永不超时的方法(一)

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务

Qt 设置软件版本信息的实现

《Qt设置软件版本信息的实现》本文介绍了Qt项目中设置版本信息的三种常用方法,包括.pro文件和version.rc配置、CMakeLists.txt与version.h.in结合,具有一定的参考... 目录在运行程序期间设置版本信息可以参考VS在 QT 中设置软件版本信息的几种方法方法一:通过 .pro

MySQL DQL从入门到精通

《MySQLDQL从入门到精通》通过DQL,我们可以从数据库中检索出所需的数据,进行各种复杂的数据分析和处理,本文将深入探讨MySQLDQL的各个方面,帮助你全面掌握这一重要技能,感兴趣的朋友跟随小... 目录一、DQL 基础:SELECT 语句入门二、数据过滤:WHERE 子句的使用三、结果排序:ORDE

PostgreSQL 默认隔离级别的设置

《PostgreSQL默认隔离级别的设置》PostgreSQL的默认事务隔离级别是读已提交,这是其事务处理系统的基础行为模式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一 默认隔离级别概述1.1 默认设置1.2 各版本一致性二 读已提交的特性2.1 行为特征2.2