趋近智
当你利用 LangChain 的高级功能(例如 LangChain 表达式语言 (LCEL)、异步操作和自定义组件)构建更精巧的应用时,明确执行流程变得愈发重要。让 LangChain 功能强大的分层抽象有时会掩盖链或代理运行期间发生的具体情况。因此,高效调试必不可少,它不仅用于修正错误,更用于真正弄懂并优化应用的表现。本文将介绍专门用于追踪和分析 LangChain 执行流程的方法和工具。
与传统软件相比,用 LangChain 构建的应用在调试时面临独有的挑战:
LangChain 包含内置机制,可在执行期间提高可见度。
获取更多情况最简单的办法是通过 globals 模块启用全局详细设置:
from langchain.globals import set_verbose
set_verbose(True)
# 现在,当你运行链或代理时,详细日志会打印到标准输出
# 例如,显示发送给 LLM 的准确提示、LLM 的原始响应等。
虽然易于启用,但详细日志会产生大量输出,特别是对于涉及多次 LLM 调用或工具使用的精巧链或代理。它对初步察看有益,但对于有目标的调试可能会变得难以应对。
一个更规整的替代方案是全局调试设置:
from langchain.globals import set_debug
set_debug(True)
# 运行组件现在会打印出更规整的调试信息,
# 通常包含时间信息和更清楚的步骤划分。
与详细模式相比,将调试设置为 true 通常会提供更清晰、可能带颜色编码的输出,使其稍微更容易追踪执行路径。然而,与详细设置一样,它全局生效,仍可能生成过多信息。
对于认真的开发和生产监控,LangSmith 是推荐工具。虽然第 5 章详细介绍了 LangSmith 用于评估和监控,但其追踪功能在开发期间进行调试时是不可或缺的。
要使用 LangSmith,你通常需要设置环境变量:
export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY="..."
# 可选:设置项目名称
# export LANGCHAIN_PROJECT="我的高级应用"
配置完成后,LangChain 自动将执行追踪记录到 LangSmith。网页界面允许你进行如下操作:
LangSmith 将调试从解读原始日志转变为交互式查看规整的追踪信息,大大加快了找出根本原因的过程。
为了精细控制和程序化访问执行事件,LangChain 的回调系统功能强大。回调函数允许你介入 LangChain 生命周期中的各个阶段(例如,on_llm_start、on_chain_end、on_agent_action)。
你通过继承 BaseCallbackHandler 并覆盖你想要拦截事件对应的方法来实行自定义回调处理器。
from langchain_core.callbacks import BaseCallbackHandler
from langchain_core.outputs import LLMResult
from langchain_core.agents import AgentAction
from typing import Any, Dict, List
class MyCustomHandler(BaseCallbackHandler):
def on_llm_start(self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any) -> None:
print(f"LLM Start: Sending {len(prompts)} prompts.")
# 将提示记录到自定义位置,也许只在它们符合特定条件时才记录
def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:
print("LLM End:")
# 记录 token 使用量或成本估算
if response.llm_output:
print(f" Tokens Used: {response.llm_output.get('token_usage')}")
def on_chain_start(self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs: Any) -> None:
print(f"Chain Start: Input keys: {list(inputs.keys())}")
def on_agent_action(self, action: AgentAction, **kwargs: Any) -> None:
print(f"Agent Action: Tool={action.tool}, Input={action.tool_input}")
# 在此处添加工具输入的验证逻辑
# --- 用法 ---
# from langchain_openai import ChatOpenAI
# from langchain_core.prompts import PromptTemplate
# llm = ChatOpenAI(temperature=0) # 假设 OPENAI_API_KEY 已设置
# prompt = PromptTemplate.from_template("Tell me a joke about {topic}")
# chain = prompt | llm
# handler = MyCustomHandler()
# # 回调函数通过 LCEL 中的 config 字典传递
# result = chain.invoke({"topic": "debugging"}, config={"callbacks": [handler]})
# print(f"\n最终结果:\n{result.content}")
回调函数提供精准控制。你可以在恰好需要的时候和地方记录特定数据片段、触发外部警报、实行自定义验证或收集精细的性能指标,而不依赖全局设置或外部平台。LangChain 也提供 StdOutCallbackHandler 等标准处理器,它模仿了部分全局详细行为,但可以有选择地应用。
使用 LangChain 表达式语言 (LCEL) 构建精巧链时,了解其结构本身就可以是调试的一个步骤。LCEL 对象有帮助可视化其组成的办法:
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
# 定义一个简单的 LCEL 链
prompt = ChatPromptTemplate.from_template("Explain {topic} simply.")
model = ChatOpenAI() # 假设 OPENAI_API_KEY 已设置
output_parser = StrOutputParser()
chain = prompt | model | output_parser
# 获取图的可打印表示
# print(chain.get_graph().draw_ascii())
# 或者生成一个 Graphviz 图(需要安装 Graphviz 库)
try:
graph_viz_object = chain.get_graph().draw_graphviz()
# 你可以将其保存到文件或在合适的坏境(例如 Jupyter)中显示
# graph_viz_object.render("chain_structure", format="png", view=True) # 保存并打开图片
graph_dot_string = graph_viz_object.source
print("Graphviz 定义:\n")
# 显示 Graphviz DOT 字符串以供表示
print(f'```graphviz\ndigraph G {{\ncompound=true;\n\t"{chain.first.id}" [label="ChatPromptTemplate" shape=box style=rounded];\n\t"{chain.middle[0].id}" [label="ChatOpenAI" shape=box style=rounded];\n\t"{chain.last.id}" [label="StrOutputParser" shape=box style=rounded];\n\t"{chain.first.id}" -> "{chain.middle[0].id}" [ltail=lc_0 lhead=lc_1];\n\t"{chain.middle[0].id}" -> "{chain.last.id}" [ltail=lc_1 lhead=lc_2];\n}} \n```')
except ImportError:
print("未找到 Graphviz 库。请通过 'pip install graphviz' 安装。")
print("改为 ASCII 表示:")
print(chain.get_graph().draw_ascii())
一个简单 LCEL 链结构的可视化:提示词 -> 模型 -> 解析器。
可视化图有助于确认组件按预期连接,这在进一步研究精巧 LCEL 组合的运行时调试之前尤其有用。
别忘了标准 Python 调试技术。使用自定义组件(封装为 RunnableLambda 或自定义子类的函数、类)时,使用 print 语句、日志记录或 Python 调试器(如 pdb 或 IDE 的调试器)通常是检查自定义代码内部变量和控制流程最直接的途径。
print、logging、pdb)。掌握这些调试方法非常基本,可帮助你超越简单的原型。随着你构建越来越精巧的链和代理,有效追踪、检查和诊断执行流程的能力将是创建可靠且高性能的生产应用不可或缺的。
简洁的语法。内置调试功能。从第一天起就可投入生产。
为 ApX 背后的 AI 系统而构建
这部分内容有帮助吗?
© 2026 ApX Machine Learning用心打造