在一个阳光明媚的早晨,小王坐在他的工作台前,面前是一堆复杂的代码和文档。他是一位充满激情的码农,正在用LangChain构建一个超级助理一般的聊天机器人。小王对机器人的未来充满憧憬,但眼下他面临着一个巨大的挑战:如何将他的聊天机器人转化为一个用户友好的在线服务。他需要一个能够将模型快速而可靠地部署为API的工具,这个API不仅要稳定可靠,还要易于使用和理解。他开始在互联网上寻找答案,直到有一天,他偶然发现了一个名为LangServe的库。
假如你有一个超级智能的机器人,它可以帮你完成各种复杂的任务,比如聊天、写文章、甚至还能帮你处理数据。但是,这个机器人需要一个家,一个让它能够发挥全部能力的平台。这就是LangServe的作用,它是一个工具,可以帮助开发者把这样的智能机器人变成一个在线服务,让其他人也能使用。
LangServe结合了FastAPI和一个叫做pydantic的库,用来确保数据的正确性。它还提供了一个客户端,可以让人们通过网络与这些智能机器人互动。如果你喜欢编程,你可以用LangServe快速搭建一个项目,或者用LangChain的模板来快速开始。
功能亮点
- LangServe能够自动推断出你的智能机器人能处理什么样的输入和输出,并且在每次使用时都会检查这些数据是否正确。
- 它还提供了一个网页界面,让你可以看到API的文档,并且有一个叫做Playground的地方,可以让你实时地和机器人互动,看到它的输出和中间步骤。
- LangServe还支持并发请求,也就是说,很多人可以同时使用你的机器人,而不会出现问题。
- 它还提供了一些安全性的措施,比如可以追踪每个请求,确保数据的安全。
使用限制
虽然LangServe很强大,但也有一些它目前还做不到的事情。比如,如果你的智能机器人需要在任务开始前就和用户进行一些互动,这种功能目前还不支持。另外,如果你使用的是pydantic的第二个版本,那么当你使用FastAPI时,它不会生成OpenAPI的文档。不过别担心,这些问题未来都会得到解决。
部署LangServe
LangServe的团队正在准备一个在线版本的LangServe,你只需要点击一下就可以部署你的智能机器人应用了。如果你对这个在线版本感兴趣,可以去官网注册,加入等待名单。
安全性
LangServe在0.0.13到0.0.15版本中存在一个安全问题,就是任何人都可以通过playground接口访问服务器上的任意文件。不过这个问题在0.0.16版本中已经被修复了。
安装LangServe
安装LangServe非常简单,无论你是想用它来开发客户端还是服务器端的应用,都可以通过简单的pip命令来安装。例如,如果你想安装服务器端的代码,可以使用以下命令:
bash
pip install "langserve[server]"
如果你想安装客户端的代码,可以使用:
bash
pip install "langserve[client]"
如果你两个都想要,那就安装全部:
bash
pip install "langserve[all]"
LangChain CLI工具
LangServe提供了一个叫做LangChain CLI的工具,这个工具可以帮助你快速启动一个LangServe项目。要使用这个CLI工具,你需要先安装langchain-cli
。安装很简单,用以下命令就可以了:
bash
pip install -U langchain-cli
安装好之后,你就可以用它来创建一个新的LangServe应用了。比如,如果你想在当前路径的上一级目录中创建一个新的应用,你可以用这个命令:
bash
langchain app new ../path/to/directory
示例应用
LangServe团队还提供了一系列模板,你可以通过这些模板快速了解LangServe的各种用法。比如,有一个模板展示了如何使用OpenAI和Anthropic的聊天模型,还有一个模板教你如何通过LangServe创建一个可以通过网络访问的检索器。
这些模板都可以在GitHub上找到,你可以克隆下来自己尝试。每个模板都有一个服务器端的部分和一个客户端的部分,这样你可以看到整个请求和响应的过程。
示例代码
这里还有一个简单的例子,展示了如何部署一个使用Anthropic模型来讲笑话的服务器:
python
# 这是一个Python代码片段,用于创建一个FastAPI应用
# 并添加一个使用Anthropic模型的路由
from fastapi import FastAPI
from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatAnthropic
from langserve import add_routes
app = FastAPI(
title="LangChain Server",
version="1.0",
description="A simple api server using Langchain's Runnable interfaces",
)
# 添加路由到应用中
add_routes(
app,
ChatAnthropic(),
path="/anthropic",
)
# 创建一个讲笑话的模板
model = ChatAnthropic()
prompt = ChatPromptTemplate.from_template("tell me a joke about {topic}")
add_routes(
app,
prompt | model,
path="/joke",
)
# 如果你直接运行这个Python脚本,它会启动一个服务器
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="localhost", port=8000)
如果你想从浏览器调用你的接口,你可能还需要设置CORS(跨源资源共享)头部。FastAPI内置了中间件来处理这个,你可以这样设置:
python
from fastapi.middleware.cors import CORSMiddleware
# 设置CORS头部,允许所有来源
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
expose_headers=["*"],
)
客户端调用
如果你已经部署了一个LangServe服务器,你可以使用客户端SDK来调用服务器上的智能机器人。这里有一个Python SDK的例子,展示了如何使用客户端与服务器进行交互:
python
from langchain.schema import SystemMessage, HumanMessage
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnableMap
from langserve import RemoteRunnable
# 创建远程Runnable对象,指向服务器上的接口
openai = RemoteRunnable("http://localhost:8000/openai/")
anthropic = RemoteRunnable("http://localhost:8000/anthropic/")
joke_chain = RemoteRunnable("http://localhost:8000/joke/")
# 调用讲笑话的链
joke_chain.invoke({"topic": "parrots"})
# 异步调用
# 支持astream,可以实时接收消息
prompt = [SystemMessage(content='Act like either a cat or a parrot.')]
# 支持异步流式传输
await anthropic.astream(prompt):
print(msg, end="", flush=True)
# 定义自定义的链
prompt = ChatPromptTemplate.from_messages([
("system", "Tell me a long story about {topic}"),
# 可以在这里添加更多的消息
])
chain = prompt | RunnableMap({
"openai": openai,
"anthropic": anthropic,
})
chain.batch([{"topic": "parrots"}, {"topic": "cats"}])
此外,你还可以使用TypeScript(需要LangChain.js版本0.0.166或更高版本)来调用服务器:
typescript
import { RemoteRunnable } from "@langchain/core/runnables/remote";
const chain = new RemoteRunnable({
url: `http://localhost:8000/joke/`,
});
const result = await chain.invoke({ topic: "cats" });
这些例子展示了如何使用Python和TypeScript客户端与LangServe服务器进行交互,包括同步和异步调用。
接口详解
LangServe为每个部署的智能机器人提供了一系列的接口。例如:
POST /my_runnable/invoke
:调用智能机器人处理单个输入。POST /my_runnable/batch
:调用智能机器人批量处理输入。POST /my_runnable/stream
:调用智能机器人并实时获取输出结果。POST /my_runnable/stream_log
:调用智能机器人并实时获取包括中间步骤的输出。GET /my_runnable/input_schema
:获取智能机器人输入的JSON模式。GET /my_runnable/output_schema
:获取智能机器人输出的JSON模式。
这些接口遵循LangChain表达式语言接口的标准,你可以通过官方文档了解更多细节。
玩转Playground
Playground是一个交互式的界面,你可以在这里配置和测试你的智能机器人。通过/my_runnable/playground/
路径,你可以访问到这个界面。它还支持小部件,比如文件上传和聊天功能,可以帮助你测试不同的输入。
此外,对于可配置的智能机器人,Playground还允许你配置并分享带有配置的链接,这样其他人就可以直接使用你的智能机器人了。
处理认证
在LangServe中,如果你需要为你的服务器添加认证机制,你可以参考FastAPI的文档来了解如何使用依赖项(dependencies)和安全性(security)特性。以下是一些示例,展示了如何在LangServe端点中添加认证逻辑:
- 使用
add_routes
时添加简单认证:这种认证可以应用于应用中的所有端点,但不适用于实现每个用户的逻辑。 - 基于路径的认证机制:这种认证机制基于路径依赖性,但不适用于实现每个用户的逻辑。
- 使用每个请求的配置修改器实现用户特定的逻辑和认证:这种方法允许你为端点实现用户特定的逻辑和认证。
如果你对认证有更多的需求,你可以使用FastAPI的中间件或者APIHandler
来实现更复杂的认证逻辑。
使用APIHandler
如果你对FastAPI比较熟悉,并且想要更多的灵活性来定义端点,你可以使用LangServe的APIHandler
。通过APIHandler
,你可以完全控制端点的定义,从而实现任何你需要的认证逻辑。
文件处理
大型语言模型(LLM)应用经常需要处理文件。LangServe支持多种文件处理架构,包括:
- 通过专用端点上传文件,然后使用另一个端点进行处理。
- 文件可以通过值(例如Base64编码)或引用(例如,指向文件内容的S3 URL)上传。
- 处理端点可以是阻塞的或非阻塞的。
- 如果需要大量处理,可以将处理卸载到专用的进程池中。
目前,LangServe支持通过Base64编码的方式上传文件。你可以在这里找到一个示例,展示了如何使用Base64编码将文件发送到远程Runnable。
自定义输入输出类型
在LangServe中,你可以为智能机器人定义特定的输入和输出类型。这些类型可以通过input_schema
和output_schema
属性来访问。LangServe使用这些类型来进行数据验证和生成API文档。如果你想要自定义这些类型,而不是使用LangServe自动推断的类型,你可以使用with_types
方法来指定。
例如,如果你有一个函数,它应该接受一个整数作为输入,但实际上可以接受任何类型的数据,你可以这样定义Runnable:
python
from typing import Any
from fastapi import FastAPI
from langchain.schema.runnable import RunnableLambda
app = FastAPI()
def func(x: Any) -> int:
"""Mistyped function that should accept an int but accepts anything."""
return x + 1
runnable = RunnableLambda(func).with_types(
input_type=int,
)
add_routes(app, runnable)
自定义用户类型
如果你想要数据在反序列化后保持为pydantic模型,而不是转换为字典,你可以继承CustomUserType
。这样,服务器会保持解码后的数据类型为pydantic模型。
python
from fastapi import FastAPI
from langchain.schema.runnable import RunnableLambda
from langserve import add_routes
from langserve.schema import CustomUserType
app = FastAPI()
class Foo(CustomUserType):
bar: int
def func(foo: Foo) -> int:
"""Sample function that expects a Foo type which is a pydantic model."""
assert isinstance(foo, Foo)
return foo.bar
# 注意,这里不需要指定输入和输出类型,因为它们会自动推断出来。
# runnable = RunnableLambda(func).with_types(
# input_type=Foo,
# output_type=int,
# )
add_routes(app, RunnableLambda(func), path="/foo")
Playground小部件
Playground允许你在后端为Runnable定义自定义的小部件。小部件是在JSON模式的字段级别指定的,并作为输入类型的JSON模式的一部分发送。小部件必须包含一个名为type
的键,其值为已知的小部件类型列表中的一个。
例如,如果你想在Playground UI中创建一个文件上传输入,你可以这样定义你的请求模型:
python
try:
from pydantic.v1 import Field
except ImportError:
from pydantic import Field
from langserve import CustomUserType
class FileProcessingRequest(CustomUserType):
"""Request including a base64 encoded file."""
# extra字段用于为Playground UI指定小部件。
file: str = Field(..., extra={
"widget": {
"type": "base64file"
}
})
num_chars: int = 100
可用小部件
目前,用户可以手动指定两种小部件:文件上传小部件和聊天历史小部件。其他小部件由Playground UI根据Runnable的配置模式自动创建和管理。
python
try:
from pydantic.v1 import Field
except ImportError:
from pydantic import Field
from langserve import CustomUserType
# ATTENTION: Inherit from CustomUserType instead of BaseModel otherwise
# the server will decode it into a dict instead of a pydantic model.
class FileProcessingRequest(CustomUserType):
"""Request including a base64 encoded file."""
# The extra field is used to specify a widget for the playground UI.
file: str = Field(..., extra={"widget": {"type": "base64file"}})
num_chars: int = 100
文件上传小部件
文件上传小部件允许在UI playground中创建一个文件上传输入,文件将以Base64编码的字符串形式上传。这是一个完整的示例。
聊天小部件
如果你想在Playground中定义一个聊天小部件,确保你传递了"type": "chat"
。"input"
是指向_请求_中包含新输入消息的字段的JSON路径。"output"
是指向_响应_中包含新输出消息的字段的JSON路径。如果你希望使用整个输入或输出,那么不需要指定这些字段。
这是一个定义聊天小部件的代码片段:
python
class ChatHistory(CustomUserType):
chat_history: List[Tuple[str, str]] = Field(
...,
examples=[[("human input", "ai response")]],
extra={
"widget": {
"type": "chat",
"input": "question",
"output": "answer",
},
},
)
question: str
def _format_to_messages(input: ChatHistory) -> List[BaseMessage]:
"""Format the input to a list of messages."""
# ... 这里是消息格式化的代码 ...
现在,我们来讨论LangServe中如何启用或禁用特定的端点,以及如何使用Pulumi进行基础设施即代码(Infrastructure as Code, IaC)的部署。 ![[Pasted image 20240328233227.png]]
启用/禁用端点
从LangServe 0.0.33版本开始,你可以选择性地启用或禁用为特定链(runnable)添加的端点。这在你想要控制哪些功能对用户可用时非常有用。例如,如果你只想启用invoke
和batch
端点,可以使用enabled_endpoints
参数:
python
add_routes(app, chain, enabled_endpoints=["invoke", "batch", "config_hashes"], path="/mychain")
如果你想禁用某个端点,比如Playground,可以使用disabled_endpoints
参数:
python
add_routes(app, chain, disabled_endpoints=["playground"], path="/mychain")
部署使用基础设施即代码
LangServe支持使用Pulumi进行基础设施即代码(IaC)的部署,这意味着你可以使用Pulumi来管理和部署你的LangServe服务器到不同的云服务提供商。Pulumi提供了跨多种语言的支持,包括.NET、Go、Python和TypeScript。
以下是一些快速入门示例,展示了如何将LangServe部署到不同的云服务提供商:
- AWS:你可以使用AWS Copilot CLI来部署LangServe。
- Azure:你可以使用Azure Container Apps(无服务器)来部署。
- GCP:你可以使用GCP Cloud Run来部署。
对于每种云服务提供商,都有详细的指南和命令行操作说明。此外,Pulumi还提供了一些快速入门模板,帮助你开始使用。
Pulumi示例
对于AWS,你可以使用以下命令行操作来初始化一个新的Pulumi项目并部署LangServe:
bash
copilot init --app [application-name] --name [service-name] --type 'Load Balanced Web Service' --dockerfile './Dockerfile' --deploy
点击这里可以了解更多关于AWS Copilot的信息。
兼容性和支持
LangServe是为与LangChain生态系统中的其他工具和库协同工作而设计的。它支持与FastAPI和pydantic等流行的Python库的集成。此外,LangServe还提供了对Pydantic 2的支持,尽管在使用Pydantic V2时有一些限制,例如不生成OpenAPI文档的某些部分。但是,LangServe的开发团队正在不断努力,以确保与新版本的库和框架的兼容性。
社区和支持
LangServe拥有一个活跃的社区,你可以通过GitHub、Discord等渠道与其他开发者交流和寻求帮助。无论你遇到技术问题还是想要分享你的项目,社区都是一个很好的资源。此外,LangServe的文档提供了详细的指南和示例,帮助你快速上手和解决常见问题。
持续集成和部署
对于希望自动化部署和测试流程的开发者,LangServe支持与CI/CD工具的集成。你可以使用像GitHub Actions、GitLab CI/CD或Bitbucket Pipelines这样的服务来自动化测试、构建和部署你的LangServe应用。这不仅可以提高开发效率,还可以确保你的应用在部署前经过充分的测试。
监控和日志记录
为了确保你的LangServe应用运行顺畅,它提供了监控和日志记录的功能。你可以使用像Prometheus、Grafana或ELK Stack这样的工具来监控你的应用性能和健康状况。此外,LangServe还可以与日志记录服务(如Loggly、Papertrail或Elastic Stack)集成,以便更好地跟踪和分析日志。
未来展望
LangServe的开发团队持续在改进和扩展其功能。未来的更新可能会包括更多的端点、更好的认证和授权机制、更丰富的Playground小部件,以及对更多编程语言和框架的支持。随着人工智能和自然语言处理技术的不断进步,LangServe将继续适应这些变化,为用户提供最先进的工具和功能。
总之,LangServe是一个强大而灵活的工具,可以帮助开发者轻松地将LangChain应用部署为REST API。无论你是想要创建一个简单的聊天机器人还是一个复杂的数据处理流水线,LangServe都能满足你的需求。通过不断更新和改进,LangServe将继续为开发者提供最佳的开发体验和最强大的功能。