AI全栈大模型工程师(二十)SKvs.LangChain

编程入门 行业动态 更新时间:2024-10-27 15:21:47

AI全栈大模型工程师(<a href=https://www.elefans.com/category/jswz/34/1766924.html style=二十)SKvs.LangChain"/>

AI全栈大模型工程师(二十)SKvs.LangChain

文章目录

    • SK vs. LangChain
      • 概念对照
      • 功能对照
    • 环境搭建
    • Plugins
      • Semantic Functions
        • skprompt.txt
        • config.json
      • Semantic Kernel Tools
      • Native Functions
      • 内置 Plugins
    • Memory
    • Planner
    • 后记

SK vs. LangChain

#%% md

概念对照

LangChainSemantic Kernel
ModelConnector
ToolsConnector
VectorstoreConnector
MemoryMemory
Prompt TemplatesPlugins
ChainPipeline / Chain
AgentPlanner
TextSplittertext.*
OutputParser

功能对照

LangChainSemantic Kernel
大模型60+5+
向量数据库40+11
Agent10+4

#%% md

环境搭建

#%% md

  1. 安装 Python 3.x:/
  2. 安装 SK 包:pip install semantic-kernel
  3. 在项目目录创建 .env 文件,添加以下内容:
# .env
OPENAI_API_KEY=""
OPENAI_API_BASE=""
AZURE_OPENAI_DEPLOYMENT_NAME=""
AZURE_OPENAI_ENDPOINT=""
AZURE_OPENAI_API_KEY=""

OpenAI 和 Azure,配置好一个就行。

#%% md

## Hello, World!#%% md
这是一个简单示例。第一段代码是初始化。后面所有代码都要在执行过这段代码后,才能执行。#%%
import semantic_kernel as sk
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
import os# 加载 .env 到环境变量from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())# 创建 semantic kernelkernel = sk.Kernel()# 配置 OpenAI 服务api_key = os.getenv('OPENAI_API_KEY')
endpoint = os.getenv('OPENAI_API_BASE')
model = OpenAIChatCompletion("gpt-3.5-turbo", api_key, endpoint=endpoint)# 把 LLM 服务加入 kernel# 可以加多个。第一个加入的会被默认使用,非默认的要被指定使用kernel.add_text_completion_service("my-gpt3", model)
#%% md
执行讲笑话的 prompt。#%%# 定义 semantic functiontell_joke_about = kernel.create_semantic_function("给我讲个关于{{$input}}的笑话吧")# 看结果print(tell_joke_about("Hello world"))

#%% md

划重点: 用我们熟悉的操作系统来类比,可以更好地理解 SK。
  1. 启动操作系统:kernel = sk.Kernel()
  2. 安装驱动程序:kernel.add_xxx_service()
  3. 安装应用程序:func = kernel.create_semantic_function()
  4. 运行应用程序:func()

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

#%% md

Plugins

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

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

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

注意:Plugins 最初命名为 Skills,后来改为 Plugins。但是无论文档还是代码,都还有大量的「Skill」遗留。见到后,就知道两者是一回事就好

#%% md

Semantic Functions

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

一个典型的 semantic function 包含两个文件:

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

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

#%% md

skprompt.txt

#%% raw
将用户的指令转换成 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}}
#%% md

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”: “”
}
]
}
}
#%% md
上面两个文件都在 sk_samples/SamplePlugin/GenerateCommand 目录下。

#%% md

#### 调用 Semantic Functions#%%# 加载 semantic function。注意目录结构functions = kernel.import_semantic_skill_from_directory("./sk_samples/", "SamplePlugin")
cli = functions["GenerateCommand"]# 看结果print(cli("将系统日期设为2023-04-01"))

#%% md
官方提供了大量的 Semantic Functions 可以参考:

#%% md

Semantic Kernel Tools

#%% md
这是个 VS Code 的插件,在 VS Code 里可以直接创建和调试 Semantic Function。

安装地址:=ms-semantic-kernel.semantic-kernel

#%% md

Native Functions

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

下面,写一个过滤有害 Linux 命令的函数,和 GenerateCommand 组合使用。

这个函数名是 harmful_command。如果输入的命令是有害的,就返回 true,否则返回 false

它也要放到目录结构中,在 sk_samples/SamplePlugin/SamplePlugin.py 里加入。

#%%# 因为是代码,不是数据,所以必须 importfrom sk_samples.SamplePlugin.SamplePlugin import SamplePlugin# 加载 semantic functionfunctions = kernel.import_semantic_skill_from_directory("./sk_samples/", "SamplePlugin")
cli = functions["GenerateCommand"]# 加载 native functionfunctions = kernel.import_skill(SamplePlugin(), "SamplePlugin")
harmful_command = functions["harmful_command"]# 看结果command = cli("删除根目录下所有文件")
print(command)  # 这个 command 其实是 SKContext 类型
print(harmful_command(context=command))  # 所以要传参给 context
#%% md### 用 SKContext 实现多参数 Functions#%% md
如果 Function 都只有一个参数,那么只要把参数定义为 `{{$input}}`,就可以按前面的例子来使用,比较直观。`{{$input}}`会默认被赋值。多参数时,就不能用默认机制了,需要定义 `SKContext` 类型的变量。#%%# 因为是代码,不是数据,所以必须 importfrom sk_samples.SamplePlugin.SamplePlugin import SamplePlugin# 加载 native functionfunctions = kernel.import_skill(SamplePlugin(), "SamplePlugin")
add = functions["add"]# 看结果context = kernel.create_new_context()
context["number1"] = 1024
context["number2"] = 65536
total = add(context=context)
print(total)
#%% md

内置 Plugins

#%% md
SK 内置了若干好用的 plugin,但因为历史原因,它们叫 skill……

加载方法:

from semantic_kernel.core_skills import SkillName

它们是:

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

#%% md

Memory

#%% md
SK 的 memory 使用非常简单:

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

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

#%% md### 初始化 Embedding#%%
import semantic_kernel as sk
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion, OpenAITextEmbedding
import os# 加载 .env 到环境变量from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())# 创建 semantic kernelkernel = sk.Kernel()# 配置 OpenAI 服务api_key = os.getenv('OPENAI_API_KEY')
endpoint = os.getenv('OPENAI_API_BASE')
model = OpenAIChatCompletion("gpt-3.5-turbo", api_key, endpoint=endpoint)# 把 LLM 服务加入 kernel# 可以加多个。第一个加入的会被默认使用,非默认的要被指定使用kernel.add_text_completion_service("my-gpt3", model)# 添加 embedding 服务kernel.add_text_embedding_generation_service("ada", OpenAITextEmbedding("text-embedding-ada-002", api_key, endpoint=endpoint))
#%% md### 文本向量化#%%# 使用内存做 memory storekernel.register_memory_store(memory_store=sk.memory.VolatileMemoryStore())# 读取文件内容with open('../05-langchain/ChatALL.md', 'r') as f:# with open('sk_samples/SamplePlugin/SamplePlugin.py', 'r') as f:content = f.read()# 将文件内容分片,单片最大 100 token(注意:SK 的 text split 功能目前对中文支持不如对英文支持得好)lines = sk.text.split_markdown_lines(content, 100)# 将分片后的内容,存入内存for index, line in enumerate(lines):await kernel.memory.save_information_async("chatall", id=index, text=line)
#%% md### 向量搜索#%%
result = await kernel.memory.search_async("chatall", "ChatALL怎么下载?")
print(result[0].text)
#%% md## Pipeline / Chain#%% md
SK 更想用 pipeline 来描述 LangChain 中 chain 的概念,大概因为 pipeline 这个词更操作系统吧。但 chain 这个名词影响力太大,所以 SK 时不时也会用它。但是,SK 没有在代码里定义什么是 pipeline,它并不是一个类,或者函数什么的。它是贯彻整个 kernel 的一个概念。当一个 kernel 添加了 LLM、memory、functions,我们写下的 functions 之间的组合调用,就是个 pipeline 了。如果需要多条 pipeline,就定义多个 kernel。<div class="alert alert-block alert-info">
<b>思考:</b>LangChain 定义了好几种 Chain;SK 只是用 kernel 把抽象功能组合起来,pipeline 的过程完全交给开发者自己定义。你觉得哪种设计更好?
</div>#%% md
现在用 pipeline 思想把对话式搜索 ChatALL 的 README.md 功能做完整。要用到内置的 `TextMemorySkill`。#%%# 导入内置的 `TextMemorySkill`。主要使用它的 `recall()`kernel.import_skill(sk.core_skills.TextMemorySkill())# 直接在代码里创建 semantic function。里面调用了 `recall()`sk_prompt = """
基于下面的背景信息回答问题。如果背景信息为空,或者和问题不相关,请回答"我不知道"。[背景信息开始]
{{recall $input}}
[背景信息结束]问题:{{$input}}
回答:
"""
ask = kernel.create_semantic_function(sk_prompt)# 提问context = kernel.create_new_context()
context[sk.core_skills.TextMemorySkill.COLLECTION_PARAM] = "chatall"
context[sk.core_skills.TextMemorySkill.RELEVANCE_PARAM] = 0.8
context["input"] = "ChatALL 怎么下载?"
result = ask(context=context)
print(result)
#%% md

Planner

#%% md
SK 的 planner 概念上对标 LangChain 的 agent,但目前实现得还比较简单(C# 版丰富些)。SK Python 提供了三种 planner:1. `BasicPlanner` - 把任务拆解,自动调用各个函数,完成任务。它只是个用于基础验证的功能,最终会被 `SequentialPlanner` 替代。[Prompt 地址](.py#L27-L123)
2. `SequentialPlanner` - 开发中,未发布。比 `BasicPlanner` 更高级,但目标一致。[Prompt 地址](.txt)、[官方例程](.py)
3. `ActionPlanner` - 已发布。只输出 action,不执行。[Prompt 地址](.txt)、[官方例程](.py)来,把查周杰伦的生日是星期几,用 SK 的 `BasicPlanner` 再做一遍(版本 > 0.3.7dev 才能工作)。#%%
from semantic_kernel.core_skills import WebSearchEngineSkill, TimeSkill, MathSkill
from semantic_kernel.connectors.search_engine import BingConnector
from semantic_kernel.planning import BasicPlanner
import semantic_kernel as sk
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion, OpenAITextEmbedding
import os# 加载 .env 到环境变量from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())# 创建 semantic kernelkernel = sk.Kernel()# 配置 OpenAI 服务api_key = os.getenv('OPENAI_API_KEY')
endpoint = os.getenv('OPENAI_API_BASE')
model = OpenAIChatCompletion("gpt-4", api_key, endpoint=endpoint)    # GPT-4 才能完成此任务。不信改成 gpt-3.5-turbo 试试# 把 LLM 服务加入 kernel# 可以加多个。第一个加入的会被默认使用,非默认的要被指定使用kernel.add_text_completion_service("my-gpt4", model)# 导入搜索 pluginconnector = BingConnector(api_key=os.getenv("BING_API_KEY"))
kernel.import_skill(WebSearchEngineSkill(connector), "WebSearch")# 导入其它 plugin。所有被导入的 plugin,都是可以被 planner 调用的kernel.import_skill(MathSkill(), "math")
kernel.import_skill(TimeSkill(), "time")# 创建 plannerplanner = BasicPlanner()# 开始ask = "周杰伦的生日是星期几?"
plan = await planner.create_plan_async(ask, kernel)
print(plan.generated_plan)
result = await planner.execute_plan_async(plan, kernel)
print(result)

后记

📢博客主页:

📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📢本文由 Maynor 原创,首发于 CSDN博客🙉
📢不能老盯着手机屏幕,要不时地抬起头,看看老板的位置⭐
📢专栏持续更新,欢迎订阅:.html

更多推荐

AI全栈大模型工程师(二十)SKvs.LangChain

本文发布于:2023-11-15 17:27:10,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1603390.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:二十   模型   工程师   全栈大   AI

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!