LangServe 的核心:add_routes 函数
LangServe 的使用非常简单,其核心功能由 add_routes 函数提供。这个函数负责将一个 LangChain 的可运行对象(Runnable)“挂载”到一个 FastAPI 应用实例上,并自动为其创建一套标准化的 REST API 端点。
下面是一个最基础的示例:
import uvicorn
from fastapi import FastAPI
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langserve import add_routes
# 1. 创建 FastAPI 应用实例
app = FastAPI(
title="LangServe 示例",
version="1.0",
description="一个简单的 LangServe API 服务器",
)
# 2. 创建一个 LangChain 可运行对象 (Runnable)
model = ChatOpenAI()
prompt = ChatPromptTemplate.from_template("给我讲一个关于 {topic} 的笑话")
chain = prompt | model
# 3. 使用 add_routes 将 chain 部署在 /joke 路径
add_routes(
app,
chain,
path="/joke",
)
if __name__ == "__main__":
uvicorn.run(app, host="localhost", port=8000)
仅仅通过调用 add_routes,我们就为这个“笑话生成器”链创建了一整套功能完备的 API 接口,无需手动编写任何路由处理逻辑。
add_routes 自动生成的端点
当您调用 add_routes(app, chain, path="/joke") 后,LangServe 会在指定的路径下自动生成一系列 API 端点。这些端点遵循 LangChain 表达式语言(LCEL)的接口标准,提供了丰富的功能,包括调用、批量处理、流式传输和模式检查 。
下表详细列出了所有自动生成的端点及其功能:
|
HTTP 方法 |
路径 |
功能描述 |
|
POST |
/joke/invoke |
在单个输入上调用链(Chain)。 |
|
POST |
/joke/batch |
在一批输入上批量调用链,提高效率。 |
|
POST |
/joke/stream |
在单个输入上调用链,并以流式方式返回最终的输出。 |
|
POST |
/joke/stream_log |
在单个输入上调用链,并流式返回所有中间步骤的输出和最终结果。 |
|
POST |
/joke/astream_events |
(v0.0.40+ 新增) 在单个输入上调用链,并以事件流的形式返回,更容易处理中间步骤。 |
|
GET |
/joke/input_schema |
获取链的输入数据模型的 JSON Schema,用于客户端验证。 |
|
GET |
/joke/output_schema |
获取链的输出数据模型的 JSON Schema。 |
|
GET |
/joke/config_schema |
获取链的配置参数的 JSON Schema。 |
|
GET |
/joke/playground/ |
提供一个交互式的 Web UI 界面,用于测试和调试您的链。 |
通过 add_routes ,LangServe 极大地简化了 API 的创建过程,让开发者可以专注于业务逻辑的实现,而不是繁琐的路由配置。
终极灵活性:集成自定义 FastAPI 路由
LangServe 的强大之处不仅在于其自动化能力,更在于它与 FastAPI 的无缝集成。这意味着您可以在使用 add_routes 的同时,利用 FastAPI 提供的所有原生功能来定义任意数量的自定义路由。这为您提供了无与伦比的灵活性,可以构建完全符合您需求的复杂 API。
正如您在问题中提到的,您可以非常轻松地添加一个标准的 FastAPI 路径操作(Path Operation),例如 @app.get("/test")。
添加自定义端点
让我们在之前的示例代码基础上,增加一个自定义的 GET 端点和一个 POST 端点:
import uvicorn
from fastapi import FastAPI
from pydantic import BaseModel
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langserve import add_routes
# 创建 FastAPI 应用实例
app = FastAPI(
title="LangServe 示例与自定义路由",
version="1.0",
description="一个结合了 LangServe 和自定义 FastAPI 端点的 API 服务器",
)
# --- LangServe 部分 ---
model = ChatOpenAI()
prompt = ChatPromptTemplate.from_template("给我讲一个关于 {topic} 的笑话")
add_routes(app, prompt | model, path="/joke")
# --- 自定义 FastAPI 路由部分 ---
# 1. 添加一个简单的 GET 端点
@app.get("/test")
async def test_get():
"""这是一个自定义的 GET 测试端点"""
return {
"message": "这是一个来自自定义 FastAPI 端点的 GET 响应",
"method": "GET"
}
# 2. 添加一个接收数据的 POST 端点
class CustomData(BaseModel):
name: str
value: int
@app.post("/custom-data")
async def create_custom_data(data: CustomData):
"""这是一个接收自定义数据的 POST 端点"""
return {
"message": "成功接收到数据",
"received_data": data
}
if __name__ == "__main__":
uvicorn.run(app, host="localhost", port=8000)
FastAPI 支持的所有 HTTP 方法装饰器
通过这种方式 ,您可以利用 FastAPI 支持的所有 HTTP 方法装饰器来定义您的 API 行为。这为您处理各种客户端请求(如网页表单、其他后端服务、物联网设备等)提供了完整的工具集。
下表总结了 FastAPI 中所有可用的路径操作装饰器 3:
|
装饰器 |
HTTP 方法 |
典型用途 |
|
@app.get() |
GET |
读取或检索数据。 |
|
@app.post() |
POST |
创建新数据。 |
|
@app.put() |
PUT |
完全更新现有数据。 |
|
@app.delete() |
DELETE |
删除数据。 |
1. GET 请求
GET 方法通常用于检索数据。
无参数
您甚至可以使用 @app.api_route() 装饰器,为一个路径同时指定多种 HTTP 方法,进一步简化代码 。
@app.get("/items")
async def get_all_items():
"""获取所有项目"""
return {"items": [{"id": 1, "name": "A"}, {"id": 2, "name": "B"}]}
路径参数 (Path Parameters)
路径参数用于从 URL 路径中捕获值,通常用于标识特定资源。
@app.get("/items/{item_id}")
async def get_item_by_id(item_id: int):
"""根据 ID 获取单个项目"""
return {"item_id": item_id, "name": f"Item {item_id}"}
查询参数 (Query Parameters)
查询参数是 URL 中 ? 之后的部分,用于过滤或分页。
from typing import Optional
@app.get("/items/search")
async def search_items(keyword: str, limit: int = 10, skip: Optional[int] = 0):
"""根据关键字搜索项目,支持分页"""
return {"keyword": keyword, "limit": limit, "skip": skip}
2. POST 请求
POST 方法通常用于创建新资源。
无参数
无参数的 POS
@app.post("/actions/reset")
async def reset_system():
"""触发系统重置动作"""
return {"message": "System has been reset"}
请求体 (Request Body)
这是 POST 最常见的用法,客户端通过请求体发送数据(通常是 JSON)。
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
@app.post("/items")
async def create_item(item: Item):
"""创建一个新项目"""
return {"message": "Item created successfully", "item_data": item}
3. PUT 请求
PUT 方法通常用于完整地更新一个现有资源。
路径参数 + 请求体
PUT 请求几乎总是同时需要路径参数(指定要更新哪个资源)和请求体(提供新的完整数据)。
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
"""完整更新一个项目"""
return {"item_id": item_id, "message": "Item updated successfully", "new_data": item}
4. DELETE 请求
DELETE 方法用于删除资源。
无参数
例如,用于删除所有资源。
@app.delete("/items")
async def delete_all_items():
"""删除所有项目"""
return {"message": "All items have been deleted"}
路径参数
这是 DELETE 最常见的用法,通过路径参数指定要删除的资源。
from fastapi import status, Response
@app.delete("/items/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_item(item_id: int):
"""根据 ID 删除单个项目"""
# 在实际应用中,这里会执行数据库删除操作
# 成功删除后,返回 204 状态码,无需响应体
return Response(status_code=status.HTTP_204_NO_CONTENT)

被折叠的 条评论
为什么被折叠?



