有效部署LangChain应用不仅意味着管理性能,还需管理运营开支。大型语言模型虽然强大,但会消耗计算资源,其用量通常直接转化为金钱成本,主要通过按令牌计费的API调用产生。忽视成本管理可能导致不可持续的运营开支,特别是当你的应用扩展时。这里介绍了理解、追踪和控制LangChain应用相关成本的方法,主要关注令牌用量,这是LLM开支的主要因素。了解令牌经济学大多数商业LLM提供商(如OpenAI、Anthropic、Google)采用基于处理“令牌”数量的按用量付费模式。一个令牌大致对应一个单词或单词的一部分。掌握这些成本是如何累积的,这很必要:输入与输出定价: 许多模型对于发送给模型的令牌(输入/提示令牌)和从模型接收的令牌(输出/完成令牌)有不同的价格点。通常,输出令牌更昂贵。模型等级: 同一提供商家族内的不同模型带有明显不同的价格标签。例如,OpenAI的GPT-4模型每令牌的价格明显高于其GPT-3.5 Turbo对应产品。这体现了能力、规模和计算要求的差异。上下文很重要: 你发送的提示,包括RAG系统中检索到的任何上下文或对话历史,都会增加输入令牌计数。冗长繁琐的提示或大量上下文会直接增加成本。计算: 单次LLM调用的基本成本公式通常为: $$ \text{成本} = (\text{输入令牌} \times \text{价格}{\text{输入}}) + (\text{输出令牌} \times \text{价格}{\text{输出}}) $$ 其中 $\text{价格}{\text{输入}}$ 和 $\text{价格}{\text{输出}}$ 分别是输入和输出的每令牌成本,对于所使用的特定模型而言。了解这种定价结构是实现有效成本管理的第一步。你需要清楚地知道你的应用消耗了多少令牌以及在哪里消耗。在LangChain中追踪令牌用量LangChain提供了便捷的方式来追踪令牌用量,特别是对于通过OpenAI等标准API接口的模型。主要机制涉及使用回调函数。get_openai_callback 上下文管理器是一种直接的方法,用于追踪执行OpenAI调用的代码块的用量:from langchain_openai import ChatOpenAI from langchain_community.callbacks import get_openai_callback from langchain_core.messages import HumanMessage # 假设 OPENAI_API_KEY 已在环境中设置 llm = ChatOpenAI(model="gpt-3.5-turbo") messages = [HumanMessage(content="Explain the concept of tokenization in LLMs in about 50 words.")] # 使用回调上下文管理器 with get_openai_callback() as cb: response = llm.invoke(messages) print(response.content) print("\n--- 用量统计 ---") print(f"总令牌数: {cb.total_tokens}") print(f"提示令牌数: {cb.prompt_tokens}") print(f"完成令牌数: {cb.completion_tokens}") print(f"总成本 (美元): ${cb.total_cost:.6f}") 当你运行此代码时,get_openai_callback 上下文管理器 (cb) 会捕获在 with 块内进行的LLM调用的令牌计数和预估成本。它提供诸如 total_tokens、prompt_tokens、completion_tokens 和 total_cost 的属性。对于涉及链或代理的更复杂情况,或者处理异步操作时,你可能需要更精密的追踪方法:自定义回调处理器: 你可以实现继承自 BaseCallbackHandler 的自定义回调处理器,以汇总多个步骤或异步任务中的令牌计数。这些处理器可以将数据记录到数据库、监控系统或自定义仪表板中。链/代理的详细模式: 以 verbose=True 运行链或代理通常会打印每个步骤的令牌用量信息,这在开发期间可能有用,但在生产日志记录中不太实用。使用LangSmith进行全面的成本监控尽管内置回调函数很有用,LangSmith为生产监控(包括成本追踪)提供了一个更集成、功能更强的解决方案。当你配置LangChain应用使用LangSmith时(详见第五章),它会自动捕获应用执行的详细追踪,包括:令牌计数: 对于追踪中的每次LLM调用,LangSmith会记录提示令牌、完成令牌和总令牌。预估成本: 根据所使用的模型和令牌计数,LangSmith会自动计算每次LLM交互的预估成本。汇总: LangSmith用户界面允许你查看不同追踪、时间段或项目中的汇总令牌用量和成本。你可以轻松地辨别哪些链、代理或特定的LLM调用对你的总成本贡献最大。元数据标记: 你可以添加自定义标签(例如,用户ID、会话ID、功能名称)到你的LangChain调用或LangSmith追踪中。这使得精细的成本归因成为可能,允许你在多租户应用中按用户、按功能或按租户分析成本。使用LangSmith将成本追踪从手动日志记录或简单回调函数变为一个持久化、可搜索和可汇总的系统,明显提高了生产环境中的可见性。digraph G { bgcolor="transparent"; node [shape=box, style=rounded, fontname="Arial", fontsize=10, margin=0.2, color="#adb5bd"]; edge [fontname="Arial", fontsize=9, color="#495057"]; UserInput [label="用户输入"]; RAGChain [label="RAG链"]; Retriever [label="检索器"]; LLM [label="LLM调用\n(追踪令牌/成本)", color="#fa5252", style="rounded,filled", fillcolor="#ffc9c9"]; Output [label="最终输出"]; LangSmith [label="LangSmith\n(记录追踪、令牌、成本)", shape=cylinder, color="#4263eb", style="filled", fillcolor="#bac8ff"]; UserInput -> RAGChain; RAGChain -> Retriever [label="查询"]; Retriever -> RAGChain [label="上下文文档"]; RAGChain -> LLM [label="提示 + 上下文"]; LLM -> RAGChain [label="LLM响应"]; RAGChain -> Output; LLM -> LangSmith [style=dashed, arrowhead=open]; {rank=same; Retriever; LLM} }简化流程图,演示了在一个RAG应用中,令牌用量和成本通常在哪里被追踪(在LLM调用处)和记录(例如,到LangSmith)。成本削减策略一旦你清楚地掌握了令牌用量和成本,你就可以实施策略来减少开支:战略性模型选择: 这通常是最具影响力的手段。评估是否更便宜的模型(例如,GPT-3.5-Turbo、Claude Haiku)能充分完成某些任务,而非默认选择最强大(且昂贵)的选项(例如,GPT-4、Claude Opus)。如果你有特定、重复的任务,可以考虑微调更小的开源模型,尽管这会涉及前期训练成本。提示优化: 简洁很重要。优化你的提示,使其尽可能简洁,同时仍能达到预期输出。删除多余的指令或例子。分析小样本示例是否总是必需的。上下文窗口管理: 在RAG或对话系统中,发送过多上下文会显著增加输入令牌计数。采用以下技术:摘要: 在将对话历史或长文档包含到提示中之前进行摘要(第三章)。选择性检索: 提高检索准确性(第四章),这样只发送最相关的文本块,而不是大量可能不相关的文本。滑动窗口: 对于长对话,只包含最近的轮次。LLM响应缓存: 如果你的应用经常收到相同的请求,缓存LLM响应可以带来显著的节省和延迟改进。LangChain提供了多种缓存实现(InMemoryCache、SQLAlchemyCache、RedisCache等)。如果底层数据或预期响应可能改变,请注意缓存失效问题。from langchain.globals import set_llm_cache from langchain_openai import OpenAI from langchain_community.cache import InMemoryCache # 全局启用缓存 set_llm_cache(InMemoryCache()) llm = OpenAI(model="gpt-3.5-turbo-instruct") # 第一次调用(将请求API并缓存结果) print("第一次调用:") result1 = llm.invoke("Why is the sky blue?") # print(result1) # 为简洁省略输出 # 第二次调用,提示完全相同(将从缓存返回) print("\n第二次调用 (已缓存):") result2 = llm.invoke("Why is the sky blue?") # print(result2) # 为简洁省略输出 # 注意:get_openai_callback 不会显示缓存调用的成本/令牌控制输出长度: 在LLM调用中使用 max_tokens 参数来限制生成响应的长度。当你只需要一个简短答案、摘要或分类时,这很有用,可以防止模型生成过长(且昂贵)的文本。批量请求: 一些LLM API支持批量处理,允许你在单个请求中发送多个独立的提示。尽管这通常不会改变每令牌成本,但它可以减少网络开销并可能提高整体吞吐量,间接影响基础设施成本。查阅你的提供商文档以了解批量处理能力和定价。{"layout": {"title": {"text": "月度成本:模型对比"}, "xaxis": {"title": {"text": "模型"}}, "yaxis": {"title": {"text": "预估月度成本 (美元)"}, "range": [0, 550]}, "legend": {"traceorder": "reversed"}, "autosize": true, "height": 350, "template": "plotly_white", "margin": {"l": 50, "r": 20, "t": 50, "b": 50}}, "data": [{"type": "bar", "x": ["GPT-3.5-Turbo", "GPT-4", "GPT-4 (Cached)"], "y": [100, 500, 200], "marker": {"color": ["#96f2d7", "#ffc9c9", "#bac8ff"], "line": {"color": "#495057", "width": 1}}, "name": "成本"}]}月度成本的示意性对比,展示了使用不同模型或技术处理相同工作负载的情况。与未缓存的GPT-4用量相比,缓存显著降低成本,如果某些请求需要GPT-4的质量,这可能使其比始终使用更便宜的GPT-3.5模型更可行。成本归因与预算编制在生产环境中,特别是在多功能或多租户应用中,仅仅知道总成本是不够的。你需要将成本归因于特定的活动:标记: 使用LangSmith的标记功能或自定义日志记录,将API调用与用户ID、会话ID、租户ID或功能标志关联起来。分析: 定期分析按这些标签细分的成本数据(例如,在LangSmith或你自己的监控仪表板中)。这有助于辨别哪些功能或用户产生的成本最高。预算: 为整体LLM用量或特定功能/团队设定预算。设置警报(可能通过LangSmith集成或自定义监控),在支出接近或超过预算阈值时通知你。积极的成本管理需要持续的监控、分析和优化。通过精细追踪令牌用量,运用LangSmith等工具,并应用成本节约策略,你可以确保你的LangChain应用在扩展时保持经济可行。这种积极主动的方法是负责任地运营生产级LLM系统的重要组成部分。