如何用 WB Tracer 追踪 LangChain 链的 Token 消耗、输入输出与耗时

发布时间:2026/9/13 1:42:10

如何用 WB Tracer 追踪 LangChain 链的 Token 消耗、输入输出与耗时 如何用 WB Tracer 追踪 LangChain 链的 Token 消耗、输入输出与耗时【免费下载链接】llm-cookbook面向开发者的 LLM 入门教程吴恩达大模型系列课程中文版项目地址: https://gitcode.com/GitHub_Trending/ll/llm-cookbook在调试 LLM 链或代理时一次运行背后会发生多步调用选参数、调工具、请求大模型。只看最终输出很难定位是哪一步耗时、哪一步多花了 token。本仓库的《选修-Evaluating and Debugging Generative AI》第五章 大语言模型评估以及用 WB 追踪 Evaluation and Tracing 演示了两种记录方式对自写的链用wandb.sdk.data_types.trace_tree里的Trace类显式打点对 LangChain 代理通过一个环境变量让 WB 自动记录。两种方式的记录内容都包括输入与输出、开始和结束时间、调用是否成功、token 使用量以及附加元数据。准备条件Python 环境。仓库的 环境配置 建议用 Anaconda 创建 Python 3.9 环境并安装openai等依赖本章代码还会用到wandb和tenacity重试装饰器。OpenAI API key按 环境配置 中的说明获取并按笔记本中的方式设置openai.api_key。登录 WB。笔记本中使用的是匿名登录方式不需要预先注册项目。导入并登录import os import random import time import datetime import openai from tenacity import ( retry, stop_after_attempt, wait_random_exponential, # 为指数回退 (for exponential backoff) ) import wandb from wandb.sdk.data_types.trace_tree import Trace # 获取 OpenAI 的 API openai.api_key sk-XXX # 替换为你自己的 key # 定义相应变量 PROJECT dlai_llm MODEL_NAME gpt-3.5-turbo # 登陆wandb wandb.login(anonymousallow)带退避重试的调用函数用于避免速率限制retry(waitwait_random_exponential(min1, max60), stopstop_after_attempt(6)) def completion_with_backoff(**kwargs): 这个函数能避免速率限制 (rate limits) return openai.ChatCompletion.create(**kwargs)用 Trace 显式追踪一条自定义链先看一条不经过 LangChain 的两步链WorldPicker随机选一个虚幻世界对应一个toolspan然后把结果拼进 Prompt 调 OpenAI 生成名字对应一个llmspan两个 span 都挂在顶层chainspan 下。文档说明中记录的字段正是标题关心的三类信息输入与输出、开始和结束时间、OpenAI 调用是否成功、token 使用量和额外元数据。worlds [ a mystic medieval island inhabited by intelligent and funny frogs, a modern castle sitting on top of a volcano in a faraway galaxy, a digital world inhabited by friendly machine learning engineers ] # 定义配置 model_name gpt-3.5-turbo temperature 0.7 system_message You are a creative copywriter. Youre given a category of game asset and a fantasy world. Your goal is to design a name of that asset. Provide the resulting name only, no additional description. Single name, max 3 words output, remember! def run_creative_chain(query): # 部分1 - 链开始了 start_time_ms round(datetime.datetime.now().timestamp() * 1000) # 顶层 root span root_span Trace( nameMyCreativeChain, kindchain, start_time_msstart_time_ms, metadata{user: student_1}, model_dict{_kind: CreativeChain} ) # 部分2 - 链随机选择一个虚幻世界 time.sleep(3) world random.choice(worlds) expanded_prompt fGame asset category: {query}; fantasy world description: {world} tool_end_time_ms round(datetime.datetime.now().timestamp() * 1000) # 创建一个tool span tool_span Trace( nameWorldPicker, kindtool, status_codesuccess, start_time_msstart_time_ms, end_time_mstool_end_time_ms, inputs{input: query}, outputs{result: expanded_prompt}, model_dict{_kind: tool, num_worlds: len(worlds)} ) # 将 tool span 添加为 root span 的子 root_span.add_child(tool_span) # 部分3 - 将工具 span 的输出传递至大语言模型 messages[ {role: system, content: system_message}, {role: user, content: expanded_prompt} ] response completion_with_backoff(modelmodel_name, messagesmessages, max_tokens12, temperaturetemperature) llm_end_time_ms round(datetime.datetime.now().timestamp() * 1000) response_text response[choices][0][message][content] token_usage response[usage].to_dict() llm_span Trace( nameOpenAI, kindllm, status_codesuccess, metadata{temperature: temperature, token_usage: token_usage, model_name: model_name}, start_time_mstool_end_time_ms, end_time_msllm_end_time_ms, inputs{system_prompt: system_message, query: expanded_prompt}, outputs{response: response_text}, model_dict{_kind: Openai, engine: response[model], model: response[object]} ) # 将大模型 span 添加为链 span 的子 root_span.add_child(llm_span) # 更新链 span 的输入和输出 root_span.add_inputs_and_outputs( inputs{query: query}, outputs{response: response_text}) # 更新链 span 的结束时间 root_span.end_time_ms llm_end_time_ms # 部分4 - 通过记录 root span 来记录所有 spans 到 WB root_span.log(namecreative_trace) print(fResult: {response_text})这段代码里几个打点约定值得注意每个 span 的start_time_ms/end_time_ms是毫秒时间戳耗时通过起止时间差体现。子 span 的开始时间接前一个 span 的结束时间llm_span的start_time_ms用的是tool_end_time_ms链的总结束时间由root_span.end_time_ms指定。token 消耗来自 API 响应的response[usage]含 prompt/completion/total tokens以token_usage放进llmspan 的metadata。inputs/outputs分别记录该步骤的输入 Prompt 与模型回答status_codesuccess表示这次调用成功。只有root_span.log(namecreative_trace)执行后整棵树才会上报只记录 root其所有子 span 会一并被记录。运行并开启一个新的 WB 记录# 开启新的 WB 表 wandb.init(projectPROJECT, job_typegeneration) # 运行 run_creative_chain(hero) run_creative_chain(jewel) wandb.finish()用环境变量自动追踪 LangChain 代理代理与固定链的区别在于每一步由大模型推理决定路径不确定因此更难调试——文档给出的理由正是使用追踪程序将会很有帮助。这一部分演示了让 WB 自动记录 LangChain 的方式只多一行环境变量# 导入需要的库 from langchain.agents import AgentType, initialize_agent from langchain.chat_models import ChatOpenAI from langchain.tools import BaseTool from typing import Optional from langchain.callbacks.manager import ( AsyncCallbackManagerForToolRun, CallbackManagerForToolRun, ) # 初始化 wandb.init(projectPROJECT, job_typegeneration) # 这将设置跟踪因此会自动记录这些跟踪 os.environ[LANGCHAIN_WANDB_TRACING] true文档明确说明LANGCHAIN_WANDB_TRACINGtrue的作用设置跟踪自动记录这些跟踪无需再对每个 span 手动打点。工具与代理的搭建工具各带一个time.sleep(1)用于模拟真实延迟便于在追踪里看到耗时class WorldPickerTool(BaseTool): name pick_world description pick a virtual game world for your character or item naming worlds [ a mystic medieval island inhabited by intelligent and funny frogs, a modern anthill featuring a cyber-ant queen and her cyber-ant-workers, a digital world inhabited by friendly machine learning engineers ] def _run( self, query: str, run_manager: Optional[CallbackManagerForToolRun] None ) - str: time.sleep(1) return random.choice(self.worlds) async def _arun( self, query: str, run_manager: Optional[AsyncCallbackManagerForToolRun] None ) - str: raise NotImplementedError(pick_world does not support async) class NameValidatorTool(BaseTool): # 检查 query 或 name 是否少于20个字符 name validate_name description validate if the name is properly generated def _run( self, query: str, run_manager: Optional[CallbackManagerForToolRun] None ) - str: time.sleep(1) if len(query) 20: return fThis is a correct name: {query} else: return fThis name is too long. It should be shorter than 20 characters. async def _arun( self, query: str, run_manager: Optional[AsyncCallbackManagerForToolRun] None ) - str: raise NotImplementedError(validate_name does not support async) # 实例化大模型 llm ChatOpenAI(temperature0.7, openai_api_keyopenai.api_key) # 生成可选择工具的list、生成代理 tools [WorldPickerTool(), NameValidatorTool()] agent initialize_agent( tools, llm, agentAgentType.ZERO_SHOT_REACT_DESCRIPTION, handle_parsing_errorsTrue, verboseTrue ) # 输入、运行 agent.run( Find a virtual game world for me and imagine the name of a hero in that world ) agent.run( Find a virtual game world for me and imagine the name of a jewel in that world ) wandb.finish()代理的每一步LLM 推理、工具调用都会由 WB 集成自动记录不再需要手写Trace。在 WB 中查看追踪结果文档给出的验证方式是回到 WB 网页自定义链打开运行结果行中的网址run_creative_chain打印结果之后对应的 WB 页面点击WorldPicker和OpenAI两个 span可以看到背后相应的过程——即每一步的输入、输出、起止时间与 token 使用量。LangChain 代理打开运行结果行中的网址点击相应板块同样可以查看背后的执行过程。注意文档中一条明确的说明大语言模型输出是可变的所以结果可能每次不一致。看追踪面板时应关注步骤结构、耗时与 token 数字的变化而不是期待复现某一次的具体文本。限制显式打点方式需要自己维护Trace对象、起止时间戳和add_child父子关系root_span.log()之前上报的内容不会进入记录LangChain 自动追踪依赖LANGCHAIN_WANDB_TRACING环境变量需要在agent.run之前设置两种路径都要求wandb.login成功后再wandb.init(projectPROJECT, job_typegeneration)开启记录结束时调用wandb.finish()。【免费下载链接】llm-cookbook面向开发者的 LLM 入门教程吴恩达大模型系列课程中文版项目地址: https://gitcode.com/GitHub_Trending/ll/llm-cookbook创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/13 1:42:10

外贸GEO公司有哪些?怎么选才不踩坑?

文/林芳老师 先搞清楚:GEO服务商分哪几类? 2026年,GEO(Generative Engine Optimization,生成式引擎优化)成了外贸行业的热词。当海外采购商习惯用ChatGPT、Perplexity、Google AI Mode等AI工具找供应商时&a…

2026/9/13 2:42:13

蚂蚁电竞高刷显示器选购指南:从300Hz到1000Hz全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/13 2:42:13

MySQL 5.7升级8.0实战:完整路径、踩坑记录与备份方案

我上周刚帮朋友把一套跑了三年的MySQL 5.7实例升到了8.0,整个过程比预想的要顺,但中间也踩了软件源、认证插件、sql_mode几个坑。MySQL 8.0发布好几年,社区版和企业版都已经非常稳定,5.7官方维护也进入了末期,从安全补…

2026/9/13 2:42:13

MySQL备份恢复全攻略:从工具选型到误删数据恢复实战

去年接管一套老系统时,赶上一次典型事故:运营误操作把订单表 truncate 了,结果发现这台 MySQL 上一次全量备份是十几天前,binlog 也没有异地归档。最后花了一整天从磁盘碎片和 binlog 残留里手动拼数据,业务停机超过 8…

2026/9/13 0:01:16

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/13 0:01:16

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/12 14:32:17

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/12 6:37:43

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码