AI智能体的“神经系统”:基于LangSmith或自研方案的日志追踪与性能调优
一、为什么日志系统在AI智能体面前失效了
在传统软件开发中,print加日志文件排查问题几乎是本能反应。但AI智能体完全打破了这套惯性——一次用户请求背后可能串起Query改写、向量检索、重排序、工具调用、多轮LLM推理,日志散落在五六个服务里,靠grep根本拼不回一条完整的时间线。更棘手的是,LLM是非确定性的,同一个输入两次运行结果可能不同,日志里的“复现步骤”经常复现不了。
我经历过一次刻骨铭知的教训:夜里黄金测试集跑批,Faithfulness分数从0.83掉到0.61,直接触发了P0拦截。先看Context Recall,正常;再看Prompt有没有改,也没改。三个人对着日志文件从检索模块的print输出翻到生成模块的日志,中间夹着Query改写和工具调用,硬是花了小半天才发现——Reranker服务偷偷升级了模型版本,返回的片段顺序变了,进而影响了Prompt里片段的排列顺序,模型“理解”错了优先级。
这件事让我彻底认清:靠print和肉眼翻日志去调试一个多步骤Agent,本质上是在用石器时代的工具修复宇宙飞船。我们需要的是把每一次调用组织成一棵结构化的Trace树——根节点是用户请求,子节点是检索、重排、生成、工具调用……每个节点自带耗时、Token数、输入输出,点开就能看。
二、LangSmith Tracing核心机制:把一次调用拆成一棵树
LangSmith将可观测数据按照Run → Trace → Thread → Trajectory四级结构组织。
2.1 四级数据模型
| 概念 | 含义 | 对应传统观测 |
|---|---|---|
| Run | 一次执行的原子单元,如一次LLM调用、一次工具调用 | 类似Span |
| Trace | 一次完整用户请求产生的所有Run的集合 | 类似Trace |
| Thread | 多轮会话中多个Trace的序列(通过thread_id关联) |
类似Session |
| Trajectory | Thread的扁平化视图——将所有轮次的消息按时间顺序平铺为列表 | 类似对话历史 |
如果你熟悉OpenTelemetry,可以把Run理解为Span。一次用户请求触发Agent调用模型→模型调用工具→工具返回结果→模型再次调用,所有这些Run通过同一个trace_id绑定在一起。
from langsmith import traceable
from langsmith import Client
client = Client()
# 最简单的用法:装饰器自动捕捉
@traceable(run_type="llm")
def call_model(prompt: str):
# 这里调用OpenAI或其他LLM
return openai.chat.completions.create(...)
@traceable(run_type="retriever", name="hybrid_search")
def retrieve(query: str, top_k: int = 10):
dense = vector_search(query, top_k)
sparse = bm25_search(query, top_k)
return merge_and_dedup(dense, sparse)
@traceable(run_type="chain", name="kb_agent")
def answer(query: str):
ctx = retrieve(query)
return call_model(f"基于以下信息回答:{ctx}\n问题:{query}")
关键在于run_type参数——它决定了这个节点在Trace树里怎么展示、怎么统计。LangSmith内置了几种类型:chain(编排逻辑)、llm(模型调用,自动统计Token)、retriever(检索)、tool(工具调用)。类型标对后,一次请求跑完,UI上就是一棵完整的树,每层缩进清清楚楚,点开就能看到耗时、输入输出和Token消耗。
2.2 手动细粒度追踪
对于LangChain没有封装的场景,@traceable可以装饰任意Python函数:
from langsmith import traceable
@traceable(run_type="tool", name="bge_rerank")
def rerank(query: str, contexts: list):
"""自定义重排序函数——任意代码都能进追踪树"""
scores = bge_reranker.score(query, contexts)
return sorted_by_score(contexts, scores)
@traceable(run_type="retriever", name="knowledge_graph_query")
def query_knowledge_graph(question: str):
"""知识图谱查询——同样被追踪"""
# 任意复杂逻辑...
return results
# 嵌套调用自动形成父子关系
@traceable(run_type="chain")
def rag_pipeline(question: str):
docs = retrieve(question) # 子Run
docs = rerank(question, docs) # 子Run
graph = query_knowledge_graph(question) # 子Run
return generate(question, docs, graph) # 子Run
2.3 多轮会话的Thread追踪
跨境电商客服场景中,用户可能连续多轮对话。LangSmith通过thread_id将多次请求关联为一个线程:
from langsmith import traceable
@traceable(
run_type="chain",
project_name="ecommerce-cs"
)
def handle_user_message(user_id: str, message: str):
# 在metadata中注入thread_id,LangSmith自动聚合
# 在调用时,通过metadata传递thread_id
pass
# 调用侧注入线程标识
def process_conversation(user_id: str, message: str):
result = handle_user_message.with_config(
metadata={"thread_id": f"user_{user_id}"}
)(message)
return result
配置后,LangSmith UI会自动将同一thread_id的所有Trace聚合为Thread视图,支持按时间顺序回放完整对话过程。
三、OpenTelemetry方案:标准化的厂商中立选择
LangSmith的优势在于开箱即用,但也带来厂商锁定的顾虑——所有Trace数据流向LangSmith云端。对于数据敏感或预算受限的团队,OpenTelemetry提供了另一种选择。
3.1 OpenTelemetry GenAI语义规范
OpenTelemetry社区已推出GenAI语义规范,为LLM调用、Embedding、RAG检索、Tool执行等AI原语定义标准化的Span属性。阿里云基于此推出了LoongSuite GenAI可观测语义规范,并实现了基于eBPF的无侵入式采集方案(OBI),无需修改代码即可自动识别LLM、Embedding、Rerank、MCP等AI调用类型。
# 手动使用OTel SDK追踪Agent调用
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
# 配置OTLP导出器(支持各类后端)
provider = TracerProvider()
processor = BatchSpanProcessor(OTLPSpanExporter(endpoint="http://otel-collector:4318/v1/traces"))
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)
def process_agent_request(user_query: str):
with tracer.start_as_current_span("agent_workflow") as span:
span.set_attribute("user.query", user_query)
# 子Span:模型调用
with tracer.start_as_current_span("llm_generate") as llm_span:
llm_span.set_attribute("llm.model", "gpt-4o")
response = call_model(user_query)
llm_span.set_attribute("llm.usage.total_tokens", response.usage.total_tokens)
# 子Span:工具调用
if tool_needed:
with tracer.start_as_current_span("tool_execute") as tool_span:
tool_span.set_attribute("tool.name", "search_products")
tool_result = execute_tool(...)
tool_span.set_attribute("tool.result", str(tool_result))
return response
3.2 OpenAI Agents SDK的OTel集成
OpenAI官方为Agents SDK提供了OpenTelemetry Instrumentation包,可以自动将Runner.run、Agent调用、Tool调用转换为OTel Span:
from opentelemetry.instrumentation.genai.openai_agents import OpenAIAgentsInstrumentor
# 一行代码启用
OpenAIAgentsInstrumentor().instrument()
# 之后所有Agent运行自动生成Trace
# Runner.run 产生 workflow Span
# 每个Agent产生 Agent Span
# 每个Function Tool产生 Tool Span
四、自研轻量化方案:无厂商锁定的替代选择
对于不想使用LangSmith云端服务或需要完全控制数据的团队,目前已有成熟的开源自研方案。
4.1 OpenSmith:LangSmith的本地替代
OpenSmith是一个100%本地、无需云账号的开源替代方案,数据存储在本地SQLite数据库中,提供可视化Dashboard。
from opensmith import trace, autopatch
# 自动补丁:零代码侵入
autopatch(only=["openai"]) # 只追踪OpenAI调用
@trace(tags=["production", "rag"], token_budget=1000)
def my_pipeline(query: str):
# 任意代码,自动追踪
docs = search_docs(query)
return call_llm(docs + query)
# 或使用上下文管理器
with trace("agent_run", tags=["debug"]) as t:
t.log("query", "什么是退换货政策")
response = call_llm("...")
t.log("response", response)
运行opensmith ui即可在localhost:7823查看Dashboard,所有Trace数据只存在于本地。
4.2 Agent Observability Kit:跨框架开源方案
Agent Observability Kit是另一个框架无关的开源可观测方案,通过装饰器和回调机制捕获LangChain、CrewAI、AutoGen等多种框架的调用痕迹。
from agent_observability import observe, init_tracer
from agent_observability.span import SpanType
tracer = init_tracer(agent_id="customer-service")
@observe(span_type=SpanType.AGENT_DECISION)
def choose_action(state):
# Agent决策逻辑
return my_llm.predict(state)
# LangChain集成
from agent_observability.integrations import LangChainCallbackHandler
handler = LangChainCallbackHandler(agent_id="my-agent")
chain.run(input="query", callbacks=[handler])
该项目宣称相比Dynatrace和DataDog,可在3年内节省90%以上的可观测成本。
五、跨境电商实战:可观测性驱动性能调优
回到开篇那个“Reranker升级导致分数下降”的场景,有了Trace树之后排查路径完全不同:
- 打开LangSmith UI,找到失败的那条Trace
- 展开调用树,依次查看:Query改写Span → 检索Span → Rerank Span → 生成Span
- 点开Rerank Span,看到
model_version从v2变为v3 - 对比Rerank前后排序变化,确认是片段顺序影响生成质量
- 锁定根因:Reranker升级后片段排序逻辑改变,导致LLM解读优先级错乱
整个过程从“小半天”压缩到几分钟。
对于跨境电商的广告调价Agent,可观测性还能帮助回答一个关键问题:为什么这个Agent今天多花了5000美元预算? 通过Trace树可以追踪到:用户意图→Agent决策→工具调用参数(调价幅度)→广告平台响应,整个决策链一目了然。
六、总结
AI智能体的可观测性不只是“打点日志”,而是把Agent的决策过程变成一棵可以点开、可以回放的调用树。LangSmith提供开箱即用但绑定厂商的体验,OpenTelemetry提供标准化但需要搭建后端,OpenSmith/Agent Observability Kit提供本地化但功能相对简洁。
三个方案并非互斥——生产中可搭配LangSmith做开发调试,搭配OTel后端做生产监控数据持久化。关键是:Agent“神经”是否清晰,决定了这个系统是可控的工具还是不可控的黑盒。
更多推荐


所有评论(0)