用 TraceAI 调试 AI 智能体

基于OpenTelemetry原生追踪的LLM调用、检索、工具和Agent决策追踪,支持Python、TypeScript、Java和C#,span数据可以流向Jaeger、Tempo、Datadog或Future AGI Observe

用 TraceAI 调试 AI 智能体
微信 ezpoda免费咨询:AI编程 | AI模型微调| AI私有化部署
AI模型价格对比 | AI工具导航 | ONNX模型库 | Tripo 3D | Meshy AI | ElevenLabs | KlingAI | ArtSpace | Phot.AI | InVideo

最难排查的生产AI bug不会导致系统崩溃。它们返回200 OK,让所有仪表板保持绿色,却仍然给用户提供错误的答案,而你的技术栈无法解释原因。

我们曾在一个基于临床指南构建的医疗RAG Agent中见过这种情况。一个分块bug将剂量表分割到了两个块中,检索器找到了正确的文档,但模型只看到了表格的一半,Agent建议一种限制在200mg的药物使用500mg的剂量,持续了三周才被一位资深护士发现。

这就是AI系统中真正的可观测性缺口。检索、嵌入、重排序、推理、工具调用和防护栏检查在传输层看起来一切正常,而系统内部已经在链路中失败了。

这正是traceAI发挥作用的地方。它是一个基于OpenTelemetry构建的开源检测层,可以自动追踪35+个LLM提供商、编排框架和Agent系统,支持Python、TypeScript、Java和C#,并将这些span发送到你已经在使用的后端,而不是强制你使用专有路径。

1、日志的局限性

LLM应用不是一个服务,它是一系列相互依赖的步骤序列,通常包括检索、嵌入、重排序、模型推理、工具执行和防护栏,所有步骤按顺序相互馈送。

传统日志可以告诉你链路完成了,但它们无法告诉你哪个步骤在语义上失败了,哪个步骤变慢了,或者哪个交接点毒害了最终答案。

这个缺口以三种实际方式体现出来。当Agent产生幻觉时,你遇到调试缺口——无法判断是检索器、提示词、工具输出还是模型导致了问题;当延迟从800ms跳到4.2秒时,你遇到性能缺口——无法隔离慢的span;当LangChain、OpenAI和Pinecone各自显示自己的部分,但没有人展示端到端的完整路径时,你遇到工作流缺口。

你可以在一个开发者的一条管道上用print语句修补其中一个问题。但当每天有数千个请求通过多个框架时,你不能这样运行生产Agent。

传统APM产品非常擅长追踪HTTP。它们不理解LLM调用是什么,为什么Agent选择了一个工具而不是另一个,或者检索步骤向模型返回了什么。

OpenTelemetry为我们提供了分布式追踪所需的标准,但它本身不知道AI特定操作长什么样。较新的AI追踪层试图弥补这个缺口,但许多仍然把你引向特定供应商的后端、SDK或span格式,这意味着当你的技术栈改变时,你最终需要重写检测层。

traceAI通过直接基于OpenTelemetry语义约定构建来解决这个问题。相同的span可以流入Jaeger、Grafana Tempo、Datadog或Future AGI Observe,这让你的AI追踪与其余系统遥测保持在一起。

2、traceAI改变了什么

traceAI的核心是检测层,而不是平台。它自动追踪LLM调用、检索步骤、工具调用和Agent决策,捕获AI特定的属性,如模型名称、提示词、token数量和延迟,并将所有这些导出到任何OpenTelemetry兼容的后端。

这个区别很重要,因为AI的可观测性不应该存在于一个封闭的SDK中。当检测本身是开源的,工程师可以检查它、扩展它,并以与信任其余基础设施相同的方式信任它——traceAI采用MIT许可证正是这个原因。

代码库托管在 GitHub上,概念文档在这里 。两者都清楚地说明了同一个观点——traceAI原生于Future AGI,但不绑定于Future AGI。

Python支持最为成熟,这也是首次集成的最佳起点。源文章中的当前覆盖包括OpenAI、Anthropic、LangChain、LlamaIndex、CrewAI、AutoGen、DSPy、Haystack、OpenAI Agents SDK、SmolAgents、LiteLLM、Groq、Mistral AI、AWS Bedrock、Vertex AI、Google GenAI、Guardrails AI和MCP的包,以及LiveKit、Pipecat和n8n。

相同的追踪模型也扩展到Python之外。TypeScript使用@traceai/fi-core以及@traceai/openai等包,Java使用Traced<Client>包装器模式,C#使用FITracer.Initialize()初始化追踪,覆盖范围持续扩展。

3、追踪模型的工作原理

在底层,traceAI遵循OpenTelemetry的instrumentor模式。每个框架都有自己的instrumentor类,如OpenAIInstrumentorLangChainInstrumentor,一旦你调用.instrument(),库就会包装核心方法,使每个LLM调用、检索步骤或工具调用自动成为一个OTel span。

这些span不是通用的。它们携带AI特定的属性,如模型名称、token数量、提示模板、检索分数、工具参数、输出、延迟和执行状态——这正是Agent静默失败时你真正需要的信息。

span种类也以普通HTTP追踪不具备的方式进行了类型化。traceAI区分CHAINLLMTOOLRETRIEVEREMBEDDINGAGENTRERANKERGUARDRAILEVALUATOR,因此追踪读取起来就像系统的逻辑,而不是扁平的网络调用列表。

在实践中,这意味着你可以打开一个追踪,看到类似Agent -> Retriever -> Embedding -> LLM -> Guardrail -> Response的时间线。一旦你的Agent以这种方式呈现,失败通常就无处隐藏了。

导出路径保持简单,因为traceAI不拥有它——OpenTelemetry拥有。流程是你的代码,然后是traceAI instrumentor,然后是OTel TracerProvider,然后是BatchSpanProcessor,然后是OTLP导出器,最后是你的后端,可以是OTLP over HTTP或gRPC、Jaeger、Zipkin或自定义导出器。

这个设计选择是保持系统实用性的关键。你的AI追踪可以与HTTP追踪、数据库追踪和队列追踪共存,因此同一个团队可以调试完整的应用程序,而不是将可观测性分散到不同的产品中。

4、五步调试流程

现在来看一个更熟悉的生产问题。你构建了一个内部销售准备助手,有两个工具——用于知识库的search_company_docs和用于CRM数据的fetch_deal_context——销售人员开始说机器人在编造交易细节。

真正的bug不在模型中。CRM API在高峰期超时,一个try/except块吞掉了超时并返回空字符串,LLM用听起来合理的虚构内容填充缺失的上下文,因为你的日志中没有任何东西标记该工具输出是损坏的。

第1步是注册追踪器,以便在任何span发出之前导出管道就存在。在源代码演示中,register()在一个调用中设置TracerProviderBatchSpanProcessor和OTLP导出器,端点可以切换到Jaeger、Tempo或Datadog,而无需更改应用程序逻辑。

python

from fi_instrumentation import register
from fi_instrumentation.fi_types import ProjectType

trace_provider = register(
    project_type=ProjectType.OBSERVE,
    project_name="sales-prep-agent",
)

第2步是检测OpenAI。两行代码就足以包装代码库中的每个OpenAI调用,并发出包含模型名称、token数量、延迟、完整消息数组和完整响应的span。

python

from traceai_openai import OpenAIInstrumentor
OpenAIInstrumentor().instrument(tracer_provider=trace_provider)

第3步是真正调试价值体现的地方,因为LLM通常不是唯一重要的东西。源文章使用@tracer.tool包装工具函数,使它们的输入、输出和状态成为可见的span——这意味着空字符串不再是不可见的失败。

python

from fi_instrumentation import FITracer

tracer = FITracer(trace_provider.get_tracer(__name__))

@tracer.tool(name="search_company_docs")
def search_company_docs(query: str) -> str:

@tracer.tool(name="fetch_deal_context")
def fetch_deal_context(prospect_name: str) -> str:

在故障情况下,fetch_deal_context在超时后返回""。traceAI将该空输出暴露为span数据,在示例中还显示了3,002ms的延迟,告诉你该工具不仅仅是什么都没返回——它先卡住了。

第4步是包装Agent本身并运行请求。生成的追踪有一个AGENT类型的根span用于sales_prep_agent,然后是search_company_docsfetch_deal_contextopenai.chat.completions.create的子span——这在一个地方给了你完整的调用树。

python
@tracer.agent
def sales_prep_agent(rep_question: str, prospect_name: str) -> str:
    ...

第5步是改变调试体验的部分。你打开追踪,确认search_company_docs在120ms内返回了五个相关块,看到fetch_deal_context在3,002ms后返回了"",然后检查LLM span,发现模型编造交易阶段、最后交互日期和不存在的未解决问题时,提示中的deal_context字段是空白的。

根本原因在一分钟内就暴露出来了,因为失败终于可见了。源示例中的修复不是一个新的提示词,而是将except块改为返回交易上下文不可用。CRM API未响应。而不是空字符串。

这一个更改很重要,因为它阻止了模型用自信的虚构内容填充静默的缺口。在追踪之前,你可能要花几天时间尝试复现一个时序bug并归咎于提示词;在追踪之后,你点击三个span就能找到损坏的工具。

5、这在生产中给你带来什么

一旦你以这种方式追踪Agent,模糊的抱怨就不再模糊。"机器人给了错误答案"变成了"检索器在第二步返回了三个不相关的块,LLM根据第三个块回答了问题,而防护栏没有发现它,因为它只检查PII"——这是一个工程团队可以真正修复的问题。

你还可以在正确的细节级别获得成本和延迟。每个LLM span都携带输入、输出和总token数量,因此你可以乘以你的每token价格来直接查看运行成本,而跨工具、检索器和模型span的延迟分割告诉你瓶颈是在你的基础设施还是模型调用本身。

导出选项在设计上保持广泛。源材料列出了用于自托管追踪视图的Jaeger和Grafana Tempo、用于统一基础设施加AI监控的Datadog、用于归档的S3/Azure Blob/GCS、用于流式事件的SQS和Pub/Sub,以及用于追踪到评估工作流的Future AGI Observe。

这里还有一个有用的运维模式。源文章中的一个团队在生产运行三个月后添加了traceAI,发现12%的检索调用因为过时的索引而返回空结果,而Agent一直用可信的幻觉掩盖这个问题。

这就是为什么我们认为追踪在黑客马拉松期间是可选的,在预发布阶段是明确的肯定,在生产中是不可协商的,而当你有多个Agent相互传递工作时是至关重要的。当你发布没有追踪的AI的那一刻,你不再调试一个你能看到的系统——你在等待用户先发现失败。


原文链接: Your AI Agent Is Failing Quietly, traceAI Shows You Where

汇智网翻译整理,转载请标明出处