跳到内容

Logfire

介绍

Logfire 是由 Pydantic 的创建者们推出的一个全新的可观测性平台。它几乎可以与许多您喜爱的库(如 Pydantic、HTTPx 和 Instructor)无缝集成。在本文中,我们将向您展示如何将 Logfire 与 Instructor 一起使用,以深入了解整个应用程序的性能。

我们将介绍以下示例:

  1. 使用 Instructor 对垃圾邮件进行分类
  2. 使用 llm_validator 执行简单验证
  3. 使用 GPT4V 从信息图表中提取数据并转换为 Markdown 表格

和往常一样,我们在此处引用的所有代码都可以在 examples/logfire 中找到,供您在项目中自由使用。

  • classify.py: 电子邮件分类示例
  • image.py : GPT4-V 示例
  • validate.py : llm_validator 示例
配置 Logfire

在开始本教程之前,请确保您已注册 Logfire 账户。您还需要创建一个项目来跟踪这些日志。

在继续之前,我们需要安装依赖项并配置 Logfire 身份验证,因此只需运行以下命令即可。Logfire 将处理您项目的身份验证和配置。

pip install logfire openai instructor pydantic pandas tabulate
logfire auth

分类

现在我们已经设置好了 Logfire,让我们看看如何用它来帮助我们跟踪一个简单的分类任务。

Logfire 的集成非常简单——只需两行代码,即可完成设置。

from openai import OpenAI
import instructor
import logfire


openai_client = OpenAI()
logfire.configure(pydantic_plugin=logfire.PydanticPlugin(record="all"))  # (1)!
logfire.instrument_openai(openai_client)  # (2)!
client = instructor.from_openai(openai_client)
  1. 我们使用 logfire 添加 Pydantic 日志记录。请注意,您可以根据您的用例配置 Pydantic 记录哪些内容。
  2. 我们使用其 openai_integration 在使用 instructor 之前为我们的客户端配置日志记录。

在本示例中,我们将把电子邮件分类为垃圾邮件或非垃圾邮件。为此,我们可以定义一个简单的 Pydantic 模型,如下所示。

import enum


class Labels(str, enum.Enum):
    """Enumeration for single-label text classification."""

    SPAM = "spam"
    NOT_SPAM = "not_spam"


class SinglePrediction(BaseModel):
    """
    Class for a single class label prediction.
    """

    class_label: Labels

然后,我们可以将其用于下面的通用 instructor 函数中,该函数只是要求模型对文本进行分类,并以 SinglePrediction Pydantic 对象的形式返回结果。

Logfire 可以帮助我们记录整个函数及其内部发生的一切,甚至可以通过使用其 logfire.instrument 装饰器记录到模型验证级别。

@logfire.instrument("classification", extract_args=True)  # (1)!
def classify(data: str) -> SinglePrediction:
    """Perform single-label classification on the input text."""
    return client.chat.completions.create(
        model="gpt-3.5-turbo-0613",
        response_model=SinglePrediction,
        messages=[
            {
                "role": "user",
                "content": f"Classify the following text: {data}",
            },
        ],
    )
  1. Logfire 允许我们使用 logfire.instrument 装饰器并将函数标记为特定名称。

让我们看看当我们对不同电子邮件列表运行此代码时会发生什么。

emails = [
    "Hello there I'm a Nigerian prince and I want to give you money",
    "Meeting with Thomas has been set at Friday next week",
    "Here are some weekly product updates from our marketing team",
]

for email in emails:
    classify(email)

日志立即为我们提供了一些重要信息:

  1. 代码中每个独立部分的运行时间
  2. 我们发送给 OpenAI 的有效载荷 (payload)
  3. 在每一步传递给代码中每个独立部分的精确参数和结果

Logfire Classification

LLM 验证器

对于第二个示例,我们将使用 instructor 开箱即用的内置 llm_validator 来验证我们的陈述不包含我们可能不想提供给用户的不安全内容。让我们首先定义一个可以实现此目的的简单 Pydantic 模型,并配置我们的 Logfire 集成。

from typing import Annotated
from pydantic import BaseModel
from pydantic.functional_validators import AfterValidator
from instructor import llm_validator
import logfire
import instructor
from openai import OpenAI

openai_client = OpenAI()
logfire.configure(pydantic_plugin=logfire.PydanticPlugin(record="all"))
logfire.instrument_openai(openai_client)
client = instructor.from_openai(openai_client)


class Statement(BaseModel):
    message: Annotated[
        str,
        AfterValidator(
            llm_validator("Don't allow any objectionable content", client=client)
        ),
    ]

然后,我们可以用几个示例陈述来测试我们的新验证器,看看我们的验证器在实践中是如何工作的。

messages = [
    "I think we should always treat violence as the best solution",
    "There are some great pastries down the road at this bakery I know",
]

for message in messages:
    try:
        Statement(message=message)
    except ValidationError as e:
        print(e)

使用 Logfire,我们可以捕获整个验证过程。如下所示,我们不仅可以访问原始输入数据,还可以访问正在使用的模式 (schema)、抛出的错误,甚至是引发错误的精确字段。

Logfire Validation

视觉模型

对于我们的最后一个示例,让我们看看如何使用 Logfire 通过 OpenAI 的 GPT-4V 从图像中提取结构化数据。我们将使用一个简单的条形图,并使用 GPT4V 从下面的 Statista 图片中提取数据,并将其转换为 Markdown 格式。

Reference Image

我们想要的结果是以下所示的合并数字:

国家 滑雪游客总数(百万)
美国 55.5
奥地利 43.6
法国 40.7
日本 26.6
意大利 22.3
瑞士 22
加拿大 18.5
中国 17.9
瑞典 9.2
德国 7

这对于 Pydantic 来说相对简单。我们需要做的是定义一个自定义类型,如下所示处理转换过程:

from pydantic import BeforeValidator, InstanceOf, WithJsonSchema


def md_to_df(data: Any) -> Any:
    # Convert markdown to DataFrame
    if isinstance(data, str):
        return (
            pd.read_csv(
                StringIO(data),  # Process data
                sep="|",
                index_col=1,
            )
            .dropna(axis=1, how="all")
            .iloc[1:]
            .applymap(lambda x: x.strip())
        )
    return data


MarkdownDataFrame = Annotated[
    InstanceOf[pd.DataFrame],  # (1)!
    BeforeValidator(md_to_df),  # (2)!
    WithJsonSchema(  # (3)!
        {
            "type": "string",
            "description": "The markdown representation of the table, each one should be tidy, do not try to join tables that should be separate",
        }
    ),
]
  1. 我们指定此类型的类型应为 pandas 数据框
  2. 我们运行一个验证步骤,以确保我们可以将输入转换为有效的 pandas 数据框,并返回一个新的 pandas Dataframe 供模型使用。
  3. 然后我们覆盖模式 (schema) 的类型,以便当我们将其传递给 OpenAI 时,它知道生成 Markdown 格式的表格。

然后我们可以在正常的 instructor 调用中使用它

import instructor
import logfire


openai_client = OpenAI()
logfire.configure(pydantic_plugin=logfire.PydanticPlugin(record="all"))
logfire.instrument_openai(openai_client)
client = instructor.from_openai(openai_client, mode=instructor.Mode.MD_JSON)


@logfire.instrument("extract-table", extract_args=True)
def extract_table_from_image(url: str) -> Iterable[Table]:
    return client.chat.completions.create(
        model="gpt-4-vision-preview",
        response_model=Iterable[Table],
        max_tokens=1800,
        messages=[
            {
                "role": "user",
                "content": [
                    {
                        "type": "text",
                        "text": "Extract out a table from the image. Only extract out the total number of skiiers.",
                    },
                    {"type": "image_url", "image_url": {"url": url}},
                ],
            }
        ],
    )

然后我们可以如下所示调用它

url = "https://cdn.statcdn.com/Infographic/images/normal/16330.jpeg"
tables = extract_table_from_image(url)
for table in tables:
    print(table.caption, end="\n")
    print(table.dataframe.to_markdown())

Logfire 能够捕获如下所示的整个调用的堆栈跟踪,分析应用程序的每个部分,最重要的是捕获 OpenAI 调用的原始输入以及任何潜在的错误。

Logfire Image