Agent 框架 03:Semantic Kernel——微软企业级 AI SDK 与插件系统编排

在 AI 原生应用开发的浪潮中,大多数开源框架(如早期的 LangChain)主要由 Python 极客社区主导,设计风格偏向动态黑盒与快速原型实验。但在传统政企和跨国公司的大型系统里,主力工程栈往往是 C#(.NET)和 Java,严苛的静态类型检查、依赖注入(DI)设计模式、严格的代码可维护性与合规审计是绕不开的硬门槛。

微软于 2023 年开源的 Semantic Kernel(简称 SK),正是为了破除这种生态断层而生。SK 统一提供了 C#、Python 和 Java 三门语言的第一方 SDK,其核心设计理念不是“又一个包装 LLM 的实验玩具”,而是将大语言模型能力无缝嵌入现有企业级软件体系的控制中枢。


核心架构:Kernel 作为中枢容器

Semantic Kernel 的核心设计高度借鉴了现代操作系统的“微内核”与后端服务容器的依赖注入思想:一切能力皆围绕 Kernel 容器挂载,通过模块化的 Plugin(插件)和标准化签名统一编排。


核心概念原语

Semantic Kernel 抽象出了五个正交的基础概念:

构件 运行时角色 核心职责
Kernel 核心调度容器 管理 AI 模型服务连接、依赖注入、插件注册、过滤器钩子与统一调用入口
Plugin 业务能力插件包 组织特定领域能力的模块,内部可以聚合多个原生代码函数或语义提示词函数
KernelFunction 原子可执行函数 统一的抽象调用单元,无论是 Python/C# 的本地方法还是一段 Prompt,对外都暴露同构的调用签名
Planner 自动目标规划器 根据用户的自然语言意图,从已注册的插件库中自动筛选出合适函数并生成执行拓扑
Memory 语义向量记忆 为智能体提供基于向量嵌入的长期记忆存储、语义相似度搜索与上下文注入机制

安装与基础环境搭建

在 Python 环境下安装核心包,如果使用微软 Azure 企业级云服务,可安装带有 Azure 扩展的版本:

1
2
3
4
5
# 基础 Python 包
pip install semantic-kernel

# 企业级 Azure OpenAI 依赖
pip install semantic-kernel[azure]

最小示例:创建 Kernel 并调用对话服务

在 Semantic Kernel 中,所有模型调用都必须显式注册到 Kernel 服务容器中,通过统一的服务标识符(service_id)进行解耦寻址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import asyncio
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
from semantic_kernel.contents import ChatHistory

async def main():
# 1. 初始化 Kernel 容器
kernel = Kernel()

# 2. 注入大模型后端服务 (支持 OpenAI 或 Azure OpenAI)
kernel.add_service(
OpenAIChatCompletion(
service_id="chat-service",
ai_model_id="gpt-4o-mini",
api_key="sk-your-openai-api-key",
)
)

# 3. 按 service_id 获取聊天服务句柄
chat = kernel.get_service("chat-service")

# 4. 构建结构化多轮历史
history = ChatHistory()
history.add_user_message("请用一句话讲清楚 Semantic Kernel 的核心设计优势。")

# 5. 执行调用
settings = kernel.get_prompt_execution_settings_from_service_id("chat-service")
result = await chat.get_chat_message_content(
chat_history=history,
settings=settings,
)
print(f"Agent 回复:\n{result}")

if __name__ == "__main__":
asyncio.run(main())

插件体系:Native Functions 强类型定义

在大型企业中,插件往往由后端工程师编写,必须保证参数强类型约束和自动文档生成。Semantic Kernel 通过 @kernel_function 装饰器和 Python 原生 typing.Annotated 实现零元数据冗余的函数暴露:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from typing import Annotated
from semantic_kernel.functions import kernel_function

class WeatherPlugin:
"""天气查询业务插件"""

@kernel_function(
name="get_current_weather",
description="获取指定城市的实时天气数据",
)
def get_current_weather(
self,
city: Annotated[str, "需要查询的城市名称,例如:北京、上海、深圳"],
) -> Annotated[str, "天气描述字符串"]:
data_mock = {
"北京": "晴朗,气温 24°C,微风",
"上海": "多云转小雨,气温 21°C",
"深圳": "雷阵雨,气温 29°C",
}
return data_mock.get(city, f"{city}:暂未接入气象监控站点数据")

@kernel_function(
name="get_forecast",
description="预测指定城市未来 3 天的天气走势",
)
def get_forecast(
self,
city: Annotated[str, "城市名称"],
) -> str:
return f"{city} 未来 3 天趋势:第 1 天晴,第 2 天阴,第 3 天小雨"


class FinancialMathPlugin:
"""高精度企业计算插件"""

@kernel_function(description="计算两个数值的和")
def add(
self,
a: Annotated[float, "被加数"],
b: Annotated[float, "加数"],
) -> float:
return a + b

@kernel_function(description="计算两数之积")
def multiply(
self,
a: Annotated[float, "被乘数"],
b: Annotated[float, "乘数"],
) -> float:
return a * b

挂载插件并直接触发执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import asyncio
from semantic_kernel import Kernel

async def run_plugin():
kernel = Kernel()

# 注册插件实例到 Kernel 中
kernel.add_plugin(WeatherPlugin(), plugin_name="Weather")
kernel.add_plugin(FinancialMathPlugin(), plugin_name="Math")

# 显式根据插件名和方法名调用
weather_res = await kernel.invoke(
kernel.get_function("Weather", "get_current_weather"),
city="北京",
)
print("插件输出:", weather_res) # 晴朗,气温 24°C,微风

calc_res = await kernel.invoke(
kernel.get_function("Math", "multiply"),
a=12.5,
b=8.0,
)
print("计算输出:", calc_res) # 100.0

asyncio.run(run_plugin())

语义函数:Prompt Function 代码化

除了执行本地 Native 代码,SK 允许将一段提示词模板(Prompt Template)直接封装为标准 KernelFunction,在系统看来,原生代码和 Prompt 是完全对等的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from semantic_kernel.functions import KernelFunctionFromPrompt

# 用 Prompt 模板生成标准函数
summarize_function = KernelFunctionFromPrompt(
function_name="summarize_text",
plugin_name="TextProcessing",
prompt="""
请对以下输入文本进行结构化提炼,提取出 3 个核心要点,每点控制在 20 字以内:

文本内容:
{{$input}}

提炼结果:
""",
)

# 挂载到 kernel
kernel.add_function("TextProcessing", summarize_function)

# 执行语义函数
res = await kernel.invoke(
summarize_function,
input="AgentScope 是阿里巴巴达摩院开源的分布式 Agent 框架,主打消息一等公民和 RPC 解耦...",
)
print("语义摘要结果:\n", res)

自动工具选择:Function Calling 闭环

大语言模型最强大的能力在于根据用户意图自主决策何时调用何种插件。Semantic Kernel 提供了 FunctionChoiceBehavior.Auto() 机制,将已注册插件的 Schema 自动注入大模型上下文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import asyncio
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.open_ai import (
OpenAIChatCompletion,
OpenAIChatPromptExecutionSettings,
)
from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior
from semantic_kernel.contents import ChatHistory

async def auto_tool_calling():
kernel = Kernel()
kernel.add_service(
OpenAIChatCompletion(service_id="chat", ai_model_id="gpt-4o")
)

# 注册可用插件
kernel.add_plugin(WeatherPlugin(), plugin_name="Weather")
kernel.add_plugin(FinancialMathPlugin(), plugin_name="Math")

# 启用自动函数选择 (Auto Tool Calling)
execution_settings = OpenAIChatPromptExecutionSettings(
function_choice_behavior=FunctionChoiceBehavior.Auto(
auto_invoke=True, # 由 Kernel 自动拦截并执行函数,将结果送回 LLM 获得最终回答
max_auto_invoke_attempts=5,
)
)

history = ChatHistory()
history.add_user_message("北京现在的天气如何?另外帮我算一下 24.5 乘以 4 等于多少?")

chat_service = kernel.get_service("chat")
response = await chat_service.get_chat_message_content(
chat_history=history,
settings=execution_settings,
kernel=kernel, # 将 kernel 传入上下文,赋予 LLM 检索和运行插件的权限
)

print("最终 Agent 综合回答:\n", response.content)

asyncio.run(auto_tool_calling())

企业语义记忆:Memory 与向量存储检索

Semantic Kernel 抽象出了 SemanticTextMemory 接口,原生对接各类向量数据库(如 Chroma、Qdrant、Azure AI Search):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from semantic_kernel.memory import SemanticTextMemory
from semantic_kernel.connectors.memory.chroma import ChromaMemoryStore
from semantic_kernel.connectors.ai.open_ai import OpenAITextEmbedding

# 构建持久化语义记忆系统
memory = SemanticTextMemory(
storage=ChromaMemoryStore(persist_directory="./sk_chroma_db"),
embeddings_generator=OpenAITextEmbedding(ai_model_id="text-embedding-3-small"),
)

# 写入业务文档
await memory.save_information(
collection="enterprise_docs",
id="policy_001",
text="公司年假制度规定:入职满一年的员工每年享有 10 个工作日的全薪年假。",
)

# 检索最相关的事实
matches = await memory.search(
collection="enterprise_docs",
query="新员工入职第二年有多少天带薪假?",
limit=2,
min_relevance_score=0.7,
)

for m in matches:
print(f"相似度: {m.relevance:.2f} | 内容: {m.text}")

优缺点分析与工程选型边界

核心优势

  1. 多语言与企业级治理:C#、Java 和 Python 并重,在微软庞大的企业级客户群体与 .NET 生态中拥有无与伦比的技术支撑。
  2. 架构严谨规整:依赖注入、统一 Function 抽象、类型注解严格,极少出现像早期社区框架那样随意侵入猴子补丁的丑陋代码。
  3. Azure 生态深度绑定:如果企业 IT 基础设施部署在微软 Azure(Azure OpenAI、Azure AI Search、Microsoft Fabric),SK 是第一方首选工具链。

现实痛点与妥协

  1. 历史版本断层重:v0.x 到 v1.x 经历过数次重构,网上大量旧版教程(如旧版 SKContext、旧版 Planner API)已经失效,踩坑成本较高。
  2. 社区与第三方工具滞后:相较于 LangChain/LlamaIndex 数以百计的开源社区三方 Connector,SK 的三方插件生态相对克制,许多小众 API 需自己手写封装。
  3. Python 侧文档略滞后:核心团队侧重 .NET,部分新特性(如最新版复杂图工作流支持)往往是 C# 先行发布,Python 社区随后跟进。

选型决策准则

  • 强烈推荐:跨国企业级研发团队、核心资产重度依赖 .NET / C# 平台、或者云厂商首选为微软 Azure 的大型应用。
  • 不建议选择:纯 Python 小型创业团队做轻量 POC 验证、或者需要海量开箱即用开源知识库 Loader 的快速原型场景。

关联导航