赞
踩
阅读原文
人工智能 (AI) 正迅速改变我们的世界,从智能助手到自动驾驶汽车,AI 的应用无处不在。对开发者而言,快速构建功能强大的 AI 应用是一个挑战。LangChain 作为一款流行的 AI 开发框架,虽然因其丰富的预制组件而广受欢迎,但由于其抽象再抽象、封装再封装,灵活性非常低,且框架的学习、理解及复杂业务逻辑调试的成本很高,使其难以大规模应用于企业业务线上部署。随着 AI 领域的快速发展,微软开源的 Semantic Kernel 框架应运而生,其独特的优势和强大功能可能使其成为 LangChain 的强力替代品。
经过笔者亲子踩坑,将在本文探讨 Semantic Kernel 的核心特点和优势,提供快速入门实践指导,并与 LangChain 的局限性进行比较,旨在帮助开发者选择并入门这个企业级 AI 应用开发框架。
Semantic kernel是微软开源的一个轻量级的开源开发套件,它让你可以轻松构建 AI Agent,并将最新的 AI 模型集成到您的 C#、Python 或 Java 代码库中;它提供了一个简单易用的 API,可以连接到各种 AI 服务,例如 OpenAI、Azure OpenAI 和 Hugging Face 等;并且它作为业高效的中间件,能够快速交付企级解决方案。
插件(Plugin)是 Semantic Kernel 的一大特色
Kernel 是 Semantic Kernel 的核心组件。简单来说,Kernel是一个依赖管理容器,管理那些运行你的 AI 应用所需的所有服务(Services)和插件(Plugins)。你需要将 AI 应用所有依赖的服务和插件提供给Kernel,在必要的时候 AI 应用会自动使用它们。
组件 | 说明 |
---|---|
服务 | 包括所需的 AI 服务(OpenAI)和其他服务(例如日志记录、HTTP 服务等),因此可以支持跨所有语言的服务依赖项引入。 |
插件 | 是一类工具函数的集合,被 AI 服务用来执行,例如,搜索插件可以包含google搜索、bing搜索等工具 |
由于 Kernel 管理着所有服务和插件,因此 Semantic Kernel 的每个组件都基于它来驱动你的 AI 应用。这非常的 Amazing,因为意味着你作为开发者,有个统一的地方可以配置来管理和监控你的 AI 应用。 比如,当你从 Kernel 调用一个 Prompt 时,Kernel会做如下事情:
在这整个过程中,你可以在上述任何步骤中间执行诸如日志记录、向用户提供更新等任何操作,因为这整个过程都在一个地方(Kernel)完成,名副其实的 Kernel is All You Need。
在 Semantic Kernel 中定义Kernel十分方便:
# Initialize the kernel
kernel = Kernel()
Agent 是基于软件的实体,利用 AI 模型为你完成工作。它们被构建用来执行广泛的任务,并根据它们的工作性质有不同的称呼:
Semantic Kernel 提供了构建任何类型的 Agent 的能力,不需要你是 AI 专家。
在 Semantic Kernel 中,一个 Agent 主要由三个核心构建模块组成:插件(Plugin)、规划器(Planner)和角色(Persona)。
AI 服务是指基于大模型等能力提供的一系列服务,比如ChatGPT等。
Semantic Kernel 的主要功能之一是其能够将不同的AI服务(Services)添加到 Kernel 中,包括 OpenAI、Azure OpenAI 和 Hugging Face 等。这使你可以轻松地替换不同的AI服务,以比较它们的性能,并利用最适合你需求的服务。
比如在接入Azure的GPT-4 Chat服务并添加到 Kernel 的代码如下,是不是非常便捷
# Add Azure OpenAI chat completion
kernel.add_service(
AzureChatCompletion(
deployment_name="your_models_deployment_name",
api_key="your_api_key",
base_url="your_base_url",
)
)
在Semantic Kernel中,有目前最主流的 AI 服务的接口。下表是在不同语言上的支持情况。
服务 | C# | Python | Java |
---|---|---|---|
Chat completion | ✅ | ✅ | ✅ |
Text generation | ✅ | ✅ | ✅ |
Embedding generation (Experimental) | ✅ | ✅ | ✅ |
Text-to-image (Experimental) | ✅ | ❌ | ❌ |
Image-to-text (Experimental) | ✅ | ❌ | ❌ |
Text-to-audio (Experimental) | ✅ | ❌ | ❌ |
Audio-to-text (Experimental) | ✅ | ❌ | ❌ |
插件(Plugin)是 Semantic Kernel 的一个关键组成部分。如果你已经使用过 ChatGPT 或 Microsoft 365 中的 Copilot 扩展的插件,那么你就已经对它有所了解。通过插件,可以将现有的 API 封装成一个集合,供 AI 应用使用。这使 AI 应用能够执行它原本无法执行的操作。
Semantic Kernel 本质上是在利用函数调用(function calling)功能让 LLM 进行规划(planning)并调用 API。通过函数调用,LLM 可以请求(即调用)特定的函数。Semantic Kernel 随后将请求发送给你定义的合适的函数,并将结果返回给 LLM,以便 LLM 生成最终结果。
在企业业务场景中,插件非常有价值,因为它对一组功能进行了封装,还能很好地与依赖注入配合使用。在插件的构造函数中,可以注入执行插件工作所需的服务(例如,数据库连接、HTTP 客户端等),这在其它不支持插件的架构中难以实现的。
Note
在其它框架中,functions 通常称为“tools”或“actions”。 在 Semantic Kernel 中,仍然使用“functions”来称呼,因为从本质上来看依然是定义在代码中的函数。
下图是一个 Writer 插件示例,里面包含了 ShortPoem 和 StoryGen 等 functions,这些 functions 就是其它框架中的“tools”或“actions”
在 Semantic Kernel 中定义插件主要有两种方式(在快速实践
中会进一步举例说明):使用代码定义 functions 或使用 OpenAPI 规范的 API。通过第一种方式你可以在代码库中编写函数的具体功能和细节,可以利用您已有的依赖和服务。通过第二种方式你可以直接接入 OpenAPI 规范的 API 作为插件,这种方式可以十分方便的跨不同的编程语言和平台共享。
当 AI 应用拥有多个插件时,就需要一种方法让 AI 应用能够自主的选择合适的一个或多个插件来解决问题,这就需要Planning了。
OpenAI 引入了一种让模型使用函数的原生方法:函数调用(function calling),其他 AI 模型如 Gemini、Claude 和 Mistral 也已采用函数调用作为核心能力。由于这个能力的支持,Semantic Kernel 将函数调用作为规划(plan)和执行(execute)任务的主要方式。
那 Semantic kerenl 是如何知道什么时候该调用什么工具、什么时候调用结束的呢。这其实是通过一个反馈循环来实现的,LLM 会根据用户问请求和插件功能的描述,决定当下需要调用的插件以及具体的函数和参数,Semantic Kernel 会将函数执行结果反馈给 LLM,由 LLM 决定下一步是继续调用插件还是直接回复。
以下就是 Semantic Kernel 基于插件的 AI 驱动的规划过程:
整个反馈循环的过程全部由 Semantic Kernel 支持。规划(planning)什么时候调用调用哪个函数则完全由 LLM 决定,包括函数调用出错 Semantic Kernel 都做了很好的处理,我们只需要定义好插件即可。
角色(Persona)通常称为“元提示(Meta Prompt)”或“指令(Instruction)”,用于定义 AI 应用的响应方式或风格。 通过角色的设定,你可以定义 Agent 规划任务、生成回复以及与用户交互的方式和风格。
在Semantic Kernel中,经常将这些 Prompt 描述为“角色”,主要是通设置 System Prompt 实现设定的,而且实现方式也非常的方便。
chat_history = ChatHistory()
chat_history.add_system_message("""
You are a technical support specialist for a software company.
Your primary task is to assist users with technical issues,
such as installation problems, software bugs, and feature
inquiries. Use technical jargon appropriately, but ensure that
explanations are easy to understand. If a problem is too complex,
suggest advanced troubleshooting steps or escalate to a higher-level
support team using the escalate tool.
""")
定义有效的角色需要仔细考虑 Agent 的目标受众以及 Agent 即将执行的具体任务。以下是一些角色定义的实践建议:
步骤 | 描述 |
---|---|
明确目标 | 在创建角色之前,清晰地定义 Agent 需要达成的目标。这包括了解 Agent 将执行的任务以及你期望它与用户的交互方式和风格。 |
提供示例和场景 | 为了帮助 Agent 更好地理解其角色,提供展示角色行动的示例和场景,比如示例对话、用户故事等,展示 Agent 在不同情况下是如何响应的。 |
提供备用方案 | 指导 Agent 在遇到未知情况或无法提供回答时应该怎么做。比如包括寻求用户帮助、提供替代解决方案、或直接说明没有明确答案等。 |
迭代和优化 | 角色设定不是固定不变的,根据用户的反馈和评估情况不断的优化和调整角色设定。 |
以下是一个关于 Langchain 与 Semantic Kernel 的直观比较:
特性/框架 | Langchain | Semantic Kernel |
---|---|---|
设计理念 | 高度抽象与封装 | 高度模块化与灵活性 |
插件架构 | 抽象概念多,使得代码复杂 | 灵活、易于集成现有API和服务 |
系统化配置和管理 | 复杂多样,让人一头雾水 | 唯一核心组件Kernel提供所有系统化配置和管理 |
灵活性 | 不灵活,与快速变化的AI场景不够协同 | 面向未来设计,易于适应新技术 |
学习成本 | 抽象层次多,学习成本较高 | 设计直观,初学者门槛低 |
编程语言支持 | 不包含详情 | 支持C#、Python和Java |
企业适用性 | 适用性有限,复杂业务调试困难 | 专为企业设计,强调模块化和灵活性 |
微软推出的开源 Semantic Kernel 是一款强大的 AI SDK,携企业级实力和未来洞察,开创智能应用构建新方案。其自动化、模块化设计预示着AI开发的新风向。对替换 LangChain 而言,Semantic Kernel 绝对是理想的选择。
接入 LLM 是进行一系列 Agent 开发的最基本能力,因此我们先接入一个 Azure 提供的 GPT 服务试试,参考Getting Started以及文档,实践了下 LLM 的非流式和流式接入。
import os import sys ## 因为是使用的.env对LLM进行的配置,所以需要指明.env路径,具体参考Getting Started notebook_dir = os.path.abspath("") sys.path.append(notebook_dir) # 导入Azure服务和服务配置以及聊天历史类 from semantic_kernel.connectors.ai.open_ai import ( AzureChatCompletion, AzureChatPromptExecutionSettings, ) from semantic_kernel.contents import ChatHistory # 选择azure服务类型 service_id = "azure" # 实例化一个Azure服务 azure_chat_service = AzureChatCompletion( service_id=service_id, ) # 对实例进行相关设置 azure_prompt_execution_settings = AzureChatPromptExecutionSettings( service_id=service_id, max_tokens=150, temperature=0.7, top_p=1, frequency_penalty=0.5, presence_penalty=0.5, ) # 构造Message,通过ChatHistory高效实现 content = "You are an AI assistant that helps people find information." chat = ChatHistory() chat.add_system_message(content) chat.add_user_message("你是谁?") # 非流式调用并输出 result = await azure_chat_service.get_chat_message_contents( chat_history=chat, settings=azure_prompt_execution_settings ) print(str(result[-1]))
你好!我是一个人工智能助手,可以帮助你查找信息、解答问题和进行对话。有什么我可以帮助你的吗?
# 流式调用和输出
stream = azure_chat_service.get_streaming_chat_message_contents(
chat_history=chat,
settings=azure_prompt_execution_settings
)
async for token in stream:
print(token[-1], end="") # end = "" to avoid newlines
你好!我是一个人工智能助手,可以帮助你查找信息、解答问题和进行对话。有什么我可以帮助你的吗?
是不是非常的方便和简单。
尝试一个简单的灯具控制 Agent
import asyncio from semantic_kernel import Kernel from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion from semantic_kernel.connectors.ai.function_call_behavior import FunctionCallBehavior from semantic_kernel.connectors.ai.chat_completion_client_base import ChatCompletionClientBase from semantic_kernel.functions.kernel_arguments import KernelArguments from semantic_kernel.contents.chat_history import ChatHistory from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.azure_chat_prompt_execution_settings import ( AzureChatPromptExecutionSettings ) from typing import Annotated from semantic_kernel.functions import kernel_function # 定义一个灯具控制的插件(Plugin,一系列工具的集合) # LightsPlugin 包含 get_state 和 change_state 两个 functions,通过@kernel_function装饰器高效实现 class LightsPlugin: lights = [ {"id": 1, "name": "Table Lamp", "is_on": False}, {"id": 2, "name": "Porch lite", "is_on": False}, {"id": 3, "name": "Chandelier", "is_on": True}, ] @kernel_function( name="get_lights", description="Gets a list of lights and their current state", ) def get_state(self) -> Annotated[str, "the output is a string"]: """Gets a list of lights and their current state.""" return self.lights @kernel_function( name="change_state", description="Changes the state of the light", ) def change_state(self, id: int, is_on: bool) -> Annotated[str, "the output is a string"]: """Changes the state of the light""" for light in self.lights: if light["id"] == id: light["is_on"] = is_on return light return None # 定义主函数 async def main(): # 初始化Kernel kernel = Kernel() # 添加Azure OpenAI chat服务,仍然是通过.env配置 kernel.add_service(AzureChatCompletion( env_file_path="./.env" )) # 如果需要直接诶使用Azure服务,可以通过kernel直接获取,十分方便 chat_completion: AzureChatCompletion = kernel.get_service(type=ChatCompletionClientBase) # 插件添加到kernel kernel.add_plugin( LightsPlugin(), plugin_name="Lights" ) # 配置LLM工具调用的方式,auto自主决定 execution_settings = AzureChatPromptExecutionSettings(tool_choice="auto") execution_settings.function_call_behavior = FunctionCallBehavior.EnableFunctions(auto_invoke=True, filters={}) history = ChatHistory() userInput = None while True: userInput = input("User > ") if userInput == "exit": break history.add_user_message(userInput) result = (await chat_completion.get_chat_message_contents( chat_history=history, settings=execution_settings, kernel=kernel, arguments=KernelArguments() ))[0] print("Assistant > ", result) if __name__ == "__main__": asyncio.run(main())
User > 有哪些灯? Assistant > 我们有以下几盏灯: 1. 台灯 (Table Lamp) - 关闭状态 2. 门廊灯 (Porch lite) - 关闭状态 3. 吊灯 (Chandelier) - 打开状态 User > 把2打开,把3关了 Assistant > 操作完成 。 2. 门廊灯 (Porch lite) 已打开。 3. 吊灯 (Chandelier) 已关闭。 User > 完了吗,我看看状态 Assistant > 当前灯光状态如下: 1. 台灯 (Table Lamp) - 关闭状态 2. 门廊灯 (Porch lite) - 打开状态 3. 吊灯 (Chandelier) - 关闭状态 User >
[1] https://learn.microsoft.com/en-us/semantic-kernel/overview/
[2] https://mp.weixin.qq.com/s/ZJTfCkWOrE8omRZEhrj_3g
[3] https://github.com/microsoft/semantic-kernel
[4] https://mp.weixin.qq.com/s/mtaXOGFw3852F1RsZNqF4Q
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。