Ben.SemanticKernel
                             
                            
                                5.3.1
                            
                        
                    dotnet add package Ben.SemanticKernel --version 5.3.1
NuGet\Install-Package Ben.SemanticKernel -Version 5.3.1
<PackageReference Include="Ben.SemanticKernel" Version="5.3.1" />
<PackageVersion Include="Ben.SemanticKernel" Version="5.3.1" />
<PackageReference Include="Ben.SemanticKernel" />
paket add Ben.SemanticKernel --version 5.3.1
#r "nuget: Ben.SemanticKernel, 5.3.1"
#:package Ben.SemanticKernel@5.3.1
#addin nuget:?package=Ben.SemanticKernel&version=5.3.1
#tool nuget:?package=Ben.SemanticKernel&version=5.3.1
Ben.SemanticKernel 完整指南
基于 Microsoft Semantic Kernel 的企业级 AI Agent 框架
版本: v3.0 (ReAct Agent)
更新时间: 2025-10-24
.NET 版本: 8.0
📑 目录
1. 项目概览
1.1 项目简介
Ben.SemanticKernel 是一个生产级的 .NET AI Agent 框架,提供完整的 ReAct(Reasoning + Acting)模式实现、智能联网搜索、知识库管理和企业工具集成能力。
核心亮点:
- ✅ ReAct Agent 模式:完整的 Planning → Action → Observation 循环
- ✅ 深度思考可见:捕获 DeepSeek/OpenAI o1 的 reasoning_content
- ✅ 智能分支选择:自动判断简单/复杂问题,优化执行策略
- ✅ 企业级搜索:多引擎聚合(百度/Bing/Google)+ 语义重排
- ✅ 专业 API 集成:天气(和风/OpenWeatherMap)、可扩展股票/新闻
- ✅ MCP 工具支持:Model Context Protocol 企业工具集成
- ✅ 知识库 RAG:向量检索(Qdrant/PgVector)+ 知识图谱
1.2 技术栈
| 组件 | 技术 | 版本 | 
|---|---|---|
| 框架 | Microsoft Semantic Kernel | 1.66.0 | 
| 运行时 | .NET | 8.0 | 
| AI 模型 | DeepSeek / OpenAI / Ollama | - | 
| 向量数据库 | Qdrant / PostgreSQL (pgvector) | - | 
| 浏览器自动化 | Playwright | 1.x | 
| 弹性策略 | Polly | 8.x | 
1.3 架构演进
v1.0 预检索 RAG (2024 Q1)
├─ 用户问题 → 系统强制搜索 → 注入结果 → LLM 生成
└─ ❌ 总是搜索,浪费资源;无深度思考
v2.0 简单 Agent RAG (2024 Q3)
├─ 用户问题 → LLM 自主决策 → 自动执行工具 → 返回结果
└─ ✅ LLM 自主决策  ❌ 思考不可见,无迭代
v3.0 ReAct Agent (2025 Q1) ⭐ 当前版本
├─ Planning → Action → Observation → Planning → ...
├─ ✅ 深度思考完全可见 (reasoning_content)
├─ ✅ 决策链透明 (planning/action/observation)
├─ ✅ 多轮迭代支持 (最多10次)
└─ ✅ 智能分支选择 (简单问题快速响应)
2. 快速开始 (10分钟)
2.1 环境要求
- ✅ .NET 8.0 SDK 或更高版本
- ✅ AI 服务 API Key (DeepSeek/OpenAI/Ollama)
- ⚡ 可选:Playwright(联网搜索)
- ⚡ 可选:Qdrant/PostgreSQL(知识库)
2.2 三步启动
步骤 1:安装 Playwright(可选,用于联网搜索)
cd Ben.SemanticKernel
.\install-playwright.ps1
步骤 2:配置 appsettings.json
{
  "BEN_SK": {
    "AIConfig": {
      "TextInfo": {
        "ApiKey": "sk-your-api-key",
        "Model": "deepseek-chat",
        "BaseUri": "https://api.deepseek.com",
        "Provider": "openai"
      },
      "EmbeddingInfo": {
        "ApiKey": "sk-your-api-key",
        "Model": "text-embedding-3-small",
        "BaseUri": "https://api.openai.com/v1",
        "Provider": "openai",
        "VectorSize": 1536,
        "Index": "default"
      }
    }
  }
}
步骤 3:运行示例项目
# 编译项目
dotnet build -c Release
# 启动 Web 服务
cd Ben.Examples
dotnet run
预期输出:
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
2.3 快速测试
使用 REST Client 或 curl 测试:
POST http://localhost:5000/api/Chat/Chat
Content-Type: application/json
{
  "sessionId": 1,
  "text": "今天深圳天气怎么样?",
  "networking": true
}
预期响应(SSE 流式):
data: {"type":"thinking","data":"用户询问今天深圳天气,需要使用工具..."}
data: {"type":"planning","data":{"name":"search_weather",...}}
data: {"type":"action","data":"执行中..."}
data: {"type":"observation","data":"【深圳天气预报】..."}
data: {"type":"chat","data":"根据最新天气预报[1],深圳今天..."}
data: {"type":"times","data":4850}
data: {"type":"done","data":"done"}
3. 核心架构
3.1 整体架构图
graph TB
    User[用户请求] --> Controller[ChatController]
    Controller --> ChatService[ChatService<br/>核心编排器]
    
    ChatService --> Branch{智能分支选择}
    Branch -->|简单问题| Simple[简单模式<br/>快速响应 < 1s]
    Branch -->|复杂问题| ReAct[ReAct 模式<br/>完整循环]
    
    ReAct --> Loop{迭代循环}
    Loop --> Planning[💭 Planning<br/>决策阶段]
    Planning --> Action[⚡ Action<br/>执行工具]
    Action --> Observation[👁️ Observation<br/>获取结果]
    Observation --> Check{是否需要<br/>继续迭代?}
    Check -->|是| Loop
    Check -->|否| Answer[📢 Final Answer]
    
    Action --> Tools[工具层]
    Tools --> WebSearch[联网搜索]
    Tools --> Weather[天气 API]
    Tools --> MCP[MCP 工具]
    Tools --> KMS[知识库]
    
    WebSearch --> Aggregator[SearchAggregator<br/>多引擎聚合]
    Aggregator --> Baidu[百度]
    Aggregator --> Bing[Bing]
    Aggregator --> Google[Google]
    
    Aggregator --> Reranker[SemanticReranker<br/>语义重排]
    
    Answer --> SSE[SSE 流式输出]
    SSE --> User
3.2 目录结构
Ben.SemanticKernel/
├── AI/                          # AI 核心
│   ├── KernelFactory.cs         # Kernel 工厂(缓存、多提供商)
│   ├── KernelFactory.WebSearch.cs  # 联网搜索工具注册
│   ├── KernelFactory.Mcp.cs     # MCP 工具注册
│   └── MemoryKernelFactory.cs   # 向量检索
│
├── Services/
│   ├── ChatService/
│   │   ├── ChatService.cs       # 🔥 核心对话编排(1768行)
│   │   ├── WebSearchPlugin.cs   # Kernel 插件
│   │   └── ChatServiceExtension.cs  # DI 注册
│   │
│   ├── Common/
│   │   ├── SearchAggregator.cs  # 多引擎聚合
│   │   ├── SemanticReranker.cs  # 语义重排
│   │   ├── WeatherApiService.cs # 天气 API(三层降级)
│   │   ├── BingScraper.cs       # 搜索引擎抓取
│   │   ├── ContentExtractor.cs  # 网页正文提取
│   │   └── QueryClassifier.cs   # 查询分类(6大类)
│   │
│   ├── TextMemory/              # 向量存储
│   ├── KnowledgeGraph/          # 知识图谱
│   ├── Mcp/                     # MCP 服务
│   └── Tools/                   # 工具服务
│
├── Models/                      # 数据模型
├── Prompts/                     # 提示词模板
└── Utils/                       # 工具类
Ben.Examples/                    # 示例 Web 项目
├── Controllers/
│   ├── ChatController.cs        # 🔥 ReAct Agent API
│   ├── McpController.cs         # MCP 测试 API
│   └── KnowledgeController.cs   # 知识库管理
├── appsettings.json             # 配置文件
└── Program.cs                   # 启动入口
3.3 数据流
HTTP 请求 (POST /api/Chat/Chat)
  ↓
ChatController 接收
  ↓
构建系统提示词 + 历史消息
  ↓
ChatService.ChatAsync()
  ├─ IsLikelyNeedingTools("今天深圳天气") → true
  ├─ 用户启用工具 (networking=true) → true
  └─ 选择 ReAct 模式
  ↓
创建 Kernel + 注册 WebSearchPlugin
  ├─ search_web
  ├─ search_weather
  └─ search_news
  ↓
ReAct 循环 - 迭代 1
  ├─ 💭 Planning(非流式调用)
  │   └─ 捕获 reasoning_content → yield "thinking" 事件
  ├─ 检测 FunctionCallContent → search_weather("深圳", 1)
  └─ ⚡ Action:手动执行工具
  ↓
WebSearchPlugin.SearchWeatherAsync()
  ├─ 优先:WeatherApiService.GetWeatherAsync()
  │   ├─ 和风天气 API → 成功 ✅
  │   └─ 失败 → OpenWeatherMap → 失败 → 网页搜索
  └─ 降级:SearchWebAsync(..., extractFullContent: true)
  ↓
网页搜索流程(降级时)
  ├─ SearchAggregator.AggregateAsync()
  │   ├─ 智能引擎选择:百度 + Bing(并行)
  │   ├─ 合并去重:URL 归一化
  │   └─ ContentExtractor 抓取完整正文(Top 5)
  └─ SemanticReranker.RerankAsync()
      └─ Score = 余弦相似度 + 新鲜度 + 质量
  ↓
👁️ Observation:工具结果添加到历史
  ↓
ReAct 循环 - 迭代 2
  ├─ 💭 Planning(再次非流式调用)
  │   └─ 捕获 reasoning_content: "已获取信息,可以回答…"
  ├─ 无 FunctionCall → 最终答案阶段
  └─ 使用 chatResult.Content 伪流式输出(逐字符 3ms)
  ↓
输出完成
  ├─ yield "times" 事件(总耗时)
  ├─ yield "done" 事件
  └─ 触发 onCompletion 回调
4. 功能特性
4.1 ReAct Agent 模式
Planning → Action → Observation 完整循环
// 自动进入 ReAct 模式(系统智能判断)
await chatService.ChatAsync(
    input: "今天深圳天气",
    assistantPrompt: systemPrompt,
    aiOptions: options,
    _history: null,
    netWork: true,                     // 启用联网搜索
    serviceProvider: serviceProvider,  // 必须传递(工具注册)
    enableDeepThinking: true,          // 捕获深度思考
    maxIterations: 10                  // 最大迭代次数
);
控制台输出示例:
================================================================================
🧠 ReAct Agent 模式 - Planning → Action → Observation
================================================================================
📝 用户问题: 今天深圳天气怎么样?
💭 深度思考: 已启用(DeepSeek 兼容)
--------------------------------------------------------------------------------
[智能分支选择]
  - 系统判断需要工具: True
  - 用户启用工具: True
  - 系统自动选择: ReAct 模式(复杂问题)
💭 [Thinking] 用户询问今天深圳的天气,这是实时信息查询...
📋 [Planning] 决定调用工具: search_weather
    参数: {"location":"深圳","days":1}
⚡ [Action] 执行中...
✅ 天气 API 调用成功,返回 1 天预报
【深圳天气预报】来源: 和风天气
📅 10月24日(周四)
   天气: 多云 转 晴
   温度: 25°C ~ 31°C
   风向: 东南风 2级
👁️ [Observation] 工具执行成功
🔄 迭代 2/10
💭 [Thinking] 已获取天气信息,可以回答了...
📢 AI回答: 根据最新天气预报[1],深圳今天(10月24日)天气多云转晴...
⏱️  耗时: 4850ms (4.85秒)
================================================================================
4.2 智能分支选择
自动判断简单/复杂问题,优化执行策略
| 场景 | 判断 | 模式 | 响应时间 | 特点 | 
|---|---|---|---|---|
| "你好" | 简单问题 | 简单模式 | < 1秒 | 不传 tools,真流式,极速响应 | 
| "1+1=?" | 简单问题 | 简单模式 | < 1秒 | 直接回答,无工具调用 | 
| "今天深圳天气" | 复杂问题 | ReAct 模式 | 4-8秒 | 完整流程,思考可见 | 
| "特斯拉股价" | 复杂问题 | ReAct 模式 | 8-12秒 | 多引擎搜索 + 分析 | 
判断规则(IsLikelyNeedingTools):
// ✅ 明确需要工具
if (input.Contains("天气") || input.Contains("新闻") || input.Contains("股票"))
    return true;
// ❌ 明确不需要工具
if (input.Matches(@"^\s*\d+\s*[\+\-\*/]\s*\d+"))  // 简单数学
    return false;
if (input.Matches(@"^(你好|hello|hi)"))  // 打招呼
    return false;
// 🤔 启发式判断
if (input.Length > 50)  // 长问题可能需要工具
    return true;
return input.Length >= 10;  // 保守策略
4.3 联网搜索系统
多引擎聚合 + 语义重排 + 全文抓取
搜索引擎策略
| 策略 | 引擎组合 | 适用场景 | 
|---|---|---|
| smart(推荐) | 智能选择 | 中文→百度+Bing;英文→Google+Bing | 
| baidu | 仅百度 | 中文查询、中国本地信息 | 
| bing | 仅 Bing | 国际信息、平衡搜索 | 
| google | 仅 Google | 学术研究、技术文档 | 
| all | 三引擎全开 | 需要最全面结果(较慢) | 
查询分类(6大类)
public enum QueryCategory
{
    Stock,      // 股票财经 → 东方财富、雪球
    News,       // 新闻资讯 → 全文抓取 + 时间优先
    Weather,    // 天气查询 → 优先天气 API
    Technical,  // 技术问题 → 增加 Google
    Academic,   // 学术研究 → Google + Bing
    General     // 通用查询 → 智能引擎
}
语义重排算法
最终分数 = 基础分 + 加权分
基础分 = Cosine(查询向量, 结果向量)  // 0.0-1.0
加权分 =
  + 标题匹配 × 0.05       // 标题包含关键词
  + 时间新鲜度 × 0.15     // 越新越好(时间敏感查询)
  + 内容质量 × 0.10       // 有 FullContent 优先
内容质量分 =
  + 有 FullContent: 0.5
  + 长度适中 (500-5000字): 0.2
  + ContentQuality 分数: 0.3
4.4 天气 API(三层降级)
search_weather("深圳", 7)
  ↓
① 和风天气 API(推荐)
  ├─ JWT Token 认证(EdDSA 签名)
  ├─ 自动生成 Token + 缓存(15分钟)
  ├─ Gzip 自动解压缩
  ├─ 成功 → 返回详细数据 ✅ (1-2秒)
  └─ 失败 ↓
② OpenWeatherMap API
  ├─ 成功 → 返回详细数据 ✅ (2-3秒)
  └─ 失败 ↓
③ 网页搜索(extractFullContent: true)
  └─ 返回网页抓取内容 ⚠️ (25-30秒)
配置示例:
{
  "WeatherApi": {
    "QWeather": {
      "KeyId": "ABCDE12345",                    // JWT 凭据ID
      "ProjectId": "HE2408041234567",           // 项目ID
      "PrivateKey": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",
      "ApiHost": "https://xxx.qweatherapi.com", // 自定义域名
      "Enabled": true
    },
    "OpenWeather": {
      "ApiKey": "your-openweather-api-key",
      "Enabled": true
    }
  }
}
技术特性:
- ✅ JWT Token:自动生成并缓存(Ed25519 签名)
- ✅ 安全性高:私钥本地保管,无法伪造
- ✅ 自动降级:和风 → OpenWeather → 网页搜索
- ✅ Gzip 压缩:自动解压缩响应数据
- ✅ 详细日志:完整的调试信息输出
详细配置:参见 5.3 和风天气 JWT Token 配置指南
4.5 深度思考捕获
兼容 DeepSeek / OpenAI o1 的 reasoning_content
// 自动捕获并输出
var jsonContent = JsonNode.Parse(ModelReaderWriter.Write(chatResult.InnerContent));
var reasoningNode = jsonContent["choices"]?[0]?["message"]?["reasoning_content"];
if (reasoningNode != null)
{
    var thought = reasoningNode.ToString();
    yield return JsonSerializer.Serialize(new
    {
        data = thought,
        type = "thinking",  // ReAct 模式用 "thinking"
    });
}
SSE 事件流:
{"type":"thinking","data":"用户询问今天深圳天气,这是实时信息查询..."}
{"type":"planning","data":{"name":"search_weather",...}}
{"type":"action","data":"执行中..."}
{"type":"observation","data":"【深圳天气预报】..."}
{"type":"chat","data":"根据最新天气预报[1]..."}
{"type":"times","data":4850}
{"type":"done","data":"done"}
5. 配置说明
5.1 完整配置文件(appsettings.json)
{
  "BEN_SK": {
    "AIConfig": {
      // 🔥 文本生成模型(必需)
      "TextInfo": {
        "ApiKey": "sk-112e82a5f6fa4be89ed223fbf955b565",
        "Model": "deepseek-chat",
        "BaseUri": "https://api.deepseek.com",
        "Provider": "openai"  // openai/deepseek/ollama/azure/grok
      },
      
      // 🔥 向量嵌入模型(知识库必需)
      "EmbeddingInfo": {
        "ApiKey": "sk-112e82a5f6fa4be89ed223fbf955b565",
        "Model": "bge-m3:latest",
        "BaseUri": "http://localhost:11434",
        "Provider": "ollama",
        "VectorSize": 1024,
        "Index": "MES-V002-test",
        
        // 向量数据库连接
        "KmsPoint": "Host=localhost;Port=5432;Username=postgres;Password=admin;Database=mes_vector",
        "VertorType": "pgsql",  // qdrant/pgsql/sqlite
        
        // 检索配置
        "SearchOption": {
          "SearchMinRelevance": 0.5,
          "SearchLimit": 3,
          "NodeDepth": 3,
          "MaxNodes": 300,
          "MaxTokens": 32000
        }
      },
      
      // ⚡ 知识图谱(可选)
      "Neo4j": {
        "Uri": "neo4j://localhost:7687",
        "User": "neo4j",
        "Password": "strongpassword"
      }
    },
    
    // 🔥 MCP 配置(可选)
    "McpConfig": {
      "Enabled": true,
      "DefaultTimeoutSeconds": 30,
      "RetryCount": 3,
      "EnableDebugLogging": true,
      "Servers": [
        {
          "Name": "mes-mcp-server",
          "Type": "http",
          "Url": "http://localhost:5278/api/mcp",
          "Description": "MES系统MCP服务器",
          "Enabled": true,
          "TimeoutSeconds": 60
        }
      ]
    }
  },
  
  // 🔥 天气 API 配置(可选,提升天气查询质量)
  // 推荐使用和风天气 JWT Token 认证(更安全、更稳定)
  "WeatherApi": {
    "QWeather": {
      // JWT Token 认证(推荐)- 需要配置三个参数
      // 步骤1:在控制台 → 项目管理 → 查看项目ID
      "KeyId": "your-credential-id",          // 凭据ID(kid),在控制台获取
      // 步骤2:在控制台 → 项目管理 → 创建凭据(选择 JSON Web Token)
      "ProjectId": "your-project-id",         // 项目ID(sub),在控制台获取  
      // 步骤3:使用 OpenSSL 生成 Ed25519 密钥对(参考文档)
      // 命令:openssl genpkey -algorithm ED25519 -out ed25519-private.pem
      // 将生成的私钥文件内容(包含 BEGIN/END 标记)粘贴到下方
      "PrivateKey": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",  // Ed25519 私钥(PEM格式)
      // "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIOoH...\n-----END PRIVATE KEY-----"
      // 注意:
      // - PrivateKey 必须包含完整的 PEM 格式(包括 -----BEGIN PRIVATE KEY----- 和 -----END PRIVATE KEY-----)
      // - 公钥需要在控制台上传,私钥由你自己保管
      // - JWT 有效期默认 15 分钟,自动缓存重用
      // ⚠️ 如果遇到 404 错误,请检查控制台的自定义域名配置
      // 在控制台 → 项目管理 → 查看【Host】或【API 域名】
      // 如果有自定义域名(如 xxx.qweatherapi.com),请在此配置:
      "ApiHost": "https://xxx.qweatherapi.com", // 自定义域名(可选),在控制台查看
      "Enabled": true
    },
    "OpenWeather": {
      // OpenWeatherMap 备用(降级使用)
      "ApiKey": "your-openweather-api-key",
      "Enabled": true
    }
  },
  
  // 🔥 内容抓取配置(可选)
  "ContentExtraction": {
    "Enabled": true,
    "MaxConcurrent": 3,
    "TimeoutSeconds": 10,
    "MaxContentLength": 5000
  }
}
5.2 支持的 AI 模型提供商
DeepSeek(推荐,支持深度思考)
{
  "TextInfo": {
    "ApiKey": "sk-xxx",
    "Model": "deepseek-chat",
    "BaseUri": "https://api.deepseek.com",
    "Provider": "openai"
  }
}
优势:
- ✅ 支持 reasoning_content(深度思考)
- ✅ 支持 Function Calling
- ✅ 价格低廉(1元/百万token)
- ✅ 完美适配 ReAct 模式
OpenAI GPT-4
{
  "TextInfo": {
    "ApiKey": "sk-xxx",
    "Model": "gpt-4",
    "BaseUri": "https://api.openai.com/v1",
    "Provider": "openai"
  }
}
Ollama(本地模型)
{
  "TextInfo": {
    "ApiKey": "not-needed",
    "Model": "qwen2.5:7b",
    "BaseUri": "http://localhost:11434",
    "Provider": "ollama"
  }
}
安装:
# 下载 Ollama: https://ollama.ai/download
# 启动模型
ollama pull qwen2.5:7b
ollama pull nomic-embed-text
5.3 和风天气 JWT Token 配置指南
和风天气 API 使用 JWT (JSON Web Token) 认证方式,基于 Ed25519 非对称加密算法,提供更高的安全性。
为什么使用 JWT 认证?
| 特性 | API Key | JWT Token | 
|---|---|---|
| 安全性 | ⚠️ 中等(Key 可能泄露) | ✅ 高(私钥本地保管) | 
| 防伪造 | ⚠️ Key 泄露后可被伪造 | ✅ 无法伪造(非对称加密) | 
| 长期支持 | ❌ SDK 5+ 不再支持 | ✅ 官方推荐方式 | 
| 有效期 | 永久有效 | 15分钟(自动续期) | 
配置步骤(5步完成)
步骤 1:注册和风天气账号
- 访问 和风天气开发平台
- 注册并登录账号
- 进入 控制台 - 项目管理
步骤 2:获取项目 ID
- 在项目管理页面,查看或创建一个项目
- 记录项目 ID(10位字符,用作 JWT 的 sub字段)- 示例:HE2408041234567
 
- 示例:
步骤 3:生成 Ed25519 密钥对
使用 OpenSSL 生成 Ed25519 密钥对(推荐 OpenSSL 3.0.1+):
# Windows(使用 PowerShell 或 Git Bash)
# 安装 OpenSSL: winget install --id=OpenSSL.OpenSSL -e
# Linux / macOS
openssl genpkey -algorithm ED25519 -out ed25519-private.pem \
&& openssl pkey -pubout -in ed25519-private.pem > ed25519-public.pem
这将生成两个文件:
- ed25519-private.pem:私钥(⚠️ 请妥善保管,不要泄露)
- ed25519-public.pem:公钥(需要上传到和风天气控制台)
私钥示例(ed25519-private.pem):
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIOoHhOGko015veaBJKAueX90eC3YoxhKi3qaZktu1Dke
-----END PRIVATE KEY-----
公钥示例(ed25519-public.pem):
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAARbeZ5AhklFG4gg1Gx5g5bWxMMdsUd6b2MC4wV0/M9Q=
-----END PUBLIC KEY-----
步骤 4:在控制台创建 JWT 凭据
- 在控制台 → 项目管理中,点击你的项目
- 在凭据区域点击"添加凭据"按钮
- 填写表单:
- 凭据名称:自定义名称(如"生产环境JWT凭据")
- 身份认证方式:选择 JSON Web Token
- 公钥:复制 ed25519-public.pem的全部内容(包括BEGIN/END标记)
 
- 点击"保存"
- 记录生成的凭据 ID(10位字符,用作 JWT 的 kid字段)- 示例:ABCDE12345
 
- 示例:
步骤 5:查看自定义域名(重要)
- 在控制台 → 项目管理 → 点击你的项目
- 查看Host 配置或API 域名
- 记录你的专属域名(每个项目都有独立的域名)
- 示例:https://nm4ewt2hfu.re.qweatherapi.com
- ⚠️ 不是统一的 devapi.qweather.com
 
- 示例:
完整配置示例
{
  "WeatherApi": {
    "QWeather": {
      "KeyId": "ABCDE12345",                    // 步骤4 中的凭据ID
      "ProjectId": "HE2408041234567",           // 步骤2 中的项目ID
      "PrivateKey": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIOoHhOGko015veaBJKAueX90eC3YoxhKi3qaZktu1Dke\n-----END PRIVATE KEY-----",  // 步骤3 中的私钥
      "ApiHost": "https://nm4ewt2hfu.re.qweatherapi.com",  // 步骤5 中的自定义域名
      "Enabled": true
    },
    "OpenWeather": {
      "ApiKey": "your-openweather-api-key",    // 备用选项
      "Enabled": false
    }
  }
}
配置要点
✅ 必须配置:
- KeyId:JWT 类型的凭据ID(不是 API KEY 类型)
- ProjectId:项目ID(在项目管理页面顶部显示)
- PrivateKey:完整的 Ed25519 私钥(包含- BEGIN/END标记)
⚡ 强烈推荐:
- ApiHost:自定义域名(避免 404 错误)
❌ 常见错误:
- 使用了 API KEY 类型的凭据ID(不是 JWT 类型)
- 私钥格式不完整(缺少 BEGIN/END标记)
- 私钥中的 \n换行符丢失(JSON 中必须转义)
- 未配置 ApiHost,使用默认域名导致 404
验证配置
启动应用后,查看控制台输出:
[和风天气] ✅ 成功生成 JWT Token(有效期至 2025-10-27 09:25:12 UTC)
[和风天气] 🔍 方式1:https://nm4ewt2hfu.re.qweatherapi.com + Authorization Header
  (使用自定义域名配置)
[和风天气] ✅ 方式1 请求成功!
[和风天气] ✅ JSON 解析成功!
[和风天气] ✅ 找到城市: 深圳 (ID: 101280601)
[和风天气] ✅ 成功解析 3 天的天气预报
在线验证工具
如果遇到问题,可以使用和风天气官方 JWT 验证工具:
粘贴生成的 JWT Token,点击【验证】:
- ✅ 绿色勾 = JWT 正确
- ❌ 红色叉 = JWT 错误(检查配置)
技术细节
JWT Token 结构:
eyJhbGciOiJFZERTQSIsImtpZCI6IktLQjMyUjQ5VFQifQ.eyJzdWIiOiI0TURXTkE5Rk1RIiwiaWF0IjoxNzYxNTU2MjEyLCJleHAiOjE3NjE1NTcxMTJ9.lwfWmqZlVxy7UzKVai3Rn7EL4oAIjjdl7hofjhm_XvAbP0GX0GXtf2Td9w7n4lyGdP_TiHyFVLouMa45IkQxAg
Header(Base64Url 编码):
{
  "alg": "EdDSA",
  "kid": "KKB32R49TT"
}
Payload(Base64Url 编码):
{
  "sub": "4MDWNA9FMQ",
  "iat": 1761556212,
  "exp": 1761557112
}
Signature(Ed25519 签名,Base64Url 编码)
自动功能:
- ✅ JWT Token 自动生成(Ed25519 签名)
- ✅ Token 缓存(15分钟有效期内重用)
- ✅ Gzip 响应自动解压缩
- ✅ 多端点自动降级(自定义域名 → devapi → geoapi)
相关文档
6. API 接口
6.1 接口清单
| 接口 | 路由 | 方法 | 说明 | 响应格式 | 
|---|---|---|---|---|
| 通用对话 | /api/Chat/Chat | POST | ReAct Agent 模式(详细流程) | SSE | 
| MCP 对话 | /api/Chat/ChatWithMcp | POST | 支持 MCP 工具 + 联网 | SSE | 
| 知识库对话 | /api/Chat/KmsChatCompleteAsync | POST | 基于向量库的 RAG 对话 | SSE | 
6.2 通用对话接口(ReAct Agent)
请求:
POST /api/Chat/Chat
Content-Type: application/json
{
  "sessionId": 123,
  "parentId": null,
  "assistantMessageId": 456,
  "text": "今天深圳天气怎么样?",
  "functionCalls": [],
  "networking": true
}
响应事件类型:
| 事件类型 | 说明 | 示例 | 
|---|---|---|
| thinking | 💭 深度思考(DeepSeek reasoning_content) | "用户询问天气,需要工具..." | 
| planning | 📋 规划阶段(决定调用哪个工具) | {"name":"search_weather",...} | 
| action | ⚡ 行动阶段(执行工具) | "执行中..." | 
| observation | 👁️ 观察阶段(工具结果) | "【深圳天气预报】..." | 
| iteration | 🔄 迭代信息 | "迭代 2/10" | 
| chat | 💬 最终回答(逐 token 流式) | "根据最新天气预报[1]..." | 
| times | ⏱️ 耗时统计(毫秒) | 4850 | 
| done | ✅ 完成标记 | "done" | 
| error | ❌ 错误信息 | {"message":"..."} | 
响应示例(SSE):
data: {"type":"thinking","data":"用户询问今天深圳天气..."}
data: {"type":"planning","data":{"name":"search_weather","arguments":"..."}}
data: {"type":"action","data":"执行中..."}
data: {"type":"observation","data":"【深圳天气预报】来源: 和风天气\n..."}
data: {"type":"chat","data":"根"}
data: {"type":"chat","data":"据"}
data: {"type":"chat","data":"最"}
data: {"type":"chat","data":"新"}
data: {"type":"times","data":4850}
data: {"type":"done","data":"done"}
6.3 MCP 对话接口
请求:
POST /api/Chat/ChatWithMcp
Content-Type: application/json
{
  "message": "查询编号为 WO-2025-001 的生产工单信息",
  "enableMcp": true,
  "enableNetwork": false,
  "searchEngine": "smart",
  "siteFilters": null,
  "systemPrompt": "你是MES系统助手,可以查询生产数据..."
}
适用场景:
- 需要调用企业内部系统(MES/ERP/数据库)
- 同时需要联网搜索补充信息
- 混合使用内外部工具
6.4 前端集成示例
JavaScript (EventSource)
const eventSource = new EventSource('/api/Chat/Chat');
eventSource.onmessage = (event) => {
    const data = JSON.parse(event.data);
    
    switch (data.type) {
        case 'thinking':
            displayThinking(data.data);  // 显示思考过程
            break;
        
        case 'chat':
            appendChatContent(data.data);  // 追加回答内容
            break;
        
        case 'times':
            showElapsedTime(data.data);  // 显示耗时
            break;
        
        case 'done':
            eventSource.close();
            enableInput();  // 启用输入框
            break;
        
        case 'error':
            showError(data.data);
            break;
    }
};
eventSource.onerror = (error) => {
    console.error('SSE 连接错误:', error);
    eventSource.close();
};
Python (requests)
import requests
import json
def chat_stream(message):
    url = "http://localhost:5000/api/Chat/Chat"
    response = requests.post(url, json={"text": message}, stream=True)
    
    for line in response.iter_lines():
        if line and line.startswith(b'data: '):
            data = json.loads(line[6:].decode('utf-8'))
            
            if data['type'] == 'thinking':
                print(f"💭 {data['data']}")
            elif data['type'] == 'chat':
                print(data['data'], end='', flush=True)
            elif data['type'] == 'done':
                print("\n✅ 完成")
                break
# 使用
chat_stream("今天深圳天气怎么样?")
7. ReAct Agent 模式
7.1 什么是 ReAct?
ReAct (Reasoning + Acting) 是一种 AI Agent 模式,结合了推理和行动:
Planning (思考)
   ↓
Action (行动)
   ↓
Observation (观察)
   ↓
Planning (再次思考)
   ↓
... (循环)
   ↓
Final Answer (最终答案)
7.2 实现细节
ToolCallBehavior 策略
if (useReActLoop)
{
    if (enableDeepThinking)
    {
        // 🔥 手动执行工具,保留完整思考过程
        toolBehavior = ToolCallBehavior.EnableKernelFunctions;
    }
    else
    {
        // ⚡ 自动执行工具,快速响应
        toolBehavior = ToolCallBehavior.AutoInvokeKernelFunctions;
    }
}
else
{
    // 简单问题:不传 tools,性能最优
    toolBehavior = null;
}
循环控制
for (int iteration = 1; iteration <= maxIterations; iteration++)
{
    Console.WriteLine($"🔄 迭代 {iteration}/{maxIterations}");
    
    // 1. Planning(非流式调用)
    var chatResult = await chat.GetChatMessageContentAsync(history, settings, kernel);
    
    // 2. 捕获深度思考
    var reasoning = ExtractReasoningContent(chatResult);
    if (!string.IsNullOrEmpty(reasoning))
    {
        yield return JsonSerializer.Serialize(new { type = "thinking", data = reasoning });
    }
    
    // 3. 检测工具调用
    if (chatResult.Items.Any(item => item is FunctionCallContent))
    {
        // 4. Action: 手动执行工具
        var functionResult = await ExecuteFunction(functionCall);
        
        // 5. Observation: 添加结果到历史
        history.Add(new ChatMessageContent
        {
            Role = AuthorRole.Tool,
            Content = functionResult
        });
        
        continue; // 下一轮迭代
    }
    else
    {
        // 6. Final Answer: 伪流式输出
        foreach (char c in chatResult.Content)
        {
            yield return JsonSerializer.Serialize(new { type = "chat", data = c.ToString() });
            await Task.Delay(3);
        }
        break;
    }
}
7.3 对比:三种模式
| 特性 | 简单模式 | AutoInvoke | ReAct (手动执行) | 
|---|---|---|---|
| 工具调用 | ❌ 不支持 | ✅ 自动 | ✅ 手动 | 
| 深度思考 | ⚡ 可能有 | ❌ 不可见 | ✅ 完全可见 | 
| 迭代循环 | ❌ 无 | ❌ 无 | ✅ 支持 | 
| 响应速度 | ⭐⭐⭐⭐⭐ < 1s | ⭐⭐⭐⭐ 4-6s | ⭐⭐⭐ 4-8s | 
| 流程透明 | ❌ 无流程 | ⚠️ 部分可见 | ✅ 完全透明 | 
| 适用场景 | 简单问答 | 中等复杂 | 复杂任务 | 
8. 联网搜索系统
8.1 搜索流程
用户输入: "分析寒武纪2025/10/10股价走势"
  ↓
QueryClassifier.Classify() → Stock
  ↓
生成查询变体(移除日期,简化关键词):
  [1] 寒武纪 股价
  [2] 寒武纪 股票
  [3] 寒武纪 行情
  [4] 寒武纪 最新消息
  ↓
SearchAggregator.AggregateAsync()
  ├─ 智能引擎选择: 百度 + Bing
  ├─ 并行搜索(5个变体 × 2个引擎)
  └─ 合并去重: 18条 → 13条(URL归一化)
  ↓
ContentExtractor.ExtractBatchAsync()(可选)
  └─ 抓取 Top 5 完整网页内容(并发 3)
  ↓
SemanticReranker.RerankAsync()
  ├─ 计算相似度分数
  ├─ 时间新鲜度加权
  ├─ 内容质量加权
  └─ 选出 Top 8 结果
  ↓
返回搜索结果 JSON
8.2 查询优化示例
股票查询
输入: "分析寒武纪2025/10/10股价走势"
ExtractCoreEntity():
  - 移除: "分析|股价|走势|2025/10/10|并给出|策略"
  - 结果: "寒武纪"
BuildStockQueryVariants():
  [1] 寒武纪 股价
  [2] 寒武纪 股票
  [3] 寒武纪 行情
  [4] 寒武纪 最新消息
推荐站点: eastmoney.com, xueqiu.com, finance.sina.com.cn
时间范围: 最近 30 天
天气查询
输入: "深圳近7天天气预报"
ExtractCoreEntity():
  - 移除: "天气|预报|近7天|一周"
  - 结果: "深圳"
BuildWeatherQueryVariants():
  [1] 深圳天气
  [2] 深圳天气预报
  [3] 深圳7天天气预报
  [4] 深圳一周天气预报
优先: 天气 API (和风/OpenWeatherMap)
降级: 网页搜索 + 全文抓取
8.3 内容提取器
智能识别网页类型并提取关键信息
public enum PageType
{
    Weather,      // 天气网站 → 提取温度、湿度、风向
    News,         // 新闻网站 → 提取正文、发布时间
    Encyclopedia, // 百科网站 → 提取定义、描述
    Forum,        // 论坛网站 → 提取问题、回答
    Stock,        // 股票网站 → 提取价格、涨跌
    General       // 通用网站 → 智能提取 <main>/<article>
}
内容质量评分:
int score = 50;  // 基础分
// 长度适中(+20分)
if (length > 500 && length < 5000) score += 20;
// 包含数字(+10分)- 数据类查询
if (Regex.Matches(content, @"\d+").Count > 5) score += 10;
// 包含日期(+10分)- 新鲜度
if (Regex.IsMatch(content, @"\d{4}[年\-/]\d{1,2}")) score += 10;
// 特定类型(+10分)
if (pageType == PageType.Weather) score += 10;
9. MCP 工具集成
9.1 什么是 MCP?
Model Context Protocol (MCP) 是 Anthropic 推出的企业工具集成标准,允许 AI 模型调用外部工具和服务。
9.2 配置 MCP 服务器
appsettings.json:
{
  "BEN_SK": {
    "McpConfig": {
      "Enabled": true,
      "DefaultTimeoutSeconds": 30,
      "RetryCount": 3,
      "Servers": [
        {
          "Name": "mes-mcp-server",
          "Type": "http",
          "Url": "http://localhost:5278/api/mcp",
          "Description": "MES系统MCP服务器",
          "Enabled": true,
          "TimeoutSeconds": 60
        }
      ]
    }
  }
}
9.3 使用 MCP 工具
Program.cs:
var builder = WebApplication.CreateBuilder(args);
// 注册所有服务(包括 MCP)
builder.Services.AddBenSKAllService(builder.Configuration);
var app = builder.Build();
// 🔥 初始化 MCP 服务(重要!)
app.Services.InitializeMcpServices();
app.Run();
调用示例:
POST /api/Chat/ChatWithMcp
Content-Type: application/json
{
  "message": "查询编号为 WO-2025-001 的生产工单信息",
  "enableMcp": true,
  "enableNetwork": false
}
9.4 MCP 工具清单
根据 MES MCP 服务器,可用的工具包括:
| 工具 | 参数 | 说明 | 
|---|---|---|
| query_production_orders | orderId, status, pageSize | 查询生产订单 | 
| query_material_inventory | materialCode, materialName | 查询物料库存 | 
| query_bom_info | productCode, version | 查询BOM信息 | 
| generate_production_report | reportType, startDate, endDate | 生成生产报表 | 
9.5 混合使用(MCP + 联网)
POST /api/Chat/ChatWithMcp
Content-Type: application/json
{
  "message": "搜索深圳今天的天气情况,并记录到系统日志",
  "enableMcp": true,      // 启用 MCP 工具
  "enableNetwork": true,  // 同时启用联网搜索
  "searchEngine": "smart"
}
预期流程:
- AI 调用 search_weather获取天气信息
- AI 调用 MCP 工具 create_system_log保存记录
- 返回完整结果
10. 知识库 RAG
10.1 向量数据库配置
使用 Qdrant
docker run -p 6333:6333 qdrant/qdrant
{
  "EmbeddingInfo": {
    "KmsPoint": "http://localhost:6333",
    "VertorType": "qdrant",
    "Index": "my-knowledge-base"
  }
}
使用 PostgreSQL (pgvector)
docker run -p 5432:5432 -e POSTGRES_PASSWORD=password pgvector/pgvector:pg16
{
  "EmbeddingInfo": {
    "KmsPoint": "Host=localhost;Port=5432;Database=vectors;Username=postgres;Password=password",
    "VertorType": "pgsql",
    "Index": "my-knowledge-base"
  }
}
10.2 导入文档
POST /api/Knowledge/ImportDocument
Content-Type: multipart/form-data
file: document.pdf
indexName: my-knowledge-base
10.3 知识库对话
POST /api/Chat/KmsChatCompleteAsync
Content-Type: application/json
{
  "sessionId": 123,
  "text": "生产车间的工单流程是什么?",
  "networking": false
}
流程:
用户问题: "生产车间的工单流程是什么?"
  ↓
向量检索 (SearchMinRelevance: 0.5, SearchLimit: 3)
  ↓
找到相关文档片段:
  [1] 工单管理流程.pdf - 第3页 (相似度: 0.87)
  [2] 生产作业指导书.docx - 第2章 (相似度: 0.76)
  [3] MES系统操作手册.pdf - 第15页 (相似度: 0.68)
  ↓
拼接文档内容注入提示词
  ↓
LLM 生成回答(基于检索到的内容)
  ↓
返回答案 + 来源标注 [1][2][3]
11. 测试指南
11.1 测试用例(6大类)
1. 股票财经 📈
POST /api/Chat/Chat
Content-Type: application/json
{"text": "分析寒武纪2025/10/10股价走势", "networking": true}
预期:
- 分类: Stock
- 引擎: 百度 + Bing
- 结果: 15-25条(东方财富、雪球、新浪财经)
- 回答: 包含具体数据(价格、涨跌幅)
2. 新闻资讯 📰
POST /api/Chat/Chat
Content-Type: application/json
{"text": "最近一周AI芯片行业新闻", "networking": true}
预期:
- 自动识别为新闻类查询
- 启用全文抓取
- 语义重排优先最新内容
- 回答包含多个来源 [1][2][3]
3. 技术问题 💻
POST /api/Chat/Chat
Content-Type: application/json
{"text": "如何使用C# Semantic Kernel实现RAG", "networking": true}
预期:
- 分类: Technical
- 引擎: 百度 + Bing + Google
- 结果: 技术文档、Stack Overflow、GitHub
4. 学术研究 🎓
POST /api/Chat/Chat
Content-Type: application/json
{"text": "Transformer模型最新研究论文", "networking": true}
预期:
- 引擎: Google + Bing
- 结果: Google Scholar、arXiv
5. 天气查询 ⛅
POST /api/Chat/Chat
Content-Type: application/json
{"text": "今天北京天气", "networking": true}
预期:
- 优先: 和风天气 API(1-2秒)
- 降级: 网页搜索 + 完整内容抓取
- 结果: 包含温度、湿度、风向、降水
6. 通用查询 🔍
POST /api/Chat/Chat
Content-Type: application/json
{"text": "什么是量子计算机", "networking": true}
预期:
- 分类: General
- 引擎: 百度 + Bing
- 结果: 百科、技术博客
11.2 性能基准
| 场景 | 目标时间 | 实际时间 | 状态 | 
|---|---|---|---|
| 简单问题("你好") | < 1秒 | 0.5-0.8秒 | ✅ | 
| 天气查询(API) | < 10秒 | 4-8秒 | ✅ | 
| 天气查询(网页) | < 35秒 | 25-30秒 | ✅ | 
| 新闻查询(全文) | < 35秒 | 28-32秒 | ✅ | 
| 股票查询 | < 15秒 | 8-12秒 | ✅ | 
| 通用搜索 | < 15秒 | 6-10秒 | ✅ | 
11.3 HTTP 测试文件
Ben.Examples/ChatService_AgentRAG测试示例.http
包含完整的测试用例和预期输出示例,涵盖:
- 天气查询(完整 ReAct 流程)
- 简单计算(不需要工具)
- 复杂查询(多次迭代)
- 股票分析(深度思考)
- 禁用联网(对比测试)
12. 开发指南
12.1 依赖注入注册
Program.cs:
using Ben.SemanticKernel.Services;
using Ben.SemanticKernel.Services.ChatService;
using Ben.SemanticKernel.Services.Mcp;
var builder = WebApplication.CreateBuilder(args);
// 🔥 一行注册所有核心服务
builder.Services.AddBenSKAllService(builder.Configuration);
// 或分别注册
// builder.Services.AddChatService(builder.Configuration);    // 对话服务
// builder.Services.AddGraphRagNetService(builder.Configuration);  // 知识图谱
// builder.Services.AddMcpServices(builder.Configuration);    // MCP 服务
builder.Services.AddControllers();
builder.Services.AddHttpContextAccessor();
var app = builder.Build();
// 初始化 MCP 服务(可选但推荐)
app.Services.InitializeMcpServices();
app.MapControllers();
app.Run();
12.2 创建自定义 Kernel 工具
1. 创建插件类:
public class CustomToolPlugin
{
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly ILogger<CustomToolPlugin> _logger;
    public CustomToolPlugin(
        IHttpClientFactory httpClientFactory,
        ILogger<CustomToolPlugin> logger)
    {
        _httpClientFactory = httpClientFactory;
        _logger = logger;
    }
    [KernelFunction("custom_tool")]
    [Description(@"自定义工具的描述,告诉 LLM 何时使用。
用途:具体用途
示例:custom_tool(param='value')")]
    public async Task<string> CustomToolAsync(
        [Description("参数描述")] string param1,
        [Description("可选参数")] string param2 = "default",
        CancellationToken cancellationToken = default)
    {
        try
        {
            _logger.LogDebug($"🔧 LLM 调用自定义工具 - 参数: {param1}");
            // 实现工具逻辑
            var result = await DoSomethingAsync(param1, param2, cancellationToken);
            _logger.LogDebug($"✅ 工具执行成功");
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"工具执行失败: {param1}");
            return $"工具执行失败: {ex.Message}";
        }
    }
}
2. 注册到 DI 容器:
// ChatServiceExtension.cs
services.AddScoped<CustomToolPlugin>();
3. 注册到 Kernel:
// KernelFactory.CustomTools.cs
public static Kernel CreateKernelWithCustomTools(
    AIOptions aiOptions,
    IServiceProvider serviceProvider)
{
    var kernel = CreateKernel(aiOptions);
    var customToolPlugin = serviceProvider.GetRequiredService<CustomToolPlugin>();
    
    kernel.Plugins.AddFromObject(customToolPlugin, "CustomTools");
    
    return kernel;
}
12.3 添加新的搜索引擎
扩展 BingScraper.cs:
private string BuildSearchUrl(string query, string engine, ...)
{
    return engine.ToLower() switch
    {
        "baidu" => BuildBaiduUrl(query, ...),
        "bing" => BuildBingUrl(query, ...),
        "google" => BuildGoogleUrl(query, ...),
        "duckduckgo" => BuildDuckDuckGoUrl(query, ...), // 🆕
        _ => BuildBaiduUrl(query, ...)
    };
}
private string BuildDuckDuckGoUrl(string query, ...)
{
    var encodedQuery = Uri.EscapeDataString(query);
    return $"https://duckduckgo.com/?q={encodedQuery}&t=h_&ia=web";
}
private List<SearchResultDto> ParseDuckDuckGoResults(string html)
{
    // 使用 XPath/CSS 选择器解析
    var results = new List<SearchResultDto>();
    // ...
    return results;
}
12.4 自定义查询分类
编辑 ChatService.cs 的 IsLikelyNeedingTools:
// 添加业务规则
if (Regex.IsMatch(trimmedInput, @"(工单|订单|生产|库存|MES)", RegexOptions.IgnoreCase))
    return true;  // MES 系统查询必须使用工具
if (trimmedInput.Contains("公司制度") || trimmedInput.Contains("内部文档"))
    return false; // 内部文档不需要联网
13. 部署指南
13.1 Docker 容器化
Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["Ben.SemanticKernel/Ben.SemanticKernel.csproj", "Ben.SemanticKernel/"]
COPY ["Ben.Examples/Ben.Examples.csproj", "Ben.Examples/"]
RUN dotnet restore "Ben.Examples/Ben.Examples.csproj"
COPY . .
WORKDIR "/src/Ben.Examples"
RUN dotnet build "Ben.Examples.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Ben.Examples.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
# 安装 Playwright 浏览器(可选)
RUN apt-get update && apt-get install -y wget \
    && playwright install chromium \
    && apt-get clean
ENTRYPOINT ["dotnet", "Ben.Examples.dll"]
docker-compose.yml:
version: '3.8'
services:
  app:
    build: .
    ports:
      - "5000:80"
    environment:
      - BEN_SK__AIConfig__TextInfo__ApiKey=sk-xxx
      - BEN_SK__AIConfig__TextInfo__Model=deepseek-chat
      - BEN_SK__AIConfig__TextInfo__BaseUri=https://api.deepseek.com
    depends_on:
      - qdrant
  qdrant:
    image: qdrant/qdrant
    ports:
      - "6333:6333"
    volumes:
      - qdrant_data:/qdrant/storage
volumes:
  qdrant_data:
13.2 生产环境配置
环境变量:
# AI 配置
BEN_SK__AIConfig__TextInfo__ApiKey=sk-xxx
BEN_SK__AIConfig__TextInfo__Model=deepseek-chat
BEN_SK__AIConfig__TextInfo__BaseUri=https://api.deepseek.com
# 天气 API
WeatherApi__QWeather__ApiKey=your-key
# 日志级别
Logging__LogLevel__Default=Information
Logging__LogLevel__Ben.SemanticKernel=Warning
13.3 横向扩展
无状态设计:
- ✅ ChatService 无状态(历史由调用方管理)
- ✅ Kernel 缓存共享(ConcurrentDictionary 线程安全)
- ✅ PlaywrightHelper Singleton(跨请求共享)
负载均衡:
- 使用 Nginx/Traefik 负载均衡
- Session Sticky 不需要(无状态)
- 数据库连接池(向量库)需要配置
14. 常见问题
Q1: 所有查询返回 0 结果?
症状:
⏳ 开始并行搜索...
   查询 [1] 返回 0 条结果 ⚠️
   查询 [2] 返回 0 条结果 ⚠️
原因 & 解决:
- Playwright 未安装 - cd Ben.SemanticKernel .\install-playwright.ps1
- 验证安装 - playwright --version
Q2: 天气 API 调用失败?
症状 1:401 Unauthorized 或 404 Not Found
⚠️ 天气 API 调用失败: 401 Unauthorized
或
❌ 404 错误:API 端点不存在
解决方案:
- 检查 JWT 配置是否完整 - { "WeatherApi": { "QWeather": { "KeyId": "你的凭据ID", // ← 必须配置(JWT类型) "ProjectId": "你的项目ID", // ← 必须配置 "PrivateKey": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----", // ← 必须包含完整PEM格式 "ApiHost": "https://xxx.qweatherapi.com" // ← 强烈推荐配置 } } }
- 验证 JWT Token 是否有效 - 启动应用,查看控制台输出的 JWT Token
- 访问 https://dev.qweather.com/help/jwt
- 粘贴 Token 并点击【验证】
- ✅ 绿色勾 = 配置正确
- ❌ 红色叉 = 需要检查配置
 
- 常见错误排查 - ❌ KeyId 使用了 API KEY 类型(应该使用 JWT 类型)
- ❌ PrivateKey 格式不完整(缺少 BEGIN/END 标记)
- ❌ 未配置 ApiHost(每个项目有独立域名)
- ❌ 私钥和公钥不匹配
 
- 查看详细日志 - [和风天气] ✅ 成功生成 JWT Token(有效期至 ...) [和风天气] ✅ 方式1 请求成功! [和风天气] ✅ 找到城市: 深圳 (ID: 101280601)
- 自动降级机制 - 即使 API 失败,也会自动降级到 OpenWeatherMap
- 如果 OpenWeatherMap 也失败,会降级到网页搜索
 
详细配置指南:参见 5.3 和风天气 JWT Token 配置指南
Q3: DeepSeek 不显示深度思考?
症状:
- 启用 enableDeepThinking: true
- 控制台无 reasoning_content输出
原因 & 解决:
- 简单问题被优化 - 系统判断为简单问题(如"你好"),不传递 tools
- 这是正常的性能优化
 
- 检查模型配置 - 确保使用 DeepSeek 模型
- 确保 Provider设置正确
 
Q4: Google 搜索失败(中国环境)?
症状:
✗ google 失败: Timeout
解决:
- 使用 Smart 策略(推荐) - engine: "smart" // 中文查询自动避开 Google
- 强制使用百度 - engine: "baidu"
Q5: MCP 工具调用失败?
检查清单:
-  MCP 服务器已启动 (http://localhost:5278/api/mcp)
-  appsettings.json配置正确
-  已调用 app.Services.InitializeMcpServices()
- 查看日志获取详细错误信息
15. 性能优化
15.1 Kernel 缓存
当前实现:
private static readonly ConcurrentDictionary<string, Lazy<Kernel>> Kernels = new();
// 缓存键:Model + Provider + BaseUri + ApiKey(哈希)
var key = $"{textConfig.Model}_{textConfig.BaseUri}_{textConfig.ApiKey}_{textConfig.Provider}";
return Kernels.GetOrAdd(key, _ => new Lazy<Kernel>(() => CreateNewKernel(...))).Value;
优势:
- ✅ 避免重复创建 Kernel(节省 200-500ms)
- ✅ 线程安全(ConcurrentDictionary)
- ✅ 懒加载(Lazy<T>)
15.2 并行搜索
// 查询变体并行(5个查询同时搜索)
var variantTasks = variants.Select(v => SearchSingleVariantAsync(v, engine));
await Task.WhenAll(variantTasks);
// 引擎并行(多个搜索引擎同时抓取)
var engineTasks = engines.Select(e => SearchEngineAsync(query, e));
await Task.WhenAll(engineTasks);
// 全文抓取并发(最多 3 个网页同时抓取)
var semaphore = new SemaphoreSlim(3);
var contentTasks = urls.Select(async url => {
    await semaphore.WaitAsync();
    try { return await ExtractAsync(url); }
    finally { semaphore.Release(); }
});
15.3 智能降级
| 场景 | 降级策略 | 
|---|---|
| 引擎失败 | 使用其他引擎的结果 | 
| 语义重排失败 | 使用原始排序 | 
| 搜索完全失败 | 基于 AI 知识回答 | 
| 天气 API 失败 | 降级网页搜索(全文抓取) | 
15.4 资源管理
| 服务 | 生命周期 | 原因 | 
|---|---|---|
| PlaywrightHelper | Singleton | 避免 ReAct 多轮迭代中释放 | 
| BingScraper | Scoped | 每次请求新实例 | 
| ChatService | Scoped | 每次请求新实例 | 
| HttpClient | 池化管理 | 使用 IHttpClientFactory | 
🎉 总结
Ben.SemanticKernel 提供了一个生产级的 AI Agent 框架:
- ✅ 10分钟快速开始:简单配置即可运行
- ✅ ReAct Agent 模式:完整的 Planning → Action → Observation 循环
- ✅ 深度思考可见:捕获 DeepSeek/OpenAI o1 的 reasoning_content
- ✅ 智能分支选择:简单问题 < 1秒,复杂问题完整流程
- ✅ 企业级搜索:多引擎聚合 + 语义重排 + 全文抓取
- ✅ 专业 API 集成:天气、股票、新闻等垂直领域
- ✅ MCP 工具支持:企业系统无缝集成
- ✅ 知识库 RAG:向量检索 + 知识图谱
- ✅ 开发友好:详细日志、丰富示例、完整文档
现在,开始构建你的智能应用吧! 🚀
📚 相关资源
- GitHub: microsoft/semantic-kernel
- 官方文档: Microsoft Learn - Semantic Kernel
- DeepSeek: api.deepseek.com
- 和风天气: dev.qweather.com
- Playwright: playwright.dev
文档版本: v1.0
更新时间: 2025-10-24
维护者: Ben.SemanticKernel Team
许可证: MIT
| Product | Versions Compatible and additional computed target framework versions. | 
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. | 
- 
                                                    net8.0- BouncyCastle.Cryptography (>= 2.6.2)
- Google.Protobuf (>= 3.30.0)
- HtmlAgilityPack (>= 1.12.1)
- itext7 (>= 9.1.0)
- Microsoft.AspNetCore.Http (>= 2.3.0)
- Microsoft.Data.SqlClient (>= 6.1.0-preview1.25120.4)
- Microsoft.Extensions.Http.Polly (>= 9.0.4)
- Microsoft.KernelMemory.AI.Ollama (>= 0.98.250508.3)
- Microsoft.KernelMemory.AI.OpenAI (>= 0.98.250508.3)
- Microsoft.KernelMemory.Core (>= 0.98.250508.3)
- Microsoft.KernelMemory.MemoryDb.Postgres (>= 0.98.250508.3)
- Microsoft.KernelMemory.MemoryDb.Qdrant (>= 0.98.250508.3)
- Microsoft.Playwright (>= 1.52.0)
- Microsoft.Playwright.NUnit (>= 1.52.0)
- Microsoft.SemanticKernel (>= 1.54.0)
- Microsoft.SemanticKernel.Connectors.Ollama (>= 1.54.0-alpha)
- Microsoft.SemanticKernel.Connectors.PgVector (>= 1.54.0-preview)
- Microsoft.SemanticKernel.Connectors.Qdrant (>= 1.54.0-preview)
- Microsoft.SemanticKernel.Connectors.SqliteVec (>= 1.54.0-preview)
- MySql.Data (>= 9.3.0)
- Polly (>= 8.5.2)
- Polly.Extensions.Http (>= 3.0.0)
- pythonnet (>= 3.1.0-preview2024-09-06)
- Selenium.Support (>= 4.31.0)
- Selenium.WebDriver (>= 4.31.0)
 
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 5.3.1 | 34 | 10/28/2025 | |
| 5.3.0 | 38 | 10/28/2025 | |
| 5.2.29 | 96 | 10/24/2025 | |
| 5.2.28 | 114 | 10/24/2025 | |
| 5.2.27 | 115 | 10/22/2025 | |
| 5.2.26 | 116 | 10/22/2025 | |
| 5.2.25 | 122 | 10/21/2025 | |
| 5.2.24 | 116 | 10/21/2025 | |
| 5.2.23 | 119 | 10/21/2025 | |
| 5.2.22 | 113 | 10/21/2025 | |
| 5.2.21 | 122 | 10/21/2025 | |
| 5.2.20 | 119 | 10/20/2025 | |
| 5.2.19 | 111 | 10/19/2025 | |
| 5.2.18 | 127 | 10/14/2025 | |
| 5.2.17 | 124 | 10/14/2025 | |
| 5.2.16 | 127 | 10/13/2025 | |
| 5.2.15 | 120 | 10/13/2025 | |
| 5.2.13 | 124 | 10/13/2025 | |
| 5.2.12 | 122 | 10/13/2025 | |
| 5.2.11 | 121 | 10/13/2025 | |
| 5.2.10 | 63 | 10/11/2025 | |
| 5.2.9 | 122 | 10/7/2025 | |
| 5.2.8 | 121 | 10/7/2025 | |
| 5.2.7 | 123 | 10/7/2025 | |
| 5.2.6 | 307 | 6/10/2025 | |
| 5.2.5 | 265 | 6/10/2025 | |
| 5.2.4 | 263 | 6/10/2025 | |
| 5.2.3 | 219 | 6/9/2025 | |
| 5.2.2 | 212 | 6/9/2025 | |
| 5.2.1 | 213 | 6/9/2025 | |
| 5.2.0 | 222 | 6/9/2025 | |
| 5.1.9 | 189 | 6/9/2025 | |
| 5.1.8 | 77 | 6/7/2025 | |
| 5.1.7 | 64 | 6/7/2025 | |
| 5.1.6 | 112 | 6/6/2025 | |
| 5.1.5 | 139 | 6/5/2025 | |
| 5.1.4 | 140 | 6/5/2025 | |
| 5.1.3 | 133 | 6/4/2025 | |
| 5.1.2 | 129 | 6/4/2025 | |
| 5.1.1 | 140 | 6/2/2025 | |
| 5.0.1 | 166 | 5/28/2025 | |
| 4.10.3 | 96 | 5/24/2025 | |
| 4.10.2 | 103 | 5/24/2025 | |
| 4.10.1 | 118 | 5/24/2025 | |
| 4.9.15 | 189 | 5/22/2025 | |
| 4.9.14 | 176 | 5/21/2025 | |
| 4.9.13 | 182 | 5/21/2025 | |
| 4.9.12 | 189 | 5/19/2025 | |
| 4.9.11 | 255 | 5/15/2025 | |
| 4.9.10 | 258 | 5/15/2025 | |
| 4.9.9 | 256 | 5/15/2025 | |
| 4.9.8 | 259 | 5/15/2025 | |
| 4.9.7 | 274 | 5/15/2025 | |
| 4.9.6 | 275 | 5/15/2025 | |
| 4.9.5 | 251 | 5/12/2025 | |
| 4.9.4 | 220 | 5/12/2025 | |
| 4.9.3 | 152 | 5/9/2025 | |
| 4.9.2 | 199 | 5/9/2025 | |
| 4.9.1 | 177 | 5/9/2025 | |
| 4.8.5 | 459 | 4/25/2025 | |
| 4.8.4 | 262 | 4/25/2025 | |
| 4.8.3 | 276 | 4/24/2025 | |
| 4.8.2 | 288 | 4/24/2025 | |
| 4.8.1 | 213 | 4/24/2025 | |
| 4.7.10 | 199 | 4/23/2025 | |
| 4.7.9 | 221 | 4/15/2025 | |
| 4.7.8 | 214 | 4/14/2025 | |
| 4.7.7 | 226 | 4/14/2025 | |
| 4.7.6 | 237 | 4/14/2025 | |
| 4.7.5 | 213 | 4/14/2025 | |
| 4.7.4 | 223 | 4/14/2025 | |
| 4.7.3 | 224 | 4/14/2025 | |
| 4.7.2 | 215 | 4/14/2025 | |
| 4.7.1 | 221 | 4/14/2025 | |
| 4.6.1 | 192 | 4/9/2025 | |
| 4.6.0 | 199 | 4/9/2025 | |
| 4.5.9 | 188 | 4/8/2025 | |
| 4.5.8 | 189 | 4/8/2025 | |
| 4.5.7 | 195 | 4/7/2025 | |
| 4.5.6 | 230 | 4/7/2025 | |
| 4.5.5 | 205 | 4/7/2025 | |
| 4.5.4 | 191 | 4/7/2025 | |
| 4.5.3 | 221 | 4/7/2025 | |
| 4.5.2 | 182 | 4/7/2025 | |
| 4.5.1 | 197 | 4/7/2025 | |
| 4.5.0 | 200 | 4/7/2025 | |
| 4.3.0 | 208 | 4/2/2025 | |
| 4.2.1 | 181 | 4/2/2025 | |
| 4.2.0 | 196 | 4/2/2025 | |
| 4.1.0 | 191 | 4/1/2025 | |
| 4.0.0 | 217 | 4/1/2025 | |
| 3.2.1 | 522 | 3/25/2025 | |
| 3.2.0 | 515 | 3/25/2025 | |
| 3.1.0 | 114 | 3/22/2025 | |
| 3.0.0 | 148 | 3/21/2025 | |
| 2.0.0 | 195 | 3/20/2025 | |
| 1.5.0 | 161 | 3/20/2025 | |
| 1.4.0 | 179 | 3/20/2025 | |
| 1.3.0 | 187 | 3/20/2025 | |
| 1.2.0 | 115 | 3/15/2025 | |
| 1.1.0 | 115 | 3/15/2025 | |
| 1.0.0 | 107 | 3/15/2025 |