Semantic Kernel


Semantic Kernel」 是一个开源 SDK,可让您轻松地将 OpenAI、Azure OpenAI 和 Hugging Face 等 AI 服务与 C# 和 Python 等传统编程语言结合起来。通过这样做,您可以创建结合两全其美的人工智能应用程序。

为了帮助开发人员在 AI 插件之上构建自己的 Copilot 体验,微软发布了 Semantic Kernel,这是一个轻量级开源 SDK,可让您编排 AI 插件。 借助 Semantic Kernel,您可以在自己的应用程序中利用与 Microsoft 365 Copilot 和 Bing 相同的 AI 编排模式,同时仍然利用现有的开发技能和投入。

sk-plugins 如果您有兴趣查看正在运行的 copilot stack 示例(以语义内核为中心),请查看 Project Miyagi。 使用了所有最新的 AI 服务和工具重新构想了 Azure 上智能应用程序的设计、开发和部署。

Semantic Kernel 现在还是未正式发版状态。1.0.0 版预计今年底发布。

  • C# 版最成熟,已开始 1.0.0-beta1
  • Python 版还在 dev 状态,但可用
  • Javaalpha 阶段
  • TypeScript 版发展缓慢,可能已经放弃了

文档写得特别好,但追不上代码更新速度:

与 LangChain 完全重叠。微软将此技术栈命名为 「Copilot Stack」。

copilot-stack
  • Plugin extensibility: 插件扩展
  • Copilots: AI 助手(副驾驶),例如 GitHub Copilot、Office 365 Copilot、Windows Copilot
  • AI orchestration: AI 编排,SK 就在这里
  • Foundation models: 基础大模型,例如 GPT-4
  • AI infrastructure: AI 基础设施,例如 PyTorch、GPU

Semantic Kernel 用 Kernel 命名,是因为它确实像个操作系统 kernel,做核心资源调配,各种资源都可以挂在它之上。

mind-and-body-of-semantic-kernel
  • Models and Memory: 和 LangChain 的概念相同,类比为大脑
  • Connectors: 用来连接各种外部服务,类似驱动程序
  • Plugins: 用来连接内部技能
  • Triggers and actions: 外部系统的触发器和动作,类比为四肢

SK 对集成第三方能力的态度是不希望放在自己的核心代码库中,像操作系统一样,它只提供最基础的能力,其它的都是外部维护,按需安装。 参考 这里。

这是一个简单示例。

收起

提示

站在操作系统的角度来理解 SK

  • 启动操作系统:kernel = sk.Kernel()
  • 安装驱动程序:kernel.add_xxx_service()
  • 安装应用程序:func = kernel.create_semantic_function()
  • 运行应用程序:func()

基于 SK 开发的主要工作是写「应用程序」,也就是 Plugins

简单说,plugin 就是一组函数的集合。它可以包含两种函数:

  • Semantic Functions - 语义函数,本质是 Prompt Engineering
  • Native Functions - 原生函数,类似 OpenAI 的 Function Calling

值得一提的是,SK 的 plugin 会和 ChatGPT、Bing、Microsoft 365 通用。 很快用 SK 写的 plugin 就可以在这些平台上无缝使用了。这些平台上的 plugin 也可以通过 SK 被调用。

注意:Plugins 最初命名为 「Skills」,后来改为 Plugins。但是无论文档还是代码,都还有大量的「Skill」遗留,预计到 1.0.0 发布才能清理干净,两者是一回事。

Semantic Functions 是纯用数据(prompt + 描述)定义的,不需要编写任何代码。所以它与编程语言无关,可以被任何编程语言调用。

一个典型的 Semantic Function 包含两个文件:

  • skprompt.txt: 存放 prompt,可以包含参数,还可以调用其它函数
  • config.json: 存放描述,包括函数功能,参数的数据类型,以及调用大模型时的参数

举例:把 LangChain 「生成 Linux 命令」的例子用 SK 实现。

准备 skprompt.txt

将用户的指令转换成 Linux 命令

The output should be formatted as a JSON instance that conforms to the JSON schema below.

As an example, for the schema {"properties": {"foo": {"title": "Foo", "description": "a list of strings", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]}}
the object {"foo": ["bar", "baz"]} is a well-formatted instance of the schema. The object {"properties": {"foo": ["bar", "baz"]}} is not well-formatted.

Here is the output schema:
```
{"properties": {"command": {"title": "Command", "description": "linux shell命令名", "type": "string"}, "arguments": {"title": "Arguments", "description": "命令的参数 (name:value)", "type": "object", "additionalProperties": {"type": "string"}}}, "required": ["command", "arguments"]}
```

{{$input}}

准备 config.json

{
    "schema": 1,
    "type": "completion",
    "description": "将用户的指令转换成 Linux 命令",
    "completion": {
        "max_tokens": 256,
        "temperature": 0,
        "top_p": 0,
        "presence_penalty": 0,
        "frequency_penalty": 0
    },
    "input": {
        "parameters": [
            {
                "name": "input",
                "description": "用户的指令",
                "defaultValue": ""
            }
        ]
    }
}

收起

官方提供了大量的 Semantic Functions 可以参考

提示Semantic Kernel Tools 是个 VS Code 的插件,在 VS Code 里可以直接创建和调试 Semantic Function。

使用编程语言写的函数,如果用 SK 的 Native Function 方式定义,就能纳入到 SK 的编排体系,可以被 Planner、其它 plugin 调用。

下面,写一个过滤有害 Linux 命令的函数,和 GenerateCommand 组合使用。 这个函数名是 harmful_command。如果输入的命令是有害的,就返回 true ,否则返回 false

收起

如果 Function 都只有一个参数,那么只要把参数定义为 {{$input}},就可以按前面的例子来使用,比较直观。{{$input}} 会默认被赋值。

多参数时,就不能用默认机制了,需要定义 SKContext 类型的变量。

收起

SK 内置了一些好用的 plugin,但因为历史原因,它们被命名为 skill……

加载方法:

包括:

  • ConversationSummarySkill - 生成对话的摘要
  • FileIOSkill - 读写文件
  • HttpSkill - 发出 HTTP 请求,支持 GET、POST、PUT 和 DELETE
  • MathSkill - 加法和减法计算
  • TextMemorySkill - 保存文本到 memory 中,可以对其做向量检索
  • TextSkill - 把文本全部转为大写或小写,去掉头尾的空格(trim)
  • TimeSkill - 获取当前时间及用多种格式获取时间参数
  • WaitSkill - 等待指定的时间
  • WebSearchEngineSkill - 在互联网上搜索给定的文本

SK 的 memory 使用说明:

  • kernel.add_text_embedding_generation_service():添加一个文本向量生成服务
  • kernel.register_memory_store():注册一个 memory store,可以是内存、文件、向量数据库等
  • kernel.memory.save_information_async():保存信息到 memory store
  • kernel.memory.search_async():搜索信息

使用 SK 的 README.md 做数据,使用内存作为 memory store,演示下基于文档对话。

收起

收起

收起

SK 更想用 Pipeline 来描述 LangChain 中 chain 的概念,大概因为 pipeline 这个词更符合操作系统吧。但 chain 这个名词影响力太大,所以 SK 时不时也会用它。

但是,SK 没有在代码里定义什么是 pipeline,它并不是一个类,或者函数什么的。它是贯彻整个 kernel 的一个概念。 当一个 kernel 添加了 LLM、memory、functions,我们写下的 functions 之间的组合调用,就是个 pipeline 了。 如果需要多条 pipeline,就定义多个 kernel。

现在用 pipeline 思想把对话式搜索 SK 的 README.md 功能做完整。

在自定义的 Semantic Function 中,嵌套调用内置的 TextMemorySkill

收起

SK 的 planner 概念上对标 LangChain 的 agent,但做得比较简单,还比较初步。

SK Python 提供了四种 planner:

1. SequentialPlanner

制定包含一系列步骤的计划,这些步骤通过自定义生成的输入和输出变量相互连接。更多参考 核心 prompt官方例程

2. ActionPlanner

类似 OpenAI Function Calling,从 kernel 中已注册的所有 plugin 中找到一个该执行的函数。更多参考 核心 prompt官方例程

3. StepwisePlanner

每执行完一步,都做一下复盘,只输出 action,不执行。更多参考 核心 prompt

4. BasicPlanner

不建议使用。把任务拆解,自动调用各个函数,完成任务。它只是个用于基础验证的功能,最终会被 SequentialPlanner 替代。更多参考 核心 prompt

planner 的使用步骤:

  • 把 plugin 注册到 kernel
  • 把 kernel 当参数实例化某个 planner
  • 调用 planner 的 create_plan_async() 方法获得 plan
  • 调用 plan 的 invoke_async() 方法执行 plan
注意:不同 planner 接口并不一致,不能简单平替。

收起