14_LangServe一行部署_LangSmith全链路追踪
概述
前面几篇我们已经讲过:
create_agent()如何创建一个能调用工具的 Agent。- Middleware 如何控制模型调用、工具调用和人工审批。
- LangGraph 如何表达复杂状态图。
- 多 Agent 如何通过 Supervisor 或 Swarm 协作。
这些内容解决的是“怎么把 LLM 应用写出来”。
但真实项目还会遇到另一个问题:
写出来之后,怎么让前端、其他服务、测试工具、外部系统调用它?
也就是部署问题。
同时,LLM 应用还有一个比传统接口更麻烦的问题:
用户说答案错了,你怎么知道错在 Prompt、模型、检索、工具,还是 Agent 决策?
这就是观测问题。
本文围绕两个工具展开:
- LangServe:把 LangChain Runnable / Chain 暴露成 REST API。
- LangSmith:记录每次 LLM 应用调用的 trace,帮助调试、评估和监控。
LangServe 解决“怎么调用”,LangSmith 解决“怎么知道它到底跑了什么”。
先建立全局图:从 Chain 到 HTTP API 再到 Trace
一个最小 LangChain 应用通常长这样:
chain = prompt | model | parser
result = chain.invoke({"question": "LangServe 是什么?"})
这只能在 Python 进程里调用。
如果前端要调用它,就需要一层 HTTP 服务。
LangServe 做的事情可以理解成:
Runnable / Chain / Agent
|
v
FastAPI + add_routes
|
v
REST API:
POST /xxx/invoke
POST /xxx/batch
POST /xxx/stream
GET /xxx/input_schema
GET /xxx/output_schema
GET /xxx/playground
LangSmith 则在运行时记录:
用户请求
|
v
Prompt 格式化
|
v
模型调用
|
v
工具调用 / 检索 / Agent 决策
|
v
最终输出
这些步骤会形成一个 trace。
你可以在 LangSmith 里看到每一步的:
- 输入。
- 输出。
- 耗时。
- token 消耗。
- 错误堆栈。
- 子步骤层级关系。
- metadata 和 tags。
LangServe 把 Runnable 变成服务,LangSmith 把服务调用变成可观察的执行链路。
当前选型提醒:什么时候还适合 LangServe?
因为 LangServe 已经 deprecated,先把边界说清楚。
| 场景 | 建议 |
|---|---|
| 维护已有 LangServe 项目 | 可以继续维护,注意版本和安全配置 |
| 部署简单 LCEL Chain | LangServe 仍然容易理解和上手 |
| 部署普通 Runnable API | LangServe 可作为轻量方案或教学方案 |
| 新建复杂 Agent / LangGraph 应用 | 优先考虑 LangGraph Platform |
| 需要长期任务、状态恢复、人审、任务队列 | 优先考虑 LangGraph Platform 或自建后端 |
| 需要完整权限、租户隔离、审计 | 不要只靠 LangServe,应该结合 FastAPI / 网关 / 权限系统 |
本文会重点讲两件事:
- 如何用 LangServe 快速把 Chain 暴露成 API。
- 如何用 LangSmith 给这个 API 加全链路 trace。
更准确的理解是:
LangServe 是理解 LangChain Runnable 服务化的最短路径;生产新项目要结合官方当前推荐和自身架构选型。
LangServe 适合简单 Runnable 服务化和旧项目维护,复杂 Agent 新项目应优先评估 LangGraph Platform。
第一步:安装依赖
一个最小服务需要:
langservefastapiuvicornlangchain-core- 对应模型包,例如
langchain-openai
安装命令:
pip install "langserve[server]" fastapi uvicorn langchain-core langchain-openai
如果你还要写客户端:
pip install "langserve[client]"
如果希望服务端和客户端都装:
pip install "langserve[all]"
LangSmith tracing 需要:
pip install langsmith
通常 langchain 相关包会间接依赖 LangSmith,但显式安装能减少环境不一致问题。
服务端关注 langserve[server],客户端关注 langserve[client],观测关注 langsmith。
第二步:写一个最小 Chain
先写一个普通 LCEL Chain。
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
prompt = ChatPromptTemplate.from_messages([
(
"system",
"你是一个严谨的 LangChain 助手。回答要准确、简洁、可执行。",
),
(
"user",
"请用中文回答这个问题:{question}",
),
])
model = ChatOpenAI(model="gpt-4o-mini", temperature=0)
chain = prompt | model | StrOutputParser()
本地直接调用:
answer = chain.invoke({
"question": "LangServe 的作用是什么?"
})
print(answer)
这时它还只是一个 Python 对象。
下一步把它挂到 FastAPI 上。
只要对象是 Runnable,就可以被 LangServe 暴露成 API。
第三步:用 add_routes() 一行发布
创建 server.py:
from fastapi import FastAPI
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langserve import add_routes
prompt = ChatPromptTemplate.from_messages([
(
"system",
"你是一个严谨的 LangChain 助手。回答要准确、简洁、可执行。",
),
(
"user",
"请用中文回答这个问题:{question}",
),
])
model = ChatOpenAI(model="gpt-4o-mini", temperature=0)
chain = prompt | model | StrOutputParser()
app = FastAPI(
title="LangChain Demo Server",
version="1.0",
description="A simple API server for LangChain runnables",
)
add_routes(
app,
chain,
path="/qa",
)
@app.get("/")
def health_check():
return {"status": "ok"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8000)
启动服务:
uvicorn server:app --host 127.0.0.1 --port 8000 --reload
现在你得到了这些端点:
| 端点 | 作用 |
|---|---|
POST /qa/invoke |
单次调用 |
POST /qa/batch |
批量调用 |
POST /qa/stream |
流式输出 |
GET /qa/input_schema |
查看输入 schema |
GET /qa/output_schema |
查看输出 schema |
GET /qa/config_schema |
查看配置 schema |
GET /qa/playground/ |
打开调试 Playground |
GET /docs |
FastAPI Swagger 文档 |
注意:
LangServe 默认不会给
/自动生成页面。上面加health_check()是为了让根路径有健康检查结果。
add_routes(app, chain, path="/qa") 会把 Runnable 的标准调用能力映射成一组 HTTP API。
第四步:用 HTTP 调用 /invoke
用 curl 调用:
curl -X POST "http://127.0.0.1:8000/qa/invoke" \
-H "Content-Type: application/json" \
-d '{
"input": {
"question": "LangSmith 能解决什么问题?"
}
}'
请求体里最重要的是:
{
"input": {
"question": "..."
}
}
因为 Chain 的输入是:
{"question": "..."}
所以 HTTP 请求要把它放到 input 字段里。
响应大致是:
{
"output": "LangSmith 用于记录、调试和分析 LLM 应用的执行过程...",
"metadata": {
"run_id": "..."
}
}
不同版本的响应字段可能有细微差异,但核心都是:
input放调用输入。output返回调用结果。metadata可能包含运行相关信息。
LangServe HTTP 协议把 Runnable 输入包在 input 字段里,把 Runnable 输出放在 output 字段里。
第五步:用 Python 客户端调用 RemoteRunnable
LangServe 不只能用 HTTP 调,还可以像本地 Runnable 一样远程调用。
from langserve import RemoteRunnable
remote_chain = RemoteRunnable("http://127.0.0.1:8000/qa/")
result = remote_chain.invoke({
"question": "LangServe 和 FastAPI 是什么关系?"
})
print(result)
这对服务拆分很有用。
例如你可以这样组织:
前端服务
|
v
业务后端
|
v
RemoteRunnable -> LangServe 服务
|
v
LLM / Tool / Retriever
在业务后端看来,远程服务仍然像 Runnable 一样:
remote_chain.invoke(...)
remote_chain.batch(...)
remote_chain.stream(...)
RemoteRunnable 让远端 LangServe 服务在调用体验上接近本地 Runnable。
第六步:打开 Playground
启动服务后,访问:
http://127.0.0.1:8000/qa/playground/
Playground 可以直接在浏览器里测试输入输出。
它适合:
- 快速验证 Chain 是否能跑。
- 给产品或测试同学试用。
- 观察输入 schema。
- 调试 streaming 输出。
- 演示简单 Runnable。
但要注意:
Playground 不是生产管理后台。生产环境是否开放 Playground,要结合认证、网络隔离和数据安全决定。
如果服务里会处理敏感数据,不要把 Playground 暴露到公网。
Playground 很适合开发和演示,但生产环境要谨慎开放。
第七步:发布 Agent 服务
LangServe 不只可以发布 Chain,也可以发布 Agent。
例如一个带工具的 Agent:
from langchain.agents import create_agent
from langchain.tools import tool
from langserve import add_routes
@tool
def get_order_status(order_id: str) -> str:
"""根据订单号查询订单状态。"""
data = {
"A1001": "已发货,预计明天送达。",
"A1002": "正在仓库拣货,预计今天 18:00 前发出。",
}
return data.get(order_id, "没有查到这个订单。")
agent = create_agent(
model="openai:gpt-4o-mini",
tools=[get_order_status],
system_prompt=(
"你是客服助手。"
"用户问订单状态时必须调用工具,不要编造订单信息。"
),
name="support_agent",
)
add_routes(
app,
agent,
path="/support-agent",
)
调用时要传 Agent 需要的 messages:
curl -X POST "http://127.0.0.1:8000/support-agent/invoke" \
-H "Content-Type: application/json" \
-d '{
"input": {
"messages": [
{
"role": "user",
"content": "帮我查一下订单 A1001 到哪了?"
}
]
}
}'
不过这里要再次提醒:
对复杂 LangGraph / 长任务 / 多 Agent 系统,新项目更建议评估 LangGraph Platform 或自建更明确的 API 层。LangServe 更适合简单 Runnable 或已有 LangServe 项目。
Agent 也是 Runnable,但复杂 Agent 的生产部署不能只看“能不能 add_routes”。
第八步:配置 LangSmith tracing
现在服务能调用了,但还看不到内部执行过程。
开启 LangSmith tracing 的当前推荐环境变量是:
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="你的 LangSmith API Key"
export LANGSMITH_PROJECT="langserve-demo"
如果你的 LangSmith 账号不在默认 US 区域,还要设置:
export LANGSMITH_ENDPOINT="https://eu.api.smith.langchain.com"
Windows PowerShell 写法:
$env:LANGSMITH_TRACING="true"
$env:LANGSMITH_API_KEY="你的 LangSmith API Key"
$env:LANGSMITH_PROJECT="langserve-demo"
然后重新启动服务:
uvicorn server:app --host 127.0.0.1 --port 8000 --reload
再调用一次:
curl -X POST "http://127.0.0.1:8000/qa/invoke" \
-H "Content-Type: application/json" \
-d '{
"input": {
"question": "为什么 LLM 应用需要 trace?"
}
}'
如果配置正确,你就能在 LangSmith 项目 langserve-demo 里看到这次调用的 trace。
补充说明:
- 旧资料里常见
LANGCHAIN_TRACING_V2=true。 - 当前 LangSmith 文档推荐使用
LANGSMITH_TRACING=true。 - 如果你维护旧项目,可能会同时看到
LANGCHAIN_PROJECT和LANGSMITH_PROJECT两种写法。 - 新项目建议使用
LANGSMITH_*这一组命名。
LangChain / LangGraph 应用接入 LangSmith,通常只需要配置环境变量,不必改业务代码。
LangSmith Trace 里能看到什么?
一次 Chain 调用的 trace 通常是树状结构:
chain
|
+-- ChatPromptTemplate
|
+-- ChatOpenAI
|
+-- StrOutputParser
如果是 RAG:
rag_chain
|
+-- retriever
| |
| +-- vectorstore search
|
+-- prompt
|
+-- model
|
+-- parser
如果是 Agent:
agent
|
+-- model call
|
+-- tool call: get_order_status
|
+-- model call
|
+-- final response
每个节点都可能包含:
- 输入。
- 输出。
- 开始时间。
- 结束时间。
- 耗时。
- token 用量。
- 模型参数。
- 错误信息。
- tags。
- metadata。
这对排查问题非常关键。
例如用户反馈:
客服机器人把订单状态答错了。
你可以看 trace:
- 模型有没有调用
get_order_status? - 工具入参是不是正确订单号?
- 工具返回了什么?
- 模型有没有篡改工具结果?
- 最终输出和工具结果是否一致?
这比只看接口日志有用得多。
LangSmith trace 的价值,是把 LLM 应用从“只知道最终答案”变成“能看到每一步为什么这样回答”。
给 Trace 加 tags 和 metadata
只打开 tracing 还不够。
生产系统里,你通常还需要知道:
- 这个请求来自哪个环境?
- 哪个用户触发?
- 哪个租户触发?
- 哪个版本的 Prompt?
- 哪个业务场景?
- 是不是灰度流量?
可以通过 Runnable config 加 metadata 和 tags。
result = chain.invoke(
{"question": "LangSmith 如何定位问题?"},
config={
"tags": ["demo", "langserve", "qa"],
"metadata": {
"env": "dev",
"user_id": "user_123",
"tenant_id": "tenant_a",
"prompt_version": "qa-v1",
},
},
)
通过 HTTP 调用时,也可以在请求体里传 config:
{
"input": {
"question": "LangSmith 如何定位问题?"
},
"config": {
"tags": ["demo", "langserve", "qa"],
"metadata": {
"env": "dev",
"user_id": "user_123",
"tenant_id": "tenant_a",
"prompt_version": "qa-v1"
}
}
}
这样 LangSmith 里就能按标签和元数据筛选 trace。
常见 tags:
prodstagingragagentcustomer-supportdaily-report
常见 metadata:
user_idtenant_idrequest_idprompt_versionmodel_namefeature_flag
tags 用来粗粒度分类,metadata 用来记录可查询的业务上下文。
手动埋点:用 @traceable 包住普通函数
并不是所有逻辑都天然在 LangChain Runnable 里。
例如你可能有一个普通函数:
def normalize_question(question: str) -> str:
return question.strip().replace("\n", " ")
如果想让它也出现在 LangSmith trace 里,可以用 @traceable。
from langsmith import traceable
@traceable(run_type="chain", name="normalize_question")
def normalize_question(question: str) -> str:
return question.strip().replace("\n", " ")
也可以把工具函数标成 tool span:
from langsmith import traceable
@traceable(run_type="tool", name="query_order_database")
def query_order_database(order_id: str) -> str:
return "订单已发货"
这样你的 trace 就不只包含模型调用,还能包含业务逻辑。
对于复杂应用,建议把这些步骤都显式埋点:
- 输入清洗。
- 意图识别。
- 权限校验。
- 检索。
- 重排序。
- 工具调用。
- 输出后处理。
LangChain 对象会自动 trace,普通业务函数可以用 @traceable 手动纳入 trace。
流式输出:/stream 和 /stream_log
LLM 应用经常需要流式输出。
LangServe 提供:
/stream:流式返回 Runnable 输出。/stream_log:流式返回输出和中间步骤日志。/astream_events或相关事件流端点:用于消费更细粒度事件,具体取决于版本。
前端聊天场景通常关注 /stream:
curl -X POST "http://127.0.0.1:8000/qa/stream" \
-H "Content-Type: application/json" \
-d '{
"input": {
"question": "请用三段话解释 LangSmith trace。"
}
}'
调试场景更关注中间步骤:
curl -X POST "http://127.0.0.1:8000/qa/stream_log" \
-H "Content-Type: application/json" \
-d '{
"input": {
"question": "请解释 RAG 的执行流程。"
}
}'
不过真实生产里,流式接口还要处理:
- 客户端断开连接。
- 超时。
- 重试。
- 网关 buffering。
- SSE / WebSocket 选择。
- 前端增量渲染。
- trace 是否完整提交。
不要只在本地 curl 成功,就认为生产流式链路已经完成。
/stream 解决用户体验,/stream_log 更适合开发调试和中间步骤观察。
Chat Playground:让对话接口更像聊天窗口
如果你的 Runnable 输入是聊天消息,可以启用 chat playground。
示例:
from typing import List, Union
from pydantic import BaseModel, Field
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai import ChatOpenAI
from langserve import add_routes
class ChatInput(BaseModel):
messages: List[Union[HumanMessage, AIMessage, SystemMessage]] = Field(
...,
description="The chat messages representing the current conversation.",
)
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个企业知识库助手。"),
MessagesPlaceholder(variable_name="messages"),
])
chat_chain = prompt | ChatOpenAI(model="gpt-4o-mini")
add_routes(
app,
chat_chain.with_types(input_type=ChatInput),
path="/chat",
playground_type="chat",
)
访问:
http://127.0.0.1:8000/chat/playground/
就能看到更接近聊天体验的 Playground。
注意输入结构:
{
"messages": [
{
"type": "human",
"content": "你好,帮我总结一下 LangServe。"
}
]
}
不同版本对 message 序列化细节可能略有差异。
如果遇到 schema 报错,优先检查:
- 输入是否是
dict。 messages是否是 list。- 每条 message 是否能被 Pydantic 正确解析。
- Runnable 输出是否是
AIMessage或 string。
chat playground 适合对话型 Runnable,但输入输出 schema 必须符合它的约束。
反馈按钮和公开 Trace 链接
LangServe 支持和 LangSmith 结合做反馈。
在 add_routes() 里可以打开:
add_routes(
app,
chat_chain.with_types(input_type=ChatInput),
path="/chat",
playground_type="chat",
enable_feedback_endpoint=True,
enable_public_trace_link_endpoint=True,
)
效果是:
- 用户可以对回复点 thumbs up / thumbs down。
- 可以生成公开 trace 链接,方便调试和分享。
但这里要非常谨慎:
公开 trace 可能暴露 Prompt、用户输入、工具返回、检索内容和中间状态。只建议在 demo 或测试环境使用。
生产系统建议:
- 默认关闭 public trace。
- 对 trace 做数据脱敏。
- 用权限系统控制谁能看 trace。
- 不在 trace 里记录密钥、token、身份证、手机号等敏感信息。
反馈端点有助于收集质量信号,公开 trace 只适合受控场景。
一个完整示例:客服 Agent + LangServe + LangSmith
下面组合一个更接近真实项目的例子。
文件结构:
support_app/
server.py
chains.py
tools.py
tools.py
from langchain.tools import tool
@tool
def query_order_status(order_id: str) -> str:
"""根据订单号查询订单状态。用户问订单、物流、发货时使用。"""
orders = {
"A1001": "订单 A1001 已发货,物流单号 SF123456,预计明天送达。",
"A1002": "订单 A1002 正在仓库拣货,预计今天 18:00 前发出。",
}
return orders.get(order_id, f"没有查到订单 {order_id}。")
@tool
def search_policy(query: str) -> str:
"""查询客服政策。用户问退款、售后、发票等规则时使用。"""
policies = {
"退款": "退款需在签收后 7 天内申请。",
"发票": "电子发票会在订单完成后 24 小时内开具。",
}
return policies.get(query, "没有找到相关政策。")
chains.py
from langchain.agents import create_agent
from tools import query_order_status, search_policy
support_agent = create_agent(
model="openai:gpt-4o-mini",
tools=[query_order_status, search_policy],
system_prompt=(
"你是企业客服助手。"
"用户询问订单、物流、退款、发票、售后时,优先调用工具。"
"如果工具没有结果,明确说明没有查到,不要编造。"
"回答要简洁、准确。"
),
name="support_agent",
)
server.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from langserve import add_routes
from chains import support_agent
app = FastAPI(
title="Support Agent API",
version="1.0",
)
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
expose_headers=["*"],
)
@app.get("/")
def health_check():
return {"status": "ok"}
add_routes(
app,
support_agent,
path="/support",
)
环境变量:
export OPENAI_API_KEY="你的 OpenAI API Key"
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="你的 LangSmith API Key"
export LANGSMITH_PROJECT="support-agent"
启动:
uvicorn server:app --host 127.0.0.1 --port 8000 --reload
调用:
curl -X POST "http://127.0.0.1:8000/support/invoke" \
-H "Content-Type: application/json" \
-d '{
"input": {
"messages": [
{
"role": "user",
"content": "帮我查一下订单 A1001 的物流状态"
}
]
},
"config": {
"tags": ["support", "demo"],
"metadata": {
"user_id": "user_123",
"channel": "web"
}
}
}'
在 LangSmith 里你应该能看到:
support_agent
|
+-- model call
|
+-- tool call: query_order_status
|
+-- model call
|
+-- final response
这样,当用户说“你查错订单了”,你可以直接看 trace 里的工具入参和工具返回。
接口服务负责对外调用,LangSmith trace 负责解释每一次调用内部到底发生了什么。
生产化注意事项一:认证和权限
LangServe 基于 FastAPI。
这意味着认证、权限、限流、审计最好通过 FastAPI、API Gateway 或公司统一网关来做。
不要把一个没有认证的 LLM API 暴露到公网。
至少要考虑:
- API Key 或 JWT。
- 用户身份。
- 租户隔离。
- 请求频率限制。
- IP 白名单。
- 操作审计。
- 工具级权限控制。
简单 FastAPI 依赖示例:
from fastapi import Depends, Header, HTTPException
def verify_api_key(x_api_key: str = Header(...)):
if x_api_key != "dev-secret":
raise HTTPException(status_code=401, detail="Invalid API key")
add_routes(
app,
chain,
path="/qa",
dependencies=[Depends(verify_api_key)],
)
真实项目不要硬编码 key,应接入配置中心或密钥管理服务。
LangServe 负责 Runnable API 化,不等于自动解决生产权限。
生产化注意事项二:输入输出 Schema
LangServe 会基于 Runnable 推断 schema。
简单 Chain 通常没问题:
{"question": "..."}
但复杂输入建议显式定义类型。
from pydantic import BaseModel, Field
class QAInput(BaseModel):
question: str = Field(description="用户问题")
user_id: str = Field(description="用户 ID")
typed_chain = chain.with_types(input_type=QAInput)
add_routes(
app,
typed_chain,
path="/qa",
)
这样有几个好处:
- Swagger 文档更清楚。
- Playground 更容易填写。
- 请求错误更早暴露。
- 前后端协作更稳定。
输出也可以定义:
class QAOutput(BaseModel):
answer: str
sources: list[str] = []
如果你的业务需要结构化结果,不要让模型自由输出一段自然语言再让后端正则解析。
生产接口最好显式定义输入输出 schema,减少调用方和模型输出的不确定性。
生产化注意事项三:CORS 和前端调用
如果前端浏览器直接调用 LangServe,需要配置 CORS。
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["https://your-frontend.example.com"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
expose_headers=["*"],
)
开发环境可以临时用:
allow_origins=["http://localhost:3000"]
不建议生产直接:
allow_origins=["*"]
尤其是带 cookie、token 或内部接口时。
CORS 是浏览器安全边界,不要为了省事在生产里无脑放开。
生产化注意事项四:错误处理和超时
LLM API 可能失败:
- 网络超时。
- 模型限流。
- 工具报错。
- 输入 schema 错误。
- 输出解析失败。
- Agent 循环超限。
建议:
- 给模型配置 timeout。
- 给外部工具配置 timeout。
- 对可恢复错误做 retry。
- 对不可恢复错误返回清晰错误码。
- 不把内部堆栈直接暴露给前端。
- 在 LangSmith trace 中保留足够调试信息。
模型示例:
model = ChatOpenAI(
model="gpt-4o-mini",
temperature=0,
timeout=30,
max_retries=2,
)
工具里也要有超时:
import requests
def call_external_api(url: str) -> dict:
response = requests.get(url, timeout=10)
response.raise_for_status()
return response.json()
LLM 服务不是普通函数调用,超时、重试和错误边界必须显式设计。
生产化注意事项五:Trace 数据安全
LangSmith trace 很有用,但也可能记录敏感数据。
可能进入 trace 的内容包括:
- 用户原始输入。
- Prompt。
- 检索到的文档片段。
- 工具参数。
- 工具返回。
- 模型输出。
- metadata。
因此要注意:
- 不要把密钥写进 Prompt。
- 不要把 access token 放进 metadata。
- 对手机号、身份证、邮箱等做脱敏。
- 对高敏业务设置数据保留策略。
- 控制 LangSmith 项目访问权限。
- 公开 trace 链接只用于 demo 或受控排查。
如果涉及强合规业务,要先和安全、法务、数据治理团队确认 trace 策略。
可观测性不能以泄露敏感数据为代价。
常见问题一:服务能跑,但 /docs 没有接口
如果你使用旧版本 LangServe 和 Pydantic v2,可能遇到 OpenAPI 文档生成问题。
LangServe README 里提到:
LangServe >= 0.3支持 Pydantic 2。LangServe <= 0.2.0在 FastAPI + Pydantic v2 混用时,部分 OpenAPI docs 可能无法正常生成。
解决思路:
- 优先升级到
langserve>=0.3.0。 - 或者在旧项目中固定
pydantic==1.10.17。 - 检查 FastAPI、Pydantic、LangServe 版本组合。
LangServe 老项目最常见兼容问题之一,就是 Pydantic 版本和 OpenAPI 文档生成。
常见问题二:只访问 /qa,忘了具体端点
很多新手启动服务后访问:
http://127.0.0.1:8000/qa
然后看到 404。
这是因为 LangServe 端点是:
/qa/invoke
/qa/batch
/qa/stream
/qa/playground/
不是 /qa 本身。
Swagger 文档在:
http://127.0.0.1:8000/docs
Playground 在:
http://127.0.0.1:8000/qa/playground/
LangServe 的 path 是端点前缀,不是单独的业务页面。
常见问题三:LangSmith 没有 trace
如果 LangSmith 里看不到 trace,按这个顺序查:
- 是否设置了
LANGSMITH_TRACING=true。 - 是否设置了正确的
LANGSMITH_API_KEY。 - 是否在同一个 shell 里启动服务。
- 是否设置了正确的
LANGSMITH_ENDPOINT。 - 是否请求真的跑到了 LangChain / LangGraph 对象。
- 是否用了不支持自动 tracing 的第三方调用。
- 是否服务进程还没来得及提交 trace 就退出了。
如果是普通 OpenAI SDK 调用,不经过 LangChain,可以用:
from openai import OpenAI
from langsmith.wrappers import wrap_openai
client = wrap_openai(OpenAI())
如果是普通函数,可以用:
from langsmith import traceable
@traceable
def my_pipeline(input_text: str) -> str:
return input_text.upper()
LangChain 对象通常能自动 trace,非 LangChain 代码要用 wrapper 或 @traceable。
常见问题四:把 LangSmith 当日志系统替代品
LangSmith 适合观察 LLM 调用链路,但它不应该替代所有业务日志。
你仍然需要:
- API access log。
- 错误日志。
- 审计日志。
- 业务事件日志。
- 监控指标。
- 告警规则。
LangSmith 解决的是:
这次 LLM 应用内部怎么跑的?
传统日志和监控解决的是:
服务是否健康?
QPS 多少?
错误率多少?
接口延迟多少?
谁在什么时候做了什么操作?
二者应该配合,而不是互相替代。
LangSmith 是 LLM 可观测平台,不是完整后端监控系统的替代品。
一张图总结:LangServe + LangSmith 工作流
这条链路里,每一层职责都不同:
- Runnable 负责业务逻辑。
- FastAPI 负责 HTTP 服务。
- LangServe 负责把 Runnable 映射成 API。
- Uvicorn 负责运行 ASGI 服务。
- LangSmith 负责 trace、调试和观测。
- 认证、权限、限流、审计需要你结合后端体系补齐。
总结
本文讲了如何用 LangServe 和 LangSmith 把 LangChain 应用推向可调用、可调试的形态。
需要记住这些结论:
- LangServe 可以用
add_routes()把 Runnable / Chain / Agent 暴露成 REST API。 - 常见端点包括
/invoke、/batch、/stream、/stream_log、/playground/和 schema 接口。 RemoteRunnable可以像调用本地 Runnable 一样调用远程 LangServe 服务。- LangSmith tracing 当前推荐环境变量是
LANGSMITH_TRACING=true、LANGSMITH_API_KEY、LANGSMITH_PROJECT。 - LangSmith trace 可以看到 Prompt、模型调用、工具调用、检索、输出解析等中间步骤。
- tags 和 metadata 能帮助按环境、用户、租户、版本筛选 trace。
- 普通业务函数可以用
@traceable手动纳入 trace。 - Playground 和 public trace link 适合开发演示,生产环境要谨慎开放。
- LangServe 已 deprecated,复杂 Agent / LangGraph 新项目要优先评估 LangGraph Platform。
- 部署 LLM 应用时,认证、权限、限流、错误处理、数据脱敏和监控都不能省。
更多推荐
所有评论(0)