LangSmith 代理服务器的默认配置旨在处理各种不同工作负载的大量读写负载。通过遵循以下概述的最佳实践,您可以调整代理服务器以针对您的特定工作负载实现最佳性能。本页描述了代理服务器的扩展注意事项,并提供示例以帮助配置您的部署。
如果您还不熟悉 API 服务器和队列工作进程在容器级别的运作方式,请先阅读运行时架构概述。
有关一些自托管配置示例,请参阅扩展的示例代理服务器配置部分。
写入负载的扩展
写入负载主要由以下因素驱动:
- 创建新的运行
- 在运行执行期间创建新的检查点
- 写入长期记忆
- 创建新的线程
- 创建新的助手
- 删除运行、检查点、线程、助手和定时任务
以下组件主要负责处理写入负载:
- API 服务器:处理初始请求并将数据持久化到数据库。
- 队列工作进程:处理运行的执行。
- Redis:处理有关正在进行的运行的临时数据存储。
- Postgres:处理所有数据的存储,包括运行、线程、助手、定时任务、检查点和长期记忆。
写入路径扩展的最佳实践
根据助手特性更改 N_JOBS_PER_WORKER
N_JOBS_PER_WORKER 的默认值为 10。您可以根据助手的特性更改此值,以调整单个队列工作进程可以同时执行的最大运行数。
更改 N_JOBS_PER_WORKER 的一些通用指南:
- 如果您的助手是 CPU 密集型的,默认值 10 可能就足够了。如果您注意到队列工作进程上 CPU 使用率过高或运行执行延迟,可以降低
N_JOBS_PER_WORKER。
- 如果您的助手是 IO 密集型的,请增加
N_JOBS_PER_WORKER 以处理每个工作进程更多的并发运行。
N_JOBS_PER_WORKER 没有上限。但是,队列工作进程在获取新运行时是贪婪的,这意味着它们会尝试获取尽可能多的运行(数量等于其可用作业数)并立即开始执行。在流量突发的环境中,将 N_JOBS_PER_WORKER 设置得过高可能导致工作进程利用率不均和运行执行时间增加。
避免同步阻塞操作
避免在代码中使用同步阻塞操作,优先使用异步操作。长时间的同步操作会阻塞主事件循环,导致请求和运行执行时间变长以及潜在的超时。
例如,考虑一个需要休眠 1 秒的应用程序。不要使用这样的同步代码:
import time
def my_function():
time.sleep(1)
优先使用这样的异步代码:
import asyncio
async def my_function():
await asyncio.sleep(1)
如果助手需要同步阻塞操作,请在 asyncio.to_thread() 或等效方法中运行它们。
最小化冗余检查点
通过将 durability 设置为确保数据持久性所需的最小值,来最小化冗余检查点。
默认的持久性模式是 "async",这意味着检查点在每个步骤之后异步写入。如果助手只需要持久化运行的最终状态,可以将 durability 设置为 "exit",仅存储运行的最终状态。这可以在创建运行时设置:
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>)
thread = await client.threads.create()
run = await client.runs.create(
thread_id=thread["thread_id"],
assistant_id="agent",
durability="exit"
)
自托管
这些设置仅适用于自托管部署。默认情况下,云部署已启用这些最佳实践。
启用队列工作进程的使用
默认情况下,API 服务器管理队列,不使用队列工作进程。您可以通过将 queue.enabled 配置设置为 true 来启用队列工作进程的使用。
这将允许 API 服务器将队列管理卸载给队列工作进程,从而显著减轻 API 服务器的负载,使其专注于处理请求。
支持与预期吞吐量相等的作业数量
并行执行的运行越多,您需要处理负载的作业就越多。有两个主要参数可用于扩展可用作业:
number_of_queue_workers:配置的队列工作进程数量。
N_JOBS_PER_WORKER:单个队列工作进程可以同时执行的运行数。默认为 10。
您可以使用以下公式计算可用作业数:
available_jobs = number_of_queue_workers * `N_JOBS_PER_WORKER`
然后,吞吐量是可用作业每秒可以执行的运行数:
throughput_per_second = available_jobs / average_run_execution_time_seconds
因此,为支持预期的稳态吞吐量,您应配置的最小队列工作进程数量为:
number_of_queue_workers = throughput_per_second * average_run_execution_time_seconds / `N_JOBS_PER_WORKER`
为突发工作负载配置自动扩展
自动扩展默认禁用,但应为突发工作负载进行配置。使用与上一节相同的计算方法,您可以根据最大预期吞吐量确定应允许自动扩展器扩展到的最大队列工作进程数量。
读取负载的扩展
读取负载主要由以下因素驱动:
以下组件主要负责处理读取负载:
- API 服务器:处理请求并直接从数据库检索数据。
- Postgres:处理所有数据的存储,包括运行、线程、助手、定时任务、检查点和长期记忆。
- Redis:处理有关正在进行的运行的临时数据存储,包括从队列工作进程到 API 服务器的流式消息。
读取路径扩展的最佳实践
使用过滤减少每次请求返回的资源数量
代理服务器为每种资源类型提供搜索 API。这些 API 默认实现分页,并提供许多过滤选项。使用过滤来减少每次请求返回的资源数量并提高性能。
设置 TTL 以自动删除旧数据
设置线程的 TTL 以自动清理旧数据。当关联的线程被删除时,运行和检查点会自动删除。
避免轮询,使用 /join 监控运行状态
避免通过轮询来监控运行状态,而是使用 /join API 端点。此方法在运行完成后返回运行的最终状态。
如果您需要实时监控运行的输出,请使用 /stream API 端点。此方法流式传输运行输出,包括运行的最终状态。
自托管
这些设置仅适用于自托管部署。默认情况下,云部署已启用这些最佳实践。
为突发工作负载配置自动扩展
自动扩展默认禁用,但应为突发工作负载进行配置。您可以根据最大预期吞吐量确定应允许自动扩展器扩展到的最大 API 服务器数量。云部署的默认值是最多 10 个 API 服务器。
示例自托管代理服务器配置
确切的最佳配置取决于您的应用程序复杂性、请求模式和数据需求。请将以下示例与前面章节中的信息以及您的具体用法结合使用,根据需要更新您的部署配置。如有任何问题,请通过 support.langchain.com 联系支持。
下表概述了针对不同负载模式(每秒读取请求数 / 每秒写入请求数)和标准助手特性(平均运行执行时间 1 秒,中等 CPU 和内存使用率)的不同 LangSmith 代理服务器配置的比较:
| 低 / 低 | 低 / 高 | 高 / 低 | 中 / 中 | 高 / 高 |
|---|
| 5 | 5 | 500 | 50 | 500 |
| 5 | 500 | 5 | 50 | 500 |
API 服务器 (每个服务器 1 CPU,2Gi) | 1(默认) | 6 | 10 | 3 | 15 |
队列工作进程 (每个工作进程 1 CPU,2Gi) | 1(默认) | 10 | 1(默认) | 5 | 10 |
N_JOBS_PER_WORKER | 10(默认) | 50 | 10 | 10 | 50 |
| Redis 资源 | 2 Gi(默认) | 2 Gi(默认) | 2 Gi(默认) | 2 Gi(默认) | 2 Gi(默认) |
| Postgres 资源 | 2 CPU 8 Gi(默认) | 4 CPU 16 Gi 内存 | 4 CPU 16 Gi | 4 CPU 16 Gi 内存 | 8 CPU 32 Gi 内存 |
以下示例配置启用了每种设置。负载级别定义为:
- 低表示大约每秒 5 个请求
- 中表示大约每秒 50 个请求
- 高表示大约每秒 500 个请求
低读取,低写入
默认的 LangSmith 部署配置将处理此负载。此处无需自定义资源配置。
低读取,高写入
您的部署正在处理大量的写入请求(每秒 500 个),但读取请求相对较少(每秒 5 个)。
为此,我们建议使用如下配置:
# 低读取、高写入的示例配置(每秒 5 个读取/500 个写入请求)
api:
replicas: 6
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "2"
memory: "4Gi"
queue:
replicas: 10
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "2"
memory: "4Gi"
config:
numberOfJobsPerWorker: 50
redis:
resources:
requests:
memory: "2Gi"
limits:
memory: "2Gi"
postgres:
resources:
requests:
cpu: "4"
memory: "16Gi"
limits:
cpu: "8"
memory: "32Gi"
高读取,低写入
您有高量的读取请求(每秒 500 个),但写入请求相对较少(每秒 5 个)。
为此,我们建议使用如下配置:
# 高读取、低写入的示例配置(每秒 500 个读取/5 个写入请求)
api:
replicas: 10
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "2"
memory: "4Gi"
queue:
replicas: 1 # 默认,最小写入负载
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "2"
memory: "4Gi"
redis:
resources:
requests:
memory: "2Gi"
limits:
memory: "2Gi"
postgres:
resources:
requests:
cpu: "4"
memory: "16Gi"
limits:
cpu: "8"
memory: "32Gi"
# 对于高读取场景,考虑使用只读副本
readReplicas: 2
中读取,中写入
这是一个平衡的配置,应能处理中等的读写负载(每秒 50 个读取/50 个写入请求)。
为此,我们建议使用如下配置:
# 中读取、中写入的示例配置(每秒 50 个读取/50 个写入请求)
api:
replicas: 3
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "2"
memory: "4Gi"
queue:
replicas: 5
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "2"
memory: "4Gi"
redis:
resources:
requests:
memory: "2Gi"
limits:
memory: "2Gi"
postgres:
resources:
requests:
cpu: "4"
memory: "16Gi"
limits:
cpu: "8"
memory: "32Gi"
高读取,高写入
您有高量的读取和写入请求(每秒 500 个读取/500 个写入请求)。
为此,我们建议使用如下配置:
# 高读取、高写入的示例配置(每秒 500 个读取/500 个写入请求)
api:
replicas: 15
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "2"
memory: "4Gi"
queue:
replicas: 10
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "2"
memory: "4Gi"
config:
numberOfJobsPerWorker: 50
redis:
resources:
requests:
memory: "2Gi"
limits:
memory: "2Gi"
postgres:
resources:
requests:
cpu: "8"
memory: "32Gi"
limits:
cpu: "16"
memory: "64Gi"
自动扩展
如果您的部署遇到突发流量,可以启用自动扩展来扩展 API 服务器和队列工作进程的数量以处理负载。
以下是针对高读取和高写入的自动扩展示例配置:
api:
autoscaling:
enabled: true
minReplicas: 15
maxReplicas: 25
queue:
autoscaling:
enabled: true
minReplicas: 10
maxReplicas: 20
确保您的部署环境有足够的资源扩展到建议的大小。监控您的应用程序和基础设施以确保最佳性能。考虑实施监控和警报以跟踪资源使用情况和应用程序性能。
将这些文档通过 MCP 连接到 Claude、VSCode 等,以获取实时答案。