跳至主要内容

遥测

TaskWeaver 现在支持通过 OpenTelemetry 进行追踪,这是最受欢迎的开源可观测性框架之一。通过该功能,您可以追踪以下内容:

  • 角色之间的交互,即规划者(Planner)、代码解释器(CodeInterpreter)和执行器(Executor)。
  • TaskWeaver中每个角色和主要组件所消耗的时间。
  • 发送给大语言模型的提示词以及从大语言模型接收到的响应。
  • 任务状态及遇到的错误。
  • 每个角色消耗的令牌数量。

以下截图展示了一个简单任务的追踪过程:分析上传的文件。

Tracing

从这个视图,你可以看到任务执行的时间线,主要分为三个部分:

  • 规划阶段,Planner决定需要执行的子任务。
  • 代码生成与执行阶段,其中CodeGenerator负责生成代码,CodeExecutor负责执行代码。
  • 回复阶段,Planner将回复发送给用户。

带有黑线的条形图表示任务执行的关键路径,这是贯穿任务执行的最长路径。这有助于识别任务执行的瓶颈。我们可以清楚地看到,当前任务执行主要由对LLM的调用所主导。

我们可以点击span(追踪中的一个工作单元)查看其详细信息,包括日志和属性。

以下截图展示了Planner回复函数跨度的详细信息:

Tracing Prompt

从这个视图可以看到用户查询、发送给大语言模型的提示词,以及大语言模型消耗的token数(prompt_size和output_size)。 我们还记录了生成的代码、不同角色之间的交互记录等追踪信息。

此外还有追踪的不同视图,例如调用图视图,它展示了各个跨度的调用层级关系。 以下是该追踪的调用图:

Tracing Call Graph

如何启用追踪

默认情况下跟踪功能是禁用的。要启用跟踪,您需要安装OpenTelemetry所需的软件包。 请查看OpenTelemetry网站获取安装指南。 基本上需要安装opentelemetry-apiopentelemetry-sdkopentelemetry-exporter-otlpopentelemetry-instrumentationtiktoken软件包。 要计算任务执行期间消耗的token数量,您还需要安装tiktoken软件包。 目前我们仅支持OpenAI模型的tokenizer。 安装完这些软件包后,您可以通过在项目配置文件中设置tracing.enabled=true来启用跟踪功能。 默认的tokenizer目标模型是gpt-4,如果想使用其他模型,可以在项目配置文件中设置tracing.tokenizer_target_model。 您可以在tiktoken代码中找到可用的模型列表。

项目配置文件中典型的追踪配置如下:

{
"tracing.enabled": true,
"tracing.exporter": "otlp",
"tracing.endpoint": "http://127.0.0.1:4317",
"tracing.tokenizer_target_model": "gpt-4"
}

接下来,我们需要搭建追踪功能的基础设施。下图展示了一个简易追踪系统的架构。 这是一个演示系统,数据不会被持久化。在实际应用场景中,您需要搭建更健壮的系统。 TaskWeaver代码中的埋点功能会将追踪数据和指标发送到OpenTelemetry收集器。 OpenTelemetry收集器是一个接收来自埋点的追踪数据和指标、进行一些处理、并将其导出到 另一个收集器或后端的组件。在本例中,我们将收集器配置为将追踪数据导出到Jaeger后端,将指标 导出到Prometheus后端。 Tracing Architecture

您可以运行以下命令来设置基础设施:

cd /TaskWeaver/tracing
docker-compose up

您将看到来自容器的一堆日志。 请查看日志以检查是否存在任何错误。 如果未发现错误,您可以通过http://localhost:9090访问Prometheus前端,通过http://localhost:16686访问Jaeger前端。 在此设置中,我们假设您在与TaskWeaver相同的机器上运行容器。 如果您在不同机器上运行容器,则需要在TaskWeaver配置文件中配置OpenTelemetry收集器的端点。 默认端点为http://127.0.0.1:4317,您可以在项目配置文件中设置tracing.endpoint来更改端点地址。

追踪基础设施配置

Jaeger和Prometheus都是流行的开源监控系统。我们已准备了一个docker-compose文件用于在/TaskWeaver/tracing_configure/docker-compose.yaml中搭建基础设施。 该文件内容如下:

version: '3'
services:
optl-collector:
image: otel/opentelemetry-collector:0.96.0
command: ["--config=/etc/collector-config.yaml"]
volumes:
- ./collector-config.yaml:/etc/collector-config.yaml
ports:
- "4317:4317" # Expose the gRPC receiver port for the collector
depends_on:
- jaeger

jaeger:
image: jaegertracing/all-in-one:1.54
ports:
- "16686:16686" # Jaeger UI

prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090" # Prometheus UI
volumes:
- ./prometheus-config.yml:/etc/prometheus/prometheus.yml
command: ["--config.file=/etc/prometheus/prometheus.yml"]
depends_on:
- optl-collector

如果查看该文件,可以看到我们使用otl/opentelemetry-collector镜像来设置OpenTelemetry收集器, 我们仅对外暴露收集器的gRPC接收端口4317。 收集器配置文件是collector-config.yaml,该文件被挂载到容器中。 配置文件内容如下:

receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318


exporters:
debug:
verbosity: detailed
otlp:
endpoint: "jaeger:4317"
tls:
insecure: true
prometheus:
endpoint: "0.0.0.0:9464"

service:
pipelines:
traces:
receivers: [otlp]
exporters: [otlp]
metrics:
receivers: [otlp]
exporters: [prometheus]
logs:
receivers: [otlp]
exporters: [debug]

由于Jaeger兼容OpenTelemetry收集器,我们可以通过设置otlp导出器将追踪数据发送到Jaeger。 同时通过设置prometheus导出器将指标数据发送到Prometheus。 prometheus-config.yml文件是Prometheus的配置文件,内容如下:

scrape_configs:
- job_name: optl-collector
scrape_interval: 5s
static_configs:
- targets: ["optl-collector:9464"]

我们仅从OpenTelemetry收集器中抓取指标数据。

如何查看指标

在第一部分中,我们已经解释了如何在Jaeger前端查看追踪记录。 在Prometheus前端查看指标更为复杂,因为每个指标都是一个时间序列。 时间序列是一系列通常带有时间戳的数据点。 OpenTelemetry允许为指标添加属性,以便您可以根据属性筛选指标。 在我们当前的实现中,只有一个名为prompt_size的指标,它记录发送给LLM的提示大小。 在Prometheus中,您应该能看到prompt_size指标的时间序列,即prompt_size_totalprompt_size_total是所有追踪记录中单调递增的累计提示大小。

我们用一个名为direction的唯一属性来标注轨迹,该属性可以是inputoutput。 它们分别表示输入提示的大小和LLM响应的输出大小。

Tracing Metrics

您可以在Prometheus前端查询指标数据。查询语言称为PromQL,功能非常强大。 您可以参考Prometheus文档了解该查询语言的详细信息。 上方图表的查询语句是increase(prompt_size_total[10m]), 表示显示过去10分钟滑动窗口内令牌消耗的增长量。

如果您想使用Grafana来可视化指标数据,可以设置一个Grafana实例并将Prometheus添加为数据源。 这可以通过在docker-compose.yaml文件中追加以下内容来实现:

    grafana:
image: grafana/grafana-enterprise:latest
ports:
- "3000:3000" # Grafana UI
environment:
- GF_SECURITY_ADMIN_PASSWORD=secret # You should change 'secret' to a password of your choosing
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
- grafana_data:/var/lib/grafana
depends_on:
- prometheus

volumes:
grafana_data:

如何自定义追踪

TaskWeaver的插装功能是通过OpenTelemetry Python SDK实现的。 因此,如果您想自定义追踪功能,需要修改TaskWeaver的代码。 在TaskWeaver中,我们对OpenTelemetry SDK添加了一层抽象, 以便更容易将OpenTelemetry SDK的细节与TaskWeaver代码隔离。 您可以在taskweaver.module.tracing模块中找到这个抽象层。

taskweaver.module.tracing模块中,我们定义了Tracing类, 这是OpenTelemetry SDK的一个封装。该Tracing类提供以下方法:

  • set_span_status: 设置span的状态。
  • set_span_attribute: 设置span的属性。
  • set_span_exception: 设置跨度的异常。
  • add_prompt_size: 将提示大小添加到跨度中。

此外,我们定义了装饰器tracing_decorator(或其非类版本tracing_decorator_non_class)来追踪函数调用。 当需要创建追踪上下文时,您可以使用

with get_tracer().start_as_current_span("span_name") as span:
# your code

当你需要追踪一个函数时,可以使用

@tracing_decorator
def your_function(self, *args, **kwargs):
# your code