Microsoft Semantic Kernel
一句话定位
Semantic Kernel(SK)是一个 DI 风格的中间件 SDK——Kernel 是服务容器(AI 连接器 + 插件 + 过滤器),“agent”是搭在 kernel 函数调用原语之上的一层,而不是相反。曾经的招牌功能 Planner 子系统在 Python SDK 里已被完全移除(docs/PLANNERS.md 只剩一个跳转 stub,grep -ril planner python/semantic_kernel 零命中),规划能力要么隐式发生在模型自己挑工具的 auto-invoke 循环里,要么显式外包给 Magentic 编排器(对 AutoGen Magentic-One 的近乎逐字移植)。
核心架构总览
Polyglot monorepo:dotnet/、python/、java/ 三套 SDK 共享 docs/decisions/(MADR 格式 ADR)。本次调研聚焦 Python SDK(python/semantic_kernel/),因为它是可读性/完整度最高的参考实现,并交叉核对了语言无关的 ADR。commit f6391ad8b6b47b6de44e80d54ce9f3ffe4f3ed42(2026-07-07 git clone --depth 1 后 git rev-parse HEAD 取得)。
关键目录/文件(均相对 python/semantic_kernel/):
kernel.py——Kernel类本体:invoke/invoke_stream/invoke_prompt/invoke_function_call(工具调用派发与参数校验)/_inner_auto_function_invoke_handler/clone()/as_mcp_server()。connectors/ai/chat_completion_client_base.py—— 真正的 agent 主循环所在地(不在Kernel里)。connectors/ai/function_choice_behavior.py——FunctionChoiceBehavior,循环轮数上限的来源。agents/——Agent抽象基类、ChatCompletionAgent、orchestration/(Magentic/Handoff/GroupChat/Concurrent/Sequential)、azure_ai/、open_ai/(OpenAI Assistants 变体)、runtime/(actor-model 运行时)。contents/history_reducer/—— 会话历史压缩(截断 / LLM 摘要)。filters/—— 洋葱式中间件链,SK 的通用拦截点(日志/缓存/审批门都要靠它自建)。connectors/mcp.py—— MCP 客户端(4 种传输)+ MCP 服务端(把 Kernel 自身暴露为 MCP server)。processes/—— 独立的确定性图/状态机工作流引擎(Process Framework),可选 Dapr 后端。docs/decisions/*.md—— ADR,含 OTel 采纳决策、Agent Framework 起源、hooks→filters 演化。
Agent Loop(主循环 / 何时继续何时停)
主循环不在 Kernel 里,而在 connectors/ai/chat_completion_client_base.py:136-174(get_chat_message_contents,非流式)与 :255-318(get_streaming_chat_message_contents,流式):
- 循环体:
for request_index in range(settings.function_choice_behavior.maximum_auto_invoke_attempts):—— 调 LLM;若返回内容里没有FunctionCallContent,直接 return(停止条件①:模型没要工具);否则通过asyncio.gather(kernel.invoke_function_call(...))并行执行所有请求的工具调用;若任一调用的AutoFunctionInvocationContext.terminate == True,提前 break/return(停止条件②:某个 auto-function-invocation filter 显式终止);否则带着更新后的 chat history 再循环一轮。 - 轮数上限:
maximum_auto_invoke_attempts默认 5(connectors/ai/function_choice_behavior.py:18,58)。for循环耗尽轮数时触发else分支:重置工具调用配置(_reset_function_choice_settings),再发起一次不带工具调用的 LLM 调用强制拿到纯文本答案(chat_completion_client_base.py:171-174)。 - 这是”单轮”(per-turn)循环;跨整个对话的”要不要继续”由更上层的 Magentic/GroupChat/Handoff 编排器负责(见”Router / 编排”节),基础循环本身不管这层。
记忆与上下文管理(压缩、长期记忆、会话持久化)
- 基础
ChatHistory没有自动的、token-budget 感知的压缩;压缩是通过挂在ChatHistoryAgentThread上的ChatHistoryReducer子类opt-in实现的:ChatHistoryTruncationReducer(contents/history_reducer/chat_history_truncation_reducer.py,105 行)—— 硬截断到target_count(留threshold_count缓冲),不调 LLM,保留第一条 system/developer 消息。ChatHistorySummarizationReducer(contents/history_reducer/chat_history_summarization_reducer.py,216 行)—— 历史超过target_count+threshold_count时用 LLM 生成滚动摘要(内置默认 prompt 要求 ≤5 句),摘要消息打上SUMMARY_METADATA_KEY避免被重复摘要,可选是否把函数调用/结果内容也纳入摘要(include_function_content_in_summary)。
.reduce()暴露在ChatHistoryAgentThread(agents/chat_completion/chat_completion_agent.py:107-113)——需要调用方/框架主动调用,不是每轮自动触发(文档提到的auto_reduce标志仍要靠线程/agent 侧接线才生效)。- 长期记忆:遗留的
memory/semantic_text_memory.py中SemanticTextMemory已标注 deprecated(“将在未来版本移除”);connectors/memory_stores/下有 13 个向量库后端(Qdrant/Redis/Pinecone/Chroma/Milvus/Weaviate/Azure Cognitive Search/CosmosDB/Postgres/MongoDB Atlas/AstraDB/usearch);官方推荐路径是semantic_kernel/data的 Vector Store 抽象(本轮未深读,仅记录路径)。 - 会话持久化:
ChatHistoryAgentThread包一个带thread_id的ChatHistory,持久化后端由调用方自行提供——core 里没有内置的数据库级线程存储;Azure AI Agent / OpenAI Assistants 变体则借用各自托管服务自身的线程持久化。
工具体系(定义/调用协议/注册/权限)
- 定义:
@kernel_function装饰器(functions/kernel_function_decorator.py)用inspect.signature内省普通 Python 函数(支持Annotated[type, "description"]),元数据存成__kernel_function_parameters__等 dunder 属性;此外还支持 prompt 驱动的函数(KernelFunctionFromPrompt,“技能”本质就是一个 prompt 模板)、OpenAPI spec 派生函数(connectors/openapi_plugin/openapi_manager.py)、MCP server 派生函数(connectors/mcp.py)。 - 注册:函数打包进
KernelPlugin(functions/kernel_plugin.py),插件注册到Kernel.plugins字典;调用时kernel.get_function(plugin_name, function_name)解析。 - 调用协议:模型发出 OpenAI 风格
tool_calls(或已废弃的 legacyfunction_call);provider 连接器把它解析成FunctionCallContent(open_ai_chat_completion_base.py:240-268的_get_tool_calls_from_chat_choice/_get_function_call_from_chat_choice);Kernel.invoke_function_call(kernel.py:326-463)依次:(a) 校验函数在模型可见的 allowlist 内(function_behavior.filters);(b) 校验必填/多余参数是否匹配function_to_call.parameters;(c) 构建AutoFunctionInvocationContext;(d) 过一遍auto_function_invocation_filters中间件链;(e) 深拷贝结果防止后续变更泄漏;(f) 把FunctionResultContent追加进 chat history。 - 权限:
FunctionChoiceBehavior.filters支持excluded_plugins/included_plugins/excluded_functions/included_functions——是最接近工具 ACL 的机制,在kernel.py:342-349强制执行(模型调用允许列表外的函数时,返回错误消息给模型而非直接崩溃)。这是静态允许列表,不是逐次交互式审批(审批相关见”安全与权限”节)。
Prompt 设计(系统提示结构、动态组装)
- 三套可互换的模板引擎:SK 自有的
{{$var}}/{{plugin.function arg=val}}mini-DSL、Handlebars、Jinja2(prompt_template/{kernel,handlebars,jinja2}_prompt_template.py),由template_format字段选择。 - Agent 指令每次调用都重新渲染:
Agent.format_instructions()(agents/agent.py:443-459)惰性地基于self.instructions构建KernelPromptTemplate并调.render(kernel, arguments)——即系统提示本身是一个模板,可在请求时插入 kernel 参数/函数输出,而不是静态字符串。 - 声明式 agent:
agents/agent.py里的AgentSpec/ModelSpec/ToolSpec类配合DeclarativeSpecMixin,允许整个 agent(指令、模型连接、工具)用 YAML 定义加载——是手写 Python 之外的配置驱动替代路径。 - 编排器级 prompt(Magentic)是纯 Python 字符串模板,同样用
{{$var}}语法,单独存在agents/orchestration/prompts/_magentic_prompts.py(facts 调查、plan、progress-ledger 严格 JSON、final answer)——值得一提:progress-ledger prompt 明确要求”DO NOT OUTPUT ANYTHING OTHER THAN JSON”并内联 schema,即靠 prompt 工程实现结构化输出,而非依赖 function-calling/JSON-mode API 特性。
Router / 编排(任务分解、多 agent、子 agent)
- Planner 子系统已从 Python SDK 完全移除(
docs/PLANNERS.md是跳转 stub;代码零命中)。被以下几者取代:(a) 单 agent 场景下原生 auto-function-invocation 循环本身承担了工具编排;(b)agents/orchestration/*承担多 agent 编排;(c)processes/*Process Framework 承担确定性工作流。 - Magentic 编排(
agents/orchestration/magentic.py,911 行)—— 移植自 AutoGen 的 Magentic-One:MagenticManagerBase这个 LLM 驱动的中央编排器维护MagenticContext(任务台账:facts + plan),每轮要求编排器 LLM 输出结构化 JSON 的ProgressLedger(is_request_satisfied/is_in_loop/is_progress_being_made/next_speaker/instruction)。停滞检测:无进展时stall_count递增,超过max_stall_count(默认 3,第 137 行)触发 plan 重置(reset_count,受max_reset_count上限约束);max_round_count是硬性轮数天花板(第 617-690 行附近检查round_count >= max_round_count)。 - Handoff 编排(
agents/orchestration/handoffs.py,530 行)—— 去中心化路由:每个 agent 被注入额外的 kernel 函数(_add_handoff_functions,代表”交接给 agent X”);由当前发言 agent 自己的 LLM决定是否调用这个交接函数(普通工具调用),编排层拦截(_handoff_function_filter)切换当前发言人——路由决策外包给模型的常规 function-calling,而非中央 planner。 - GroupChat(
agents/orchestration/group_chat.py)、Concurrent(同一输入 fan-out 给 N 个 agent)、Sequential(agent i 输出接 agent i+1 输入)补齐编排模式库;更早一代的agents/group_chat/agent_group_chat.py+ 可插拔SelectionStrategy/TerminationStrategy(agents/strategies/)仍然存在,是基于轮次的老式多 agent 聊天 API。 - Process Framework(
processes/)—— 独立的确定性图/状态机引擎:ProcessBuilder.add_step()注册步骤类,ProcessStepEdgeBuilder连接事件驱动的边;运行时支持local_runtime(进程内)或dapr_runtime(Dapr 虚拟 actor,用于持久化/分布式执行)——这是 SK 针对”业务流程式”(而非 LLM 即兴决定)编排给出的结构化答案。 agents/runtime/(core_runtime.py、in_process/in_process_runtime.py)—— 一套 actor-model 运行时(agent_id/topic/subscription/message_handler 模式),Magentic/Handoff/GroupChat/Concurrent/Sequential 全都作为 actor 跑在这套运行时上——架构上借鉴/对齐了 AutoGen 的 core runtime 设计。
Skill / 插件体系
“插件”= KernelPlugin,一袋命名好的 KernelFunction。四种填充方式:(a) 原生 Python 类/函数打 @kernel_function;(b) prompt 驱动函数(KernelFunctionFromPrompt,即”技能”字面上就是一个 prompt 模板);(c) OpenAPI spec 导入(connectors/openapi_plugin/openapi_manager.py 把 OpenAPI 文档解析成可调用函数);(d) MCP 客户端(connectors/mcp.py,stdio/SSE/streamable-HTTP/websocket 四种传输)。core_plugins/ 目录(未逐行深读,仅列目录)提供少量第一方内置插件(文本/时间/数学类工具样例)。双向 MCP 支持是一个特色点:Kernel 不仅能作为 MCP 客户端消费外部工具服务器,还能反过来通过 Kernel.as_mcp_server()(kernel.py:578-625 → connectors/mcp.py:create_mcp_server_from_kernel)把自身注册的全部函数暴露成 MCP 工具/prompt 供其他客户端使用。
自进化能力(自我改进 / 学习型记忆 / eval 驱动纠错)
未实现。 对 python/semantic_kernel 做穷举式 grep(self-improv|learn from|training data|fine-tun|eval-driven|reflexion,不区分大小写)零相关命中。没有任何机制把运行轨迹自动反馈进模型权重、prompt 或持久化的学习型记忆。最接近的邻近功能是:(a) 历史摘要 reducer(属于记忆压缩,不是学习);(b) Magentic 编排器在停滞时更新 facts/plan(仅限单次运行内的自我纠正,运行结束后通过 MagenticContext.reset() 丢弃,不持久化)。
可观测性(日志 / trace 格式)
- 采纳 OpenTelemetry GenAI 语义约定,而非自造一套 SK 专属 trace 格式——这是文档化的明确设计决策(
docs/decisions/0044-OTel-semantic-convention.md)。 - 属性词表在
utils/telemetry/model_diagnostics/gen_ai_attributes.py:gen_ai.system、gen_ai.request.model、gen_ai.request.{max_tokens,temperature,top_p,seed,...}、gen_ai.response.{id,finish_reason}、gen_ai.usage.{input_tokens,output_tokens}、gen_ai.tool.{call.id,call.arguments,call.result,name,description},外加 SK 自定义的sk.available_functions。 - Span 通过
@trace_chat_completion/@trace_streaming_chat_completion装饰器创建(包裹_inner_get_chat_message_contents,见open_ai_chat_completion_base.py:74,94),另有一个专门的AUTO_FUNCTION_INVOCATION_SPAN_NAMEspan 包住整个 auto-invoke 循环(chat_completion_client_base.py:137,256,410-426,经由_start_auto_function_invocation_activity)。 - 独立的
agent_diagnostics遥测模块(utils/telemetry/agent_diagnostics/)把 agent 级调用/流式与原始模型调用分开打点(trace_agent_get_response/trace_agent_invocation/trace_agent_streaming_invocation,在chat_completion_agent.py:34-38引入)。 - ADR 明确要求 prompt/completion 内容类遥测事件必须可 opt-out(PII 考虑)。
安全与权限(审批门、密钥管理)
- 没有内置的人工审批(HITL)原语用于工具调用。
AutoFunctionInvocationContext.terminate标志(可在auto_function_invocation_filter内设置)是应用开发者用来自建审批门的机制(例如在调用next(context)之前暂停并询问人类),但这是一个 DIY 扩展点,不是开箱即用的行为。TRANSPARENCY_FAQS.md明确把”Filtering”点名为开发者应该”落地 Responsible AI”的地方。 - 工具调用允许列表(
FunctionChoiceBehavior.filters:excluded/included plugins/functions)是最接近权限边界的东西,但只是静态允许列表,不是逐次交互式审批。 - MCP 专属的安全阀门:
sampling_consent_callback(connectors/mcp.py:62,248-260,377-410)—— 调用方提供的Callable[[str, CreateMessageRequestParams], Awaitable[bool]],在 MCP server 触发”sampling”请求(即要求客户端的 LLM 代其生成内容)之前调用。若未配置回调,此类请求默认自动通过,仅打一条警告日志(“MCP sampling request … was auto-approved because no sampling consent callback was configured”)——这是一个真实存在、代码可核实的权限门模式,但默认开放而非默认拒绝,值得在安全对比里点名。 - 密钥/凭据:仓库内无密钥保险库;API key/连接串通过连接器构造函数或基于环境变量的 Pydantic Settings 类传入(标准 SDK 做法,非特色安全功能)。
沙箱与执行隔离
本地未实现。 SK 自身没有原生代码执行沙箱。Code-interpreter 能力完全外包给托管后端:agents/azure_ai/azure_ai_agent.py 把 code_interpreter 注册为工具 spec(@_register_tool("code_interpreter") → CodeInterpreterTool),转发给 Azure AI Agent Service;OpenAI Assistants agent 变体(agents/open_ai/openai_assistant_agent.py)同理委托给 OpenAI 的托管 code interpreter。python/semantic_kernel 内没有任何本地 subprocess/容器/沙箱执行层——一个原生 @kernel_function 工具就是普通的进程内 Python 调用,权限等同宿主进程本身,框架不施加任何隔离。
与模型的协同设计
- 深度依赖模型原生的 function-calling / tool-use API(OpenAI tool_calls、legacy function_call,以及 Azure OpenAI、Bedrock(
agents/bedrock/action_group_utils.py)、Google、Mistral、ONNX、Ollama 等连接器下的等价物)—— auto-invoke 循环假定底层模型 API 能吐出结构化 tool-call 对象;每个连接器上的SUPPORTS_FUNCTION_CALLING: ClassVar[bool]标志决定循环是否启用。 FunctionChoiceType(AUTO/NONE/REQUIRED)直接映射到各 provider 原生的tool_choice参数(各连接器的_update_function_choice_settings_callback把 SK 的抽象选择翻译成 provider 特定的请求字段)——即 SK 不重新实现工具选择启发式,只是对模型 API 已有能力做一层薄的、provider 感知的透传。- MCP sampling 支持(
connectors/mcp.py的 sampling_callback)是一个双向协同设计点:MCP 工具服务器可以请求客户端配置的 chat completion 模型做一次子生成,遵循客户端自己的 model/temperature/max-token 设置——即工具服务器借用宿主的 LLM,而不是自带一个。 - 未发现模型特定的 prompt hack 或训练期协同设计痕迹(符合中间件 SDK 而非模型提供方的定位预期)。
轨迹利用(session/trajectory 是否反哺训练/评测)
未实现 / 不适用。 没有代码路径把完整会话轨迹持久化用于后续训练或离线评测反馈。ChatHistory/ChatHistoryAgentThread 只是运行时会话状态(按”记忆与上下文管理”节所述被 reduce/truncate/summarize,不导出到本仓库内任何 eval 或训练管线)。OpenTelemetry trace(见”可观测性”节)是”轨迹”唯一的持久化记录,但它是给运维方用的可观测性产物,不是 SK 自身拥有的训练反馈闭环。
与同类 harness 的关键差异(1-3 条)
- Planner 的消失与再分布:SK 曾经的招牌”Planner”子系统在 Python SDK 里被彻底移除(非弃用,是删除),规划能力拆解到两处——单 agent 场景下隐式发生在模型自己的工具选择里,多 agent 场景下显式外包给 Magentic 编排器的任务台账/进度台账 prompt。这与仍保留显式 planner 抽象的框架(如某些仍有
Planner类的框架)形成直接对比。 - 与 AutoGen 的架构收敛:Magentic 编排器是对 AutoGen Magentic-One 近乎逐字的移植(prompt 可辨识度很高),且共享 actor-model 运行时层(
agents/runtime/core)——SK 的多 agent 编排并非独立发明,值得与 AutoGen 的 dossier(如有)交叉对比。 - 安全默认值偏宽松:与”默认拒绝、需显式授权”的安全模型不同,SK 目前唯一内置的、代码可验证的许可回调(MCP sampling consent)在未配置时默认自动批准,只打警告日志;框架整体把审批门的实现责任完全留给应用开发者通过 filter 自建,这是一个值得在跨 harness 安全对比中点名的设计取舍。
原始源码定位
- repo: https://github.com/microsoft/semantic-kernel
- commit/version analyzed:
f6391ad8b6b47b6de44e80d54ce9f3ffe4f3ed42(git clone --depth 1,2026-07-07) - 关键文件列表(相对
python/semantic_kernel/,除非另注明):kernel.pyconnectors/ai/chat_completion_client_base.pyconnectors/ai/function_choice_behavior.pyconnectors/ai/open_ai/services/open_ai_chat_completion_base.pyconnectors/mcp.pyagents/agent.pyagents/chat_completion/chat_completion_agent.pyagents/orchestration/magentic.pyagents/orchestration/prompts/_magentic_prompts.pyagents/orchestration/handoffs.pyagents/orchestration/group_chat.py、orchestration_base.py、concurrent.py、sequential.pyagents/strategies/selection/*、agents/strategies/termination/*agents/runtime/core_runtime.py、agents/runtime/in_process/in_process_runtime.pycontents/history_reducer/chat_history_summarization_reducer.pycontents/history_reducer/chat_history_truncation_reducer.pyfilters/kernel_filters_extension.pyfilters/auto_function_invocation/auto_function_invocation_context.pyfunctions/kernel_function_decorator.pyreliability/kernel_reliability_extension.pyutils/telemetry/model_diagnostics/gen_ai_attributes.pyutils/telemetry/agent_diagnostics/*docs/decisions/0044-OTel-semantic-convention.mddocs/decisions/0032-agents.mddocs/decisions/0005-kernel-hooks-phase1.md、docs/decisions/0033-kernel-filters.mddocs/PLANNERS.mdprocesses/process_builder.py、processes/kernel_process/kernel_process_step.py、processes/local_runtime/local_kernel_process.pyconnectors/openapi_plugin/*memory/semantic_text_memory.pyagents/azure_ai/azure_ai_agent.pyagents/open_ai/openai_assistant_agent.pyagents/bedrock/action_group_utils.pyTRANSPARENCY_FAQS.md(repo 根目录)
一手源存档(sources/)
/Users/zhao/projects/self-wiki/ai-research/sources/harness/microsoft-semantic-kernel/ 下:
NOTES.md—— 完整调研笔记(含逐维度发现、文件:行号引用)key-files/PLANNERS.mdkey-files/TRANSPARENCY_FAQS.mdkey-files/kernel.pykey-files/connectors_mcp.pykey-files/agents/(agent.py、chat_completion_agent.py、magentic.py、handoffs.py等,具体见目录)key-files/connectors/(chat_completion_client_base.py、function_choice_behavior.py、open_ai_chat_completion_base.py 等)key-files/contents/(history_reducer 相关)key-files/docs/(ADR 节选)key-files/filters/(filter 扩展点相关)