🌵🌵目录🌵🌵
🏳️🌈LangChain 与 Semantic Kernel 对比 🌈
本文将继续延续Langchain专栏文章,本文将继续沿用文章风格,最简单易懂的语言讲解Langchain的智能体架构(Agent)、LangServe和Langchain.js,最后再对比SK之间的区别,逐渐深入学习Langchain的高级能力,帮助更好更快的接触大模型。
初识Langchain可以看看这篇文章:
😋智能体架构:Agent 🍔
什么是智能体
将大语言模型作为一个推理引擎。给定一个任务,智能体自动生成完成任务所需的步骤,执行相应动作(例如选择并调用工具),直到任务完成。 (通俗的话来说智能体就是能通过多步的自我思考,每一步的选择合适的工具,去执行这个工具,再根据这个工具执行的结果去推测下一步应该干什么,通过多步的思考完成一个复杂的流程)
其中最核心的模块就是工具集(Tools),Tools是这个模型所具备的能力,而另一个就是计划(Planning)的模块。Planning其实就是prompt来定义的,怎么执行这个逻辑是由Planning来定义的,同时它有不同的模式定义,它决定了每一步思考完成后该使用哪个工具(Tools),例如Reflection、Self-critics、Chain of thoughts和Subgoal decomposition等。可选项就是它有长时和短时的记忆,短时记忆主要则记录上一步做了什么,用于决策下一步应该做什么,长时记忆就是多轮记忆,给了一个任务,它能自己想了很多步后决策当前应该干什么。
先定义一些工具:Tools
通俗的说它可以是一个函数或三方 API,也可以把一个 Chain 或者 Agent 的 run()作为一个 Tool
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())
from langchain_community.utilities import SerpAPIWrapper
from langchain.tools import Tool, tool
# 搜索引擎的接口,封装的就是我调用引擎的过程
search = SerpAPIWrapper()
tools = [
Tool.from_function(
func=search.run,
name="Search",
description="useful for when you need to answer questions about current events"
),
]
需要注册 SerpApi: Google Search API(限量免费),并将 `SERPAPI_API_KEY` 写在环境变量中
import calendar
import dateutil.parser as parser
from datetime import date
# 自定义工具
@tool("weekday")
def weekday(date_str: str) -> str:
"""Convert date to weekday name"""
d = parser.parse(date_str)
return calendar.day_name[d.weekday()]
tools += [weekday]
智能体类型:ReAct
下载一个现有的 Prompt 模板,官方给的一个React Prompt模板写法,此处为一个模板,当简单了解即, 因为智能体这个真的要能用,里面的逻辑比较复杂的。
from langchain import hub
import json
# 下载一个现有的 Prompt 模板
# 官方给的一个React Prompt模板写法,此处为一个模板,当简单了解即可
# 因为智能体这个真的要能用,里面的逻辑比较复杂的
prompt = hub.pull("hwchase17/react")
print(prompt.template)
#Answer the following questions as best you can. You have access to the following tools:
# 工具定义,让大模型知道有什么工具
# {tools}
#
# Use the following format:
#
# 给大模型描述了一个思考的过程,
# Question: the input question you must answer
# Thought: you should always think about what to do
# 思考完成后选择一个action,这个action必须是tools其中之一
# Action: the action to take, should be one of [{tool_names}]
# 执行完action后会返回一个input
# Action Input: the input to the action
# 执行完之后会返回一个结果
# Observation: the result of the action
# ... (this Thought/Action/Action Input/Observation can repeat N times)
# 重复上面的步骤,思考执行,直到可以给最终答案
# Thought: I now know the final answer
# 知道它认为它的任务完成为止
# Final Answer: the final answer to the original input question
#
# Begin!
#
# Question: {input}
# Thought:{agent_scratchpad}
封装两个标准化流程,一个create xxx agent,根据模板工具,所需要的要素不一样,另一个是AgentExecutor,它封装了AgentExector的执行的过程,即它多步需要调一次大模型,然后选工具,然后执行结果给到模型,再传再调,这个流程是这个AgentExector来控制的。
from langchain_openai import ChatOpenAI
# 封装两个标准化流程,一个create xxx agent,根据模板工具,所需要的要素不一样,
# 另一个是AgentExecutor,它封装了AgentExector的执行的过程,即它多步需要调一次大模型,然后选工具,然后执行结果给到模型,再传再调,这个流程是这个AgentExector来控制的
from langchain.agents import AgentExecutor, create_react_agent
llm = ChatOpenAI(model_name='gpt-4', temperature=0)
# 然后它把这个过程抽象成这两步了
# 定义一个 agent: 需要大模型、工具集、和 Prompt 模板
agent = create_react_agent(llm, tools, prompt)
# 定义一个执行器:需要 agent 对象 和 工具集
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# 执行
agent_executor.invoke({"input": "周杰伦出生那天是星期几"})
# 思考过程
# > Entering new AgentExecutor chain...
# 我需要知道周杰伦的出生日期,然后我可以使用weekday函数来找出那天是星期几。
# Action: Search
# Action Input: 周杰伦的出生日期
# January 18, 1979 (age 45 years), Linkou District, Taipei, Taiwan我现在知道周杰伦的出生日期是1979年1月18日。我可以使用weekday函数来找出那天是星期几。
# Action: weekday
# Action Input: 1979-01-18
#
# Thursday我现在知道周杰伦出生那天是星期四。
# Final Answer: 周杰伦出生那天是星期四。
#
# > Finished chain.
# 最终输出结果
# {'input': '周杰伦出生那天是星期几', 'output': '周杰伦出生那天是星期四。'}
智能体类型:SelfAskWithSearch
下载一个模板,自我填充答案的例子,根据用户问的一个问题,按照这个例子的形式一步一步的去思考,这个例子最主要的就是使用search能力,除了这个其他都不要。
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())
from langchain import hub
# 下载一个模板,自我填充答案的例子
# 根据用户问的一个问题,按照这个例子的形式一步一步的去思考
prompt = hub.pull("hwchase17/self-ask-with-search")
print(prompt.template)
# Question: Who lived longer, Muhammad Ali or Alan Turing?
# Are follow up questions needed here: Yes.
# Follow up: How old was Muhammad Ali when he died?
# Intermediate answer: Muhammad Ali was 74 years old when he died.
# Follow up: How old was Alan Turing when he died?
# Intermediate answer: Alan Turing was 41 years old when he died.
# So the final answer is: Muhammad Ali
#
# Question: When was the founder of craigslist born?
# Are follow up questions needed here: Yes.
# Follow up: Who was the founder of craigslist?
# Intermediate answer: Craigslist was founded by Craig Newmark.
# Follow up: When was Craig Newmark born?
# Intermediate answer: Craig Newmark was born on December 6, 1952.
# So the final answer is: December 6, 1952
#
# Question: Who was the maternal grandfather of George Washington?
# Are follow up questions needed here: Yes.
# Follow up: Who was the mother of George Washington?
# Intermediate answer: The mother of George Washington was Mary Ball Washington.
# Follow up: Who was the father of Mary Ball Washington?
# Intermediate answer: The father of Mary Ball Washington was Joseph Ball.
# So the final answer is: Joseph Ball
#
# Question: Are both the directors of Jaws and Casino Royale from the same country?
# Are follow up questions needed here: Yes.
# Follow up: Who is the director of Jaws?
# Intermediate answer: The director of Jaws is Steven Spielberg.
# Follow up: Where is Steven Spielberg from?
# Intermediate answer: The United States.
# Follow up: Who is the director of Casino Royale?
# Intermediate answer: The director of Casino Royale is Martin Campbell.
# Follow up: Where is Martin Campbell from?
# Intermediate answer: New Zealand.
# So the final answer is: No
#
# Question: {input}
# Are followup questions needed here:{agent_scratchpad}
from langchain_community.utilities import SerpAPIWrapper
from langchain.tools import Tool, tool
# 这个例子最主要的就是使用search能力,除了这个其他都不要
from langchain.agents import create_self_ask_with_search_agent
search = SerpAPIWrapper()
tools = [
Tool(
name="Intermediate Answer",
func=search.run,
description="useful for when you need to ask with search.",
)
]
from langchain_openai import ChatOpenAI
# 封装两个标准化流程,一个create xxx agent,根据模板工具,所需要的要素不一样,
# 另一个是AgentExecutor,它封装了AgentExector的执行的过程,即它多步需要调一次大模型,然后选工具,然后执行结果给到模型,再传再调,这个流程是这个AgentExector来控制的
from langchain.agents import AgentExecutor, create_react_agent
llm = ChatOpenAI(model_name='gpt-4', temperature=0)
# self_ask_with_search_agent 只能传一个名为 'Intermediate Answer' 的 tool
agent = create_self_ask_with_search_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, handle_parsing_errors=True)
agent_executor.invoke({"input": "吴京的老婆主持过哪些综艺节目"})
思考过程
## > Entering new AgentExecutor chain...
# Yes.
# Follow up: Who is 吴京's wife?['吴京老婆谢楠:一句我养你成就战狼孕肚操办婚礼却独守空房(中) ... 简介: 战狼明星温情婚礼电影谢楠你不看到了吗?这还要明说! 一言不合就发脾气砸东西的吴京靠什么让谢楠忍到 ...', '2月16日。 一张吴京妻子谢楠与知名女演员贾玲的合影在网络上引起了热议。 两位美女同框,颜值喜人,气质更是般配得如同亲姐妹一般,让人不禁赞叹不已。', '吴京的4个老婆曝光,个个都貌美如花,唯独她老成农村卖鱼大婶 · 吴京的4个老婆曝光,前三位个个美若天仙,最后一个才是他的真爱 · 你知道吴京娶过几个老婆吗.', '主演「战狼」系列电影暴红的中国男星吴京,和小9岁的妻子谢楠结婚多年来,感情甜蜜,是圈内公认神仙眷侣。 近日,有网友翻出两人昔日一起上真人秀综艺,吴京在节目中发脾气的片段,并指责他暴力、大男子主义、不爱老婆,还劝谢楠离婚。 对此,谢楠发长文诉说真实感想。', '主演「戰狼」系列電影暴紅的中國男星吳京,和小9歲的妻子謝楠結婚多年來,感情甜蜜,是圈內公認神仙眷侶。近日,有網友翻出兩人昔日一起上真人秀 ...', '很多人都说吴京不会浪漫,不知道怎么哄老婆开心,他是一个硬汉,不懂得怎么柔情,谢楠一直给大家的感觉都是很坚强的女人,一直都留短头发,但有一次谢楠流 ...', '吴京事业再创高峰。 当选成为新一届“中国影协副主席”。 但是生活上却因为婚姻问题屡屡被骂。', '最近,吴京和谢楠夫妻两几年前参加综艺的片段又突然在互联网上拥有了姓名。 原来是在综艺里吴京被安排为大家准备食物,谢楠作为妻子不仅进入厨房协助 ...', '演员吴京的妻子是谢楠。 谢楠,1983年11月6日出生于安徽省合肥市,毕业于安徽财经大学,中国内地女主袭型持人、演员。2014年1月1日凌晨,晒出结婚证 ...']Follow up: What are some of the variety shows hosted by 谢楠?['生平 于2005年“猫人超级魅力主持秀”冠军脱颖而出,现任光线传媒旗下主打节目《娱乐现场》、《最佳现场》、《影视风云榜》当家主持。 2011年11月24日,谢楠发行首张个人ep《最好的我们》。 2014年,吴京发布新年微博公布婚讯,表示已经与谢楠结婚。', '谢楠,1983年11月6日出生于安徽省合肥市,中国内地节目女主持人、影视演员,毕业于安徽财经大学。2005年,在“魅力主持大赛”上获得冠军并签约光线传媒,从而开启了她的 ...']So the final answer is: 谢楠 has hosted variety shows such as "娱乐现场", "最佳现场", and "影视风云榜".
总结
实际应用场景要比这个要复杂的多,因为实际应用是千变万化的,实际智能体能否标准化是有待商榷的,所以智能体的创建和封装,究竟有多大价值,要看实际应用场景。目前来看,本例子中,对于agent和执行器的封装看不出有多大的价值。所以以上只是做一个参考,认识智能体即可,以上例子只是封装了一个最基本的流程。
🍉认识LangServe 🏖️
LangServe 用于将 Chain 或者 Runnable 部署成一个 REST API 服务。
# 安装 LangServe
pip install --upgrade "langserve[all]"
# 也可以只安装一端
pip install "langserve[client]"
pip install "langserve[server]"
Server端
#!/usr/bin/env python
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())
from fastapi import FastAPI
from langchain.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langserve import add_routes
import uvicorn
app = FastAPI(
title="LangChain Server",
version="1.0",
description="你是一名语文老师",
)
model = ChatOpenAI()
prompt = ChatPromptTemplate.from_template("帮我解释一下这个成语:{idiom}")
add_routes(
app,
prompt | model,
path="/idiom",
)
if __name__ == "__main__":
uvicorn.run(app, host="localhost", port=9999)
Client端
import requests
response = requests.post(
"http://localhost:9999/idiom/invoke",
json={'input': {'idiom': '繁花似锦'}}
)
print(response.json())
总结
LangServe的出现将一套复杂的Chain流程发布成Web服务成为了一种可能,它的设计初衷是为了未来低代码,或轻量级开发,或根本不需要代码,仅需配置chain流程就能部署一个服务,但LangServe只是一个做了基本实现,真正实现也不一定必须使用这套架构,真正去开发的话部署的框架有很多,选择有很多,做一个了解也可以。
🌞 认识LangChain.js 🔆
属于Python 版 LangChain 的姊妹项目,都是由 Harrison Chase 主理。
项目地址:GitHub - langchain-ai/langchainjs: 🦜🔗 Build context-aware reasoning applications 🦜🔗
特色
-
可以和 Python 版 LangChain 无缝对接
-
抽象设计完全相同,概念一一对应
-
所有对象序列化后都能跨语言使用,但 API 差别挺大,不过在努力对齐
当前支持环境
- Node.js (ESM and CommonJS) - 18.x, 19.x, 20.x
- Cloudflare Workers
- Vercel / Next.js (Browser, Serverless and Edge functions)
- Supabase Edge Functions
- Browser
- Deno
安装:
npm install langchain
能力重点
- 在逐步追上 Python 版的能力,甚至为此做了一个基于 gpt-3.5-turbo 的代码翻译器;
- 能够保持兼容尽可能多的环境;
- 当前对质量关注不多,但随时间自然能解决;
🏳️🌈LangChain 与 Semantic Kernel 对比 🌈
SK从版本即从生态的活跃度丰富度是不如LangChain的,只是它的设计理念和微软生态的融合要比Langchain强,但它的设计理念也是架构在有微软那套生态做支撑的,否则它那套宏大的设计理念可能是过度设计的结果。
对比图
功能/工具 | LangChain | Semantic Kernel |
版本号 | 0.1.7 | python-0.9.7b |
适配的 LLM | 多 | 少 + 外部生态 |
Prompt 工具 | 支持 | 支持 |
Prompt 函数嵌套 | 需要通过 LCEL | 支持 |
Prompt 模板嵌套 | 支持 | 不支持 |
输出解析工具 | 支持 | 不支持 |
上下文管理工具 | 支持 | C#版支持,Python 版尚未支持 |
内置工具 | 多,但良莠不齐 | 少 + 外部生态 |
三方向量数据库适配 | 多 | 少 + 外部生态 |
服务部署 | LangServe | 与 Azure 衔接更丝滑 |
管理工具 | LangSmith/LangFuse | Prompt Flow (* |
总结
- LangChain 随着版本迭代可用性有明显提升
- 使用 LangChain 要注意维护自己的 Prompt,尽量 Prompt 与代码逻辑解依赖;
- 它的内置基础工具,建议充分测试效果后再决定是否使用;