LangServe服务部署
概述
LangServe 🦜️🏓 帮助开发者将 LangChain 可运行和链部署为 REST API。
该库集成了 FastAPI 并使用 pydantic 进行数据验证。
Pydantic 是一个在 Python中用于数据验证和解析的第三方库,现在是Python中使用广泛的数据验证库。
- 它利用声明式的方式定义数据模型和Python 类型提示的强大功能来执行数据验证和序列化,使您的代码更可靠、更可读、更简洁且更易于调试。它还可以从模型生成 JSON 架构,提供了自动生成文档等功能,从而轻松与其他工具集成
此外,它提供了一个客户端,可用于调用部署在服务器上的可运行对象。JavaScript 客户端可在 LangChain.js 中找到。
特性
- 从 LangChain 对象自动推断输入和输出模式,并在每次 API 调用中执行,提供丰富的错误信息带有 JSONSchema 和 Swagger 的 API 文档页面高效的 /invoke、/batch 和 /stream 端点,支持单个服务器上的多个并发请求/stream_log 端点,用于流式传输链/代理的所有(或部分)中间步骤新功能:自 0.0.40 版本起,支持 /stream_events,使流式传输更加简便,无需解析 /stream_log 的输出使用经过严格测试的开源 Python 库构建,如 FastAPI、Pydantic、uvloop 和 asyncio使用客户端 SDK 调用 LangServe 服务器,就像本地运行可运行对象一样(或直接调用 HTTP API)
限制
- 目前不支持服务器发起的事件的客户端回调当使用 Pydantic V2 时,将不会生成 OpenAPI 文档。FastAPI 支持混合使用 pydantic v1 和 v2 命名空间。
安装
对于客户端和服务器:
pip install langserve或者分别安装:
# 客户端代码pip install "langserve[client]"# 服务器代码pip install "langserve[server]"LangChain CLI 🛠️
使用 LangChain CLI 快速启动 LangServe 项目。
要使用 langchain CLI,请确保已安装最新版本的 langchain-cli:
pip install -U langchain-cli设置
注意:我们使用 poetry 进行依赖管理。请参阅 poetry 文档 了解更多信息。
使用 langchain cli 命令创建新应用
langchain app new my-app在 add_routes 中定义可运行对象。转到 server.py 并编辑
使用 poetry 添加第三方包
cd my-apppoetry add langchain-openai设置相关环境变量。例如:
export OPENAI_API_KEY=your-api-key启动您的应用
poetry run uvicorn my_app.server:app --reload示例应用
服务器
以下是一个部署 OpenAI 聊天模型,讲述有关特定主题笑话的链的服务器:
#!/usr/bin/env pythonfrom fastapi import FastAPIfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_openai import ChatOpenAIfrom langserve import add_routesapp = FastAPI( title="LangChain Server", version="1.0", description="A simple API server using LangChain's Runnable interfaces",)# 创建一个链model = ChatOpenAI(temperature=0.8)prompt = ChatPromptTemplate.from_template("讲一个关于{topic}的笑话")chain = prompt | model# 添加链路由add_routes( app, chain, path="/joke",)if __name__ == "__main__": import uvicorn uvicorn.run(app, host="localhost", port=8000)如果您打算从浏览器调用您的端点,您还需要设置 CORS 头。您可以使用 FastAPI 的内置中间件来实现:
from fastapi.middleware.cors import CORSMiddlewareapp = FastAPI()# 配置 CORSapp.add_middleware( CORSMiddleware, allow_origins=["*"], # 允许所有源访问,生产环境中应该限制 allow_credentials=True, allow_methods=["*"], allow_headers=["*"],)文档
如果您已部署上述服务器,可以使用以下命令查看生成的 OpenAPI 文档:
文档地址:http://localhost:8000/docs
请确保添加 /docs 后缀。
⚠️ 首页 / 没有被设计定义,因此 curl localhost:8000 或访问该 URL 将返回 404。如果您想在 / 上有内容,请定义一个端点 @app.get("/")。
客户端
Python SDK
from langserve.client import RemoteRunnable# 连接到远程可运行项remote_chain = RemoteRunnable("http://localhost:8000/joke/")# 同步调用response = remote_chain.invoke({"topic": "人工智能"})print(response)# 流式调用for chunk in remote_chain.stream({"topic": "人工智能"}): print(chunk, end="", flush=True)# 异步调用import asyncioasync def main(): async for chunk in remote_chain.astream({"topic": "人工智能"}): print(chunk, end="", flush=True)asyncio.run(main())在 TypeScript 中(需要 LangChain.js 版本 0.0.166 或更高):
import { RemoteRunnable } from "langchain/runnables/remote";const chain = new RemoteRunnable({ url: "http://localhost:8000/joke/",});const response = await chain.invoke({ topic: "人工智能",});console.log(response);使用 requests 的 Python 代码:
import requestsresponse = requests.post( "http://localhost:8000/joke/invoke", json={"input": {"topic": "人工智能"}})print(response.json())您也可以使用 curl:
curl -X 'POST' \ 'http://localhost:8000/joke/invoke' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"input": {"topic": "人工智能"}}'端点
以下代码:
add_routes( app, chain, path="/my_runnable",)将以下端点添加到服务器:
- POST
/my_runnable/invoke - 对单个输入调用可运行项POST /my_runnable/batch - 对一批输入调用可运行项POST /my_runnable/stream - 对单个输入调用并流式传输输出POST /my_runnable/stream_log - 对单个输入调用并流式传输输出,包括生成的中间步骤的输出POST /my_runnable/astream_events - 对单个输入调用并在生成时流式传输事件,包括来自中间步骤的事件GET /my_runnable/input_schema - 可运行项的输入的 JSON 模式GET /my_runnable/output_schema - 可运行项的输出的 JSON 模式GET /my_runnable/config_schema - 可运行项的配置的 JSON 模式这些端点与 LangChain 表达式语言接口 相匹配。
LangChain 服务监控
与构建任何类型的软件一样,使用LLM构建时,总会有调试的需求。模型调用可能会失败,模型输出可能格式错误,或者可能存在一些嵌套的模型调用,不清楚在哪一步出现了错误的输出。有三种主要的调试方法:
- 详细模式(Verbose):为你的链中的"重要"事件添加打印语句调试模式(Debug):为你的链中的所有事件添加日志记录语句LangSmith跟踪:将事件记录到 LangSmith,以便在那里进行可视化
| 详细模式(Verbose Mode) | 调试模式(Debug Mode) | LangSmith跟踪 | |
|---|---|---|---|
| 免费 | ✅ | ✅ | ✅ |
| 用户界面 | ❌ | ❌ | ✅ |
| 持久化 | ❌ | ❌ | ✅ |
| 查看所有事件 | ❌ | ✅ | ✅ |
| 查看"重要"事件 | ✅ | ❌ | ✅ |
| 本地运行 | ✅ | ✅ | ❌ |
LangSmith Tracing(跟踪)
使用LangChain构建的许多应用程序将包含多个步骤,其中包含多次LLM调用。随着这些应用程序变得越来越复杂,能够检查链或代理内部发生了什么变得至关重要。
这样做的最佳方式是使用 LangSmith。在上面的链接上注册后,请确保设置你的环境变量以开始记录跟踪:
import osos.environ["LANGCHAIN_TRACING_V2"] = "true"os.environ["LANGCHAIN_API_KEY"] = "your-api-key" # 从LangSmith获取# 对于特定项目os.environ["LANGCHAIN_PROJECT"] = "My Project Name" # 可选LangSmith官网:smith.langchain.com/
tavily官网:tavily.com/
假设我们有一个代理,并且希望可视化它所采取的操作和接收到的工具输出。在没有任何调试的情况下,这是我们看到的:
from langchain.agents import initialize_agent, AgentTypefrom langchain.tools import Toolfrom langchain_openai import ChatOpenAIllm = ChatOpenAI(temperature=0)# 定义工具tools = [ Tool( name="Search", func=lambda x: "搜索结果: " + x, description="用于在网络上搜索信息的工具" )]# 初始化代理agent = initialize_agent( tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)# 运行代理agent.run("谁是当前中国的国家主席?")我们没有得到太多输出,但由于我们设置了LangSmith,我们可以轻松地看到发生了什么:smith.langchain.com/public/a89f…
Verbose(详细日志打印)
如果你在Jupyter笔记本中进行原型设计或运行Python脚本,打印出链运行的中间步骤可能会有所帮助。有许多方法可以以不同程度的详细程度启用打印。
注意:即使启用了LangSmith,这些仍然有效,因此你可以同时打开并运行它们。
set_verbose(True)
设置 verbose 标志将以稍微更易读的格式打印出输入和输出,并将跳过记录某些原始输出(例如 LLM 调用的令牌使用统计信息),以便您可以专注于应用程序逻辑。
import langchainlangchain.set_verbose(True)# 也可以在创建时设置verbose参数from langchain.chains import LLMChainfrom langchain_openai import ChatOpenAIfrom langchain.prompts import PromptTemplatellm = ChatOpenAI(temperature=0)prompt = PromptTemplate.from_template("告诉我关于{topic}的一个事实")chain = LLMChain(llm=llm, prompt=prompt, verbose=True)# 运行链chain.run(topic="人工智能")输出示例:
> Entering new LLMChain chain...Prompt after formatting:告诉我关于人工智能的一个事实> Finished chain.'人工智能(AI)领域的一个有趣事实是:图灵测试是由英国数学家和计算机科学家艾伦·图灵于1950年提出的,用于测试机器是否具有与人类相当的智能。这个测试要求评判者与隐藏的人类和计算机进行文本对话,如果评判者无法可靠地区分出谁是人类谁是计算机,那么这台计算机就被认为通过了测试。直到今天,没有AI系统能够完全通过严格的图灵测试。'Debug(调试日志打印)
set_debug(True)
设置全局的 debug 标志将导致所有具有回调支持的 LangChain 组件(链、模型、代理、工具、检索器)打印它们接收的输入和生成的输出。这是最详细的设置,将完全记录原始输入和输出。
import langchainlangchain.set_debug(True)# 运行相同的链chain.run(topic="深度学习")输出示例(将比verbose模式更详细):
[chain/start] [1:chain:LLMChain] Entering Chain run with input:{ "topic": "深度学习"}[chain/start] [1:chain:LLMChain > 2:llm:ChatOpenAI] Entering LLM run with input:{ "prompts": [ "Human: 告诉我关于深度学习的一个事实" ]}[chain/end] [1:chain:LLMChain < 2:llm:ChatOpenAI] [3.52s] Exiting LLM run with output:{ "generations": [ [ { "text": "深度学习的一个有趣事实是,尽管这个领域在2010年代才真正兴起,但其核心概念——人工神经网络的基础理论——实际上可以追溯到20世纪40年代。沃伦·麦卡洛克和沃尔特·皮茨在1943年提出了第一个数学神经元模型,为现代深度学习奠定了理论基础。然而,由于当时计算能力的限制,这些早期理论直到几十年后才能在实践中充分应用。", "generation_info": { "finish_reason": "stop" }, "message": { "content": "深度学习的一个有趣事实是,尽管这个领域在2010年代才真正兴起,但其核心概念——人工神经网络的基础理论——实际上可以追溯到20世纪40年代。沃伦·麦卡洛克和沃尔特·皮茨在1943年提出了第一个数学神经元模型,为现代深度学习奠定了理论基础。然而,由于当时计算能力的限制,这些早期理论直到几十年后才能在实践中充分应用。", "additional_kwargs": {}, "type": "ai", "example": false } } ] ], "llm_output": { "token_usage": { "completion_tokens": 187, "prompt_tokens": 13, "total_tokens": 200 }, "model_name": "gpt-3.5-turbo" }}[chain/end] [1:chain:LLMChain] [3.52s] Exiting Chain run with output:{ "text": "深度学习的一个有趣事实是,尽管这个领域在2010年代才真正兴起,但其核心概念——人工神经网络的基础理论——实际上可以追溯到20世纪40年代。沃伦·麦卡洛克和沃尔特·皮茨在1943年提出了第一个数学神经元模型,为现代深度学习奠定了理论基础。然而,由于当时计算能力的限制,这些早期理论直到几十年后才能在实践中充分应用。"}
