Logfire
介绍¶
Logfire 是由 Pydantic 的创建者们推出的一个全新的可观测性平台。它几乎可以与许多您喜爱的库(如 Pydantic、HTTPx 和 Instructor)无缝集成。在本文中,我们将向您展示如何将 Logfire 与 Instructor 一起使用,以深入了解整个应用程序的性能。
我们将介绍以下示例:
- 使用 Instructor 对垃圾邮件进行分类
- 使用
llm_validator
执行简单验证 - 使用 GPT4V 从信息图表中提取数据并转换为 Markdown 表格
和往常一样,我们在此处引用的所有代码都可以在 examples/logfire 中找到,供您在项目中自由使用。
classify.py
: 电子邮件分类示例image.py
: GPT4-V 示例validate.py
:llm_validator
示例
配置 Logfire
在开始本教程之前,请确保您已注册 Logfire 账户。您还需要创建一个项目来跟踪这些日志。
在继续之前,我们需要安装依赖项并配置 Logfire 身份验证,因此只需运行以下命令即可。Logfire 将处理您项目的身份验证和配置。
分类¶
现在我们已经设置好了 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)
- 我们使用
logfire
添加 Pydantic 日志记录。请注意,您可以根据您的用例配置 Pydantic 记录哪些内容。 - 我们使用其 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}",
},
],
)
- 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)
日志立即为我们提供了一些重要信息:
- 代码中每个独立部分的运行时间
- 我们发送给 OpenAI 的有效载荷 (payload)
- 在每一步传递给代码中每个独立部分的精确参数和结果
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 通过 OpenAI 的 GPT-4V 从图像中提取结构化数据。我们将使用一个简单的条形图,并使用 GPT4V
从下面的 Statista 图片中提取数据,并将其转换为 Markdown 格式。
我们想要的结果是以下所示的合并数字:
国家 | 滑雪游客总数(百万) |
---|---|
美国 | 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",
}
),
]
- 我们指定此类型的类型应为 pandas 数据框
- 我们运行一个验证步骤,以确保我们可以将输入转换为有效的 pandas 数据框,并返回一个新的 pandas Dataframe 供模型使用。
- 然后我们覆盖模式 (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 调用的原始输入以及任何潜在的错误。