作者:计缘
AI 应用观测体系
上一篇内容我们重点分析了 AI Agent 如何合理地、生产级地与 LLM 结合。
在 AI 时代,随着模型和应用侧的快速演化,对于推理过程,成本和性能显得尤为重要,而端到端的 AI 可观测是其中至关重要的一环,当前的 AI 应用生态主要可以分为三个方面:
- 第一个是模型,以 DeepSeek, Qwen 等为代表的模型正在快速追进国外的 OpenAI,Claude 等模型的能力。
- 第二个方面是开发框架,AI 应用当前以 Python 语言为出发点,从最早一代的 LangChain、LlamaIndex,这一批框架主要以高代码为主要形态,而在其他语言方面也逐步涌现出各种开发框架,例如 Java 的 Spring AI Alibaba 等都在快速对齐 Python 生态的能力。而以 Dify、Coze 这样的低代码开发平台,也成为 AI 应用一种快速的载体,AI 应用相比传统的微服务来说,特点更加轻量化,因此低代码开发也非常适合这类开发场景。在开发 AI 应用的过程中也需要 MCP/Tools,向量数据库等配套的服务设施。
- 第三个方面则是 AI 应用,从最开始的聊天机器人,到编程 Copilot,再到通用的智能体 Agent,可以说是百花齐放,层出不穷。
AI 应用遇到的问题
在 AI 应用的开发的时候,主要会面临哪些痛点呢?主要总结了以下三个方面。

第一个就是怎么把它用起来。第二个是要用的省,第三个是用得好。
-
用起来的问题。我们发现最大的问题就是,其实很容易能够基于一个开源的框架去搭建一个 AI 应用,比如聊天机器人,或者类似的 AI Agent,但是我们发现同一个问题问他两三次的话,每次的回答都不一样,这时候我们就会困惑,到底是哪里有问题,或者说我同样的提示词,同样的应用,换了一个模型,怎么回答的效果就大打折扣了。再有,突然这个模型某一次的推理请求或者用户的请求发过去,怎么回答就卡住了,或者响应怎么老是回不来。所以,真正把这个 AI 应用从我们是第一步去做 PoC,或者去做一些 demo,到我们真正把它真正的用到生产实践里面,还是会有非常遇到非常多的问题。
-
用起来之后,我们就要考虑用的省的问题。大家都知道这个模型的调用是会消耗 token 的。我们每一次的调用到底消耗多少 token,到底是哪些请求消耗了比较多的 token,到底是哪些 AI 应用在消耗比较多的成本?其实我们是希望能够一目了然地知道它的成本情况,帮助我们去做整体的一个运营规划。
-
需要解决用得好,也就是数据质量的问题,我们构建出来的 Agent 使用了各种各样的模型能力,但是它的回答到底质量好不好,是不是在我们预期的范围内,有没有一些不合理的不合规的回答,都是我们需要去关注的。
AI 应用典型框架
基本上我们就在解决这三个问题,通过一些可观测性的手段去解决这三个问题。在解决问题之前,先介绍下我们的 AI 应用开发里面一个典型的应用架构。

基本上可以划分为 3 个大板块,从用户业务层,到 AI 应用层,也就是我们的 AI Agent(图中中间这部分),到我们的模型服务层。首先我们从用户界面进来,可以通过 iOS、Android、小程序等入口进来,我们的生产环境里面会有一个 API 网关来完成流量的防护,API 管理能力,这和传统微服务是一致的,这里的 API 网关可以通过像开源的 Higress 的能力,能够去帮大家做统一 API 管理。流量从 API 网关进入到 AI 应用层,我们有各种用 Python 或者 Java 编写的应用程序。这些程序会去调用不同的模型,从模型的高可用以及对比层面,我们通常会部署多个模型,然后根据一定的策略,在各种模型之间做一些切换,例如按照成本,按照重要程度,按照流量策略,分别调用不同的模型。这个时候,就需要一个统一的代理来实现通用的能力,也就是我们这里展示的 AI 网关。它可以去帮助我们做统一的流量防护,Token 的限流,以及敏感信息的过滤,模型内容的缓存等等。这样的话,AI 应用就不需要感知在多个模型中去做各种切换了。
我们首先要解决的是一次调用到底经过了哪些组件,通过调用链把这些组件全部串联起来。要实现全链路的诊断,首先要把这些链路能打通,一个请求出现问题的时候,到底是哪个环节出问题了,是在 AI 应用出问题了,还是这个模型内部推理出现了问题,我们需要能够快速定界。
第二需要构建一个全栈的可观测数据的平台,它能够把所有的这些数据,不仅是链路,还包括指标,例如模型内部的一些 GPU 利用率,数据之间能够很好关联起来,通过关联分析能够去知道到底是应用层出问题,还是模型底层出问题了。
最后我们还需要通过一些模型日志,了解每次调用的输入输出是什么,并利用这些数据做一些评估和分析,来验证 AI 应用的质量。
AI 全栈统一观测
从这三个手段入手,从监控的这个领域来说的话,我们在不同的层面上提供了不同的一些观察手段和核心的关注点。

例如在用户层的话,我们可能通常需要分析会话是不是有卡顿,对用户体验是否造成了影响。在应用层里面,我们通常会关注响应的耗时,是否出现了异常,还有推理的延时等等。在网关层面,或者依赖的一些组件,包括 MCP/Tools,以及一些其他的向量数据库等,我们会去关注它的一些可用性,在模型服务层,我们通常会关注它的推理的效果和成本,最好在基础设施这层,我们会关注这些资源的一些利用率,缓存的一些命中率的一些情况。
在阿里云,我们提供了一套完整的全栈解决方案,来确保整体观测是没有盲区的。

从最底层智算服务器,提供基础设施的监控能力,到通过容器服务自行部署的一些模型能力,再到 AI 平台像 PAI 这样的 PaaS 产品,覆盖了从训练到推理的各个阶段,到像百炼这样的大模型服务平台 MaaS,以及再往上到 AI 应用开发,都能够有一个从上到下的立体化的一个全栈的可观测的能力。
最佳实践
Trace 全诊断能力
接下来的话,给大家介绍一下具体的一些实践。第一个就是基于 Trace 的全链路诊断能力,如何去打通刚才说的全链路调用的。我们基于 OpenTelemetry 这套追踪的规范,从用户端侧开始,到 API 网关,到 AI 应用层,到 AI 网关,再到模型层,都进行了埋点,这些有一部分是手动的埋点,比如网关层,在应用层和模型内部层采用的是无侵入的自动埋点,最终把各个环节的追踪数据,上报到阿里云的可观测平台。

在 AI 应用内部,我们对常用的 AI 开发框架都进行了埋点,其实一个典型的 AI 应用内部的流转还是非常复杂的,包括 RAG,工具的使用,以及模型调用等多种复杂场景,我们会针对这些关键的节点进行埋点,能够抓取到每一步的详细执行过程。无论应用采用 Python 还是 Java 进行开发,我们可以通过一些无侵入的方式,挂载可观测数据采集的探针,挂载到 Python 或者 Java 程序里面,去采集 AI 应用本身内部的一些实现细节。另外,在模型推理阶段,它底层其实也是一个 Python 程序在运行,我们发现数据采集探针也可以部署到模型推理层,去采集了很多模型内部推理过程的一些信息。因此我们能够从这个用户终端开始到模型最底层推理这一条整个链路给串起来。

在这个过程中,由于 AI 应用的迭代速度非常快,OpenTelemtry 社区的语义规范也在不断演进,我们基于社区的规范和内部的实践,定义了一套面向 AI 应用的一个语义规范,这个规范其实可以理解为我们需要采集哪些指标,在调用链中需要记录哪些数据,将他们以怎样的形式存储下来。在此基础上,我们也在跟社区紧密沟通,把我们的一些能力也往社区去反馈和贡献。

跟传统微服务应用所关注的黄金三指标(请求数,错误,耗时)相比,AI 应用的黄金三指标是什么?可能是 Token,Error,Duration。耗时主要关注的是模型推理延迟,比如就是在推理过程中,我们通常需要关注模型的首包延迟,就是叫做 TTFT(Time to first token),这个指标反映了相应的速度,还有像 TPOT 反应的生成的效率和流畅度,在下面的内容会具体介绍。
Token 可能是 AI 应用最重要的一个指标,每次请求会记录 Token 的消耗情况,甚至我们需要精确地区分 Input token 和 Output token 的消耗情况,到底为什么呢?因为大家知道模型的定价里面 input token 的 output token 的定价都是不一样的,我们在成本核算的时候,会将输入 token 和输出 token 分别进行统计。还有像系统的利用率,包括 GPU 使用率,模型 KV 缓存的命中率等。在每一个领域,都会有一些比较黄金的指标。
接下来重点介绍下,在模型推理阶段比较重要的两个关键指标,TTFT 和 TPOT,这两个东西其实分别反映了模型推理时两个关键阶段的性能。

模型推理时有两个核心的阶段,第一个叫 Prefill,其实就是在我们把提示词输入给模型的时候,它会把提示词作一个输入,然后去进行 tokenize,也就是把你的那些自然语言变成一个模型的 token,然后这些 token 之间会计算它的一些相似度,然后把它的结果保存在一个 KV Cache 里面,从input 到了模型,然后模型吐出第一个 token 为止,这个阶段叫做 Prefill。TTFT,就是首包延迟时间,是衡量这个阶段的耗时,去衡量我们的推理效率的一个非常核心的指标。
第二个阶段就是在吐出第一个 token 以后,接下来每一个新的 token 都需要把这个 token 的过去生成的那些结果作为一个输入,再喂给模型,然后计算下一个 token,它是一个不断迭代的过程。所以他这个过程中会有模型的推理过程,会有一些缓存,能够帮我们去缓存中间的结果。从第二 token 开始到最后一个 token 出来,整个阶段就是我们叫做 decode,这是第二个比较重要的阶段。在这里面它每一个 token 出来的平均间隔时间,我们叫做 TPOP(Time Per Output Token)。TTFT + TPOT *(总 token 数 -1),基本就能推导出推理的关键耗时。
针对单个请求来说,最关注的就是这两个指标,一个 TTFT,一个 TPOT。然后还有一个指标比较重要的就是我们的吞吐率。吞吐率的话其实就是衡量我们这个模型本身,同时能够去支撑多少个推理请求。所以这几个指标它是有一些平衡在里面,也不可能就是这三个指标同时满足的特别好。比如说在线推理的场景下,我们会通常会关注更快的 TTFT 和 TPOT。但是在离线分析的时候,我们可能一批一批量会为给模型一批数据他去做分析。我们希望模型能够提供更好的吞吐率,而 TTFT 反而就没有那么关注了。这些关键指标,我们都会采集上报上来,并且重点展示出来。

接下来介绍下我们是如何实现对上述数据的采集的。作为一个 Python 程序,它其实有一些机制能够让我们去实现一个无侵入的一个埋点,我们的方案基本上基于这个 OpenTelemetry 的 Python agent 为底座,然后在上面做了一些扩展和增强,首先就是我们对于一些常用的国内的一些开发框架,比如说国内比较流行的 Dify、LangChain 或者 LlamaIndex 等框架进行了埋点的支持,使得我们通过无侵入的方式能够把这些数据信息给采集上来。其次,我们在开源探针的基础上,做了一些稳定性和性能优化的一些事情,能够帮助探针以一个非常低成本的方式进入到 AI 框架的工作流程里面,去采集到各种各样的想要的那些调用链、指标和日志等信息。
这里是对探针的埋点原理的一个简单的介绍。

左边是一个 Python 程序,简单的 hello 方法。Python 语言,它本身提供了一个叫做 monkey patch 的一种机制,允许我们的程序在运行的时候去动态地修改一个函数,包括它的属性和方法。所以我们只需要去在它的外层重新定义一个包装的方法,这个方法可以在原始方法执行前后做一些事情。这有点像我们在设计模式中见到过的装饰器模式。
这个 hello 就是原始的方法定义,Python 程序运行的初始化的阶段,可以把原来那个函数的类似于引用给替换掉。实际执行的就是替换后的包装方法。在包装后的方法里面,还会去调原来的那个方法。最后的结果,就像第 4 步看到的,可以实现在原始的方法的前后去插入一些我们想要的一些逻辑。然后通过这种方式,我们就能够实现一个在用户的代码不修改的情况下去采集各种数据。
那阿里云提供的 Python 探针能力和开源的有什么区别呢?

第一个就是我们在刚才说的在 AI 应用开发框架中,在一些常见的开发框架的支持上是最为全面的,包括大模型的一些核心指标。TTFT/TPOT 等指标,以及在模型的输入输出这些数据上,做了一个非常完整的支持,包括流式场景下的数据采集能力也是完整的支持。
另外,我们还支持一些生产实践上的特性,很多 Python 应用会使用多进程来提升并发度,例如 unicorn 或者 gunicorn。在这种模式下,开源的 OpenTelemetry 探针在支持上面都会有一些问题,某些场景下挂载了探针之后有可能导致应用无法启动,或者数据无法采集等等一些问题。在更严重的情况下,它可能还会把一些进程给搞挂。另一方面,很多 Python 进程还会使用 gevent 来实现协程,来进一步提高程序整体的吞吐率,比如 Dify 就会使用这个能力。当开了 gevent 能力之后,开源的 OTel 探针,会让这个进程卡住,业务无法工作,更不要说去采集数据了等等一系列问题。这些场景下我们都提供了完整支持。基本上能够让这些 Python 程序很好的在生产实践上能够部署起来,能够比较安全稳定地采集可观测数据。

此外,针对流式上报的场景,我们也做了一些优化。在阿里云的内部很多业务也使用了这个数据采集的探针,当一些大流量的场景下,比如网关想要去采集这个流式的数据,模型的返回结果可能是比较大的,一次调用可能会有几千上万个 token 产生,流式场景下 token 是一批一批的返回的,如果要完整的采集输入输出,需要在网关中去缓存这些 token 数据,一直等到结束以后再把数据往上报,在高并发的情况下,这种方式会对我们的应用有一些内存占用造成一些压力,因此我们也做了一些优化方案,将数据进行拆分上报,把这些数据分批地上报到服务端,然后在服务端把这些内容再组合还原,起到降低内存占用的效果。
Dify 生产级部署应用

接下来专门介绍下 Dify 这块的实践。就我们目前接触下来,大量的开发者都在使用 Dify 做这个 AI Agent 的开发平台,包括我们内部也用到了 Dify,给大家分享下在生产中遇到的一些问题以及建议。
首先简单介绍下 Dify 的系统架构。请求从前端进来,通过 Nginx 反向代理,达到 API 后端,这个后端是由 Flask 部署的后端。这个 API 后端会将一些复杂的任务,放到 Redis,再由另外一个 worker 组件去执行这些后台任务,同时把一些数据存储在对象存储和 PGSQL 当中。
-
在做 RAG 的过程中,在上传一些文档的时候,有时候会超过 Nginx 默认的上传的限制,此时建议的话是调大 NGINX_CLIENT_MAX_BODY_SIZE 这个值。
-
就是数据库的连接池,Dify 的 workflow 在运行的时候,一个请求就会一直保持一个数据库连接,Dify 默认的这个 PGSQL 的连接池的大小是比较小的。如果一旦那个连接打满了,就会出现整个业务卡住的这个情况。当平台上运行的应用任务变多的时候,很容易出现连接池打满的情况,所以我们建议的话是把这个 PGSQL 的数据库连接池调大到 300 或者以上。
-
Dify 中的 Redis 同时承担了两个职责,一个是做缓存,同时也做消息堆列,可以使用 Redis 的哨兵模式来提升高可用性。同时,我们通过挂载探针,采集到的数据,也观察到它的架构上使用不合理的地方,比如通过 Redis 去管理任务的时候,一次 workflow 的请求,实际我们观察到可能会访问上千次 Redis,原因是 Dify 一直在轮询 Redis,去获取这个任务的状态是否结束。这个本质上就是一个消息队列,是一个非常常用的场景,完全可以用消息队列去实现它。只要在这个任务结束之后发一个消息,然后另外的一个组件就可以去直接消费它,不需要去频繁地查询 Redis。我们建议在大规模的场景下,用这个消息队列 RocketMQ 来替换 Redis。
-
Dify 内部使用的是存放在本地的,也建议替换为第三方向量数据库,还有内置的一些存储,其实在高可用性,稳定性上面都是有问题的,建议替换为云存储。
-
最后是可观测性,Dify 本身内置的一定的可观特能力。开启之后,每次执行一个 workflow,都能看到每一个阶段它的一个耗时这些情况。但是这个功能需要每个应用单独去配置。然后,观测维度上相对比较单一,就是在 workflow 的每一步能观测到,但如果这个程序又跟外部的一些微服务,比如说传统的 Java 应用互相调用的话,或者调用了模型侧的能力,它的调用链就没法串起来的,也就是数据相对比较孤立。另外,它的可观测性的数据是存到 PGSQL 数据库中,在规模量很大的时候,它的查询效率也很低,如果要去拉长时间去查询,结果会发现查询会非常卡。

使用阿里云的探针在采集可观测数据,可以解决上述的问题,一次接入,所有应用全体生效,并且支持将多个 APP 的观测数据进行拆分。同时,基于 OpenTelemetry 可以将 Dify 内部的流程和外部的微服务调用和模型推理完整的穿起来,包括每个流程的 input/output 和 token 消耗,能够支持多层级的全局维度进行分析,并且解决了高可用和稳定性的问题。我们在实践的过程中发现,当 Dify 开启 gevent 协程的时候,挂载开源的探针会造成程序 hang 住业务无法继续运行的问题,对业务造成了严重的影响,我们也解决了这个问题,能够让业务低成本稳定的采集可观测数据。
针对模型推理这一侧,我们也进行了可观测数据的采集,能够观测到模型内部推理过程中的细节。目前市面上开源的 vLLM 和 SGLang 这两个比较著名的推理加速框架,通过内存分块,KV 缓存复用等方式大幅度模型的推理的效率。

由于它本身也是一个 Python 程序,我们可以用同样的方式去观测采集到 vLLM 内部的流转的细节,去采集到它内部的一些执行路径,能够采集到调用链和前面提到的核心指标例如 TTFT 和 TPOT 等。这里也介绍一个通过我们的可观测能力定位问题的真实案例,某个业务通过 AI 网关发现调用自建的 Deepseek 模型耗时特别高的场景。
首先通过全链路追踪,分析调用链能够看到定位到底是哪一个阶段的问题,由于 Dify 和模型都接入了探针,通过耗时分析发现不是应用层的问题,而是模型推理那一层的问题。然后再看模型侧的一些黄金指标,包括 TTFT 和 TPOT,发现都比较正常。那再进一步的检查,由于我们记录了单个推理请求运行相关的信息,包括推理引擎里面的一些排队的情况,可以发现当时这个请求本身在推理引擎里面在排队,所以确认是这个推理请求排队导致的耗时升高。解决办法就是调大推理引擎中请求队列的大小配置,所以通过这个可观测性,我们就能够定位到一些推理的根本原因,同时指导下一步的动作和建议。
基于大模型生成结果评估

然后接下来讨论一下这个模型的质量的问题,我们想要解决模型回答得好不好,每次模型的升级和优化,我们都需要建立一个基线,并且确保模型的迭代满足这个基线,否则回答的质量会导致用户体验的受损。为此,我们把模型的 input/output 全部都采集到阿里云的日志平台中,然后接下来我们可以拆选出一批记录,通过一些数据加工,引用外部的裁判员模型,对当前这个模型的回答的输入输出结果进行一个评估。
这个评估我们有一些系统内置的评估模板,当然未来也支持自定义的评估模板,比如说我们可以去分析这个模型的回答到底有没有敏感词,有没有幻觉,有没有 MCP 投毒攻击等等情况。

大概的效果如上图所示,比如说我们的这个提示词是这样的,然后它去调一个模型,这是模型返回的结果。然后我们可以从一个模型的模板去评估它是不是正确地回答了这个问题,它的回答到底靠不靠谱,是否有毒等等。然后我们还可以对评估的结果进行一些分类和聚类。也就是说可以对这些结果,进行一些语义化的标签的孵化。比如说这个模型的可能这次回答同时是一个友善的回答,属于一个文化类的问题等等。
最后聊一聊 MCP 的问题,MCP 解决了 AI 应用调用 Tools 的标准化问题。在实践 MCP 的过程中,我们也发现有一个很大的问题,我们叫做 MCP 的 Token 黑洞问题。

这个最核心的问题就是当我们构建了一个使用 MCP 工具的 AI Agent,当输入问了一个问题,模型最终给出了一个回答,这个回答可能能耗 1000 个 token。但实际上他背后可能掉了几十次模型,背后调用非常多的 MCP tools,实际消耗了可能有上万个 token。如果我们只看最终它的输出,很容易忽略背后的细节,而中间的计算过程,每次和模型的对话,都会把历史的对话以及 MCP tools 的调用结果,一起作为 input 再发给大模型,这个过程是不断叠加的,次数越多消耗的 token 越大。因此我们非常需要 MCP tools 的可观测性,需要采集到每一个 MCP tools 的调用的耗时,消耗的 token 情况。
这是阿里云的云监控 2.0 平台,这是我们的大模型可观测产品页面。我们提前部署了一个 Dify 应用,并预先编排了一些 workflow,并且挂载了探针,接入了云监控 2.0 平台,可以看到应用概览,能够展示模型的调用次数,Token 消耗,调用排行等信息。

查看关联的拓扑信息,从 Client 到 Dify,再到 vLLM 部署的一个 7b 模型都看到关联关系,并且支持进一步的下钻。

调用量分析视图,能够看到 input/output 的情况,Dify 中 workflow 的每一步执行情况,这里的每一步都对应了 Dify 中的一个流程,以及 vLLM 内部的推理执行情况。

这个 vLLM 7b 的模型是部署在 PAI 平台上的,通过实体关联,可以进一步分析 PAI 底层模型的指标信息,例如 GPU 利用率,KV cache 命中率等。

通过会话分析,展示多轮对话的每一个轮的对话详情。

通过外部裁判员模型对历史的模型输入输出,进行评估。

对模型的回答进行语义提取,并进行聚类展示。

到这里,这个系列的内容我们就要暂告一个段落了。如果您关于企业 AI 应用落地实践,还有什么希望讨论的话题,欢迎通过文章留言告诉我们。
关注阿里云云原生公众号,后台回复"企业AI实践"获得我们整理的完整的企业级 AI 应用构建的最佳实践 PPT,配合系列文章一起食用,效果更佳。