Skip to content

第 26 章 性能优化与成本控制 ​

26.1 成本构成与延迟分析 ​

Agent 系统的成本由四部分构成:LLM API 调用(token 费用 + 首字延迟与解码时间)、工具调用(外部 API 延迟与费用,如搜索、数据库、第三方 SaaS)、Checkpoint 序列化(每次状态快照写入后端的 IO 与反序列化开销)、State 膨胀(消息与字段无限追加,每次迭代都序列化并占据上下文窗口,token 与 IO 双膨胀)。

典型端到端延迟分解:网络往返(同地域约 20–80ms)+ LLM TTFT(首字延迟,云端主模型约 300–1200ms)+ LLM 输出解码(按 token 数 × 每 token 时间)+ 工具执行(HTTP/DB 延迟)+ 状态合并 reducer 计算 + Checkpoint 序列化与写入。定位瓶颈首选 LangSmith Trace:每个 Run 的 latency 字段、LLM Run 的 token 用量、Tool Run 的耗时都已自动打点,按 P50/P95/P99 聚合后即可识别长尾环节。

26.2 Token 优化与模型缓存 ​

Token 是 Agent 运行成本的核心变量,优化策略覆盖输入侧与输出侧:

  • 消息裁剪:使用 langchain_core.messages.trim_messages,按 max_tokens 或消息条数截断,strategy="last" 保留 system prompt 与最近若干轮,超出部分丢弃或合并。
  • 消息摘要:对长对话周期性调用小模型生成摘要,替换历史消息为一条 SystemMessage 或 RemoveMessage,保留关键实体、决策与未完成任务。
  • 系统提示词精简:删除礼貌语、重复描述、散文式说明,改为结构化(JSON/XML)提示;将稳定规则与动态示例分离,示例仅在需要时注入。
  • 工具描述精简:每个工具 description 控制在 1–2 句,参数描述聚焦必填字段;并行工具数超过 6 个时考虑分组路由节点先筛选,避免一次性绑入大量工具造成 tool schema 占满上下文。
  • 上下文压缩:RAG 场景对检索文档做 rerank + 片段摘要,再拼入 prompt;长文档用 map-reduce 或分块引用式回答,避免一次性塞入。
  • 模型分级:路由/分类/意图识别等简单任务用 gpt-4o-mini、qwen-turbo、glm-4-flash 等小模型,复杂推理与最终答案生成才调用大模型;with_structured_output 抽取字段时也优先小模型。
python
from langchain_core.messages import trim_messages, SystemMessage, HumanMessage, AIMessage

def trimmed_history(messages, llm, max_tokens=4000):
    return trim_messages(
        messages, max_tokens=max_tokens, strategy="last",
        token_counter=llm, include_system=True, start_on="human",
    )

模型缓存 对 temperature=0、完全相同 prompt 的请求可命中缓存,跳过 LLM 推理。LangChain 提供 RedisCache、InMemoryCache、SQLiteCache 与语义缓存(Semantic Cache,对语义相近的 prompt 也命中)。缓存键必须包含模型名、prompt 模板版本、工具 schema 版本,任一变更需使缓存失效,否则会造成"修改了 prompt 但线上还在返回旧结果"的缓存污染。流式场景不建议启用缓存,因缓存返回难以还原原始 chunk 节奏。

并行化 从三个层面展开:静态 Fan-out 适用于无数据依赖的节点(如同时检索多个知识库),在图中用并行边表达,LangGraph 自动在同一 step 内调度;Send API 支持动态并行,根据运行时 state 决定向某节点发送若干份输入,由 reducer 合并;工具批处理 通过 llm.bind_tools(..., parallel_tool_calls=True) 让模型一次性产出多个 tool_calls,ToolNode 使用线程池或 asyncio.gather 并发执行。

流式输出 将首字延迟(TTFT)直接暴露给用户,显著降低感知等待;结构化输出场景可在客户端增量解析 JSON,目标字段齐备即提前终止渲染,无需等待完整响应。

26.3 Checkpointer、并发、降级与监控 ​

Checkpointer 优化 针对状态持久化的 IO 成本:大对象(原始文档、二进制、长列表)不要放入 State,改由 Store(语义长期存储)按 namespace 保存,State 中仅保留引用 ID;定期清理历史 checkpoint(按 TTL 或按 thread 保留最近 N 个快照);消息列表在每轮结束时主动 trim,避免无限增长;LangGraph 支持启用 STRICT_MSGPACK_ENABLED 使用 msgpack 二进制序列化替代 JSON,体积可降低 30%–50%,反序列化延迟同步下降。

并发与限流 面向 LLM API 的频控约束:使用 asyncio.Semaphore 控制单进程对同一模型 endpoint 的并发数,避免瞬时打爆 TPM/RPM;对 429 与 5xx 错误采用指数退避 + 抖动重试(tenacity 或 langchain 内置的 with_retry),重试上限与总超时需业务可控;httpx 与 psycopg 连接池大小根据并发量设置,避免新建连接开销和端口耗尽。

降级与回退(Fallback) 在模型或工具异常时保障可用性:主模型(gpt-4o)失败或 P99 超时触发 fallback 到备用模型(gpt-4o-mini、deepseek-chat、qwen-plus);RAG 检索为空时降级为通用问答 + 告知用户"未检索到相关文档";核心路径工具失败时返回兜底响应而非抛出未处理异常,避免整轮对话崩溃。可通过 llm.with_fallbacks([llm_backup]) 或在节点内 try/except 显式实现。

成本监控 依托 LangSmith Monitor:每次运行的 token 用量与模型单价自动换算为成本,按 tenant、agent_version、model、environment 维度聚合;设置预算告警(日/周/月阈值),超限通知或自动切流到小模型;区分工具调用成本(搜索 API、第三方 SaaS)与 LLM 成本,避免 LLM 侧优化掩盖工具滥用。

性能基准 基于 LangSmith Run 数据建立 P50/P95/P99 延迟基线与 token/请求均值,每次发版在预发环境跑基准对照集,指标劣化超过阈值(如 P95 延迟 +20%、平均 token +15%)阻断发布。

本章小结:性能与成本优化覆盖 token、并行、缓存、序列化、并发治理、降级回退、监控基线七个维度;token 优化是投入产出比最高的手段,并行化与流式主要改善延迟,checkpointer 与限流治理稳定性,降级与成本监控保障线上可控。

常见错误:盲目把上下文窗口调到 128k/200k,成本几乎线性增长但效果边际递减;所有任务(包括分类、打标签)都使用最强模型,成本被低价值路径消耗;消息列表无限追加而不裁剪,几十轮对话后 token 爆炸;缓存键未纳入 prompt/工具版本号,导致新旧结果污染;Semaphore 并发值设得过高,触发 LLM 供应商持续 429 反而整体吞吐下降;Checkpointer 中存入原始文档或二进制大对象,数据库 IO 成为瓶颈。

生产建议:建立"小模型优先"的路由策略,用分类节点决策是否升级到大模型;每次发版前对比 token 基线与延迟基线,形成版本级成本报告;缓存 key 统一加入模型名、prompt_hash、tools_hash,部署新 prompt 时主动失效;按租户设置并发与预算配额,避免单租户拖垮全局;checkpointer 与业务数据库物理分离,避免 IO 争抢;定期(每周)分析 LangSmith 中 Top N 高成本 trace,针对冗余工具调用、无效循环、重试风暴做专项优化。 ​

第五篇 实战篇 ​