首页 > 基础资料 博客日记
AI Chat 封装, SemanticKerne.AiProvider.Unified 已发布
2026-04-17 22:00:01基础资料围观1次
文章AI Chat 封装, SemanticKerne.AiProvider.Unified 已发布分享给大家,欢迎收藏极客资料网,专注分享技术知识
最近项目中需要继承AI对话功能,由于甲方对部署方式不确定,所以云端和本地部署我们都实验了,用的Microsoft Semantic Kernel ,但是官方的SDK对非标准OpenAI协议的适配做的不够好,所以我自己基于它重新小小封装了一下。
SemanticKerne.AiProvider.Unified
基于 Microsoft Semantic Kernel 的统一 AI 服务提供者封装库,支持多种 AI 服务商(OpenAI、Ollama、DashScope),提供流式聊天、MCP 插件、工具调用等功能。
特性
- 🚀 多服务商支持:统一接口支持 OpenAI、Ollama、DashScope(阿里云)
- 🧠 思考过程输出:支持模型的思考过程流式输出(reasoning_content)
- 🔧 工具调用:支持 MCP(Model Context Protocol)插件和自定义工具
- ⚙️ 灵活配置:所有参数可通过配置文件或代码自定义
- 📦 开箱即用:完整的依赖注入支持,快速集成到 ASP.NET Core 项目
- 🔍 真正流式:基于 SSE 的实时流式输出,低延迟
安装
dotnet add package SemanticKerne.AiProvider.Unified
快速开始
1. 配置文件(appsettings.json)
{
"SemanticKernel": {
"AiServiceType": "dashscope",
"ModelId": "qwen3.6-plus-2026-04-02",
"Endpoint": "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions",
"ApiKey": "sk-your-api-key-here",
"HttpClientTimeout": "00:05:00",
"ExtensionData": {
"enable_thinking": true,
"preserve_thinking": true,
"temperature": 0.7,
"max_tokens": 4096
}
},
"Mcp": {
"Enabled": true,
"Servers": [
{
"Name": "sql-mcp-http",
"Enabled": true,
"Description": "Data API Builder MCP 服务",
"Transport": "http",
"Endpoint": "http://localhost:5000/mcp",
"TimeoutSeconds": 30
}
]
}
}
2. 服务注册(Program.cs)
using Microsoft.Extensions.Options;
using SemanticKerne.AiProvider.Unified.Models;
using SemanticKerne.AiProvider.Unified.Services;
using SemanticKerne.AiProvider.Unified.Services.Mcp;
var builder = WebApplication.CreateBuilder(args);
// 注册 SemanticKernelOptions 配置
builder.Services.Configure<SemanticKernelOptions>(
builder.Configuration.GetSection("SemanticKernel"));
builder.Services.AddSingleton<ISemanticKernelService, SemanticKernelService>();
builder.Services.AddSingleton<ISessionManager, SessionManager>();
builder.Services.AddSingleton<BailianErrorHandler>();
// 注册 MCP 服务
builder.Services.AddHttpClient();
builder.Services.AddSingleton<IMcpClientService, McpClientService>(sp =>
{
var httpClientFactory = sp.GetRequiredService<IHttpClientFactory>();
var logger = sp.GetRequiredService<ILogger<McpClientService>>();
return new McpClientService(httpClientFactory, logger, builder.Configuration);
});
var app = builder.Build();
app.Run();
3. 使用示例
/// <summary>
/// 聊天控制器
/// </summary>
[ApiController]
[Route("api/[controller]")]
public class ChatController : ControllerBase
{
private readonly ISessionManager _sessionManager;
private readonly ISemanticKernelService _kernelService;
private readonly ILogger<ChatController> _logger;
private readonly BailianErrorHandler _errorHandler;
public ChatController(
ISessionManager sessionManager,
ISemanticKernelService kernelService,
ILogger<ChatController> logger,
BailianErrorHandler errorHandler)
{
_sessionManager = sessionManager;
_kernelService = kernelService;
_logger = logger;
_errorHandler = errorHandler;
}
private string UserId => User.FindFirst(ClaimTypes.Name)?.Value ?? "test-user";
/// <summary>
/// 获取当前用户的所有会话
/// </summary>
[HttpGet("sessions")]
public IActionResult GetSessions()
{
_logger.LogInformation("GetSessions called, UserId: {UserId}, AllClaims: {Claims}",
UserId,
string.Join(", ", User.Claims.Select(c => $"{c.Type}={c.Value}")));
var sessions = _sessionManager.GetUserSessions(UserId);
_logger.LogInformation("GetSessions result, count: {Count}", sessions.Count());
return Ok(sessions);
}
/// <summary>
/// 创建新的聊天会话
/// </summary>
[HttpPost("sessions")]
public IActionResult CreateSession()
{
_logger.LogInformation("CreateSession called, UserId: {UserId}", UserId);
var session = _sessionManager.CreateSession(UserId);
_logger.LogInformation("CreateSession created, SessionId: {SessionId}, UserId: {UserId}", session.SessionId, UserId);
return Ok(new CreateSessionResponse
{
SessionId = session.SessionId,
CreatedAt = session.CreatedAt
});
}
/// <summary>
/// 删除指定的聊天会话
/// </summary>
[HttpDelete("sessions/{sessionId}")]
public IActionResult DeleteSession(string sessionId)
{
_logger.LogInformation("DeleteSession called, UserId: {UserId}, SessionId: {SessionId}", UserId, sessionId);
var result = _sessionManager.DeleteSession(UserId, sessionId);
if (!result)
{
_logger.LogWarning("DeleteSession failed, session not found, UserId: {UserId}, SessionId: {SessionId}", UserId, sessionId);
return NotFound(new { message = "会话不存在" });
}
return NoContent();
}
/// <summary>
/// 停止会话当前正在进行的请求(不删除会话)
/// </summary>
[HttpPost("sessions/{sessionId}/stop")]
public IActionResult StopSession(string sessionId)
{
var session = _sessionManager.GetSession(UserId, sessionId);
_logger.LogInformation("StopSession called, UserId: {UserId}, SessionId: {SessionId}, SessionExists: {Exists}, IsProcessing: {IsProcessing}",
UserId, sessionId, session != null, session?.IsProcessing);
var result = _sessionManager.StopSession(UserId, sessionId);
_logger.LogInformation("StopSession result: {Result}", result);
if (!result)
{
return NotFound(new { message = "会话不存在或没有正在进行的请求" });
}
return Ok(new { message = "已停止当前请求" });
}
/// <summary>
/// 发送消息并获取流式响应(SSE)
/// </summary>
[HttpPost("sessions/{sessionId}/chat")]
public async Task Chat(string sessionId, [FromBody] ChatRequest request, CancellationToken cancellationToken)
{
var session = _sessionManager.GetSession(UserId, sessionId);
if (session == null)
{
Response.StatusCode = 404;
await Response.WriteAsync("会话不存在");
return;
}
// 设置 SSE 响应头
Response.ContentType = "text/event-stream";
Response.Headers.CacheControl = "no-cache";
Response.Headers.Connection = "keep-alive";
try
{
await foreach (var response in _kernelService.StreamChatAsync(session, request.Message, cancellationToken))
{
// 构建响应对象
if (response.Type == StreamingResponseType.Error)
{
// 错误响应,包含详细错误信息
var errorObj = new
{
type = response.Type.ToString().ToLower(),
content = response.Content,
errorCode = response.ErrorCode,
httpStatus = response.HttpStatus,
title = response.ErrorTitle,
reason = response.ErrorReason,
solution = response.ErrorSolution,
isCritical = response.IsCritical
};
var json = JsonSerializer.Serialize(errorObj);
// SSE 格式: data: {json}\n\n
await Response.WriteAsync($"data: {json}\n\n", cancellationToken: cancellationToken);
await Response.Body.FlushAsync(cancellationToken);
break; // 遇到细错类型的响应后停止继续发送
}
else if(response.Type == StreamingResponseType.Exception)
{
// 错误响应,包含详细错误信息
var errorObj = new
{
type = response.Type.ToString().ToLower(),
content = response.Content,
errorCode = response.ErrorCode,
httpStatus = response.HttpStatus,
title = response.ErrorTitle,
reason = response.ErrorReason,
solution = response.ErrorSolution,
isCritical = response.IsCritical
};
var json = JsonSerializer.Serialize(errorObj);
// SSE 格式: data: {json}\n\n
await Response.WriteAsync($"data: {json}\n\n", cancellationToken: cancellationToken);
await Response.Body.FlushAsync(cancellationToken);
break; // 遇到异常类型的响应后停止继续发送
}
else
{
// 普通内容响应
var responseObj = new
{
type = response.Type.ToString().ToLower(),
content = response.Content
};
var json = JsonSerializer.Serialize(responseObj);
// SSE 格式: data: {json}\n\n
await Response.WriteAsync($"data: {json}\n\n", cancellationToken: cancellationToken);
await Response.Body.FlushAsync(cancellationToken);
}
}
// 发送结束标记
await Response.WriteAsync("data: [DONE]\n\n", cancellationToken: cancellationToken);
await Response.Body.FlushAsync(cancellationToken);
}
catch (OperationCanceledException)
{
_logger.LogInformation("客户端断开连接,SessionId: {SessionId}", sessionId);
}
catch (Exception ex)
{
try
{
_logger.LogError(ex, "聊天处理出错,SessionId: {SessionId}", sessionId);
// 使用错误处理器转换异常
var errorInfo = _errorHandler.HandleException(ex);
_logger.LogWarning("错误信息: {ErrorCode} - {Title}: {Reason}",
errorInfo.ErrorCode, errorInfo.Title, errorInfo.Reason);
// 构建用户友好的错误消息
var friendlyErrorMessage = BuildFriendlyErrorMessage(errorInfo);
// 将错误信息作为系统消息添加到会话历史中(不影响AI对后续消息的理解)
session?.History.AddSystemMessage(friendlyErrorMessage);
// 返回错误信息 - 包含用户可读的内容
var errorObj = new
{
type = "error",
content = friendlyErrorMessage, // 使用用户友好的错误消息
errorCode = errorInfo.ErrorCode,
httpStatus = errorInfo.HttpStatus,
title = errorInfo.Title,
reason = errorInfo.Reason,
solution = errorInfo.Solution,
isCritical = errorInfo.IsCritical
};
var json = JsonSerializer.Serialize(errorObj);
await Response.WriteAsync($"data: {json}\n\n", cancellationToken: cancellationToken);
await Response.WriteAsync($"data: [DONE]\n\n", cancellationToken: cancellationToken);
}
catch (Exception innerEx)
{
// 即使错误处理失败,也确保返回一些内容
_logger.LogCritical(innerEx, "错误处理也失败了,SessionId: {SessionId}", sessionId);
try
{
var fallbackError = new
{
type = "error",
content = "系统内部错误,请稍后重试",
errorCode = "InternalError",
httpStatus = 500,
title = "系统错误",
reason = "处理请求时发生内部错误",
solution = "请稍后重试或联系管理员",
isCritical = true
};
var fallbackJson = JsonSerializer.Serialize(fallbackError);
await Response.WriteAsync($"data: {fallbackJson}\n\n", cancellationToken: cancellationToken);
await Response.WriteAsync($"data: [DONE]\n\n", cancellationToken: cancellationToken);
}
catch
{
// 如果连回退错误都无法发送,至少尝试发送一个简单的错误
await Response.WriteAsync("data: {\"type\":\"error\",\"content\":\"系统错误\"}\n\n", cancellationToken: cancellationToken);
}
}
}
}
/// <summary>
/// 发送消息并获取完整响应(非流式,便于 Swagger 测试)
/// </summary>
[HttpPost("sessions/{sessionId}/chat/complete")]
public async Task<IActionResult> ChatComplete(string sessionId, [FromBody] ChatRequest request, CancellationToken cancellationToken)
{
var session = _sessionManager.GetSession(UserId, sessionId);
if (session == null)
{
return NotFound(new { message = "会话不存在" });
}
var thinkingContent = new List<string>();
var responseContent = new List<string>();
try
{
await foreach (var response in _kernelService.StreamChatAsync(session, request.Message, cancellationToken))
{
if (response.Type == StreamingResponseType.Thinking)
{
thinkingContent.Add(response.Content);
}
else
{
responseContent.Add(response.Content);
}
}
return Ok(new
{
thinking = thinkingContent.Count > 0 ? string.Join("", thinkingContent) : null,
content = string.Join("", responseContent)
});
}
catch (Exception ex)
{
try
{
_logger.LogError(ex, "聊天处理出错,SessionId: {SessionId}", sessionId);
// 使用错误处理器转换异常
var errorInfo = _errorHandler.HandleException(ex);
_logger.LogWarning("错误信息: {ErrorCode} - {Title}: {Reason}",
errorInfo.ErrorCode, errorInfo.Title, errorInfo.Reason);
// 构建用户友好的错误消息
var friendlyErrorMessage = BuildFriendlyErrorMessage(errorInfo);
// 将错误信息作为系统消息添加到会话历史中(不影响AI对后续消息的理解)
session?.History.AddSystemMessage(friendlyErrorMessage);
return StatusCode(errorInfo.HttpStatus, new
{
type = "error",
content = friendlyErrorMessage, // 使用用户友好的错误消息
errorCode = errorInfo.ErrorCode,
httpStatus = errorInfo.HttpStatus,
title = errorInfo.Title,
reason = errorInfo.Reason,
solution = errorInfo.Solution,
isCritical = errorInfo.IsCritical
});
}
catch (Exception innerEx)
{
// 即使错误处理失败,也确保返回一些内容
_logger.LogCritical(innerEx, "错误处理也失败了,SessionId: {SessionId}", sessionId);
return StatusCode(500, new
{
type = "error",
content = "系统内部错误,请稍后重试",
errorCode = "InternalError",
httpStatus = 500,
title = "系统错误",
reason = "处理请求时发生内部错误",
solution = "请稍后重试或联系管理员",
isCritical = true
});
}
}
}
/// <summary>
/// 获取会话的聊天历史
/// </summary>
[HttpGet("sessions/{sessionId}/history")]
public IActionResult GetHistory(string sessionId)
{
var session = _sessionManager.GetSession(UserId, sessionId);
if (session == null)
{
return NotFound(new { message = "会话不存在" });
}
var history = session.History.Select(msg => new
{
Role = msg.Role.ToString(),
Content = msg.Content
});
return Ok(history);
}
/// <summary>
/// 构建用户友好的错误消息
/// </summary>
private static string BuildFriendlyErrorMessage(BailianErrorMessage errorInfo)
{
// 根据错误类型构建不同的友好消息
var errorType = errorInfo.Category switch
{
BailianErrorCategory.ParameterError => "参数配置问题",
BailianErrorCategory.AuthenticationError => "认证失败",
BailianErrorCategory.PermissionError => "权限不足",
BailianErrorCategory.NotFoundError => "资源不存在",
BailianErrorCategory.RateLimitError => "请求频率过高",
BailianErrorCategory.ServerError => "服务器内部错误",
BailianErrorCategory.FileError => "文件处理问题",
BailianErrorCategory.ValidationError => "输入验证失败",
BailianErrorCategory.QuotaError => "配额不足",
BailianErrorCategory.NetworkError => "网络连接问题",
BailianErrorCategory.ContentError => "内容安全检查失败",
_ => "系统错误"
};
// 添加时间戳和上下文信息
var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
// 构建更详细的错误消息
var isRetryable = !errorInfo.IsCritical;
var retryAdvice = isRetryable ? "您可以稍后重试此操作。" : "此错误无法通过重试解决,请按照解决方案进行操作。";
return $""""
抱歉,处理您的请求时遇到了问题:
**错误类型**: {errorType}
**具体原因**: {errorInfo.Reason}
**解决方案**: {errorInfo.Solution}
**错误代码**: {errorInfo.ErrorCode}
**发生时间**: {timestamp}
**状态**: {(isRetryable ? "可重试" : "严重错误")}
**建议**: {retryAdvice}
如果您已按照解决方案操作但问题仍然存在,请联系系统管理员。
"""";
}
}
配置项说明
必需配置项
| 配置项 | 类型 | 说明 | 示例 |
|---|---|---|---|
AiServiceType |
string | AI 服务类型 | "dashscope", "openai", "ollama" |
ModelId |
string | 模型 ID | "qwen3.6-plus-2026-04-02" |
Endpoint |
string | API 端点地址 | "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions" 只有阿里的url必须使用完全URL |
ApiKey |
string | API 密钥 | "sk-xxx" |
可选配置项
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
HttpClientTimeout |
TimeSpan | 00:05:00 |
HttpClient 超时时间 |
ExtensionData |
Dictionary<string, object> | 见下方 | 扩展配置数据,可自定义 AI 服务参数 |
ExtensionData 默认值
{
"enable_thinking": true,
"preserve_thinking": true
}
ExtensionData 支持的所有配置项【参数效果要看对接的AI是否支持,另外也可自行根据对接的AI进行扩展】
| 配置项 | 类型 | 说明 |
|---|---|---|
enable_thinking |
bool | 是否启用思考过程输出 |
preserve_thinking |
bool | 是否保留思考过程(用于后续分析) |
temperature |
float | 采样温度(0-2),值越高越随机 |
max_tokens |
int | 最大生成 token 数 |
top_p |
float | 核采样参数(0-1) |
frequency_penalty |
float | 频率惩罚(0-2) |
presence_penalty |
float | 存在惩罚(0-2) |
返回数据格式
StreamingResponse 类型说明
StreamingResponse 是包的核心返回类型,包含以下属性:
public class StreamingResponse
{
/// <summary>
/// 响应类型
/// </summary>
public StreamingResponseType Type { get; set; }
/// <summary>
/// 响应内容
/// </summary>
public string Content { get; set; }
/// <summary>
/// 错误码(仅当 Type = Error 时有效)
/// </summary>
public string? ErrorCode { get; set; }
/// <summary>
/// 错误标题(仅当 Type = Error 时有效)
/// </summary>
public string? ErrorTitle { get; set; }
/// <summary>
/// 错误原因(仅当 Type = Error 时有效)
/// </summary>
public string? ErrorReason { get; set; }
/// <summary>
/// 错误解决方案(仅当 Type = Error 时有效)
/// </summary>
public string? ErrorSolution { get; set; }
}
StreamingResponseType 枚举
public enum StreamingResponseType
{
/// <summary>
/// 思考过程(thinking / reasoning_content)
/// </summary>
Thinking,
/// <summary>
/// 正常回答内容
/// </summary>
Content,
/// <summary>
/// 工具调用结果
/// </summary>
ToolResult,
/// <summary>
/// 错误信息
/// </summary>
Error
}
各类型响应示例
1. Thinking - 思考过程
当模型进行推理时,会逐字输出思考过程:
{
"Type": "Thinking",
"Content": "让我先分析一下用户的问题..."
}
前端处理建议:
if (response.Type === 'Thinking') {
// 在侧边栏或单独区域显示思考过程
displayThinking(response.Content);
}
2. Content - 正常回答
模型生成的正常回答内容:
{
"Type": "Content",
"Content": "根据您的问题分析..."
}
前端处理建议:
if (response.Type === 'Content') {
// 添加到聊天主窗口的回答区域
appendToChat(response.Content);
}
3. ToolResult - 工具调用结果
当模型调用工具(如 MCP 插件)后返回的执行结果:
{
"Type": "ToolResult",
"Content": "{\"table\": \"users\", \"count\": 150}"
}
前端处理建议:
if (response.Type === 'ToolResult') {
// 可选:显示工具执行状态
showToolExecutionStatus('工具执行完成');
// 工具结果会自动传递给模型继续生成回答
}
4. Error - 错误信息
发生错误时的详细信息:
{
"Type": "Error",
"Content": "API 调用失败,请检查网络连接",
"ErrorCode": "HttpRequestFailed",
"ErrorTitle": "请求失败",
"ErrorReason": "Connection timeout",
"ErrorSolution": "请检查网络配置或稍后重试"
}
前端处理建议:
if (response.Type === 'Error') {
// 显示友好的错误提示
showErrorToast(response);
// 记录错误日志(可选)
logError({
code: response.ErrorCode,
title: response.ErrorTitle,
reason: response.ErrorReason,
solution: response.ErrorSolution
});
}
完整响应流示例
以下是一个完整的流式调用过程示例:
用户输入:"查询数据库中有多少用户"
[Thinking] "让我先分析一下这个问题..."
[Thinking] "这个问题需要调用数据库查询工具..."
[ToolResult] "{\"table\": \"users\", \"count\": 150}"
[Content] "根据数据库查询结果,"
[Content] "当前系统中共有 "
[Content] "**150 个用户**。"
[Content] "这些用户包括管理员、普通用户等不同角色..."
前端渲染效果:
🤔 [思考过程] 让我先分析一下这个问题...
🤔 [思考过程] 这个问题需要调用数据库查询工具...
🔧 [工具执行] 调用成功,返回 150 条记录
🤖 [回答] 根据数据库查询结果,当前系统中共有 **150 个用户**。
服务商配置示例
OpenAI
{
"SemanticKernel": {
"AiServiceType": "openai",
"ModelId": "gpt-4",
"Endpoint": "https://api.openai.com/v1",
"ApiKey": "sk-xxx",
"ExtensionData": {
"temperature": 0.7,
"max_tokens": 4096
}
}
}
Ollama
{
"SemanticKernel": {
"AiServiceType": "ollama",
"ModelId": "qwen3.5:9b",
"Endpoint": "http://localhost:11434",
"ApiKey": "",
"ExtensionData": {
"enable_thinking": true
}
}
}
DashScope(阿里云)
{
"SemanticKernel": {
"AiServiceType": "dashscope",
"ModelId": "qwen3.6-plus-2026-04-02",
"Endpoint": "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions",
"ApiKey": "sk-xxx",
"HttpClientTimeout": "00:10:00",
"ExtensionData": {
"enable_thinking": true,
"preserve_thinking": true,
"temperature": 0.7,
"top_p": 0.9
}
}
}
环境变量配置
支持使用环境变量覆盖配置(适用于 Docker、K8s 等环境):
# Linux/Mac
export SemanticKernel__ApiKey="sk-new-api-key"
export SemanticKernel__HttpClientTimeout="00:10:00"
export SemanticKernel__ExtensionData__enable_thinking=true
# Windows
set SemanticKernel__ApiKey=sk-new-api-key
set SemanticKernel__HttpClientTimeout=00:10:00
Docker Compose 示例
version: '3.8'
services:
app:
image: your-app:latest
environment:
- SemanticKernel__ApiKey=${AI_API_KEY}
- SemanticKernel__Endpoint=https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions
- SemanticKernel__ModelId=qwen3.6-plus-2026-04-02
- SemanticKernel__AiServiceType=dashscope
- SemanticKernel__HttpClientTimeout=00:10:00
ports:
- "5000:80"
高级用法
1. 自定义工具调用
// 创建自定义插件
public class WeatherPlugin
{
[KernelFunction("get_weather")]
[Description("获取指定城市的天气信息")]
public string GetWeather(
[Description("城市名称")] string city)
{
// 调用天气 API...
return $"天气晴朗,温度 25°C";
}
}
// 注册插件
kernel.Plugins.AddFromType<WeatherPlugin>("Weather");
2. 多会话管理
// 每个会话独立管理历史对话和取消令牌
var session = await _sessionManager.GetOrCreateSessionAsync(sessionId);
session.UserId = userId;
session.History.AddUserMessage(userInput);
// 支持会话级别的取消
session.CancelCurrentRequest();
3. 流式响应前端集成
JavaScript/TypeScript 示例:
async function streamChat(input: string) {
const response = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sessionId: 'session-123',
userInput: input
})
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = JSON.parse(line.slice(6));
handleStreamingResponse(data);
}
}
}
}
function handleStreamingResponse(data: StreamingResponse) {
switch (data.Type) {
case 'Thinking':
updateThinkingPanel(data.Content);
break;
case 'Content':
appendToChatBox(data.Content);
break;
case 'ToolResult':
showToolStatus('工具执行完成');
break;
case 'Error':
showError(data.ErrorTitle, data.Content);
break;
}
}
依赖项
- .NET 8.0
- Microsoft.Extensions.AI (9.10.2)
- Microsoft.SemanticKernel (1.66.0)
- Microsoft.SemanticKernel.Connectors.Ollama (1.66.0-alpha)
- ModelContextProtocol (0.4.0-preview.3)
- OllamaSharp (5.3.5)
兼容性
| 包版本 | .NET 版本 | Semantic Kernel 版本 |
|---|---|---|
| 1.x.x | net8.0 | 1.66.0 |
常见问题
Q: 如何禁用思考过程输出?
在配置文件中设置:
"ExtensionData": {
"enable_thinking": false
}
Q: 如何增加 API 请求超时时间?
"HttpClientTimeout": "00:10:00"
Q: 如何调用自定义工具?
- 创建包含
[KernelFunction]标记的类 - 通过
kernel.Plugins.AddFromType<T>()注册 - 模型会自动识别并调用可用的工具
Q: 支持哪些服务商?
目前支持:
- ✅ OpenAI(包括兼容 OpenAI API 格式的服务商)
- ✅ Ollama(本地部署)
- ✅ DashScope(阿里云通义千问)
更新日志
v1.0.0
- ✨ 初始版本发布
- ✨ 支持 OpenAI、Ollama、DashScope 服务商
- ✨ 支持思考过程流式输出(reasoning_content)
- ✨ 支持 MCP 插件和工具调用
- ✨ 配置化 HttpClient 超时时间
- ✨ 可自定义 ExtensionData 配置项
- ✨ 完整的使用示例和文档
许可证
MIT License - 详见 LICENSE 文件
贡献
欢迎提交 Issue 和 Pull Request!
联系方式
如有问题或建议,请通过以下方式联系:
- 📧 Email: 1374733325@qq.com
- 💬 GitHub Issues: https://github.com/Dean-ZhenYao-Wang/SemanticKerne.AiProvider.Unified/issues
文章来源:https://www.cnblogs.com/wangzhenyao1994/p/19885603
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签:
相关文章
最新发布
- 最小二乘问题详解20:无先验约束下的增量式SFM自由网平差
- 痞子衡嵌入式:大话双核i.MXRT1180之XIP应用里实现可靠Flash IAP的方法
- Atcoder - abc453_d Go Straight
- Windows下右键编辑js文件无法打开记事本——在注册表中使用环境变量
- AI Chat 封装, SemanticKerne.AiProvider.Unified 已发布
- 在后台服务中使用 Scoped 服务,为什么总是报错?
- H200 安装驱动并使用sglang启动模型
- 玩转控件:封装个带图片的Label控件
- Oracle数据库SCN推进技术详解与实践指南
- [A Primer On MC and CC] 2.1 Memory Consistency 1 - 指令重排序和 SC 模型

